Skip to content

Consolidate IPC types into shared module, enforce with satisfies PearAPI#36

Merged
willwashburn merged 2 commits into
mainfrom
refactor/ipc-shared-types
May 25, 2026
Merged

Consolidate IPC types into shared module, enforce with satisfies PearAPI#36
willwashburn merged 2 commits into
mainfrom
refactor/ipc-shared-types

Conversation

@willwashburn
Copy link
Copy Markdown
Member

Summary

The IPC seam had two competing source-of-truth definitions for the same surface:

  • src/preload/index.ts exposes window.pear = api and exported PearAPI = typeof api (auto-derived from the implementation).
  • src/renderer/src/lib/ipc.ts:468 also declared export interface PearAPI { ... } — a 220-line hand-typed interface — and wired that into declare global { interface Window { pear: PearAPI } }.

Nothing forced the two to agree:

  • 13 types were duplicated verbatim across the two files (the BurnAgent*, BurnProject*, BurnSession*, AiHist* families).
  • Many preload methods used invoke<unknown>(...) while the renderer's PearAPI interface promised concrete return types like BrokerListAgent[], GitFileStatus[], AuthStatus, etc. The renderer was working off a contract the preload never actually honored — type-correct only because nobody was checking.
  • Methods like the entire cloudAgent, proactiveAgent, and integrations namespaces called ipcRenderer.invoke(...) directly (returns Promise<any>) — passing all type checks vacuously.

This PR:

  • Adds src/shared/types/ipc.ts as the single source of truth for every type that crosses the bridge, plus the PearAPI interface itself.
  • Rewrites src/preload/index.ts to import from shared, tightens every invoke<T> to the real return type, replaces direct ipcRenderer.invoke calls with the typed wrapper, and ends with satisfies PearAPI so any future drift between implementation and interface fails to compile.
  • Reduces src/renderer/src/lib/ipc.ts from 691 lines to ~20: it now just re-exports @shared/types/ipc and declares window.pear. All existing import { ..., type Foo } from '@/lib/ipc' call sites resolve unchanged.

Net change: +1043 / -819 (most of the additions are in shared/types; the deletions are deduped renderer-side declarations).

Test plan

  • tsc -b error count matches baseline (85 errors before and after — all pre-existing, none in the refactored files)
  • npm test — all 11 tests pass
  • npm run build — electron-vite build succeeds (main + preload + renderer)
  • Smoke test the running app to confirm IPC still works end-to-end (recommend reviewer try one IPC-heavy flow: project list, broker spawn, git status)

🤖 Generated with Claude Code

