Skip to content

Commit 9c7c2c6

Browse files
authored
feat: Initial tRPC setup, removes dead code (#258)
1 parent bd8721a commit 9c7c2c6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

71 files changed

+547
-3256
lines changed

.env.example

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
OPENAI_API_KEY="xxx"
2-
ANTHROPIC_API_KEY="xxx"
3-
41
APPLE_CODESIGN_IDENTITY="Developer ID Application: PostHog Inc. (xxx)"
52
63
APPLE_APP_SPECIFIC_PASSWORD="xxxx-xxx-xxx-xxx"

CLAUDE.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,8 @@ Import directly from source files instead.
8282
## Environment Variables
8383

8484
- Copy `.env.example` to `.env`
85-
- `ANTHROPIC_API_KEY` - Required for agent
86-
- `OPENAI_API_KEY` - Optional
87-
- `VITE_POSTHOG_*` - PostHog tracking config
85+
86+
TODO: Update me
8887

8988
## Testing
9089

apps/array/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,9 @@
111111
"@tiptap/react": "^3.11.0",
112112
"@tiptap/starter-kit": "^3.11.0",
113113
"@tiptap/suggestion": "^3.11.0",
114+
"@trpc/client": "^11.7.2",
115+
"@trpc/react-query": "^11.7.2",
116+
"@trpc/server": "^11.7.2",
114117
"@xterm/addon-fit": "^0.10.0",
115118
"@xterm/addon-serialize": "^0.13.0",
116119
"@xterm/addon-web-links": "^0.11.0",
@@ -142,6 +145,7 @@
142145
"react-resizable-panels": "^3.0.6",
143146
"remark-gfm": "^4.0.1",
144147
"sonner": "^2.0.7",
148+
"trpc-electron": "^0.1.2",
145149
"uuid": "^9.0.1",
146150
"vscode-icons-js": "^11.6.1",
147151
"zod": "^4.1.12",

apps/array/src/main/index.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,16 @@ import {
1616
type MenuItemConstructorOptions,
1717
shell,
1818
} from "electron";
19+
import { createIPCHandler } from "trpc-electron/main";
1920
import "./lib/logger";
2021
import { ANALYTICS_EVENTS } from "../types/analytics.js";
2122
import { dockBadgeService } from "./services/dockBadge.js";
2223
import {
2324
cleanupAgentSessions,
2425
registerAgentIpc,
2526
} from "./services/session-manager.js";
27+
import { setMainWindowGetter } from "./trpc/context.js";
28+
import { trpcRouter } from "./trpc/index.js";
2629

2730
// Legacy type kept for backwards compatibility with taskControllers map
2831
type TaskController = unknown;
@@ -37,14 +40,11 @@ import {
3740
registerExternalAppsIpc,
3841
} from "./services/externalApps.js";
3942
import { registerOAuthHandlers } from "./services/oauth.js";
40-
import { registerOsIpc } from "./services/os.js";
41-
import { registerPosthogIpc } from "./services/posthog.js";
4243
import {
4344
initializePostHog,
4445
shutdownPostHog,
4546
trackAppEvent,
4647
} from "./services/posthog-analytics.js";
47-
import { registerSettingsIpc } from "./services/settings.js";
4848
import { registerShellIpc } from "./services/shell.js";
4949
import { registerAutoUpdater } from "./services/updates.js";
5050
import { registerWorkspaceIpc } from "./services/workspace/index.js";
@@ -115,6 +115,9 @@ function createWindow(): void {
115115
mainWindow?.show();
116116
});
117117

118+
setMainWindowGetter(() => mainWindow);
119+
createIPCHandler({ router: trpcRouter, windows: [mainWindow] });
120+
118121
setupExternalLinkHandlers(mainWindow);
119122

120123
// Set up menu for keyboard shortcuts
@@ -293,10 +296,8 @@ registerAutoUpdater(() => mainWindow);
293296
ipcMain.handle("app:get-version", () => app.getVersion());
294297

295298
// Register IPC handlers via services
296-
registerPosthogIpc();
297299
registerOAuthHandlers();
298-
registerOsIpc(() => mainWindow);
299-
registerGitIpc(() => mainWindow);
300+
registerGitIpc();
300301
registerAgentIpc(taskControllers, () => mainWindow);
301302
registerFsIpc();
302303
registerFileWatcherIpc(() => mainWindow);
@@ -305,4 +306,3 @@ registerWorktreeIpc();
305306
registerShellIpc();
306307
registerExternalAppsIpc();
307308
registerWorkspaceIpc(() => mainWindow);
308-
registerSettingsIpc();

apps/array/src/main/preload.ts

Lines changed: 10 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { ContentBlock } from "@agentclientprotocol/sdk";
22
import { contextBridge, type IpcRendererEvent, ipcRenderer } from "electron";
3+
import { exposeElectronTRPC } from "trpc-electron/main";
34
import type {
45
CreateWorkspaceOptions,
56
RegisteredFolder,
@@ -19,6 +20,12 @@ import type {
1920
} from "./services/contextMenu.types.js";
2021
import "electron-log/preload";
2122

23+
process.once("loaded", () => {
24+
exposeElectronTRPC();
25+
});
26+
27+
/// -- Legacy IPC handlers -- ///
28+
2229
type IpcEventListener<T> = (data: T) => void;
2330

2431
function createIpcListener<T>(
@@ -38,16 +45,6 @@ function createVoidIpcListener(
3845
return () => ipcRenderer.removeListener(channel, listener);
3946
}
4047

41-
interface MessageBoxOptions {
42-
type?: "none" | "info" | "error" | "question" | "warning";
43-
title?: string;
44-
message?: string;
45-
detail?: string;
46-
buttons?: string[];
47-
defaultId?: number;
48-
cancelId?: number;
49-
}
50-
5148
interface AgentStartParams {
5249
taskId: string;
5350
taskRunId: string;
@@ -64,20 +61,6 @@ interface AgentStartParams {
6461
}
6562

6663
contextBridge.exposeInMainWorld("electronAPI", {
67-
storeApiKey: (apiKey: string): Promise<string> =>
68-
ipcRenderer.invoke("store-api-key", apiKey),
69-
retrieveApiKey: (encryptedKey: string): Promise<string | null> =>
70-
ipcRenderer.invoke("retrieve-api-key", encryptedKey),
71-
fetchS3Logs: (logUrl: string): Promise<string | null> =>
72-
ipcRenderer.invoke("fetch-s3-logs", logUrl),
73-
rendererStore: {
74-
getItem: (key: string): Promise<string | null> =>
75-
ipcRenderer.invoke("renderer-store:get", key),
76-
setItem: (key: string, value: string): Promise<void> =>
77-
ipcRenderer.invoke("renderer-store:set", key, value),
78-
removeItem: (key: string): Promise<void> =>
79-
ipcRenderer.invoke("renderer-store:remove", key),
80-
},
8164
// OAuth API
8265
oauthStartFlow: (
8366
region: CloudRegion,
@@ -90,16 +73,9 @@ contextBridge.exposeInMainWorld("electronAPI", {
9073
ipcRenderer.invoke("oauth:refresh-token", refreshToken, region),
9174
oauthCancelFlow: (): Promise<{ success: boolean; error?: string }> =>
9275
ipcRenderer.invoke("oauth:cancel-flow"),
93-
selectDirectory: (): Promise<string | null> =>
94-
ipcRenderer.invoke("select-directory"),
95-
searchDirectories: (query: string, searchRoot?: string): Promise<string[]> =>
96-
ipcRenderer.invoke("search-directories", query, searchRoot),
97-
findReposDirectory: (): Promise<string | null> =>
98-
ipcRenderer.invoke("find-repos-directory"),
76+
// Repo API
9977
validateRepo: (directoryPath: string): Promise<boolean> =>
10078
ipcRenderer.invoke("validate-repo", directoryPath),
101-
checkWriteAccess: (directoryPath: string): Promise<boolean> =>
102-
ipcRenderer.invoke("check-write-access", directoryPath),
10379
detectRepo: (
10480
directoryPath: string,
10581
): Promise<{
@@ -108,25 +84,6 @@ contextBridge.exposeInMainWorld("electronAPI", {
10884
branch?: string;
10985
remote?: string;
11086
} | null> => ipcRenderer.invoke("detect-repo", directoryPath),
111-
validateRepositoryMatch: (
112-
path: string,
113-
organization: string,
114-
repository: string,
115-
): Promise<{
116-
valid: boolean;
117-
detected?: { organization: string; repository: string } | null;
118-
error?: string;
119-
}> =>
120-
ipcRenderer.invoke(
121-
"validate-repository-match",
122-
path,
123-
organization,
124-
repository,
125-
),
126-
checkSSHAccess: (): Promise<{
127-
available: boolean;
128-
error?: string;
129-
}> => ipcRenderer.invoke("check-ssh-access"),
13087
cloneRepository: (
13188
repoUrl: string,
13289
targetPath: string,
@@ -140,18 +97,13 @@ contextBridge.exposeInMainWorld("electronAPI", {
14097
message: string;
14198
}) => void,
14299
): (() => void) => createIpcListener(`clone-progress:${cloneId}`, listener),
143-
showMessageBox: (options: MessageBoxOptions): Promise<{ response: number }> =>
144-
ipcRenderer.invoke("show-message-box", options),
145-
openExternal: (url: string): Promise<void> =>
146-
ipcRenderer.invoke("open-external", url),
147100
listRepoFiles: (
148101
repoPath: string,
149102
query?: string,
150103
limit?: number,
151104
): Promise<Array<{ path: string; name: string }>> =>
152105
ipcRenderer.invoke("list-repo-files", repoPath, query, limit),
153-
clearRepoFileCache: (repoPath: string): Promise<void> =>
154-
ipcRenderer.invoke("clear-repo-file-cache", repoPath),
106+
// Agent API
155107
agentStart: async (
156108
params: AgentStartParams,
157109
): Promise<{ sessionId: string; channel: string }> =>
@@ -165,18 +117,6 @@ contextBridge.exposeInMainWorld("electronAPI", {
165117
ipcRenderer.invoke("agent-cancel", sessionId),
166118
agentCancelPrompt: async (sessionId: string): Promise<boolean> =>
167119
ipcRenderer.invoke("agent-cancel-prompt", sessionId),
168-
agentListSessions: async (
169-
taskId?: string,
170-
): Promise<
171-
Array<{
172-
sessionId: string;
173-
acpSessionId: string;
174-
channel: string;
175-
taskId: string;
176-
}>
177-
> => ipcRenderer.invoke("agent-list-sessions", taskId),
178-
agentLoadSession: async (sessionId: string, cwd: string): Promise<boolean> =>
179-
ipcRenderer.invoke("agent-load-session", sessionId, cwd),
180120
agentReconnect: async (params: {
181121
taskId: string;
182122
taskRunId: string;
@@ -200,68 +140,6 @@ contextBridge.exposeInMainWorld("electronAPI", {
200140
listener: (payload: unknown) => void,
201141
): (() => void) => createIpcListener(channel, listener),
202142
// Plan mode operations
203-
agentStartPlanMode: async (params: {
204-
taskId: string;
205-
taskTitle: string;
206-
taskDescription: string;
207-
repoPath: string;
208-
apiKey: string;
209-
apiHost: string;
210-
projectId: number;
211-
}): Promise<{ taskId: string; channel: string }> =>
212-
ipcRenderer.invoke("agent-start-plan-mode", params),
213-
agentGeneratePlan: async (params: {
214-
taskId: string;
215-
taskTitle: string;
216-
taskDescription: string;
217-
repoPath: string;
218-
questionAnswers: unknown[];
219-
apiKey: string;
220-
apiHost: string;
221-
projectId: number;
222-
}): Promise<{ taskId: string; channel: string }> =>
223-
ipcRenderer.invoke("agent-generate-plan", params),
224-
readPlanFile: (repoPath: string, taskId: string): Promise<string | null> =>
225-
ipcRenderer.invoke("read-plan-file", repoPath, taskId),
226-
writePlanFile: (
227-
repoPath: string,
228-
taskId: string,
229-
content: string,
230-
): Promise<void> =>
231-
ipcRenderer.invoke("write-plan-file", repoPath, taskId, content),
232-
ensurePosthogFolder: (repoPath: string, taskId: string): Promise<string> =>
233-
ipcRenderer.invoke("ensure-posthog-folder", repoPath, taskId),
234-
listTaskArtifacts: (repoPath: string, taskId: string): Promise<unknown[]> =>
235-
ipcRenderer.invoke("list-task-artifacts", repoPath, taskId),
236-
readTaskArtifact: (
237-
repoPath: string,
238-
taskId: string,
239-
fileName: string,
240-
): Promise<string | null> =>
241-
ipcRenderer.invoke("read-task-artifact", repoPath, taskId, fileName),
242-
appendToArtifact: (
243-
repoPath: string,
244-
taskId: string,
245-
fileName: string,
246-
content: string,
247-
): Promise<void> =>
248-
ipcRenderer.invoke(
249-
"append-to-artifact",
250-
repoPath,
251-
taskId,
252-
fileName,
253-
content,
254-
),
255-
saveQuestionAnswers: (
256-
repoPath: string,
257-
taskId: string,
258-
answers: Array<{
259-
questionId: string;
260-
selectedOption: string;
261-
customInput?: string;
262-
}>,
263-
): Promise<void> =>
264-
ipcRenderer.invoke("save-question-answers", repoPath, taskId, answers),
265143
readRepoFile: (repoPath: string, filePath: string): Promise<string | null> =>
266144
ipcRenderer.invoke("read-repo-file", repoPath, filePath),
267145
writeRepoFile: (
@@ -467,6 +345,7 @@ contextBridge.exposeInMainWorld("electronAPI", {
467345
): Promise<string | null> =>
468346
ipcRenderer.invoke("worktree-get-main-repo", mainRepoPath, worktreePath),
469347
},
348+
// External Apps API
470349
externalApps: {
471350
getDetectedApps: (): Promise<
472351
Array<{
@@ -533,17 +412,6 @@ contextBridge.exposeInMainWorld("electronAPI", {
533412
}>,
534413
): (() => void) => createIpcListener("workspace:warning", listener),
535414
},
536-
// Settings API
537-
settings: {
538-
getWorktreeLocation: (): Promise<string> =>
539-
ipcRenderer.invoke("settings:get-worktree-location"),
540-
setWorktreeLocation: (location: string): Promise<void> =>
541-
ipcRenderer.invoke("settings:set-worktree-location", location),
542-
getTerminalLayout: (): Promise<"split" | "tabbed"> =>
543-
ipcRenderer.invoke("settings:get-terminal-layout"),
544-
setTerminalLayout: (mode: "split" | "tabbed"): Promise<void> =>
545-
ipcRenderer.invoke("settings:set-terminal-layout", mode),
546-
},
547415
// Dock Badge API
548416
dockBadge: {
549417
show: (): Promise<void> => ipcRenderer.invoke("dock-badge:show"),

apps/array/src/main/services/folders.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ import type { RegisteredFolder } from "../../shared/types";
77
import { generateId } from "../../shared/utils/id";
88
import { createIpcHandler } from "../lib/ipcHandler";
99
import { logger } from "../lib/logger";
10+
import { clearAllStoreData, foldersStore } from "../utils/store";
1011
import { isGitRepository } from "./git";
1112
import { getWorktreeLocation } from "./settingsStore";
12-
import { clearAllStoreData, foldersStore } from "./store";
1313
import { deleteWorktreeIfExists } from "./worktreeUtils";
1414

1515
const execAsync = promisify(exec);

0 commit comments

Comments
 (0)