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 Jun 29, 2026
3 high 1 medium
🔍
// convert to your repo
PullLight caught 4 3 high, 1 medium on this PR.
Install on stripe/link-cli to get this on every PR automatically — 60 seconds.
Findings
4 issues
medium race-condition
The `nextRequestId` counter is a module-level mutable variable (`let nextRequestId = 1`). In environments where multiple `UcpResource` instances are used concurrently (e.g., multiple parallel requests), this shared mutable state can produce duplicate or out-of-order IDs across instances. It should be an instance variable or use a more robust ID generation strategy.
// packages/sdk/src/resources/ucp.ts:97
high auth
The `clientSecret` is passed as a plain string through CLI args (`--client-secret`) and stored in `UcpAuth`. When constructing the Basic auth header via `btoa('clientId:clientSecret')`, if `clientSecret` contains a colon (`:`) character, the credential will be silently malformed — the server will parse everything after the first colon as the password, but the client may have intended a different split. Additionally, `btoa` will throw a `DOMException` if either `clientId` or `clientSecret` contains non-Latin1 characters. There is no guard against either case.
// packages/sdk/src/resources/ucp.ts:(truncated)
high error-handling
In `cartCreate`, when `c.options.input` is falsy, `c.options.lineItems` is passed directly to `JSON.parse` without any null/undefined guard. The schema marks `lineItems` as required (non-optional) in `cartCreateOptions`, but if the CLI framework allows it to be absent or empty, `JSON.parse(undefined)` throws a `SyntaxError` that will surface as an unhandled exception rather than a user-friendly error message.
// packages/cli/src/commands/ucp/index.tsx:130
high error-handling
In `checkoutUpdate`, `c.options.input` is passed to `JSON.parse` unconditionally without a try/catch. If the user supplies malformed JSON, this will throw an unhandled `SyntaxError` instead of a structured CLI error. The same issue exists in `cartCreate` (line ~130) and `checkoutCreate` (line ~155) for the `input` path. All `JSON.parse` calls on user-supplied strings should be wrapped in try/catch.
// packages/cli/src/commands/ucp/index.tsx:175
model: claude-sonnet-4-5   input: 16319 tokens   output: 724 tokens