Get this on every PR automatically. Webhook fires, AI reviews, you approve.
Install on stripe/link-cli →
// reviewed by pulllight

PullLight found 4 issues

stripe/link-cli #184 — Basic UCP support by @raubrey-stripe Jul 7, 2026
2 high 1 medium 1 low
🔍
// convert to your repo
PullLight caught 4 2 high, 1 medium, 1 low on this PR.
Install on stripe/link-cli to get this on every PR automatically — 60 seconds.
Findings
4 issues
medium race-condition
The module-level `nextRequestId` counter is shared across all `UcpResource` instances. In a concurrent environment (e.g., multiple requests in-flight simultaneously), two calls could read the same value before either increments it, producing duplicate JSON-RPC request IDs. The counter should be instance-level or use an atomic increment pattern.
// packages/sdk/src/resources/ucp.ts:97
high auth
The `discoveryCache` and `negotiatedCache` are instance-level Maps, but `UcpResource` instances are created per-CLI-invocation (one per command run). This is fine for the CLI, but in the SDK the caches are never invalidated. More critically: if a `UcpResource` instance is shared across users (e.g., in a server context), the discovery cache will return stale results that include `rest_endpoint` and `mcp_endpoint` URLs from a prior user's discovery, potentially routing requests to the wrong merchant endpoint. The cache has no TTL or invalidation mechanism.
// packages/sdk/src/resources/ucp.ts:130
high error-handling
`JSON.parse(c.options.lineItems)` at line 113 (and similar calls at lines 130, 155, 165, 183, 196) will throw an unhandled exception if the user passes malformed JSON. The error will propagate as an uncaught exception rather than a clean CLI error message with a non-zero exit code. These should be wrapped in try/catch and surfaced as user-facing errors.
// packages/cli/src/commands/ucp/index.tsx:113
low other
`XDG_DATA_HOME` is hardcoded to `/tmp/link-cli-ucp-test` across all test runs. Parallel test execution (e.g., multiple CI workers) will share this directory, potentially causing state bleed between runs. Consider using a unique temp directory per test run (e.g., via `os.tmpdir()` + a random suffix).
// packages/cli/src/__tests__/ucp.test.ts:55
model: claude-sonnet-4-5   input: 16297 tokens   output: 673 tokens