Skip to content

feat(desktop): complete Effect migration for main process - #330

Draft
charleslpan wants to merge 14 commits into
mainfrom
cursor/effect-migration-0405
Draft

feat(desktop): complete Effect migration for main process#330
charleslpan wants to merge 14 commits into
mainfrom
cursor/effect-migration-0405

Conversation

@charleslpan

@charleslpancharleslpan commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Summary

Unblocks and completes the Effect migration for the desktop main process and sidecar-core.

Blockers fixed

  • Hung tests: singleFlight deadlocked on semaphore + deferred await; linear OAuth tests awaited raw Effects; update-service test called release before fetch started.
  • 154+ test failures: Cloud/local/hosted adapter tests now run Effects through runHttpEffect / runLocalEffect / runCliEffect at test boundaries.
  • Electron import in tests: action-handler injects runtime instead of importing desktop-app at module load.

Notable source fixes

  • linear-oauth.ts: clear waiting timeout when callback is claimed.
  • account-token-lifecycle.ts: fix single-flight lock scope.
  • Evaluators: fix #quietUntil Ref initialization.
  • observation-loop.ts: remove default Effect.orDie fallback.

Evidence

  • Platform-independent checks: ./scripts/check.sh pass (lint, oxlint, typecheck, 1207 desktop tests, build)
  • macOS Electron verification (./scripts/verify.sh): not run (cloud VM)

Automated visual evidence

CI will replace this block with a link to the deterministic macOS screenshots.

Physical-device evidence

  • Screenshot or screen recording: not attached
  • Physical-notch check: not performed
  • Device/display configuration: not recorded

Notes

  • Blockers or follow-up verification: ./scripts/verify.sh on macOS before merge
Open in WebOpen in Cursor

Migrate SessionProviderAdapter, InMemorySessionRegistry.refresh,
CompositeSessionProviderAdapter, IssueTrackerAdapter, and
AttentionEvaluator from Promise to Effect. Add AttentionRateLimited
tagged error and Effect.retry rate-limit handling in
SessionAttentionReviewer. Update sidecar-core tests to use
Effect.runPromise at boundaries.
Delete effect-runtime.ts; build ManagedRuntime in desktop-app.ts.
Inject runRequestEffect into makeHttpLive so http.ts never calls runPromise.
Remove runSync/runPromise from account-loopback and google-calendar-oauth timeouts.
…ators
SupersetCli/SignIn use Cli and Files. UpdateService and ProductEventSender
use singleFlight instead of Promise inFlight. Attention evaluators drop
quietUntil in favor of AttentionRateLimited. AccountSessionManager signOut
returns Effect; session IPC uses signOutForIpc at the edge.
Wrap cloud and CLI adapter observe/send/control/create calls with
runHttpEffect and runCliEffect at the test boundary. Update adapter
helpers to use Effect-based readApiKey and remove fetch from
constructor options. Fix Cursor repository refresh to use forkDaemon
so sidebar reads survive the observation pass.
Extend CliFailure with an optional stderr field so CLI adapters can
surface bounded provider error text. Update sidecar-core tests to run
Effect-returning mocks through a shared test runner.
Replace broken Ref-based rate-limit quiet windows with instance fields,
wire observation-loop through injectable runEffect, extract workspace
creation stderr from CliFailure, and align handlers with Effect-returning
stores and CLIs.
Wrap Effect-returning service and adapter calls with runLocalEffect,
runHttpEffect, and runCliWithFiles helpers. Stabilize async sign-in
openExternal assertions and align hosted, OpenAI, and Superset tests with
Effect-based APIs.
@vercel

vercelBot commented Aug 20, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
luke-webSkippedSkippedAug 20, 2026 4:28am

Request Review

@cursorcursorBot 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.

Cursor Bugbot has reviewed your changes using default effort and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit bcc4c2c. Configure here.

this.#options.onChange(this.#account);
const stored = options.revokeRemote ? yield* this.#options.store.readAccount() : undefined;
const clearing = yield* this.#options.store.clearAccount();
yield* this.#options.stopCapabilities();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sign-out skips stopping capabilities

High Severity

signOut now waits for clearAccount before stopCapabilities. A store failure leaves the UI already marked signed out while capabilities keep running. Previously clearing was started in parallel and capabilities always stopped first.

Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit bcc4c2c. Configure here.

const raw = yield* http.readJson(response);
// SAFETY: OAuth JSON responses match WireBoundaryInput at this HTTP boundary.
return wireBodyFromJson(raw as WireBoundaryInput);
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Failed JSON hides token status

Medium Severity

readOAuthJson parses the body before responseRecord reads response.ok. A 401 with empty or invalid JSON becomes CloudFailure instead of AccountClientFailure with status, so accessTokenNeedsRefresh never treats it as expiry.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit bcc4c2c. Configure here.

while: (error) => error.failure === CLOUD_FAILURE.TRANSIENT,
schedule: TRANSIENT_RETRY_SCHEDULE,
}),
);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Timed-out cloud fetches keep running

Medium Severity

Cloud reads and writes replaced AbortSignal.timeout with Effect.timeout and retry transient failures twice. The underlying fetch is not aborted, so each timeout can leave a live request and start another, stacking connections during observation.

Additional Locations (1)
Fix in CursorFix in Web

Reviewed by Cursor Bugbot for commit bcc4c2c. Configure here.

Sign up for freeto 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.

2 participants

@charleslpan@cursoragent