Feat/bridge setup - #7
Merged
Merged
Conversation
Point npm bin at dist/bin/cursor-sdk-bridge.js so global installs resolve the package correctly, bump bridge to 0.0.2, and add cmd/setup plus cursor.Setup for npm global or local clone installs.
Correct dropEmpty preserve logic that leaked empty cloud blocks, stop sending idempotency keys for local agents, decouple bridge subprocess lifetime from caller context, enforce bridge >=0.0.2, and add opt-in e2e coverage with scripts/run-e2e.sh.
There was a problem hiding this comment.
Pull request overview
This PR improves the bridge installation/launch workflow for local agents and adds opt-in local end-to-end tests, while fixing SDK wire/lifecycle behaviors that caused spurious cloud/idempotency behavior and flaky bridge subprocess shutdowns.
Changes:
- Add
go run .../cmd/setupprerequisite installer (global npm install or local clone build/link) and update docs accordingly. - Update bridge resolution/launching to support the npm 0.0.2 layout (JS entrypoint via
node) and add minimum-version gating. - Fix local-vs-cloud wire shaping and idempotency behavior; add opt-in local e2e test suite + runner script.
Reviewed changes
Copilot reviewed 32 out of 34 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| scripts/run-e2e.sh | Adds a guarded local e2e test runner wrapper. |
| references/bridge.md | Updates bridge install/dev instructions and env var semantics. |
| README.md | Documents setup command, local e2e usage, and config vars. |
| internal/bridge/version.go | Adds bridge version detection + semver gating helpers. |
| internal/bridge/version_test.go | Tests version comparison helper. |
| internal/bridge/setup.go | Adds programmatic prerequisite install (global/local). |
| internal/bridge/setup_test.go | Tests bridge-dir discovery helper. |
| internal/bridge/resolve.go | Resolves launch argv (node + .js) vs direct exec. |
| internal/bridge/resolve_test.go | Tests resolution for npm 0.0.2 layout and launch argv behavior. |
| internal/bridge/npm.go | Pins minimum required npm bridge version. |
| internal/bridge/install.go | Improves “not found” guidance and root entrypoint selection. |
| internal/bridge/bridge.go | Decouples bridge process lifetime from caller ctx after startup; uses resolved argv. |
| internal/bridge/bridge_test.go | Adds integration-ish launch tests for ctx-cancel survival. |
| examples/basic/main.go | Adds explicit API key check and model env override. |
| e2e/sdk_test.go | Adds opt-in real-API integration tests (bridge version, prompt, etc.). |
| e2e/harness_test.go | Adds e2e harness helpers and environment gating. |
| e2e/examples_test.go | Adds e2e tests for running examples/building quickstart. |
| e2e/doc.go | Documents how to run the e2e suite. |
| cursor/wire.go | Fixes dropEmpty behavior for empty maps; adds cloud-options detection helper. |
| cursor/wire_internal_test.go | Adds tests for dropEmpty and cloud-options detection. |
| cursor/setup.go | Adds public SDK Setup wrapper for bridge prerequisite install. |
| cursor/cursor_test.go | Ensures local wire omits cloud entirely. |
| cursor/client.go | Restricts idempotency key behavior to cloud; updates cloud-RPC detection logic. |
| cursor/client_internal_test.go | Tests idempotency-key behavior for local vs cloud CreateAgent. |
| cursor/agent.go | Restricts Send idempotency key to cloud agent IDs. |
| CONTRIBUTING.md | Updates contributor workflow and adds local e2e instructions. |
| cmd/setup/main.go | Adds cmd/setup CLI entrypoint for prerequisites. |
| bridge/src/constants.ts | Bumps bridge version constant to 0.0.2. |
| bridge/README.md | Documents install via Go setup and local clone workflow. |
| bridge/PUBLISHING.md | Updates publishing notes for new bin layout and 0.0.2 install example. |
| bridge/package.json | Bumps to 0.0.2; npm bin points directly to built JS; adjusts published files. |
| bridge/package-lock.json | Lockfile updates to match 0.0.2 and bin entrypoint. |
| bridge/bin/cursor-sdk-bridge | Improves dev/local shell launcher symlink resolution. |
| AGENTS.md | Updates “before coding” workflow and documents e2e location. |
Files not reviewed (1)
- bridge/package-lock.json: Generated file
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| var ok bool | ||
| bridgeDir, ok = findBridgeDir("") | ||
| if !ok { | ||
| return fmt.Errorf("bridge/ not found; run from a cursor-go-sdk clone or pass --local with CURSOR_SDK_BRIDGE_ROOT") |
Comment on lines
+102
to
+105
| func parseSemver(version string) (major, minor, patch int, ok bool) { | ||
| version = strings.TrimPrefix(strings.TrimSpace(version), "v") | ||
| parts := strings.Split(version, ".") | ||
| if len(parts) < 3 { |
Comment on lines
+54
to
+82
| func bridgePackageRoot(entry string) (string, error) { | ||
| abs, err := filepath.Abs(entry) | ||
| if err != nil { | ||
| return "", err | ||
| } | ||
| jsSuffix := filepath.Join("dist", "bin", "cursor-sdk-bridge.js") | ||
| if strings.HasSuffix(abs, jsSuffix) { | ||
| return filepath.Dir(filepath.Dir(filepath.Dir(abs))), nil | ||
| } | ||
| binSuffix := filepath.Join("bin", launcherName()) | ||
| if strings.HasSuffix(abs, binSuffix) { | ||
| return filepath.Dir(filepath.Dir(abs)), nil | ||
| } | ||
| if strings.Contains(abs, string(filepath.Separator)+"node_modules"+string(filepath.Separator)) { | ||
| dir := filepath.Dir(abs) | ||
| for { | ||
| pkgJSON := filepath.Join(dir, "package.json") | ||
| if isBridgePackage(pkgJSON) { | ||
| return dir, nil | ||
| } | ||
| parent := filepath.Dir(dir) | ||
| if parent == dir { | ||
| break | ||
| } | ||
| dir = parent | ||
| } | ||
| } | ||
| return "", fmt.Errorf("cannot locate bridge package root from %q", entry) | ||
| } |
| | `CURSOR_E2E` | Set to `1` to enable local e2e tests in `e2e/` | | ||
| | `CURSOR_E2E_MODEL` | Model for e2e (default `auto`, falls back to `CURSOR_MODEL`) | | ||
| | `CURSOR_SDK_BRIDGE_BIN` | Override bridge launcher binary | | ||
| | `CURSOR_SDK_BRIDGE_ROOT` | Directory with `bin/cursor-sdk-bridge` | |
Honor CURSOR_SDK_BRIDGE_ROOT in local setup, harden semver parsing and package-root discovery, and align docs with the npm 0.0.2 layout.
Comment on lines
+39
to
+43
| func setupGlobal(ctx context.Context, version string) error { | ||
| if version == "" { | ||
| version = BridgeNpmVersion | ||
| } | ||
| pkg := bridgePackage + "@" + version |
| func main() { | ||
| local := flag.Bool("local", false, "install from ./bridge in a repository clone (npm ci && npm run build && npm link)") | ||
| bridgeDir := flag.String("bridge-dir", "", "path to bridge/ (implies --local when set)") | ||
| version := flag.String("version", "", "npm version for global install (default: pinned release)") |
Comment on lines
+81
to
+97
| func semverAtLeast(version, min string) bool { | ||
| vMajor, vMinor, vPatch, ok := parseSemver(version) | ||
| if !ok { | ||
| return false | ||
| } | ||
| mMajor, mMinor, mPatch, ok := parseSemver(min) | ||
| if !ok { | ||
| return false | ||
| } | ||
| if vMajor != mMajor { | ||
| return vMajor > mMajor | ||
| } | ||
| if vMinor != mMinor { | ||
| return vMinor > mMinor | ||
| } | ||
| return vPatch >= mPatch | ||
| } |
Comment on lines
+21
to
+23
| {"0.0.2+meta", "0.0.2", true}, | ||
| {"0.0.2-beta", "0.0.2", true}, | ||
| {"0.0.1-rc1", "0.0.2", false}, |
Validate --version before global npm install, clarify setup errors when version checks fail, and compare prereleases correctly while still ignoring build metadata.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
binpoints atdist/bin/cursor-sdk-bridge.js(fixes broken Homebrew/npm global install with shell wrapper); dev shell launcher kept forCURSOR_SDK_BRIDGE_ROOT.go run ./cmd/setup: installs@cursor-go-sdk/cursor-sdk-bridge@0.0.2globally or builds/links from a clone (--local).dropEmpty: empty maps no longer leak into wire ascloud: {}(was triggering idempotency on local agents).opts.Cloud != nil/bc-*on Send).context(exec.Command+ startup-only ctx); fixesconnection refusedafter tests/RPC cancel.>= 0.0.2, launch vianode+.jsentrypoint, preferdist/inCURSOR_SDK_BRIDGE_ROOT.-tags=e2e,CURSOR_E2E=1, realCURSOR_API_KEY);./scripts/run-e2e.sh.CURSOR_MODELenv (defaultcomposer-2), explicit API key check.Motivation
Global
npm install -g @cursor-go-sdk/cursor-sdk-bridge@0.0.1symlinked a shell script; when invoked via Homebrew,$0resolved to/opt/homebrew/bin/...and the script looked for JS in/opt/homebrew/dist/→MODULE_NOT_FOUND.Separately, Go SDK had wire/lifecycle bugs: phantom
cloud: {}caused spurious idempotency keys on localCreateAgent, andexec.CommandContextkilled the bridge when the caller context was cancelled.Test plan
go test ./...go test -tags=e2e -parallel=1 ./e2e/...withCURSOR_E2E=1andCURSOR_API_KEY(local only, not CI)@cursor-go-sdk/cursor-sdk-bridge@0.0.2to npm before users rely ongo run .../cmd/setup@latestnpm install -g @cursor-go-sdk/cursor-sdk-bridge@0.0.2on a clean machinego run ./examples/basic/./scripts/run-e2e.shPost-merge
cd bridge && npm publish --access public).cursor-sdk-bridge-v0.0.2.Files (high level)
bridge/bin→ JS, removebin/from publishedfilescmd/setup/,cursor/setup.go,internal/bridge/setup.gointernal/bridge/cursor/e2e/,scripts/run-e2e.sh