wave: shared scaffolding for cloud-agents / integrations / proactive-agents#7
Conversation
…agents
Foundational changes that every feature branch in the cloud-agents wave shares —
IPC handlers, preload namespaces, store schema extensions, App.tsx dialog
wiring, lib/ipc types, broker / index / auth helpers, and the renderer plumbing
the per-spec features all depend on.
Notable:
- src/main/auth.ts: add resolveCloudAuth() + CloudAuth + accountKey, the
unified credential resolver used by cloud-agent, proactive-agent, and
integrations (mirrors how ../workforce + ../cloud read CLOUD_API_*).
- src/main/ipc-handlers.ts / src/preload/index.ts: wire cloud-agent:*,
integrations:*, proactive-agent:* channels and the corresponding renderer-side
namespaces.
- src/main/store.ts: extend Project schema with cloudAgent, integrations[],
proactiveAgents[].
- src/renderer/src/App.tsx + lib/ipc.ts + stores: glue for the per-spec UIs.
Per-spec feature work lands on top of this in dedicated branches:
ricky/wave-pear-cloud-agents/{01-cloud-agents,02-integrations,03-proactive-agents,
05-integrations-connect}.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Free Run ID: 📒 Files selected for processing (16)
📝 WalkthroughWalkthroughThis PR integrates cloud agent and proactive agent management into Pear by adding cloud authentication, sandbox lifecycle handling in the broker, workspace persistence, expanded IPC surface for agent operations, and new UI views for account settings with unified agent spawning dialogs. ChangesCloud Agent & Proactive Agent Integration
🎯 4 (Complex) | ⏱️ ~60 minutes
Note 🎁 Summarized by CodeRabbit FreeYour 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 |
| } catch (err) { | ||
| console.error(`[broker] Failed to connect cloud broker for project ${normalizedProjectId}:`, err) | ||
| this.sendStatusToWindow(win, normalizedProjectId, 'error', String(err)) |
There was a problem hiding this comment.
🟡 connectCloud wraps attachCloudSandbox causing duplicate error logging and IPC status messages
When connectCloud delegates to attachCloudSandbox and the inner method fails (e.g., client.getSession() at src/main/broker.ts:520 throws), both methods catch the error and independently call console.error and this.sendStatusToWindow. The error is logged twice and two identical broker:status IPC messages with status: 'error' are sent to the renderer window. While the agent store's handleBrokerStatus deduplicates error recording, the duplicate IPC round-trip and console output are wasteful. The outer connectCloud catch at line 589-593 is redundant for errors originating inside attachCloudSandbox.
(Refers to lines 589-593)
Prompt for agents
In connectCloud (src/main/broker.ts around line 549), the catch block at lines 589-593 duplicates the error handling already performed by attachCloudSandbox's own catch block (lines 537-541). When attachCloudSandbox throws, both methods log the error with console.error and call this.sendStatusToWindow with the same arguments, sending two broker:status IPC messages to the renderer.
The fix is to remove the redundant sendStatusToWindow and console.error from connectCloud's catch, since attachCloudSandbox already handles those. connectCloud's catch should still re-throw the error so the IPC handler can report it. One approach is to just re-throw without the duplicate side effects, or to distinguish between errors from sandbox creation API calls (which need local handling) and errors from attachCloudSandbox (which are already handled).
Was this helpful? React with 👍 or 👎 to provide feedback.
Split connectCloud's try/catch so it only catches errors from sandbox provisioning (POST /sandboxes, /terminal). attachCloudSandbox already console.error's and emits broker:status error for its own failures, so wrapping it in the outer catch caused duplicate console output and two identical broker:status IPC messages reaching the renderer. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…fold # Conflicts: # package-lock.json # package.json # src/main/auth.ts # src/main/broker.ts # src/main/index.ts # src/main/ipc-handlers.ts # src/main/store.ts # src/preload/index.ts # src/renderer/src/App.tsx # src/renderer/src/components/broker/BrokerDetailsPage.tsx # src/renderer/src/components/diff/DiffPane.tsx # src/renderer/src/lib/ipc.ts # src/renderer/src/lib/syntax-highlighter.tsx # src/renderer/src/stores/ui-store.ts
WIP scaffolding for Spec 05's account-wide RelayWorkspaceManager — the single
account-level relayfile workspace pear uses for the relayfile mount + integrations
connect. Replaces the random per-project crypto.randomUUID() relayWorkspaceId in
store.ts.
- src/main/relay-workspace.ts: provisions/joins the account workspace via
RelayfileSetup, caches the WorkspaceHandle.
- src/main/relay-workspace.types.ts: persisted shape.
- src/main/relay-workspace.test.ts: unit smoke.
Remaining work (full Spec 05 implementation): wire the integrations connect
flow to use handle.requestJson against connect-session / integrations/{provider}/status /
integrations/{provider} (bypassing the SDK's whitelist-gated connectIntegration),
replace project.relayWorkspaceId usages with RelayWorkspaceManager.getWorkspaceId(),
add the per-project visibility section. See specs/05-integrations-connect.md.
Builds on shared scaffolding (#7).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…olding) Spec 01 scaffolding for cloud agents in pear: - src/main/cloud-agent.ts + cloud-agent.types.ts: CloudAgentManager (attach/detach/restore/list/create/delete, warm box polling, mount session via @relayfile/sdk, conflict-policy launcher, git sync-back). - components/agents/: AddAgentDialog (local vs cloud picker), CloudAgentDialog, CloudAgentPicker, CloudAuthRequired. - hooks/use-cloud-agent.ts + stores/cloud-agent-store.ts: renderer-side binding + catalog state. Builds on the shared scaffolding (#7). The remaining gaps — restore-on-launch in index.ts and the relayfile --conflict-policy CLI flag — are covered in the slimmed spec at specs/01-cloud-agents.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… + Nango logos) Spec 02 scaffolding plus the catalog/logo work done this session: - src/main/integrations.ts: IntegrationsManager. listCatalog filters to ACTIVE_PROVIDERS (the non-deprecated relayfile providers in cloud/packages/web/lib/integrations/providers.ts). authHeaders is async and routes through resolveCloudAuth. loadStaticCatalog is a static import (not a dynamic variable import, which the bundler couldn't resolve and which left the static fallback empty at runtime). - src/main/integrations.types.ts: IntegrationAdapter + visibility types. - src/main/integrations.catalog.ts: 36 generated adapters with iconUrl pointing at https://app.nango.dev/images/template-logos/{slug}.svg. - scripts/build-integrations-catalog.mjs: regenerates the catalog from ../relayfile-adapters/packages. Adds NANGO_LOGO_SLUG override map (gmail→google-mail, teams→microsoft-teams, x→twitter) and emits iconUrl per entry. - src/renderer/src/components/settings/AccountSettings.tsx: <IntegrationLogo> component with onError fallback to the generic plug icon (light tile makes the dark/monochrome SVGs legible), used in both the CATALOG grid and the CONNECTED list. Builds on shared scaffolding (#7). Remaining gaps — scope-picker components + per-project visibility section + ../relayfile-cloud workspace-integrations route — are tracked in specs/02-integrations.md. The Connect-flow rework is spec 05. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…UI files) Spec 03 main-process + renderer scaffolding: - src/main/proactive-agent.ts + .bundle.ts + .types.ts: ProactiveAgentManager (list/create/update/deploy/pause/resume/undeploy + run-transcript), bundle stager for handler source, route through resolveCloudAuth. - components/proactive/: ProactiveAgentsSection, ProactiveAgentCard, ProactiveAgentEditor. - hooks/use-proactive-agent.ts. Builds on shared scaffolding (#7). NOTE: the UI is not wired yet — ProactiveAgentsSection is defined but never rendered, the AppTabKind union does not include 'proactive-agent-editor', App.tsx does not render the editor, and @monaco-editor/react is not in package.json. Those gaps, plus vendored runtime types and the cloud proactive-personas backend (routes/schema/runtime), are tracked in specs/03-proactive-agents.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…11) * feat(relay-workspace): RelayWorkspaceManager scaffolding for Spec 05 WIP scaffolding for Spec 05's account-wide RelayWorkspaceManager — the single account-level relayfile workspace pear uses for the relayfile mount + integrations connect. Replaces the random per-project crypto.randomUUID() relayWorkspaceId in store.ts. - src/main/relay-workspace.ts: provisions/joins the account workspace via RelayfileSetup, caches the WorkspaceHandle. - src/main/relay-workspace.types.ts: persisted shape. - src/main/relay-workspace.test.ts: unit smoke. Remaining work (full Spec 05 implementation): wire the integrations connect flow to use handle.requestJson against connect-session / integrations/{provider}/status / integrations/{provider} (bypassing the SDK's whitelist-gated connectIntegration), replace project.relayWorkspaceId usages with RelayWorkspaceManager.getWorkspaceId(), add the per-project visibility section. See specs/05-integrations-connect.md. Builds on shared scaffolding (#7). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(relay-workspace): redirect stale bootstrap rejections to current handle createGuardedBootstrap only handled the success path of a superseded bootstrap (redirecting to getCurrentOrNextHandle inside .then). When a stale bootstrap rejected — e.g. a network blip on joinWorkspace after auth changed and a newer bootstrap already succeeded — the error propagated to the original caller even though a valid handle existed. Add a .catch that applies the same redirect logic before the .finally cleanup. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…olding) (#8) * feat(cloud-agents): pear-side cloud-agent feature (manager + UI scaffolding) Spec 01 scaffolding for cloud agents in pear: - src/main/cloud-agent.ts + cloud-agent.types.ts: CloudAgentManager (attach/detach/restore/list/create/delete, warm box polling, mount session via @relayfile/sdk, conflict-policy launcher, git sync-back). - components/agents/: AddAgentDialog (local vs cloud picker), CloudAgentDialog, CloudAgentPicker, CloudAuthRequired. - hooks/use-cloud-agent.ts + stores/cloud-agent-store.ts: renderer-side binding + catalog state. Builds on the shared scaffolding (#7). The remaining gaps — restore-on-launch in index.ts and the relayfile --conflict-policy CLI flag — are covered in the slimmed spec at specs/01-cloud-agents.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(cloud-agents): tighten auth-required regex, refresh mount token, memoize callbacks - CloudAgentPicker.isAuthRequiredError: match only explicit auth signals (cloud-auth-required / sign in to / login required / not logged in) instead of /auth|required|sign in|login/ which fired on innocuous messages like 'Cloud agent name is required' or 'authorization scope insufficient' and misrouted users to the sign-in screen. - cloud-agent.startMount: pass an async accessToken callback that resolves fresh credentials via resolveCloudAuth on each call. The previous closure captured a single token value, defeating RelayfileSetup's refresh mechanism and breaking long-running mounts when the token expired. - CloudAgentDialog: wrap onAuthenticated/onAuthRequired in useCallback so the picker's useEffect doesn't refire on every parent re-render and re-fetch the agent list. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… + Nango logos) (#9) * feat(integrations): pear-side integrations feature (manager + catalog + Nango logos) Spec 02 scaffolding plus the catalog/logo work done this session: - src/main/integrations.ts: IntegrationsManager. listCatalog filters to ACTIVE_PROVIDERS (the non-deprecated relayfile providers in cloud/packages/web/lib/integrations/providers.ts). authHeaders is async and routes through resolveCloudAuth. loadStaticCatalog is a static import (not a dynamic variable import, which the bundler couldn't resolve and which left the static fallback empty at runtime). - src/main/integrations.types.ts: IntegrationAdapter + visibility types. - src/main/integrations.catalog.ts: 36 generated adapters with iconUrl pointing at https://app.nango.dev/images/template-logos/{slug}.svg. - scripts/build-integrations-catalog.mjs: regenerates the catalog from ../relayfile-adapters/packages. Adds NANGO_LOGO_SLUG override map (gmail→google-mail, teams→microsoft-teams, x→twitter) and emits iconUrl per entry. - src/renderer/src/components/settings/AccountSettings.tsx: <IntegrationLogo> component with onError fallback to the generic plug icon (light tile makes the dark/monochrome SVGs legible), used in both the CATALOG grid and the CONNECTED list. Builds on shared scaffolding (#7). Remaining gaps — scope-picker components + per-project visibility section + ../relayfile-cloud workspace-integrations route — are tracked in specs/02-integrations.md. The Connect-flow rework is spec 05. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(integrations): keep persistIntegration's load→modify→save synchronous Resolve the async displayNameForProvider lookup BEFORE loadStore() so no await sits between load and save. With the async gap in place, any concurrent IPC handler (project:update, project:add-channel, etc.) that wrote to projects.json during the awaited catalog refresh would have its changes silently overwritten when we saved the stale data we loaded earlier. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…UI files) (#10) * feat(proactive-agents): pear-side proactive-agent feature (manager + UI files) Spec 03 main-process + renderer scaffolding: - src/main/proactive-agent.ts + .bundle.ts + .types.ts: ProactiveAgentManager (list/create/update/deploy/pause/resume/undeploy + run-transcript), bundle stager for handler source, route through resolveCloudAuth. - components/proactive/: ProactiveAgentsSection, ProactiveAgentCard, ProactiveAgentEditor. - hooks/use-proactive-agent.ts. Builds on shared scaffolding (#7). NOTE: the UI is not wired yet — ProactiveAgentsSection is defined but never rendered, the AppTabKind union does not include 'proactive-agent-editor', App.tsx does not render the editor, and @monaco-editor/react is not in package.json. Those gaps, plus vendored runtime types and the cloud proactive-personas backend (routes/schema/runtime), are tracked in specs/03-proactive-agents.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(proactive-agents): map 'cancelled' run-handle status to 'error' CloudRunHandleStatus includes 'cancelled' but mapDeployStatus had no branch for it, so a cancelled deployment fell through to the default 'active' and was reported as a successful one (or produced a contradictory { status: 'active', error: '…' } pair). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Foundational IPC + preload + store + lib changes shared by every per-spec feature branch in the cloud-agents wave. Per-spec feature branches (
ricky/wave-pear-cloud-agents/{01,02,03,05}) stack on top of this PR.Key piece:
src/main/auth.tsaddsresolveCloudAuth()+CloudAuth+accountKey, the unified credential resolver used by cloud-agent, proactive-agent, and integrations — mirrors how../workforceand../cloudreadCLOUD_API_*env /~/.agent-relay/cloud-auth.json.🤖 Generated with Claude Code