…rAPI`

Previously the IPC surface had two competing definitions: preload/index.ts
exported `typeof api` (the implementation) while renderer/src/lib/ipc.ts
declared a separate, hand-maintained `PearAPI` interface that was wired into
`window.pear`. Nothing forced them to agree — the preload's `invoke<unknown>`
calls happily returned a different shape than what the renderer's interface
promised, and 13 burn/aiHist types were duplicated verbatim across the two
files.

This moves the entire IPC type surface to src/shared/types/ipc.ts:
- preload/index.ts imports types from shared, tightens every `invoke<T>` to
  the real return type, and ends with `satisfies PearAPI` so any future
  drift between implementation and interface fails to compile.
- renderer/src/lib/ipc.ts becomes a thin re-export of @shared/types/ipc
  plus the `window.pear` global declaration — no duplicated types.

All call sites continue to work unchanged (`import { ..., type Foo } from
'@/lib/ipc'` still resolves). Type-check error count and test results match
baseline.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 24, 2026

Review Change Stack

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Free

Run ID: 3eadab87-c062-42a6-a005-582ae902b993

📥 Commits

Reviewing files that changed from the base of the PR and between 9ee2ba7 and f1bef2e.

📒 Files selected for processing (2)
  • src/preload/index.ts
  • src/shared/types/ipc.ts
💤 Files with no reviewable changes (1)
  • src/shared/types/ipc.ts

📝 Walkthrough

Walkthrough

This PR centralizes IPC type definitions into src/shared/types/ipc.ts, updates the preload bridge to use typed invoke/subscribe helpers, constrains the exposed api to the shared PearAPI, and converts the renderer IPC module into a re-export of the shared types.

Changes

IPC Type Consolidation and Bridge Surface Typing

Layer / File(s) Summary
Shared IPC type contract
src/shared/types/ipc.ts
Establishes the single source of truth for IPC data models and exports the PearAPI bridge interface covering app/project/broker/burn/git/fs/auth/cloudAgent/proactiveAgent/integrations/aiHist and event hooks.
Renderer IPC module re-export
src/renderer/src/lib/ipc.ts
Replaces locally-defined IPC types with a thin renderer entry that re-exports @shared/types/ipc, preserving window.pear: PearAPI and existing import paths.
Preload type imports and invoke/subscribe helpers
src/preload/index.ts (lines 2–132)
Replaces local IPC type definitions with imports from shared types and introduces typed invoke<T> and subscribe<T> helpers for IPC calls and listeners.
Preload app/project method typing
src/preload/index.ts (lines 148–151)
Updates api.app.confirmQuit and api.project.list to return typed results, making project.list return ProjectListResult.
Preload broker methods and events
src/preload/index.ts (lines 183–229)
Refactors broker spawn/attach/send implementations to use typed invoke<T> returns and updates onStatus to use a typed BrokerStatusEvent payload.
Preload remaining IPC namespaces
src/preload/index.ts (lines 238–362)
Refactors git, fs, auth, cloudAgent, proactiveAgent, integrations, and aiHist namespaces to use typed invoke<T> returns and subscribe<T> callbacks from shared contracts.
Preload API export and satisfies constraint
src/preload/index.ts (lines 371–373)
Applies } satisfies PearAPI to the exposed api and exposes it to the renderer, removing the previous type PearAPI = typeof api.

Sequence Diagram

sequenceDiagram
  participant Renderer
  participant PreloadAPI as Preload API
  participant invoke as invoke<T>
  participant ipcRenderer

  Renderer->>PreloadAPI: api.broker.spawnAgent(input)
  PreloadAPI->>invoke: invoke<BrokerSpawnAgentResult>('broker:spawn-agent', input)
  invoke->>ipcRenderer: ipcRenderer.invoke(channel, input)
  ipcRenderer-->>invoke: Promise<BrokerSpawnAgentResult>
  invoke-->>PreloadAPI: typed result
  PreloadAPI-->>Renderer: BrokerSpawnAgentResult

  Renderer->>PreloadAPI: api.broker.onStatus(callback)
  PreloadAPI->>invoke: subscribe<BrokerStatusEvent>('broker:status', callback)
  invoke->>ipcRenderer: ipcRenderer.on(channel, callback)
  ipcRenderer-->>PreloadAPI: unsubscribe function
  PreloadAPI-->>Renderer: cleanup function
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 In burrows of code where types once sprawled,

I gathered them neat, every edge, every wall.
Preload and render now speak the same name,
PearAPI binds them — no shadows, no shame.
Hop, test, and ship — the bridge is tame!


Note

🎁 Summarized by CodeRabbit Free

Your organization is on the Free plan. CodeRabbit will generate a high-level summary and a walkthrough for each pull request. For a comprehensive line-by-line review, please upgrade your subscription to CodeRabbit Pro by visiting https://app.coderabbit.ai/login.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9ee2ba7b6e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/preload/index.ts Outdated
Comment on lines +244 to +247
getProjectBreakdown: (input: BurnProjectInput) =>
invoke<BurnProjectBreakdown>('burn:get-project-breakdown', input),
lookupSessions: (sessionIds: string[]) =>
invoke<Record<string, BurnSessionLookup>>('burn:lookup-sessions', sessionIds)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove burn IPC methods without main handlers

These new preload methods call burn:get-project-breakdown and burn:lookup-sessions, but in the main-process registration I checked (src/main/ipc-handlers.ts), only burn:list-agent-summaries and burn:get-agent-breakdown are handled. Any renderer call to either added method will fail at runtime with Electron's “No handler registered” error, so the exposed API now advertises burn functionality that cannot execute.

Useful? React with 👍 / 👎.

The previous commit on this branch picked up two preload methods (and
their types) from the working tree that don't exist on main — the matching
ipcMain handlers were sitting uncommitted alongside an in-progress burn
project page. Shipping the PR alone would have exposed two channels with
no handler, failing at runtime with "No handler registered."

Removing both preload methods plus BurnProjectInput, BurnProjectBreakdown,
BurnProjectAgentRollup, BurnSessionLookup, and BurnSessionAgentRef from
shared/types/ipc.ts. The burn-project feature will re-add them in its own
commit alongside the matching handlers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@willwashburn willwashburn merged commit 593d1af into main May 25, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant