Skip to content

Fix provider runtime readiness and browser attachment#546

Merged
arul28 merged 3 commits into
mainfrom
ade/chat-20260609-124658-fb66b79d
Jun 9, 2026
Merged

Fix provider runtime readiness and browser attachment#546
arul28 merged 3 commits into
mainfrom
ade/chat-20260609-124658-fb66b79d

Conversation

@arul28

@arul28 arul28 commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Summary

  • Fix Cursor SDK loading in packaged ADE/CLI runtimes and require verified SDK/model readiness before showing Cursor chat models as usable.
  • Harden Cursor and Droid SDK worker IPC so failed workers reject the chat instead of taking down the brain process.
  • Emit the Droid SDK worker in ADE CLI packaging and add loader fallback for packaged runtime resolution.
  • Keep built-in browser views attached when project-scoped calls resolve a window, including multi-window project switches.
  • Update Cursor settings/onboarding copy to the API dashboard link and make verification banners dismissible with proper error styling.

Validation

  • npm --prefix apps/desktop run test -- src/main/services/ai/providerConnectionStatus.test.ts src/main/services/builtInBrowser/builtInBrowserService.test.ts src/main/services/chat/cursorSdkPool.test.ts src/main/services/chat/cursorModelsDiscovery.test.ts src/main/services/chat/droidSdkPool.test.ts src/renderer/components/settings/ProvidersSection.test.tsx src/renderer/lib/modelOptions.test.ts src/renderer/components/shared/ModelPicker/providerEmptyState.test.tsx
  • npm --prefix apps/desktop run typecheck
  • npm --prefix apps/ade-cli run typecheck
  • npm --prefix apps/ade-cli run test
  • npm --prefix apps/desktop run lint (passes with existing warnings)
  • npm --prefix apps/desktop run build
  • npm run test:desktop:sharded failed only because local ADE Beta brain owned the sync singleton lock on port 8807; reran shards 3-8 with ADE_SYNC_HOST_LOCK_PATH isolated after shards 1-2 had already passed.
  • git diff --check

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved Cursor and Droid SDK loading resilience with fallback mechanisms for resolution failures
    • Enhanced error handling and reporting for SDK initialization and API key verification flows
    • Fixed browser service attachment to ensure proper initialization in project-scoped sessions
    • Updated Cursor API key verification to report runtime health more accurately
    • Corrected dashboard links from integrations page to API page across onboarding and settings
  • Tests

    • Added tests for SDK worker initialization failures and IPC error handling
    • Expanded provider connection status and model discovery test coverage

Greptile Summary

This PR hardens Cursor and Droid SDK loading in packaged/CLI runtimes with a require-based fallback, gates runtimeAvailable behind explicit verification (SDK load + model-list check), and fixes built-in browser views being detached on project-scoped window resolution.

  • SDK loader + IPC resilience: New cursorSdkLoader/droidSdkLoader modules add a createRequire-based fallback for packaged runtimes; cursorSdkPool/droidSdkPool get a sendWorkerMessage helper with closed-channel guards, an "error" event handler, and shared rejectPending/cleanupPoolEntry helpers used by both "error" and "exit" handlers.
  • Runtime readiness gating: providerConnectionStatus now sets runtimeAvailable only when providerRuntimeHealth.state === "ready"; authDetector.verifyCursorApiKey validates model access (models.list) in addition to identity (Cursor.me) and reports both auth and non-auth failures; modelOptions and the model picker only surface Cursor models after runtime is verified.
  • Browser attachment fix: builtInBrowserService.serviceForProjectRoot now calls attachToWindow immediately on every project-scoped resolution, and main.ts calls attachToWindow in bindWindowToProject so views are attached on project switches without waiting for a window-focus event.

Confidence Score: 5/5

Safe to merge; all changed paths are well-guarded and covered by the new tests.

The runtime-readiness gating, IPC hardening, and browser-attachment fix are each narrow, self-contained changes with direct test coverage. No pre-existing guarantees are removed, and the fallback loader degrades gracefully when packaged-runtime resolution fails.

No files require special attention.

Important Files Changed

Filename Overview
apps/desktop/src/main/services/ai/cursorSdkLoader.ts New file: implements a cached, fallback-aware Cursor SDK loader with require-based resolution for packaged runtimes; exposes resetCursorSdkLoaderForTests for clean test isolation.
apps/desktop/src/main/services/ai/droidSdkLoader.ts New file: symmetric counterpart to cursorSdkLoader for the Droid SDK; identical loading and error-classification logic targeting @factory/droid-sdk.
apps/desktop/src/main/services/ai/providerConnectionStatus.ts Cursor runtimeAvailable now requires providerRuntimeHealth.state === 'ready' instead of just auth presence; blocker text updated to guide users through verification.
apps/desktop/src/main/services/ai/authDetector.ts verifyCursorApiKey now validates model access via Cursor.models.list in addition to Cursor.me; reports runtime-failure (not just auth-failure) for non-auth errors like SDK unavailability or empty model list.
apps/desktop/src/main/services/chat/cursorSdkPool.ts Adds sendWorkerMessage helper that guards against closed IPC channels; adds child.on('error') handler; refactors rejectPending/cleanupPoolEntry to be shared between error and exit handlers.
apps/desktop/src/main/services/chat/droidSdkPool.ts Symmetric IPC hardening mirroring cursorSdkPool; cleanupPoolEntry for droid intentionally omits path cleanup since the droid pool entry carries no cacheRoot/stateRoot/socketPath.
apps/desktop/src/main/services/builtInBrowser/builtInBrowserService.ts serviceForProjectRoot now calls service.attachToWindow(win) after resolving the per-project service; attachToWindow short-circuits when the window object is already the same to avoid redundant re-attachment teardown.
apps/desktop/src/main/main.ts Calls builtInBrowserService.attachToWindow(win) inside bindWindowToProject so browser views are attached immediately on project switch, not only on the next window-focus event.
apps/desktop/src/renderer/components/settings/ProvidersSection.tsx Introduces a reusable AlertBanner with dismiss support; verification failures now populate the error banner with the actual error message; 'Invalid key' label renamed to 'Verification failed'.
apps/desktop/src/main/services/chat/cursorModelsDiscovery.ts SDK resolution failures now short-circuit the HTTP fallback path, record a TTL-bounded failure cache entry, and report to provider health; warmCursorModelsFromSdk skips warming during recent SDK failures.
apps/desktop/src/renderer/lib/modelOptions.ts Cursor SDK models are only included in derived model IDs when availableProviders.cursor === true or providerConnections.cursor.runtimeAvailable === true; stored key alone no longer unlocks them.
apps/ade-cli/tsup.config.ts Adds droidSdkWorker as an explicit tsup entry point so the Droid worker is emitted into the ADE CLI bundle alongside the Cursor worker.

Comments Outside Diff (1)

  1. apps/desktop/src/renderer/components/settings/ProvidersSection.tsx, line 514-538 (link)

    P2 notice and error banners can stack simultaneously

    Neither setNotice nor setError clears its counterpart before setting a value. A user who successfully verifies a key (notice appears, they don't dismiss it) and then immediately tries re-verification that fails will see both the green "Cursor connection verified." banner and the new red error banner at the same time. The same applies in the verifyApiKey path. Adding setError(null) before setNotice(...) and setNotice(null) before setError(...) in each branch would prevent the overlap.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: apps/desktop/src/renderer/components/settings/ProvidersSection.tsx
    Line: 514-538
    
    Comment:
    **`notice` and `error` banners can stack simultaneously**
    
    Neither `setNotice` nor `setError` clears its counterpart before setting a value. A user who successfully verifies a key (notice appears, they don't dismiss it) and then immediately tries re-verification that fails will see both the green "Cursor connection verified." banner and the new red error banner at the same time. The same applies in the `verifyApiKey` path. Adding `setError(null)` before `setNotice(...)` and `setNotice(null)` before `setError(...)` in each branch would prevent the overlap.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Claude Code

Reviews (2): Last reviewed commit: "Stabilize background CLI draft test" | Re-trigger Greptile

@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
ade Ignored Ignored Preview Jun 9, 2026 7:22pm

@arul28 arul28 changed the title Chat 20260609 124658 Fix provider runtime readiness and browser attachment Jun 9, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR refactors Cursor and Droid SDK module loading to support both ESM dynamic import and packaged-runtime fallback resolution, tightens runtime availability gating to depend on health-state readiness, improves SDK worker pool IPC lifecycle reliability, and updates consumer code to align with the new runtime-verified availability model.

Changes

SDK Loading and Worker Lifecycle Integration

Layer / File(s) Summary
Centralized SDK Loaders with Fallback Resolution
apps/desktop/src/main/services/ai/cursorSdkLoader.ts, apps/desktop/src/main/services/ai/droidSdkLoader.ts, apps/desktop/src/main/services/chat/cursorSdkWorker.ts, apps/desktop/src/main/services/chat/droidSdkWorker.ts, apps/desktop/src/main/services/ai/aiIntegrationService.ts, apps/desktop/src/main/services/ai/authDetector.ts, apps/desktop/src/main/services/ai/providerTaskRunner.ts, apps/ade-cli/src/cursorCloud.ts, apps/ade-cli/tsup.config.ts
New cursorSdkLoader and droidSdkLoader modules provide cached ESM-to-requireFromRuntime fallback loading with resolution-error classification. Worker modules and all SDK-consuming services now use centralized loaders instead of direct imports, enabling resilient module acquisition across packaged-runtime and development environments.
SDK Worker Pool IPC Lifecycle Hardening
apps/desktop/src/main/services/chat/cursorSdkPool.ts, apps/desktop/src/main/services/chat/cursorSdkPool.test.ts, apps/desktop/src/main/services/chat/droidSdkPool.ts, apps/desktop/src/main/services/chat/droidSdkPool.test.ts
Centralized sendWorkerMessage helpers guard IPC sends against closed/exited channels; unified error callbacks reject pending RPCs and clean up pool entries consistently. New tests verify rejection (not throw) when worker exits before initialization, ensuring graceful handling of lifecycle failures.

Runtime Availability and Model Discovery

Layer / File(s) Summary
Runtime Health-Based Availability Gating
apps/desktop/src/main/services/ai/providerConnectionStatus.ts, apps/desktop/src/main/services/ai/providerConnectionStatus.test.ts, apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerLayout.ts
Cursor runtimeAvailable now depends on cursorRuntimeHealth.state === "ready" instead of API-key presence alone. Blocker messages branch through credential sources (SDK key, admin key, invalid env, unreadable store) and direct users to Cursor dashboard API page. Tests updated to expect strict gating: stored auth alone does not mark runtime available; SDK readiness probe is required.
Cursor Model Discovery with Failure Reporting
apps/desktop/src/main/services/chat/cursorModelsDiscovery.ts, apps/desktop/src/main/services/chat/cursorModelsDiscovery.test.ts
Model discovery now uses centralized loadCursorSdk() and reports unavailable failures via reportProviderRuntimeFailure() (alongside existing auth-failure reporting). Cached results short-circuit when last failure is auth or unavailable within TTL. SDK resolution errors are explicitly detected and converted to discovery errors.

Browser Service and Consumer Updates

Layer / File(s) Summary
Built-in Browser Service Explicit Attachment
apps/desktop/src/main/services/builtInBrowser/builtInBrowserService.ts, apps/desktop/src/main/services/builtInBrowser/builtInBrowserService.test.ts, apps/desktop/src/main/main.ts
Project-scoped browser service now explicitly calls attachToWindow() when resolving live windows; same-window attachment avoids teardown/rebind via early-return. Comprehensive tests verify immediate attachment on bounds-set, stability across repeated calls, and independence across separate project windows.
UI Updates and Runtime Availability Consumer Integration
apps/desktop/src/renderer/components/chat/AgentChatPane.tsx, apps/desktop/src/renderer/components/onboarding/AiRuntimesBand.tsx, apps/desktop/src/renderer/components/settings/ProvidersSection.tsx, apps/desktop/src/renderer/components/settings/ProvidersSection.test.tsx, apps/desktop/src/renderer/components/shared/ModelPicker/providerEmptyState.tsx, apps/desktop/src/renderer/components/shared/ModelPicker/providerEmptyState.test.tsx, apps/desktop/src/renderer/lib/modelOptions.ts, apps/desktop/src/renderer/lib/modelOptions.test.ts, apps/desktop/src/main/services/chat/agentChatService.ts
Dashboard links redirect from /integrations to /api across onboarding and provider flows. ProvidersSection introduces AlertBanner component for dismissible notices and reorders verification flow to refresh status before updating UI state. Cursor Cloud availability checks and model inclusion now depend on runtimeAvailable rather than stored auth alone.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • arul28/ADE#223: New centralized cursorSdkLoader and integration into cursorSdkWorker is directly tied to Cursor SDK worker-based chat integration.
  • arul28/ADE#229: Both PRs modify cursorModelsDiscovery.ts—this PR adds loadCursorSdk() and failure reporting; PR#229 refactors discovery into probe/cached modes with structured failure kinds.
  • arul28/ADE#118: Broader Cursor provider/model discovery integration; both PRs refactor Cursor SDK loading and tighten runtime availability gating in providerConnectionStatus and discovery paths.

Suggested labels

desktop

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Fix provider runtime readiness and browser attachment' clearly summarizes the main changes: updates to provider runtime health logic and browser service attachment behavior across multiple files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ade/chat-20260609-124658-fb66b79d

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@arul28

arul28 commented Jun 9, 2026

Copy link
Copy Markdown
Owner Author

@copilot review but do not make fixes

@mintlify

mintlify Bot commented Jun 9, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
ade-ac1c6011 🟢 Ready View Preview Jun 9, 2026, 6:47 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Comment thread apps/desktop/src/main/services/ai/cursorSdkLoader.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/desktop/src/main/services/ai/authDetector.ts (1)

802-830: ⚠️ Potential issue | 🟠 Major

Don’t mark Cursor runtime "ready" after Cursor.me()
verifyCursorApiKey() calls reportProviderRuntimeReady("cursor") immediately after Cursor.me({ apiKey: key }) in apps/desktop/src/main/services/ai/authDetector.ts (around lines 802-830). Cursor.me() validates the API key’s identity, but it doesn’t prove access to the models/catalog. Since providerConnectionStatus.ts uses health.state === "ready" to set runtimeAvailable (and unblock renderer/chat), a key that later fails the models-list/access checks can temporarily enable UI incorrectly. Gate "ready" on a successful model/access discovery step (e.g., after Cursor.models.list({ apiKey })), or split auth-only vs model-ready health states.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/desktop/src/main/services/ai/authDetector.ts` around lines 802 - 830,
verifyCursorApiKey() currently calls reportProviderRuntimeReady("cursor")
immediately after Cursor.me(...) which only verifies identity and can falsely
flip health.state === "ready"; remove that ready call and instead perform a
models/access discovery (e.g., call Cursor.models.list({ apiKey: key }) or
another model-access check) and only call reportProviderRuntimeReady("cursor")
after that succeeds, or alternatively emit a distinct auth-only status and defer
setting health.state === "ready" until model discovery completes; update
references in verifyCursorApiKey(), Cursor.me, and any logic that relies on
providerConnectionStatus.ts / health.state === "ready" accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/desktop/src/main/services/ai/cursorSdkLoader.ts`:
- Around line 7-9: The fallback anchor for createRequire currently uses
process.cwd(), allowing workspace CWD to influence requireFromRuntime
resolution; change the fallback to an application-owned/module-relative path
instead. Update the createRequire call in cursorSdkLoader.ts (the
requireFromRuntime initialization) to compute a module file path anchored to
this module (e.g., derive a file path from import.meta.url using fileURLToPath
and path.dirname, then join that dirname with "package.json") so when __filename
is unavailable you use the module/app package.json location rather than
process.cwd().

In `@apps/desktop/src/main/services/ai/droidSdkLoader.ts`:
- Around line 7-9: The current requireFromRuntime uses process.cwd() when
__filename is missing, which can cause a workspace-installed `@factory/droid-sdk`
to be resolved into the privileged process; change the fallback to an
app/module-relative anchor instead. Update the createRequire call in
droidSdkLoader.ts (the requireFromRuntime creation) to use a path anchored to
this module (e.g., derive a package.json path from __dirname or import.meta.url
/ path.dirname of this file) rather than path.join(process.cwd(),
"package.json"), so the fallback require is resolved from the app/module
directory you control and not the current working directory.

In `@apps/desktop/src/main/services/chat/cursorModelsDiscovery.ts`:
- Around line 630-637: The current failure TTL check that returns null for
recent sdkLastFailure (variables: sdkLastFailure, keyHash, TTL_MS) is bypassed
by the warm path because discoverCursorSdkModelDescriptors(..., { mode:
"cached-or-fallback" }) treats null as a cold cache and calls
warmCursorModelsFromSdk(), causing repeated probes; change the logic so the
failure state is propagated to callers instead of returning null (or
alternatively add the same TTL check inside warmCursorModelsFromSdk) so
discoverCursorSdkModelDescriptors can short-circuit warmCursorModelsFromSdk when
sdkLastFailure exists and is within TTL; update code paths that call
discoverCursorSdkModelDescriptors to handle a distinct failure sentinel (or
thrown/returned failure object) rather than null, and document use of
sdkLastFailure, keyHash and TTL_MS in that flow.

---

Outside diff comments:
In `@apps/desktop/src/main/services/ai/authDetector.ts`:
- Around line 802-830: verifyCursorApiKey() currently calls
reportProviderRuntimeReady("cursor") immediately after Cursor.me(...) which only
verifies identity and can falsely flip health.state === "ready"; remove that
ready call and instead perform a models/access discovery (e.g., call
Cursor.models.list({ apiKey: key }) or another model-access check) and only call
reportProviderRuntimeReady("cursor") after that succeeds, or alternatively emit
a distinct auth-only status and defer setting health.state === "ready" until
model discovery completes; update references in verifyCursorApiKey(), Cursor.me,
and any logic that relies on providerConnectionStatus.ts / health.state ===
"ready" accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d796334a-adc7-4cc6-9ca0-658fc51bc47c

📥 Commits

Reviewing files that changed from the base of the PR and between 1720ef1 and 7cc1872.

📒 Files selected for processing (30)
  • apps/ade-cli/src/cursorCloud.ts
  • apps/ade-cli/src/tuiClient/components/ModelPicker/modelPickerLayout.ts
  • apps/ade-cli/tsup.config.ts
  • apps/desktop/src/main/main.ts
  • apps/desktop/src/main/services/ai/aiIntegrationService.ts
  • apps/desktop/src/main/services/ai/authDetector.ts
  • apps/desktop/src/main/services/ai/cursorSdkLoader.ts
  • apps/desktop/src/main/services/ai/droidSdkLoader.ts
  • apps/desktop/src/main/services/ai/providerConnectionStatus.test.ts
  • apps/desktop/src/main/services/ai/providerConnectionStatus.ts
  • apps/desktop/src/main/services/ai/providerTaskRunner.ts
  • apps/desktop/src/main/services/builtInBrowser/builtInBrowserService.test.ts
  • apps/desktop/src/main/services/builtInBrowser/builtInBrowserService.ts
  • apps/desktop/src/main/services/chat/agentChatService.ts
  • apps/desktop/src/main/services/chat/cursorModelsDiscovery.test.ts
  • apps/desktop/src/main/services/chat/cursorModelsDiscovery.ts
  • apps/desktop/src/main/services/chat/cursorSdkPool.test.ts
  • apps/desktop/src/main/services/chat/cursorSdkPool.ts
  • apps/desktop/src/main/services/chat/cursorSdkWorker.ts
  • apps/desktop/src/main/services/chat/droidSdkPool.test.ts
  • apps/desktop/src/main/services/chat/droidSdkPool.ts
  • apps/desktop/src/main/services/chat/droidSdkWorker.ts
  • apps/desktop/src/renderer/components/chat/AgentChatPane.tsx
  • apps/desktop/src/renderer/components/onboarding/AiRuntimesBand.tsx
  • apps/desktop/src/renderer/components/settings/ProvidersSection.test.tsx
  • apps/desktop/src/renderer/components/settings/ProvidersSection.tsx
  • apps/desktop/src/renderer/components/shared/ModelPicker/providerEmptyState.test.tsx
  • apps/desktop/src/renderer/components/shared/ModelPicker/providerEmptyState.tsx
  • apps/desktop/src/renderer/lib/modelOptions.test.ts
  • apps/desktop/src/renderer/lib/modelOptions.ts

Comment thread apps/desktop/src/main/services/ai/cursorSdkLoader.ts
Comment thread apps/desktop/src/main/services/ai/droidSdkLoader.ts
Comment thread apps/desktop/src/main/services/chat/cursorModelsDiscovery.ts Outdated
@arul28

arul28 commented Jun 9, 2026

Copy link
Copy Markdown
Owner Author

@copilot review but do not make fixes

@arul28

arul28 commented Jun 9, 2026

Copy link
Copy Markdown
Owner Author

@copilot review but do not make fixes

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