diff --git a/main/src/ipc/daemonRegistryBindings.test.ts b/main/src/ipc/daemonRegistryBindings.test.ts new file mode 100644 index 00000000..7d39b37e --- /dev/null +++ b/main/src/ipc/daemonRegistryBindings.test.ts @@ -0,0 +1,121 @@ +import { describe, expect, it, vi } from 'vitest'; +import { PaneCommandRegistry } from '../daemon/commandRegistry'; +import { registerFileHandlers } from './file'; +import { registerProjectHandlers } from './project'; +import { registerPromptHandlers } from './prompt'; +import type { AppServices } from './types'; + +vi.mock('../services/panelManager', () => ({ + panelManager: {}, +})); + +const PROJECT_CHANNELS = [ + 'projects:get-all', + 'projects:get-active', + 'projects:create', + 'projects:activate', + 'projects:update', + 'projects:delete', + 'projects:reorder', + 'projects:detect-branch', + 'projects:list-branches', + 'projects:refresh-git-status', + 'projects:get-running-script', + 'projects:stop-script', + 'projects:detect-config', + 'projects:resolve-run-script', + 'projects:run-script', +] as const; + +const PROMPT_CHANNELS = [ + 'sessions:get-prompts', + 'prompts:get-all', + 'prompts:get-by-id', +] as const; + +const FILE_CHANNELS = [ + 'file:read', + 'file:read-binary', + 'file:exists', + 'file:write', + 'file:write-binary', + 'file:getPath', + 'git:commit', + 'git:revert', + 'git:restore', + 'file:readAtRevision', + 'file:list', + 'file:delete', + 'file:rename', + 'file:move', + 'file:copy', + 'file:duplicate', + 'file:search', + 'file:read-project', + 'file:write-project', + 'git:execute-project', + 'file:resolveAbsolutePath', +] as const; + +interface IpcMainStub { + boundChannels: string[]; + handle(channel: string, listener: (_event: unknown, ...args: unknown[]) => unknown): void; +} + +function createIpcMainStub(): IpcMainStub { + const boundChannels: string[] = []; + + return { + boundChannels, + handle(channel: string) { + boundChannels.push(channel); + }, + }; +} + +function createServicesStub(): AppServices { + return { + sessionManager: {}, + gitStatusManager: {}, + configManager: {}, + databaseService: {}, + worktreeManager: {}, + analyticsManager: {}, + } as AppServices; +} + +describe('daemon registry IPC bindings', () => { + it('binds daemon-owned project channels through the shared registry', () => { + const registry = new PaneCommandRegistry(); + const ipcMain = createIpcMainStub(); + + registerProjectHandlers(ipcMain, createServicesStub(), registry); + + expect(registry.listChannels()).toEqual([...PROJECT_CHANNELS].sort()); + expect(ipcMain.boundChannels.sort()).toEqual([...PROJECT_CHANNELS].sort()); + }); + + it('binds daemon-owned prompt channels through the shared registry', () => { + const registry = new PaneCommandRegistry(); + const ipcMain = createIpcMainStub(); + + registerPromptHandlers(ipcMain, createServicesStub(), registry); + + expect(registry.listChannels()).toEqual([...PROMPT_CHANNELS].sort()); + expect(ipcMain.boundChannels.sort()).toEqual([...PROMPT_CHANNELS].sort()); + }); + + it('keeps file manager shell adapters outside the daemon registry surface', () => { + const registry = new PaneCommandRegistry(); + const ipcMain = createIpcMainStub(); + + registerFileHandlers(ipcMain, createServicesStub(), registry); + + expect(registry.listChannels()).toEqual([...FILE_CHANNELS].sort()); + expect(ipcMain.boundChannels).toContain('file:showInFolder'); + expect(ipcMain.boundChannels.filter(channel => channel !== 'file:showInFolder').sort()).toEqual( + [...FILE_CHANNELS].sort(), + ); + expect(registry.has('file:showInFolder')).toBe(false); + }); +}); diff --git a/main/src/ipc/file.ts b/main/src/ipc/file.ts index bb3d746e..9ae70d05 100644 --- a/main/src/ipc/file.ts +++ b/main/src/ipc/file.ts @@ -1,9 +1,11 @@ -import { IpcMain, shell } from 'electron'; +import type { IpcMain } from 'electron'; +import { shell } from 'electron'; import * as fs from 'fs/promises'; import * as fsSync from 'fs'; import * as path from 'path'; import { execFileSync } from 'child_process'; import { glob } from 'glob'; +import type { PaneCommandRegistry } from '../daemon/commandRegistry'; import type { AppServices } from './types'; import type { Session } from '../types/session'; import { GIT_ATTRIBUTION_ENV } from '../utils/attribution'; @@ -91,7 +93,35 @@ interface FileSearchRequest { limit?: number; } -export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): void { +const DAEMON_FILE_CHANNELS = [ + 'file:read', + 'file:read-binary', + 'file:exists', + 'file:write', + 'file:write-binary', + 'file:getPath', + 'git:commit', + 'git:revert', + 'git:restore', + 'file:readAtRevision', + 'file:list', + 'file:delete', + 'file:rename', + 'file:move', + 'file:copy', + 'file:duplicate', + 'file:search', + 'file:read-project', + 'file:write-project', + 'git:execute-project', + 'file:resolveAbsolutePath', +] as const; + +export function registerFileHandlers( + ipcMain: IpcMain, + services: AppServices, + commandRegistry: PaneCommandRegistry, +): void { const { sessionManager, gitStatusManager, configManager } = services; async function resolveWorktreePath(sessionId: string, relativePath = ''): Promise<{ @@ -153,7 +183,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v } // Read file contents from a session's worktree - ipcMain.handle('file:read', async (_, request: FileReadRequest) => { + commandRegistry.register('file:read', async (request: FileReadRequest) => { try { const session = sessionManager.getSession(request.sessionId); if (!session) { @@ -191,7 +221,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Read a file as binary (base64-encoded) — used for image/PDF preview - ipcMain.handle('file:read-binary', async (_, request: FileReadRequest) => { + commandRegistry.register('file:read-binary', async (request: FileReadRequest) => { try { const session = sessionManager.getSession(request.sessionId); if (!session) { @@ -226,7 +256,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Check if a file exists in a session's worktree - ipcMain.handle('file:exists', async (_, request: FilePathRequest) => { + commandRegistry.register('file:exists', async (request: FilePathRequest) => { try { const session = sessionManager.getSession(request.sessionId); if (!session) { @@ -258,7 +288,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Write file contents to a session's worktree - ipcMain.handle('file:write', async (_, request: FileWriteRequest) => { + commandRegistry.register('file:write', async (request: FileWriteRequest) => { try { // Removed verbose logging of file:write requests to reduce console noise during auto-save @@ -321,7 +351,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v } // Write binary file to a session's worktree root (for drag-and-drop uploads) - ipcMain.handle('file:write-binary', async (_, request: FileWriteBinaryRequest) => { + commandRegistry.register('file:write-binary', async (request: FileWriteBinaryRequest) => { try { if (!request.fileName) { throw new Error('File name is required'); @@ -396,7 +426,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Get the full path for a file in a session's worktree - ipcMain.handle('file:getPath', async (_, request: FilePathRequest) => { + commandRegistry.register('file:getPath', async (request: FilePathRequest) => { try { const session = sessionManager.getSession(request.sessionId); if (!session) { @@ -426,7 +456,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Commit changes in a session's worktree - ipcMain.handle('git:commit', async (_, request: { sessionId: string; message: string }) => { + commandRegistry.register('git:commit', async (request: { sessionId: string; message: string }) => { try { const session = sessionManager.getSession(request.sessionId); if (!session) { @@ -510,7 +540,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Revert a specific commit - ipcMain.handle('git:revert', async (_, request: { sessionId: string; commitHash: string }) => { + commandRegistry.register('git:revert', async (request: { sessionId: string; commitHash: string }) => { try { const session = sessionManager.getSession(request.sessionId); if (!session) { @@ -544,7 +574,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Restore all uncommitted changes - ipcMain.handle('git:restore', async (_, request: { sessionId: string }) => { + commandRegistry.register('git:restore', async (request: { sessionId: string }) => { try { const session = sessionManager.getSession(request.sessionId); if (!session) { @@ -576,7 +606,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Read file contents at a specific git revision - ipcMain.handle('file:readAtRevision', async (_, request: { sessionId: string; filePath: string; revision?: string }) => { + commandRegistry.register('file:readAtRevision', async (request: { sessionId: string; filePath: string; revision?: string }) => { try { const session = sessionManager.getSession(request.sessionId); if (!session) { @@ -623,7 +653,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // List files and directories in a session's worktree - ipcMain.handle('file:list', async (_, request: FileListRequest) => { + commandRegistry.register('file:list', async (request: FileListRequest) => { try { const session = sessionManager.getSession(request.sessionId); if (!session) { @@ -703,7 +733,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Delete a file from a session's worktree - ipcMain.handle('file:delete', async (_, request: FileDeleteRequest) => { + commandRegistry.register('file:delete', async (request: FileDeleteRequest) => { try { const { fullPath, normalizedPath } = await resolveWorktreePath(request.sessionId, request.filePath); @@ -745,7 +775,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Rename a file or folder within a session's worktree - ipcMain.handle('file:rename', async (_, request: FileRenameRequest) => { + commandRegistry.register('file:rename', async (request: FileRenameRequest) => { try { const { basePath, fullPath, normalizedPath } = await resolveWorktreePath(request.sessionId, request.filePath); const newName = validateSimpleName(request.newName); @@ -774,7 +804,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Move a file or folder into a target directory within a session's worktree - ipcMain.handle('file:move', async (_, request: FileMoveRequest) => { + commandRegistry.register('file:move', async (request: FileMoveRequest) => { try { const source = await resolveWorktreePath(request.sessionId, request.sourcePath); const target = await resolveWorktreePath(request.sessionId, request.targetDir); @@ -807,7 +837,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Copy a file or folder into a target directory within a session's worktree - ipcMain.handle('file:copy', async (_, request: FileCopyRequest) => { + commandRegistry.register('file:copy', async (request: FileCopyRequest) => { try { const source = await resolveWorktreePath(request.sessionId, request.sourcePath); const target = await resolveWorktreePath(request.sessionId, request.targetDir); @@ -833,7 +863,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Duplicate a file or folder next to itself within a session's worktree - ipcMain.handle('file:duplicate', async (_, request: FilePathRequest) => { + commandRegistry.register('file:duplicate', async (request: FilePathRequest) => { try { const source = await resolveWorktreePath(request.sessionId, request.filePath); const parentDir = path.dirname(source.fullPath); @@ -855,7 +885,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Search for files matching a pattern - ipcMain.handle('file:search', async (_, request: FileSearchRequest) => { + commandRegistry.register('file:search', async (request: FileSearchRequest) => { try { // Determine the search directory and get path resolver // storedDir = Linux path (for CommandRunner cwd), searchDirectory = filesystem path (for fs ops) @@ -1023,7 +1053,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Read file from project directory (not worktree) - ipcMain.handle('file:read-project', async (_, request: { projectId: number; filePath: string }) => { + commandRegistry.register('file:read-project', async (request: { projectId: number; filePath: string }) => { console.log('[file:read-project] Request:', request); try { const ctx = sessionManager.getProjectContextByProjectId(request.projectId); @@ -1069,7 +1099,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Write file to project directory (not worktree) - ipcMain.handle('file:write-project', async (_, request: { projectId: number; filePath: string; content: string }) => { + commandRegistry.register('file:write-project', async (request: { projectId: number; filePath: string; content: string }) => { console.log('[file:write-project] Request:', { projectId: request.projectId, filePath: request.filePath, contentLength: request.content.length }); try { const ctx = sessionManager.getProjectContextByProjectId(request.projectId); @@ -1110,7 +1140,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Execute git command in project directory - ipcMain.handle('git:execute-project', async (_, request: { projectId: number; args: string[] }) => { + commandRegistry.register('git:execute-project', async (request: { projectId: number; args: string[] }) => { console.log('[git:execute-project] Request:', request); try { const ctx = sessionManager.getProjectContextByProjectId(request.projectId); @@ -1155,7 +1185,7 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v }); // Resolve an absolute filesystem path for a file in a session's worktree - ipcMain.handle('file:resolveAbsolutePath', async (_, request: { sessionId: string; path?: string }) => { + commandRegistry.register('file:resolveAbsolutePath', async (request: { sessionId: string; path?: string }) => { try { const session = sessionManager.getSession(request.sessionId); if (!session) throw new Error(`Session not found: ${request.sessionId}`); @@ -1180,6 +1210,8 @@ export function registerFileHandlers(ipcMain: IpcMain, services: AppServices): v } }); + commandRegistry.bindChannels(ipcMain, DAEMON_FILE_CHANNELS); + // Show a file/folder from a session's worktree in the native file manager ipcMain.handle('file:showInFolder', async (_, request: { sessionId: string; path?: string }) => { try { diff --git a/main/src/ipc/index.ts b/main/src/ipc/index.ts index 87188dfe..ba25b2ac 100644 --- a/main/src/ipc/index.ts +++ b/main/src/ipc/index.ts @@ -31,13 +31,13 @@ export function registerIpcHandlers(services: AppServices): PaneCommandRegistry registerAppHandlers(ipcMain, services); registerUpdaterHandlers(ipcMain, services); registerSessionHandlers(ipcMain, services); - registerProjectHandlers(ipcMain, services); + registerProjectHandlers(ipcMain, services, commandRegistry); registerConfigHandlers(ipcMain, services); registerDialogHandlers(ipcMain, services); registerGitHandlers(ipcMain, services); registerScriptHandlers(ipcMain, services); - registerPromptHandlers(ipcMain, services); - registerFileHandlers(ipcMain, services); + registerPromptHandlers(ipcMain, services, commandRegistry); + registerFileHandlers(ipcMain, services, commandRegistry); registerFolderHandlers(ipcMain, services, commandRegistry); registerUIStateHandlers(services); registerDashboardHandlers(ipcMain, services); diff --git a/main/src/ipc/project.ts b/main/src/ipc/project.ts index 2a5cbfc9..539b3445 100644 --- a/main/src/ipc/project.ts +++ b/main/src/ipc/project.ts @@ -1,6 +1,7 @@ -import { IpcMain } from 'electron'; +import type { IpcMain } from 'electron'; import { mkdir, access } from 'fs/promises'; import path from 'path'; +import type { PaneCommandRegistry } from '../daemon/commandRegistry'; import type { AppServices } from './types'; import type { CreateProjectRequest, UpdateProjectRequest } from '../../../frontend/src/types/project'; import { scriptExecutionTracker } from '../services/scriptExecutionTracker'; @@ -50,10 +51,32 @@ async function stopProjectScriptInternal(projectId?: number): Promise<{ success: } } -export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices): void { +const DAEMON_PROJECT_CHANNELS = [ + 'projects:get-all', + 'projects:get-active', + 'projects:create', + 'projects:activate', + 'projects:update', + 'projects:delete', + 'projects:reorder', + 'projects:detect-branch', + 'projects:list-branches', + 'projects:refresh-git-status', + 'projects:get-running-script', + 'projects:stop-script', + 'projects:detect-config', + 'projects:resolve-run-script', + 'projects:run-script', +] as const; + +export function registerProjectHandlers( + ipcMain: IpcMain, + services: AppServices, + commandRegistry: PaneCommandRegistry, +): void { const { databaseService, sessionManager, worktreeManager, analyticsManager } = services; - ipcMain.handle('projects:get-all', async () => { + commandRegistry.register('projects:get-all', async () => { try { const projects = databaseService.getAllProjects(); const projectsWithEnv = projects.map(p => ({ @@ -67,7 +90,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:get-active', async () => { + commandRegistry.register('projects:get-active', async () => { try { const activeProject = sessionManager.getActiveProject(); const projectWithEnv = activeProject ? { @@ -81,7 +104,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:create', async (_event, projectData: CreateProjectRequest) => { + commandRegistry.register('projects:create', async (projectData: CreateProjectRequest) => { try { console.log('[Main] Creating project:', projectData); @@ -231,7 +254,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:activate', async (_event, projectId: string) => { + commandRegistry.register('projects:activate', async (projectId: string) => { try { const project = databaseService.setActiveProject(parseInt(projectId)); if (project) { @@ -258,7 +281,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:update', async (_event, projectId: string, updates: UpdateProjectRequest) => { + commandRegistry.register('projects:update', async (projectId: string, updates: UpdateProjectRequest) => { try { const projectIdNum = parseInt(projectId); @@ -319,7 +342,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:delete', async (_event, projectId: string) => { + commandRegistry.register('projects:delete', async (projectId: string) => { try { const projectIdNum = parseInt(projectId); @@ -413,7 +436,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:reorder', async (_event, projectOrders: Array<{ id: number; displayOrder: number }>) => { + commandRegistry.register('projects:reorder', async (projectOrders: Array<{ id: number; displayOrder: number }>) => { try { databaseService.reorderProjects(projectOrders); return { success: true }; @@ -423,7 +446,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:detect-branch', async (_event, path: string) => { + commandRegistry.register('projects:detect-branch', async (path: string) => { try { const wslInfo = parseWSLPath(path); const tempProject = { @@ -440,7 +463,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:list-branches', async (_event, projectId: string) => { + commandRegistry.register('projects:list-branches', async (projectId: string) => { try { const project = databaseService.getProject(parseInt(projectId)); if (!project) { @@ -460,7 +483,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:refresh-git-status', async (_event, projectId: string) => { + commandRegistry.register('projects:refresh-git-status', async (projectId: string) => { try { const projectIdNum = parseInt(projectId); const { gitStatusManager } = services; @@ -510,7 +533,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:get-running-script', async () => { + commandRegistry.register('projects:get-running-script', async () => { try { const runningProjectId = scriptExecutionTracker.getRunningScriptId('project'); return { success: true, data: runningProjectId }; @@ -520,7 +543,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:stop-script', async (_event, projectId?: number) => { + commandRegistry.register('projects:stop-script', async (projectId?: number) => { return stopProjectScriptInternal(projectId); }); @@ -547,7 +570,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) * - `main/src/services/projectConfigDetector.ts` — `detectProjectConfig` implementation * - `frontend/src/components/ProjectSettings.tsx` — consumer (badge rendering) */ - ipcMain.handle('projects:detect-config', async (_event, projectId: string) => { + commandRegistry.register('projects:detect-config', async (projectId: string) => { try { const project = databaseService.getProject(parseInt(projectId)); if (!project) return { success: false, error: 'Project not found' }; @@ -578,7 +601,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) * Steps 2-5 are handled by `detectProjectConfig()`. * DB values always override config files (Conductor model). */ - ipcMain.handle('projects:resolve-run-script', async (_event, sessionId: string) => { + commandRegistry.register('projects:resolve-run-script', async (sessionId: string) => { try { const dbSession = databaseService.getSession(sessionId); if (!dbSession?.project_id) return { success: true, data: null }; @@ -629,7 +652,7 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) } }); - ipcMain.handle('projects:run-script', async (_event, projectId: number) => { + commandRegistry.register('projects:run-script', async (projectId: number) => { try { // Get the project const project = databaseService.getProject(projectId); @@ -723,4 +746,5 @@ export function registerProjectHandlers(ipcMain: IpcMain, services: AppServices) return { success: false, error: error instanceof Error ? error.message : 'Failed to run project script' }; } }); + commandRegistry.bindChannels(ipcMain, DAEMON_PROJECT_CHANNELS); } diff --git a/main/src/ipc/prompt.ts b/main/src/ipc/prompt.ts index 9d92c537..13dd3705 100644 --- a/main/src/ipc/prompt.ts +++ b/main/src/ipc/prompt.ts @@ -1,8 +1,19 @@ -import { IpcMain } from 'electron'; +import type { IpcMain } from 'electron'; +import type { PaneCommandRegistry } from '../daemon/commandRegistry'; import type { AppServices } from './types'; -export function registerPromptHandlers(ipcMain: IpcMain, { sessionManager }: AppServices): void { - ipcMain.handle('sessions:get-prompts', async (_event, sessionId: string) => { +const DAEMON_PROMPT_CHANNELS = [ + 'sessions:get-prompts', + 'prompts:get-all', + 'prompts:get-by-id', +] as const; + +export function registerPromptHandlers( + ipcMain: IpcMain, + { sessionManager }: AppServices, + commandRegistry: PaneCommandRegistry, +): void { + commandRegistry.register('sessions:get-prompts', async (sessionId: string) => { try { const prompts = sessionManager.getSessionPrompts(sessionId); return { success: true, data: prompts }; @@ -13,7 +24,7 @@ export function registerPromptHandlers(ipcMain: IpcMain, { sessionManager }: App }); // Prompts handlers - ipcMain.handle('prompts:get-all', async () => { + commandRegistry.register('prompts:get-all', async () => { try { const prompts = sessionManager.getPromptHistory(); return { success: true, data: prompts }; @@ -23,7 +34,7 @@ export function registerPromptHandlers(ipcMain: IpcMain, { sessionManager }: App } }); - ipcMain.handle('prompts:get-by-id', async (_event, promptId: string) => { + commandRegistry.register('prompts:get-by-id', async (promptId: string) => { try { const promptMarker = sessionManager.getPromptById(promptId); return { success: true, data: promptMarker }; @@ -32,4 +43,6 @@ export function registerPromptHandlers(ipcMain: IpcMain, { sessionManager }: App return { success: false, error: 'Failed to get prompt by id' }; } }); -} \ No newline at end of file + + commandRegistry.bindChannels(ipcMain, DAEMON_PROMPT_CHANNELS); +}