pi-cursor-sdk 0.5.4 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -1
- package/README.md +4 -4
- package/dist/cursor-fallback-models.generated.js +161 -1
- package/dist/cursor-local-run-terminal-error.js +57 -0
- package/dist/cursor-provider-turn-finalize.js +2 -0
- package/dist/cursor-provider-turn-send.js +3 -0
- package/dist/cursor-session-store.js +2 -1
- package/docs/cursor-live-smoke-checklist.md +2 -2
- package/docs/cursor-model-ux-spec.md +4 -2
- package/docs/cursor-native-tool-visual-audit.md +1 -1
- package/docs/cursor-testing-lessons.md +7 -1
- package/docs/cursor-tool-surfaces.md +3 -3
- package/docs/development.md +15 -7
- package/docs/reference.md +9 -5
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/package.json +1 -1
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/src/v4/core/compile.ts +9 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/src/v4/core/schemas.ts +35 -1
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/src/v4/core/util.ts +13 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/src/v4/core/versions.ts +1 -1
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/compile.cjs +8 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/compile.js +8 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/schemas.cjs +30 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/schemas.d.cts +3 -1
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/schemas.d.ts +3 -1
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/schemas.js +30 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/util.cjs +15 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/util.d.cts +2 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/util.d.ts +2 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/util.js +14 -0
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/versions.cjs +1 -1
- package/node_modules/@modelcontextprotocol/core/node_modules/zod/v4/core/versions.js +1 -1
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/package.json +1 -1
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/src/v4/classic/tests/array.test.ts +27 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/src/v4/classic/tests/map.test.ts +7 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/src/v4/classic/tests/set.test.ts +6 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/src/v4/core/compile.ts +9 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/src/v4/core/schemas.ts +35 -1
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/src/v4/core/util.ts +13 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/src/v4/core/versions.ts +1 -1
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/compile.cjs +8 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/compile.js +8 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/schemas.cjs +30 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/schemas.d.cts +3 -1
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/schemas.d.ts +3 -1
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/schemas.js +30 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/util.cjs +15 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/util.d.cts +2 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/util.d.ts +2 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/util.js +14 -0
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/versions.cjs +1 -1
- package/node_modules/@modelcontextprotocol/server/node_modules/zod/v4/core/versions.js +1 -1
- package/package.json +9 -3
- package/scripts/steering-rpc-smoke.mjs +1 -1
- package/src/cursor-fallback-models.generated.ts +161 -1
- package/src/cursor-local-run-terminal-error.ts +58 -0
- package/src/cursor-provider-turn-finalize.ts +2 -0
- package/src/cursor-provider-turn-send.ts +2 -0
- package/src/cursor-session-store.ts +2 -1
package/docs/development.md
CHANGED
|
@@ -12,6 +12,14 @@ No paid Cursor Cloud testing for generic PRs or releases. Only a PR or issue exp
|
|
|
12
12
|
|
|
13
13
|
The older live smoke helpers remain useful for inner-loop debugging and focused visual audits, not as the release gate. Use [Cursor live smoke checklist](./cursor-live-smoke-checklist.md), `npm run smoke:visual`, `npm run smoke:live`, or direct `pi --approve -e . --cursor-no-fast --model cursor/grok-4.6` runs only when a changed TUI/card/runtime behavior needs new live evidence. Select one relevant check rather than executing every helper. `npm run smoke:visual` captures an offscreen PTY rendered through browser/xterm and saved as PNG screenshots with Playwright, or with `agent_browser` from the generated HTML when available. Its default matrix is native replay only: native replay registration is forced on, Cursor setting sources are disabled, the pi bridge is off, overlapping built-in pi tools are not exposed, and inherited Cursor SDK event-debug artifact env is cleared; `--event-debug` writes to a deterministic debug directory under the visual output directory. The visible TUI/output, rendered screenshots, scrubbed diagnostics, and persisted JSONL must agree. See [Cursor testing lessons](./cursor-testing-lessons.md) for auth.json seeding, isolated `/tmp` harness layout, JSONL replay-error scans, and other regression traps.
|
|
14
14
|
|
|
15
|
+
## Zod peer and bridge packaging
|
|
16
|
+
|
|
17
|
+
Keep the exact SDK peer `zod@4.6.6` external and the bridge's newer nested `zod@4.6.7` copies bundled. Both contain the upstream bounded-collection fix; their published tarballs differ only in version metadata. This uses npm's ordinary locked dependency layout, not overrides, copied dependencies or SDK patches.
|
|
18
|
+
|
|
19
|
+
Preserve that layout when updating dependencies. Installing the bridge's Zod version at the package root or deduplicating can move the shared copy to the root, where npm includes it in the bridge bundle. Pi's `--legacy-peer-deps` consumer then hoists the unbundled SDK without an accessible Zod peer. `--omit=peer` is not equivalent and does not reproduce that failure.
|
|
20
|
+
|
|
21
|
+
`test/package-metadata.test.ts` owns the required peer/entrypoint contract, SDK v4/v4-mini and bridge parser controls, and the packed-root exclusion guard. For Zod or bundling changes, also pack the built source and install that exact tarball into fresh consumers with default npm, Pi-managed npm (`--legacy-peer-deps --no-audit`), npm `--omit=peer`, Pi-managed pnpm (peer auto-installation off) and Pi-managed Bun (`--omit=peer`). Check actual SDK ESM imports and SDK-relative `zod`, `zod/v3`, `zod/v4`, `zod/v4-mini` resolution, plus the bundled bridge. Retain artifact hashes and installer versions. A clean audit or source-only parser test does not prove the published installation works.
|
|
22
|
+
|
|
15
23
|
## Maintainer Cursor SDK event capture
|
|
16
24
|
|
|
17
25
|
Use `npm run debug:sdk-events` to capture timestamped `run.stream()`, `onDelta`, and `onStep` timelines for one direct `@cursor/sdk` run.
|
|
@@ -22,19 +30,19 @@ See [Cursor testing lessons](./cursor-testing-lessons.md#cursor-sdk-event-captur
|
|
|
22
30
|
|
|
23
31
|
## Automatic npm releases (maintainers)
|
|
24
32
|
|
|
25
|
-
Follow the [shared release procedure](https://github.com/fitchmultz/.github#automatic-npm-releases)
|
|
26
|
-
|
|
27
|
-
For the first release containing the native-tool opt-out and `/cursor-abort` from #372, update their availability notes in `README.md`, `docs/reference.md`, and `docs/cursor-tool-surfaces.md` to name the minimum supporting release version. Preserve the warning that published 0.5.3 lacks these controls, and do not call the candidate published until npm/GitHub publication records confirm it.
|
|
33
|
+
Follow the [shared release procedure](https://github.com/fitchmultz/.github#automatic-npm-releases). When enabled, the `npm release` workflow plans releases on `main` pushes, a daily schedule, and manual dispatch. It runs the existing offline compatibility and native macOS/Windows jobs and qualifies a candidate tarball before publication to npm and GitHub.
|
|
28
34
|
|
|
29
|
-
|
|
35
|
+
Before merging, check the final PR head (up to date with `main`) against the [release review gate](../AGENTS.md#release-review-gate-maintainer) and [cost-conscious verification policy](#maintainer-cost-conscious-verification). Complete the exact-release-diff deep review with zero findings, the documented pre-release catalog check, and any genuinely necessary changed-behavior proof. Merging attests genuine satisfaction of existing requirements; it does not create proof. Authenticated checks remain outside CI; automated Cursor PR reviews remain unchanged, and no routine paid Cloud campaigns or paid retries are added. Automated publication disables npm hooks to publish the checked bytes; existing manual publisher instructions remain valid.
|
|
30
36
|
|
|
31
|
-
|
|
37
|
+
Before retrying a failed or unpublished candidate, inspect its exact source/run identities and the shared retry procedure. An authentication repair alone does not authorize publishing an old candidate after `main` advances. Never move an existing tag, overwrite its draft/assets, or relabel old proof. The [0.5.1 changelog](../CHANGELOG.md#051-unpublished-source-history) is unpublished source history carried into 0.5.2, not a successful publication record. Set repository variable `NPM_RELEASE_ENABLED` to anything other than `true` to stop new release plans; cancel pending runs separately when needed. Workflow validation is not evidence of a completed real OIDC publication.
|
|
32
38
|
|
|
33
|
-
Publication records are independent:
|
|
39
|
+
Publication records are independent: npm published 0.5.2, while GitHub's `v0.5.2` release remains a draft bound to source `9820ae7`. Preserve that tag, draft, and candidate assets unchanged. Verify npm and GitHub records independently for each new release.
|
|
34
40
|
|
|
35
41
|
## Development
|
|
36
42
|
|
|
37
|
-
Required qualification targets are the latest stable official Pi and latest maintained `fitchmultz/pi` main, with optional wildcard Pi/TypeBox host peers and exact Cursor SDK **1.0.
|
|
43
|
+
Required qualification targets are the latest stable official Pi and latest maintained `fitchmultz/pi` main, with optional wildcard Pi/TypeBox host peers and exact Cursor SDK **1.0.40**. CI resolves the official version/fork commit once and retains exact SDK/CLI provenance. Types, tests and package checks use each selected host's consistent dependency graph; the locked development Pi **1.1.0** dependencies are reproducible snapshots, not qualification targets. Updating these snapshots does not upgrade the user's Pi installation or change the official Pi 0.87.1 minimum. After `npm ci --ignore-scripts`, run `node scripts/ci-compatibility.mjs --automation /path/to/automation` in an empty HOME/agent profile for credential-free latest qualification. Native macOS/Windows checks select the same resolved latest official graph. This builds the manifest entry, runs existing type/unit/package checks, and tests the compiled provider's registration plus production prompt shaping against native Pi transcript/tool transitions. Replay arguments must match their JSON stream deltas. A second native contract runs the registered Cursor provider with only its external SDK transport/storage substituted: real loopback bridge execution, display-only replay, persisted usage, incremental sends, tree navigation, compaction, request-boundary steering, abort and reload/disposal. Tests use no live Cursor service.
|
|
44
|
+
|
|
45
|
+
The frozen development `pi-coding-agent@1.1.0` input declares Undici 8.10.2. A version-scoped npm override selects released Undici 8.12.3 for that owner only, addressing its development audit findings without changing the Pi cohort or SDK transport. Dependency overrides apply only at the install root; this does not patch consumers' independently installed Pi hosts. Reassess the override when updating the development cohort.
|
|
38
46
|
|
|
39
47
|
TypeScript 7 builds and checks package types. Build and typecheck commands invoke `node_modules/typescript/bin/tsc` explicitly to avoid npm's shared `tsc` shim selecting a different compiler. `@typescript/typescript6` is dev-only for AST architecture and installed-SDK contract tests because TypeScript 7 does not expose a stable compiler API. Vitest 5 runs with `clearMocks: true` by default.
|
|
40
48
|
|
package/docs/reference.md
CHANGED
|
@@ -53,7 +53,7 @@ If pi started without a key, run `/cursor-refresh-models` after `/login` to refr
|
|
|
53
53
|
- optional Pi and TypeBox peer metadata uses `"*"` ranges per Pi package guidance
|
|
54
54
|
- a Cursor SDK API key saved through `/login`, available as `CURSOR_API_KEY`, or passed with pi's `--api-key`
|
|
55
55
|
|
|
56
|
-
No global `@cursor/sdk` install is required. This package depends on exact `@cursor/sdk@1.0.
|
|
56
|
+
No global `@cursor/sdk` install is required. This package depends on exact `@cursor/sdk@1.0.40`, so normal package installation brings in that SDK. Its required Zod peer is supplied directly at patched version `4.6.6`, including for installers that do not auto-install peers. The bundled MCP bridge closure retains its own newer nested Zod `4.6.7` copies. This intentional locked layout keeps the SDK peer unbundled and reachable under Pi's managed npm installation; see [packaging verification](development.md#zod-peer-and-bridge-packaging). The extension intentionally does not bundle `@cursor/sdk` or its platform packages, because packing from one maintainer OS can ship the wrong optional SDK binary for another OS. The SDK has used its current single-file/new-chunk package layout since 1.0.28. Pi hosts that pass transcript-only provider contexts are supported through Pi 0.87.1's required public replay helpers.
|
|
57
57
|
|
|
58
58
|
## Install
|
|
59
59
|
|
|
@@ -544,7 +544,7 @@ Local Cursor runs use two separate tool surfaces (the [MCP-only opt-out](./curso
|
|
|
544
544
|
- **Cursor-native surface:** Cursor local-agent tools, Cursor settings, plugins, and configured Cursor MCP servers. These remain owned by the Cursor SDK local agent path. Pi CLI tool toggles such as `--no-tools`, `--tools`, and `--exclude-tools` do not disable this Cursor-native surface.
|
|
545
545
|
- **pi bridge surface:** pi-cursor-sdk exposes bridgeable active pi tools through a per-run local loopback MCP bridge when the bridge is enabled and the current pi tool registry has exposed tools. Pi CLI tool toggles affect this bridge surface because they change pi's active tool registry.
|
|
546
546
|
|
|
547
|
-
The bridge uses stable MCP v2 with `@modelcontextprotocol/server@2.3.1`, `@modelcontextprotocol/hono@2.0.2`, `hono@4.13.13`, and `@hono/node-server@2.1.3`, bundled as its runtime closure. It binds only to loopback and validates Hono `Host` and `Origin` headers.
|
|
547
|
+
The bridge uses stable MCP v2 with `@modelcontextprotocol/server@2.3.1`, `@modelcontextprotocol/hono@2.0.2`, `hono@4.13.13`, and `@hono/node-server@2.1.3`, bundled as its runtime closure with their Zod `4.6.7` dependency. It binds only to loopback and validates Hono `Host` and `Origin` headers.
|
|
548
548
|
|
|
549
549
|
Bridge capabilities are snapshotted from `pi.getActiveTools()` and `pi.getAllTools()` for each Cursor run, including per-tool prompt guidelines when pi exposes them. Cursor sees active bridgeable pi tools as collision-safe MCP names such as `pi__sem_reindex` only when they are exposed in that current run. Cursor is instructed to prefer exposed `pi__*` tools for their described capabilities, using the current schemas and prompt guidelines rather than hardcoded delegation/MCP names; Cursor-configured MCP and Cursor-native subagents are fallbacks when no matching exposed Pi tool is available. Pi session output, tool cards, confirmations, hooks, renderers, history, and abort behavior use the real pi tool name, such as `sem_reindex`. The bridge queues Cursor's MCP call, emits a normal pi `toolCall`, waits for the matching pi `toolResult`, and resolves that result back into the same live Cursor SDK run without creating a new `Agent`, unless the run was disposed, aborted, or cancelled. The bridge does not call pi tool `execute()` handlers directly.
|
|
550
550
|
|
|
@@ -552,7 +552,7 @@ Overlapping built-in pi tools (`read`, `bash`, `write`, `edit`, `grep`, `find`,
|
|
|
552
552
|
|
|
553
553
|
Cursor-native tool replay is separate from the bridge. Replay cards are display-only recorded Cursor SDK activity. They never re-run Cursor-side commands, reapply Cursor edits, call MCP servers, or mutate pi state. See [Cursor native tool replay](./cursor-native-tool-replay.md).
|
|
554
554
|
|
|
555
|
-
**Availability:** `PI_CURSOR_NATIVE_TOOLS` and `/cursor-abort` require **0.5.4 or later**, including [#372](https://github.com/fitchmultz/pi-cursor-sdk/pull/372).
|
|
555
|
+
**Availability:** `PI_CURSOR_NATIVE_TOOLS` and `/cursor-abort` require **0.5.4 or later**, including [#372](https://github.com/fitchmultz/pi-cursor-sdk/pull/372). Published **0.5.3 ignores the flag and does not register the command**. Verify the installed version before relying on either control; a development version label alone does not prove availability.
|
|
556
556
|
|
|
557
557
|
Pi `tool_call` hooks cannot govern native Cursor execution: replay arrives after the original work. Hiding replay or disabling the bridge does not disable native tools. On a supporting revision, `PI_CURSOR_NATIVE_TOOLS=0` instead selects public SDK `tools: ["mcp"]` for ordinary LOCAL create and resume, excluding every other main tool including native task/subagents. Only the opted-out policy changes pooled/durable/resume identity; defaults remain unchanged. It is captured before acquisition; a pending opposite-policy run rejects continuation before consuming/delivering Pi results. Restore its prior policy to finish it, or run `/cursor-abort` to explicitly release that session's pending local run before retrying; ordinary mismatch never cancels it automatically. Pi's normal abort only signals an active Pi turn, so an idle abort after the error has settled cannot reach the old Cursor waiter. A real active provider abort, including a signal already aborted before preparation, releases its exact scoped pending run. The command sends no model turn; when its owned pending run has an active Cursor Pi turn, it also calls that turn's public abort before release. It does not abort a non-Cursor Pi turn, touch sibling sessions or Cloud agents, or undo already-executed work. Cloud rejects the opt-out before SDK/lifecycle side effects; isolated text-only LOCAL summaries keep `tools: []`. The flag uses the canonical boolean parser (off: `0`, `false`, `off`, `none`, `no`, `disabled`; on: `1`, `true`, `on`, `yes`, `enabled`; trim/case-insensitive; unknown/blank/unset means default on). MCP-only retains ambient Cursor MCP unless setting sources are disabled; it is not a sandbox or OS security boundary, and a permitted Pi/MCP tool can itself execute arbitrary work.
|
|
558
558
|
|
|
@@ -628,13 +628,15 @@ These server observations do not identify the client as Cursor or prove ongoing
|
|
|
628
628
|
|
|
629
629
|
If no matching cached catalog is available in a cache-only phase, auth is missing, or live discovery fails or returns no models, the extension retains known bundled fallback identities and notifies interactive users when possible. By default these models remain available without auth. With `PI_CURSOR_HIDE_MODELS_WHEN_LOGGED_OUT=1`, unauthenticated picker/list availability is empty, but known CLI selection and native login remain functional. Pi owns `--api-key` parsing.
|
|
630
630
|
|
|
631
|
-
The fallback snapshot includes Grok 4.6, Composer 2.5 (`composer-2.5` and `composer-2-5`), Composer 2, Cursor's GPT-5.6 Luna/Sol/Terra models, Claude, Gemini, Grok 4.5, Kimi, and other model IDs exposed by the reviewed `Cursor.models.list()` output. Recommended local/smoke runs use `cursor/grok-4.6`. Pi's separate `openai-codex` catalog is owned by Pi itself and includes native `gpt-5.6-luna`, `gpt-5.6-sol`, and `gpt-5.6-terra` support. The exact checked-in Cursor snapshot lives in `src/cursor-fallback-models.generated.ts`; its generator provenance records SDK 1.0.
|
|
631
|
+
The fallback snapshot includes Grok 4.6, Composer 2.5 (`composer-2.5` and `composer-2-5`), Composer 2, Cursor's GPT-5.6 Luna/Sol/Terra models, Claude, Gemini, Grok 4.5, Kimi, and other model IDs exposed by the reviewed `Cursor.models.list()` output. Recommended local/smoke runs use `cursor/grok-4.6`. Pi's separate `openai-codex` catalog is owned by Pi itself and includes native `gpt-5.6-luna`, `gpt-5.6-sol`, and `gpt-5.6-terra` support. The exact checked-in Cursor snapshot lives in `src/cursor-fallback-models.generated.ts`; its generator provenance records SDK 1.0.40 and 49 models from the authenticated catalog-only refresh on 2026-10-31. That refresh added DeepSeek V4.1 Flash 1017 (`deepseek-v41-flash-1017`), retained the prior 48 model IDs, and recorded `cyber=false` on Claude Opus 5.5 variants. The 33 bundled checkpoint-derived entries remain unchanged; no Agent/model turn or Cloud run was performed, and no new checkpoint-derived context limit is established. A dated maintainer capture documents the assistant-visible [Cursor system prompts and tool guidance](https://github.com/fitchmultz/pi-cursor-sdk/blob/main/docs/evidence/cursor-system-prompts-2026-08-02/README.md) for Grok 4.5, Opus 5, Fable 5, and the GPT-5.6 Sol/Terra/Luna family.
|
|
632
632
|
|
|
633
633
|
Actual Cursor runs still need a key from `/login`, `CURSOR_API_KEY`, or `--api-key`. If you add auth after startup, run `/cursor-refresh-models` to refresh the full live Cursor model catalog without restarting pi.
|
|
634
634
|
|
|
635
635
|
## Limits
|
|
636
636
|
|
|
637
|
-
- **
|
|
637
|
+
- **SDK hook compatibility is not blanket enforcement.** SDK 1.0.40 enables nested Claude-format denial/rewrite translation in its LOCAL hook runtime and improves Windows hook input/exit handling. The installed-package contracts exercise the settings/command-hook boundary, not a public Agent/Pi/rtk run; original [#173](https://github.com/fitchmultz/pi-cursor-sdk/issues/173) remains unqualified. Pi hooks still do not intercept native SDK execution. See [the bounded hook contract](./cursor-testing-lessons.md#sdk-1040-hook-maintenance-boundary).
|
|
638
|
+
- **Zod's bounded-collection fix is not a universal resource cap.** The SDK resolves `zod`, `zod/v3`, `zod/v4` and `zod/v4-mini` from its direct `4.6.6` peer; the bridge uses nested `4.6.7` copies. Both versions' v4 parsers check array, set and map size bounds before parsing elements ([GHSA-mrhx-c7xc-m3w5](https://github.com/advisories/GHSA-mrhx-c7xc-m3w5)). The legacy v3 implementation is unchanged, and unbounded schemas still accumulate element errors. No active SDK exploit is established. Deduplicating the SDK peer into the bridge bundle breaks Pi's managed npm installation, so [packaging checks](development.md#zod-peer-and-bridge-packaging) remain necessary even when the audit is clean.
|
|
639
|
+
- **Commit/PR attribution has no supported opt-out.** SDK 1.0.40 exposes neither attribution control through public create/local/send/configure options. CLI-file edits and SDK-internal patches are not supported extension settings; [#302](https://github.com/fitchmultz/pi-cursor-sdk/issues/302) tracks both controls.
|
|
638
640
|
|
|
639
641
|
- **Cloud runtime is explicit and minimal.** Local remains the default. Cloud runs create Cursor cloud agents only after first-use acknowledgement and safety preflight, use fresh context by default, do not expose the pi bridge or local MCP, do not forward pi env vars, support explicit Cursor-managed environment selection, name agents from the pi session title when available, stream display-only agent/run/branch/PR/artifact/raw-usage telemetry when available, and record only explicit session-branch lifecycle commands for cleanup (`/cursor-cloud list|archive|delete`).
|
|
640
642
|
- **The pi tool bridge is local and MCP-backed.** Bridgeable active pi tools are exposed to local Cursor agents through a tokenized `127.0.0.1` MCP endpoint (the URL host can be set to `localhost` with `PI_CURSOR_PI_TOOL_BRIDGE_HOST`); internal Cursor replay activity names are excluded, and overlapping built-in pi tools are hidden by default. Set `PI_CURSOR_PI_TOOL_BRIDGE=0` to disable it or `PI_CURSOR_EXPOSE_BUILTIN_TOOLS=1` to expose overlapping built-ins too.
|
|
@@ -656,6 +658,8 @@ You may be seeing fallback startup models or a missing/invalid Cursor SDK API ke
|
|
|
656
658
|
|
|
657
659
|
When a Cursor run fails after auth is configured, pi surfaces scrubbed provider detail instead of only `Cursor SDK run failed`. Structured errors retain bounded name, code, message, and up to two nested causes; headers and other object fields are not displayed. Generic completed-run failures include safe run metadata such as model id, a short run id prefix, and duration when available, and are phrased as pi retryable provider errors so automatic retry/backoff can recover transient SDK failures. Unknown startup failures, module-loading errors, and ambiguous session authentication errors are not diagnosed as invalid API keys. Explicit missing, invalid, or revoked API-key errors still show key setup guidance.
|
|
658
660
|
|
|
661
|
+
When a LOCAL run fails, the provider cancels it while the Cursor SDK records the failure, so shell commands and other native tool processes started by that run stop instead of running until their own timeout. SDK 1.0.40 cancels native tools only while a run is still running, and it records the failure before marking the run failed. Pi still reports the SDK's failure message as an error, not a cancellation. When the SDK attaches a separate error code, that code is not available after cancellation and is omitted. An explicit Pi abort is still reported as a cancellation. Cloud runs are unchanged.
|
|
662
|
+
|
|
659
663
|
Aborted runs now include a likely cause when determinable, for example `Cancelled: prompt interrupted.` for user cancel or `Cancelled: Cursor SDK run was cancelled.` for SDK-side cancellation.
|
|
660
664
|
|
|
661
665
|
SDK 1.0.37 source preserves SDK 1.0.36's client bearer refresh and unauthenticated handling, but those mechanisms do not establish the cause of [#247](https://github.com/fitchmultz/pi-cursor-sdk/issues/247)'s historical idle failure. Reloading filesystem config is not a public auth-reset API. No guessed idle TTL or extension-level automatic resend is added: resending can duplicate executed tool effects.
|
package/node_modules/@modelcontextprotocol/core/node_modules/zod/src/v4/classic/tests/array.test.ts
CHANGED
|
@@ -140,6 +140,33 @@ test("continue parsing despite array size error", () => {
|
|
|
140
140
|
`);
|
|
141
141
|
});
|
|
142
142
|
|
|
143
|
+
test("an upper size bound fails before any element is parsed", () => {
|
|
144
|
+
let parsed = 0;
|
|
145
|
+
const el = z.string().refine(() => ++parsed);
|
|
146
|
+
let refined = 0;
|
|
147
|
+
const schema = z
|
|
148
|
+
.array(el)
|
|
149
|
+
.max(2, "too many")
|
|
150
|
+
.refine(() => ++refined);
|
|
151
|
+
expect(schema.safeParse([1, 2, 3]).error!.issues).toMatchObject([{ code: "too_big", path: [], message: "too many" }]);
|
|
152
|
+
expect(z.array(el).length(2).safeParse(["a", "b", "c"]).error!.issues).toMatchObject([
|
|
153
|
+
{ code: "too_big", exact: true },
|
|
154
|
+
]);
|
|
155
|
+
expect(z.object({ a: z.array(el).max(1) }).safeParse({ a: [1, 2] }).error!.issues).toMatchObject([
|
|
156
|
+
{ code: "too_big", path: ["a"] },
|
|
157
|
+
]);
|
|
158
|
+
expect([parsed, refined]).toEqual([0, 0]);
|
|
159
|
+
|
|
160
|
+
// a check that may rewrite the value ends the gate
|
|
161
|
+
expect(
|
|
162
|
+
z
|
|
163
|
+
.array(z.number())
|
|
164
|
+
.overwrite((a) => a.slice(0, 2))
|
|
165
|
+
.max(2)
|
|
166
|
+
.parse([1, 2, 3])
|
|
167
|
+
).toEqual([1, 2]);
|
|
168
|
+
});
|
|
169
|
+
|
|
143
170
|
test("parse should fail given sparse array", () => {
|
|
144
171
|
const schema = z.array(z.string()).nonempty().min(1).max(3);
|
|
145
172
|
const result = schema.safeParse(new Array(3));
|
package/node_modules/@modelcontextprotocol/core/node_modules/zod/src/v4/classic/tests/map.test.ts
CHANGED
|
@@ -97,6 +97,13 @@ test("failing when map is bigger than max() ", () => {
|
|
|
97
97
|
expect(result.success).toEqual(false);
|
|
98
98
|
expect(result.error!.issues.length).toEqual(1);
|
|
99
99
|
expect(result.error!.issues[0].code).toEqual("too_big");
|
|
100
|
+
const bad = new Map([
|
|
101
|
+
[1, 1],
|
|
102
|
+
[2, 2],
|
|
103
|
+
]);
|
|
104
|
+
const capped = z.map(z.string(), z.string()).max(1);
|
|
105
|
+
expect(capped.safeParse(bad).error!.issues).toMatchObject([{ code: "too_big" }]);
|
|
106
|
+
expect(capped.safeParse(new Set([1, 2])).error!.issues[0]).toMatchObject({ code: "invalid_type", expected: "map" });
|
|
100
107
|
});
|
|
101
108
|
|
|
102
109
|
test("failing when map does not match size() ", () => {
|
package/node_modules/@modelcontextprotocol/core/node_modules/zod/src/v4/classic/tests/set.test.ts
CHANGED
|
@@ -83,6 +83,12 @@ test("failing when set is bigger than max() ", () => {
|
|
|
83
83
|
expect(result.success).toEqual(false);
|
|
84
84
|
expect(result.error!.issues.length).toEqual(1);
|
|
85
85
|
expect(result.error!.issues[0].code).toEqual("too_big");
|
|
86
|
+
expect(
|
|
87
|
+
z
|
|
88
|
+
.set(z.string())
|
|
89
|
+
.max(1)
|
|
90
|
+
.safeParse(new Set([1, 2])).error!.issues
|
|
91
|
+
).toMatchObject([{ code: "too_big" }]);
|
|
86
92
|
});
|
|
87
93
|
|
|
88
94
|
test("failing when set does not match size() ", () => {
|
|
@@ -1551,6 +1551,12 @@ function generateNullableCheck(
|
|
|
1551
1551
|
return outputVar;
|
|
1552
1552
|
}
|
|
1553
1553
|
|
|
1554
|
+
function generateSizeGate(doc: Doc, schema: SomeType, size: string): void {
|
|
1555
|
+
for (const [max, check] of util.sizeCaps(schema._zod.def.checks)) {
|
|
1556
|
+
doc.write(`if (${size} > ${numericOperand(max, check._zod.def.check)}) return INVALID;`);
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1554
1560
|
function generateArrayCheck(
|
|
1555
1561
|
doc: Doc,
|
|
1556
1562
|
ctx: CompileContext,
|
|
@@ -1560,6 +1566,7 @@ function generateArrayCheck(
|
|
|
1560
1566
|
): string | null {
|
|
1561
1567
|
const def = schema._zod.def as unknown as { element: SomeType };
|
|
1562
1568
|
doc.write(`if (!Array.isArray(${accessor})) return INVALID;`);
|
|
1569
|
+
generateSizeGate(doc, schema, `${accessor}.length`);
|
|
1563
1570
|
|
|
1564
1571
|
// Build a new array with validated/transformed elements.
|
|
1565
1572
|
const outputVar = buildsValue ? newVar(ctx) : null;
|
|
@@ -2094,6 +2101,7 @@ function generateMapCheck(doc: Doc, ctx: CompileContext, schema: SomeType, acces
|
|
|
2094
2101
|
const def = schema._zod.def as unknown as { keyType: SomeType; valueType: SomeType };
|
|
2095
2102
|
|
|
2096
2103
|
doc.write(`if (!(${accessor} instanceof Map)) return INVALID;`);
|
|
2104
|
+
generateSizeGate(doc, schema, `${accessor}.size`);
|
|
2097
2105
|
|
|
2098
2106
|
const outputVar = newVar(ctx);
|
|
2099
2107
|
const kVar = newVar(ctx);
|
|
@@ -2115,6 +2123,7 @@ function generateSetCheck(doc: Doc, ctx: CompileContext, schema: SomeType, acces
|
|
|
2115
2123
|
const def = schema._zod.def as unknown as { valueType: SomeType };
|
|
2116
2124
|
|
|
2117
2125
|
doc.write(`if (!(${accessor} instanceof Set)) return INVALID;`);
|
|
2126
|
+
generateSizeGate(doc, schema, `${accessor}.size`);
|
|
2118
2127
|
|
|
2119
2128
|
const outputVar = newVar(ctx);
|
|
2120
2129
|
const valVar = newVar(ctx);
|
|
@@ -1844,6 +1844,34 @@ export interface $ZodArrayInternals<T extends SomeType = $ZodType> extends _$Zod
|
|
|
1844
1844
|
|
|
1845
1845
|
export interface $ZodArray<T extends SomeType = $ZodType> extends $ZodType<any, any, $ZodArrayInternals<T>> {}
|
|
1846
1846
|
|
|
1847
|
+
// an oversized container fails its leading size checks before any element is parsed
|
|
1848
|
+
function capSize(inst: $ZodType, size: (input: any) => number): void {
|
|
1849
|
+
const caps = util.sizeCaps(inst._zod.def.checks);
|
|
1850
|
+
if (!caps.length) return;
|
|
1851
|
+
const cap = Math.min(...caps.map((c) => c[0]));
|
|
1852
|
+
const parse = inst._zod.parse;
|
|
1853
|
+
inst._zod.parse = (payload, ctx) => {
|
|
1854
|
+
const n = size(payload.value);
|
|
1855
|
+
if (n > cap && !ctx?.skipChecks && ctx?.direction !== "backward") {
|
|
1856
|
+
for (const [max, ch] of util.sizeCaps(inst._zod.def.checks)) {
|
|
1857
|
+
if (n > max && ch._zod.def.when!(payload)) {
|
|
1858
|
+
const start = payload.issues.length;
|
|
1859
|
+
ch._zod.check(payload as ParsePayload<never>);
|
|
1860
|
+
// the value is still the raw input, so no later check may read it
|
|
1861
|
+
(payload.issues[start] as { continue?: boolean }).continue = false;
|
|
1862
|
+
util.attachSchema(payload.issues, start, inst);
|
|
1863
|
+
return payload;
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
return parse(payload, ctx);
|
|
1868
|
+
};
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
const arraySize = (input: unknown): number => (Array.isArray(input) ? input.length : -1);
|
|
1872
|
+
const mapSize = (input: unknown): number => (input instanceof Map ? input.size : -1);
|
|
1873
|
+
const setSize = (input: unknown): number => (input instanceof Set ? input.size : -1);
|
|
1874
|
+
|
|
1847
1875
|
function handleArrayResult(result: ParsePayload<any>, final: ParsePayload<any[]>, index: number) {
|
|
1848
1876
|
if (result.issues.length) {
|
|
1849
1877
|
final.issues.push(...util.prefixIssues(index, result.issues));
|
|
@@ -1899,6 +1927,7 @@ export const $ZodArray: core.$constructor<$ZodArray> = /*@__PURE__*/ core.$const
|
|
|
1899
1927
|
|
|
1900
1928
|
return payload; //handleArrayResultsAsync(parseResults, final);
|
|
1901
1929
|
};
|
|
1930
|
+
capSize(inst, arraySize);
|
|
1902
1931
|
});
|
|
1903
1932
|
|
|
1904
1933
|
//////////////////////////////////////////
|
|
@@ -3218,8 +3247,11 @@ export type $InferZodRecordInput<
|
|
|
3218
3247
|
: Record<core.input<Key> & PropertyKey, core.input<Value>>;
|
|
3219
3248
|
|
|
3220
3249
|
export interface $ZodRecordInternals<Key extends $ZodRecordKey = $ZodRecordKey, Value extends SomeType = $ZodType>
|
|
3221
|
-
extends $ZodTypeInternals
|
|
3250
|
+
extends $ZodTypeInternals {
|
|
3222
3251
|
def: $ZodRecordDef<Key, Value>;
|
|
3252
|
+
// members rather than base type arguments, which TypeScript 7.1 reports as circular for `z.json()`
|
|
3253
|
+
output: $InferZodRecordOutput<Key, Value>;
|
|
3254
|
+
input: $InferZodRecordInput<Key, Value>;
|
|
3223
3255
|
isst: errors.$ZodIssueInvalidType | errors.$ZodIssueInvalidKey<Record<PropertyKey, unknown>>;
|
|
3224
3256
|
optin?: "optional" | undefined;
|
|
3225
3257
|
optout?: "optional" | undefined;
|
|
@@ -3480,6 +3512,7 @@ export const $ZodMap: core.$constructor<$ZodMap> = /*@__PURE__*/ core.$construct
|
|
|
3480
3512
|
if (proms.length) return Promise.all(proms).then(() => payload);
|
|
3481
3513
|
return payload;
|
|
3482
3514
|
};
|
|
3515
|
+
capSize(inst, mapSize);
|
|
3483
3516
|
});
|
|
3484
3517
|
|
|
3485
3518
|
function handleMapResult(
|
|
@@ -3582,6 +3615,7 @@ export const $ZodSet: core.$constructor<$ZodSet> = /*@__PURE__*/ core.$construct
|
|
|
3582
3615
|
if (proms.length) return Promise.all(proms).then(() => payload);
|
|
3583
3616
|
return payload;
|
|
3584
3617
|
};
|
|
3618
|
+
capSize(inst, setSize);
|
|
3585
3619
|
});
|
|
3586
3620
|
|
|
3587
3621
|
function handleSetResult(result: ParsePayload, final: ParsePayload<Set<any>>) {
|
|
@@ -935,6 +935,19 @@ export function unwrapMessage(message: string | { message: string } | undefined
|
|
|
935
935
|
}
|
|
936
936
|
|
|
937
937
|
/* A check holds no link back to the schema it is attached to — the same check instance is shared by every clone of that schema — so the owner is stamped onto the issues a check just raised, at the only point where both are in scope. Runs on the failure path only; `start` is the issue count from before the check ran. */
|
|
938
|
+
/** The leading size checks of `defChecks` that set an upper bound, each paired with it. */
|
|
939
|
+
export function sizeCaps(defChecks: checks.$ZodCheck<never>[] | undefined): [number, checks.$ZodCheck<never>][] {
|
|
940
|
+
const caps: [number, checks.$ZodCheck<never>][] = [];
|
|
941
|
+
for (const ch of defChecks ?? []) {
|
|
942
|
+
const d = ch._zod.def as any;
|
|
943
|
+
// a later check may rewrite the value
|
|
944
|
+
if (!/_(length|size)$|_equals$/.test(d.check)) break;
|
|
945
|
+
const max = d.maximum ?? d.length ?? d.size;
|
|
946
|
+
if (max >= 0) caps.push([max, ch]);
|
|
947
|
+
}
|
|
948
|
+
return caps;
|
|
949
|
+
}
|
|
950
|
+
|
|
938
951
|
export function attachSchema(issues: errors.$ZodRawIssue[], start: number, inst: schemas.$ZodType): void {
|
|
939
952
|
for (let i = start; i < issues.length; i++) {
|
|
940
953
|
(issues[i] as any).schema ??= inst;
|
|
@@ -1241,9 +1241,15 @@ function generateNullableCheck(doc, ctx, schema, accessor, buildsValue = true) {
|
|
|
1241
1241
|
doc.write(`}`);
|
|
1242
1242
|
return outputVar;
|
|
1243
1243
|
}
|
|
1244
|
+
function generateSizeGate(doc, schema, size) {
|
|
1245
|
+
for (const [max, check] of util.sizeCaps(schema._zod.def.checks)) {
|
|
1246
|
+
doc.write(`if (${size} > ${numericOperand(max, check._zod.def.check)}) return INVALID;`);
|
|
1247
|
+
}
|
|
1248
|
+
}
|
|
1244
1249
|
function generateArrayCheck(doc, ctx, schema, accessor, buildsValue = true) {
|
|
1245
1250
|
const def = schema._zod.def;
|
|
1246
1251
|
doc.write(`if (!Array.isArray(${accessor})) return INVALID;`);
|
|
1252
|
+
generateSizeGate(doc, schema, `${accessor}.length`);
|
|
1247
1253
|
// Build a new array with validated/transformed elements.
|
|
1248
1254
|
const outputVar = buildsValue ? newVar(ctx) : null;
|
|
1249
1255
|
const iVar = newVar(ctx);
|
|
@@ -1707,6 +1713,7 @@ function literalPropertyKey(ctx, key) {
|
|
|
1707
1713
|
function generateMapCheck(doc, ctx, schema, accessor) {
|
|
1708
1714
|
const def = schema._zod.def;
|
|
1709
1715
|
doc.write(`if (!(${accessor} instanceof Map)) return INVALID;`);
|
|
1716
|
+
generateSizeGate(doc, schema, `${accessor}.size`);
|
|
1710
1717
|
const outputVar = newVar(ctx);
|
|
1711
1718
|
const kVar = newVar(ctx);
|
|
1712
1719
|
const valVar = newVar(ctx);
|
|
@@ -1723,6 +1730,7 @@ function generateMapCheck(doc, ctx, schema, accessor) {
|
|
|
1723
1730
|
function generateSetCheck(doc, ctx, schema, accessor) {
|
|
1724
1731
|
const def = schema._zod.def;
|
|
1725
1732
|
doc.write(`if (!(${accessor} instanceof Set)) return INVALID;`);
|
|
1733
|
+
generateSizeGate(doc, schema, `${accessor}.size`);
|
|
1726
1734
|
const outputVar = newVar(ctx);
|
|
1727
1735
|
const valVar = newVar(ctx);
|
|
1728
1736
|
doc.write(`const ${outputVar} = new Set();`);
|
|
@@ -1210,9 +1210,15 @@ function generateNullableCheck(doc, ctx, schema, accessor, buildsValue = true) {
|
|
|
1210
1210
|
doc.write(`}`);
|
|
1211
1211
|
return outputVar;
|
|
1212
1212
|
}
|
|
1213
|
+
function generateSizeGate(doc, schema, size) {
|
|
1214
|
+
for (const [max, check] of util.sizeCaps(schema._zod.def.checks)) {
|
|
1215
|
+
doc.write(`if (${size} > ${numericOperand(max, check._zod.def.check)}) return INVALID;`);
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1213
1218
|
function generateArrayCheck(doc, ctx, schema, accessor, buildsValue = true) {
|
|
1214
1219
|
const def = schema._zod.def;
|
|
1215
1220
|
doc.write(`if (!Array.isArray(${accessor})) return INVALID;`);
|
|
1221
|
+
generateSizeGate(doc, schema, `${accessor}.length`);
|
|
1216
1222
|
// Build a new array with validated/transformed elements.
|
|
1217
1223
|
const outputVar = buildsValue ? newVar(ctx) : null;
|
|
1218
1224
|
const iVar = newVar(ctx);
|
|
@@ -1676,6 +1682,7 @@ function literalPropertyKey(ctx, key) {
|
|
|
1676
1682
|
function generateMapCheck(doc, ctx, schema, accessor) {
|
|
1677
1683
|
const def = schema._zod.def;
|
|
1678
1684
|
doc.write(`if (!(${accessor} instanceof Map)) return INVALID;`);
|
|
1685
|
+
generateSizeGate(doc, schema, `${accessor}.size`);
|
|
1679
1686
|
const outputVar = newVar(ctx);
|
|
1680
1687
|
const kVar = newVar(ctx);
|
|
1681
1688
|
const valVar = newVar(ctx);
|
|
@@ -1692,6 +1699,7 @@ function generateMapCheck(doc, ctx, schema, accessor) {
|
|
|
1692
1699
|
function generateSetCheck(doc, ctx, schema, accessor) {
|
|
1693
1700
|
const def = schema._zod.def;
|
|
1694
1701
|
doc.write(`if (!(${accessor} instanceof Set)) return INVALID;`);
|
|
1702
|
+
generateSizeGate(doc, schema, `${accessor}.size`);
|
|
1695
1703
|
const outputVar = newVar(ctx);
|
|
1696
1704
|
const valVar = newVar(ctx);
|
|
1697
1705
|
doc.write(`const ${outputVar} = new Set();`);
|
|
@@ -860,6 +860,33 @@ exports.$ZodDate = core.$constructor("$ZodDate", (inst, def) => {
|
|
|
860
860
|
return payload;
|
|
861
861
|
};
|
|
862
862
|
});
|
|
863
|
+
// an oversized container fails its leading size checks before any element is parsed
|
|
864
|
+
function capSize(inst, size) {
|
|
865
|
+
const caps = util.sizeCaps(inst._zod.def.checks);
|
|
866
|
+
if (!caps.length)
|
|
867
|
+
return;
|
|
868
|
+
const cap = Math.min(...caps.map((c) => c[0]));
|
|
869
|
+
const parse = inst._zod.parse;
|
|
870
|
+
inst._zod.parse = (payload, ctx) => {
|
|
871
|
+
const n = size(payload.value);
|
|
872
|
+
if (n > cap && !ctx?.skipChecks && ctx?.direction !== "backward") {
|
|
873
|
+
for (const [max, ch] of util.sizeCaps(inst._zod.def.checks)) {
|
|
874
|
+
if (n > max && ch._zod.def.when(payload)) {
|
|
875
|
+
const start = payload.issues.length;
|
|
876
|
+
ch._zod.check(payload);
|
|
877
|
+
// the value is still the raw input, so no later check may read it
|
|
878
|
+
payload.issues[start].continue = false;
|
|
879
|
+
util.attachSchema(payload.issues, start, inst);
|
|
880
|
+
return payload;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
return parse(payload, ctx);
|
|
885
|
+
};
|
|
886
|
+
}
|
|
887
|
+
const arraySize = (input) => (Array.isArray(input) ? input.length : -1);
|
|
888
|
+
const mapSize = (input) => (input instanceof Map ? input.size : -1);
|
|
889
|
+
const setSize = (input) => (input instanceof Set ? input.size : -1);
|
|
863
890
|
function handleArrayResult(result, final, index) {
|
|
864
891
|
if (result.issues.length) {
|
|
865
892
|
final.issues.push(...util.prefixIssues(index, result.issues));
|
|
@@ -905,6 +932,7 @@ exports.$ZodArray = core.$constructor("$ZodArray", (inst, def) => {
|
|
|
905
932
|
}
|
|
906
933
|
return payload; //handleArrayResultsAsync(parseResults, final);
|
|
907
934
|
};
|
|
935
|
+
capSize(inst, arraySize);
|
|
908
936
|
});
|
|
909
937
|
function handlePropertyResult(result, final, key, input, optin, optout) {
|
|
910
938
|
const isPresent = key in input;
|
|
@@ -1942,6 +1970,7 @@ exports.$ZodMap = core.$constructor("$ZodMap", (inst, def) => {
|
|
|
1942
1970
|
return Promise.all(proms).then(() => payload);
|
|
1943
1971
|
return payload;
|
|
1944
1972
|
};
|
|
1973
|
+
capSize(inst, mapSize);
|
|
1945
1974
|
});
|
|
1946
1975
|
function handleMapResult(keyResult, valueResult, final, key, input, inst, ctx) {
|
|
1947
1976
|
if (keyResult.issues.length) {
|
|
@@ -2011,6 +2040,7 @@ exports.$ZodSet = core.$constructor("$ZodSet", (inst, def) => {
|
|
|
2011
2040
|
return Promise.all(proms).then(() => payload);
|
|
2012
2041
|
return payload;
|
|
2013
2042
|
};
|
|
2043
|
+
capSize(inst, setSize);
|
|
2014
2044
|
});
|
|
2015
2045
|
function handleSetResult(result, final) {
|
|
2016
2046
|
if (result.issues.length) {
|
|
@@ -834,8 +834,10 @@ export type $InferZodRecordOutput<Key extends $ZodRecordKey = $ZodRecordKey, Val
|
|
|
834
834
|
export type $InferZodRecordInput<Key extends $ZodRecordKey = $ZodRecordKey, Value extends SomeType = $ZodType> = Key extends $partial ? Partial<Record<core.input<Key> & PropertyKey, core.input<Value>>> : [
|
|
835
835
|
Value
|
|
836
836
|
] extends [OptionalInSchema] ? Partial<Record<core.input<Key> & PropertyKey, core.input<Value>>> : Record<core.input<Key> & PropertyKey, core.input<Value>>;
|
|
837
|
-
export interface $ZodRecordInternals<Key extends $ZodRecordKey = $ZodRecordKey, Value extends SomeType = $ZodType> extends $ZodTypeInternals
|
|
837
|
+
export interface $ZodRecordInternals<Key extends $ZodRecordKey = $ZodRecordKey, Value extends SomeType = $ZodType> extends $ZodTypeInternals {
|
|
838
838
|
def: $ZodRecordDef<Key, Value>;
|
|
839
|
+
output: $InferZodRecordOutput<Key, Value>;
|
|
840
|
+
input: $InferZodRecordInput<Key, Value>;
|
|
839
841
|
isst: errors.$ZodIssueInvalidType | errors.$ZodIssueInvalidKey<Record<PropertyKey, unknown>>;
|
|
840
842
|
optin?: "optional" | undefined;
|
|
841
843
|
optout?: "optional" | undefined;
|
|
@@ -834,8 +834,10 @@ export type $InferZodRecordOutput<Key extends $ZodRecordKey = $ZodRecordKey, Val
|
|
|
834
834
|
export type $InferZodRecordInput<Key extends $ZodRecordKey = $ZodRecordKey, Value extends SomeType = $ZodType> = Key extends $partial ? Partial<Record<core.input<Key> & PropertyKey, core.input<Value>>> : [
|
|
835
835
|
Value
|
|
836
836
|
] extends [OptionalInSchema] ? Partial<Record<core.input<Key> & PropertyKey, core.input<Value>>> : Record<core.input<Key> & PropertyKey, core.input<Value>>;
|
|
837
|
-
export interface $ZodRecordInternals<Key extends $ZodRecordKey = $ZodRecordKey, Value extends SomeType = $ZodType> extends $ZodTypeInternals
|
|
837
|
+
export interface $ZodRecordInternals<Key extends $ZodRecordKey = $ZodRecordKey, Value extends SomeType = $ZodType> extends $ZodTypeInternals {
|
|
838
838
|
def: $ZodRecordDef<Key, Value>;
|
|
839
|
+
output: $InferZodRecordOutput<Key, Value>;
|
|
840
|
+
input: $InferZodRecordInput<Key, Value>;
|
|
839
841
|
isst: errors.$ZodIssueInvalidType | errors.$ZodIssueInvalidKey<Record<PropertyKey, unknown>>;
|
|
840
842
|
optin?: "optional" | undefined;
|
|
841
843
|
optout?: "optional" | undefined;
|
|
@@ -816,6 +816,33 @@ export const $ZodDate = /*@__PURE__*/ core.$constructor("$ZodDate", (inst, def)
|
|
|
816
816
|
return payload;
|
|
817
817
|
};
|
|
818
818
|
});
|
|
819
|
+
// an oversized container fails its leading size checks before any element is parsed
|
|
820
|
+
function capSize(inst, size) {
|
|
821
|
+
const caps = util.sizeCaps(inst._zod.def.checks);
|
|
822
|
+
if (!caps.length)
|
|
823
|
+
return;
|
|
824
|
+
const cap = Math.min(...caps.map((c) => c[0]));
|
|
825
|
+
const parse = inst._zod.parse;
|
|
826
|
+
inst._zod.parse = (payload, ctx) => {
|
|
827
|
+
const n = size(payload.value);
|
|
828
|
+
if (n > cap && !ctx?.skipChecks && ctx?.direction !== "backward") {
|
|
829
|
+
for (const [max, ch] of util.sizeCaps(inst._zod.def.checks)) {
|
|
830
|
+
if (n > max && ch._zod.def.when(payload)) {
|
|
831
|
+
const start = payload.issues.length;
|
|
832
|
+
ch._zod.check(payload);
|
|
833
|
+
// the value is still the raw input, so no later check may read it
|
|
834
|
+
payload.issues[start].continue = false;
|
|
835
|
+
util.attachSchema(payload.issues, start, inst);
|
|
836
|
+
return payload;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
return parse(payload, ctx);
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
const arraySize = (input) => (Array.isArray(input) ? input.length : -1);
|
|
844
|
+
const mapSize = (input) => (input instanceof Map ? input.size : -1);
|
|
845
|
+
const setSize = (input) => (input instanceof Set ? input.size : -1);
|
|
819
846
|
function handleArrayResult(result, final, index) {
|
|
820
847
|
if (result.issues.length) {
|
|
821
848
|
final.issues.push(...util.prefixIssues(index, result.issues));
|
|
@@ -861,6 +888,7 @@ export const $ZodArray = /*@__PURE__*/ core.$constructor("$ZodArray", (inst, def
|
|
|
861
888
|
}
|
|
862
889
|
return payload; //handleArrayResultsAsync(parseResults, final);
|
|
863
890
|
};
|
|
891
|
+
capSize(inst, arraySize);
|
|
864
892
|
});
|
|
865
893
|
function handlePropertyResult(result, final, key, input, optin, optout) {
|
|
866
894
|
const isPresent = key in input;
|
|
@@ -1898,6 +1926,7 @@ export const $ZodMap = /*@__PURE__*/ core.$constructor("$ZodMap", (inst, def) =>
|
|
|
1898
1926
|
return Promise.all(proms).then(() => payload);
|
|
1899
1927
|
return payload;
|
|
1900
1928
|
};
|
|
1929
|
+
capSize(inst, mapSize);
|
|
1901
1930
|
});
|
|
1902
1931
|
function handleMapResult(keyResult, valueResult, final, key, input, inst, ctx) {
|
|
1903
1932
|
if (keyResult.issues.length) {
|
|
@@ -1967,6 +1996,7 @@ export const $ZodSet = /*@__PURE__*/ core.$constructor("$ZodSet", (inst, def) =>
|
|
|
1967
1996
|
return Promise.all(proms).then(() => payload);
|
|
1968
1997
|
return payload;
|
|
1969
1998
|
};
|
|
1999
|
+
capSize(inst, setSize);
|
|
1970
2000
|
});
|
|
1971
2001
|
function handleSetResult(result, final) {
|
|
1972
2002
|
if (result.issues.length) {
|
|
@@ -46,6 +46,7 @@ exports.aborted = aborted;
|
|
|
46
46
|
exports.explicitlyAborted = explicitlyAborted;
|
|
47
47
|
exports.prefixIssues = prefixIssues;
|
|
48
48
|
exports.unwrapMessage = unwrapMessage;
|
|
49
|
+
exports.sizeCaps = sizeCaps;
|
|
49
50
|
exports.attachSchema = attachSchema;
|
|
50
51
|
exports.finalizeIssue = finalizeIssue;
|
|
51
52
|
exports.getSizableOrigin = getSizableOrigin;
|
|
@@ -620,6 +621,20 @@ function unwrapMessage(message) {
|
|
|
620
621
|
return typeof message === "string" ? message : message?.message;
|
|
621
622
|
}
|
|
622
623
|
/* A check holds no link back to the schema it is attached to — the same check instance is shared by every clone of that schema — so the owner is stamped onto the issues a check just raised, at the only point where both are in scope. Runs on the failure path only; `start` is the issue count from before the check ran. */
|
|
624
|
+
/** The leading size checks of `defChecks` that set an upper bound, each paired with it. */
|
|
625
|
+
function sizeCaps(defChecks) {
|
|
626
|
+
const caps = [];
|
|
627
|
+
for (const ch of defChecks ?? []) {
|
|
628
|
+
const d = ch._zod.def;
|
|
629
|
+
// a later check may rewrite the value
|
|
630
|
+
if (!/_(length|size)$|_equals$/.test(d.check))
|
|
631
|
+
break;
|
|
632
|
+
const max = d.maximum ?? d.length ?? d.size;
|
|
633
|
+
if (max >= 0)
|
|
634
|
+
caps.push([max, ch]);
|
|
635
|
+
}
|
|
636
|
+
return caps;
|
|
637
|
+
}
|
|
623
638
|
function attachSchema(issues, start, inst) {
|
|
624
639
|
var _a;
|
|
625
640
|
for (let i = start; i < issues.length; i++) {
|
|
@@ -221,6 +221,8 @@ export declare function prefixIssues(path: PropertyKey, issues: errors.$ZodRawIs
|
|
|
221
221
|
export declare function unwrapMessage(message: string | {
|
|
222
222
|
message: string;
|
|
223
223
|
} | undefined | null): string | undefined;
|
|
224
|
+
/** The leading size checks of `defChecks` that set an upper bound, each paired with it. */
|
|
225
|
+
export declare function sizeCaps(defChecks: checks.$ZodCheck<never>[] | undefined): [number, checks.$ZodCheck<never>][];
|
|
224
226
|
export declare function attachSchema(issues: errors.$ZodRawIssue[], start: number, inst: schemas.$ZodType): void;
|
|
225
227
|
export declare function finalizeIssue(iss: errors.$ZodRawIssue, ctx: schemas.ParseContextInternal | undefined, config: $ZodConfig): errors.$ZodIssue;
|
|
226
228
|
export declare function getSizableOrigin(input: any): "set" | "map" | "file" | "unknown";
|
|
@@ -221,6 +221,8 @@ export declare function prefixIssues(path: PropertyKey, issues: errors.$ZodRawIs
|
|
|
221
221
|
export declare function unwrapMessage(message: string | {
|
|
222
222
|
message: string;
|
|
223
223
|
} | undefined | null): string | undefined;
|
|
224
|
+
/** The leading size checks of `defChecks` that set an upper bound, each paired with it. */
|
|
225
|
+
export declare function sizeCaps(defChecks: checks.$ZodCheck<never>[] | undefined): [number, checks.$ZodCheck<never>][];
|
|
224
226
|
export declare function attachSchema(issues: errors.$ZodRawIssue[], start: number, inst: schemas.$ZodType): void;
|
|
225
227
|
export declare function finalizeIssue(iss: errors.$ZodRawIssue, ctx: schemas.ParseContextInternal | undefined, config: $ZodConfig): errors.$ZodIssue;
|
|
226
228
|
export declare function getSizableOrigin(input: any): "set" | "map" | "file" | "unknown";
|
|
@@ -550,6 +550,20 @@ export function unwrapMessage(message) {
|
|
|
550
550
|
return typeof message === "string" ? message : message?.message;
|
|
551
551
|
}
|
|
552
552
|
/* A check holds no link back to the schema it is attached to — the same check instance is shared by every clone of that schema — so the owner is stamped onto the issues a check just raised, at the only point where both are in scope. Runs on the failure path only; `start` is the issue count from before the check ran. */
|
|
553
|
+
/** The leading size checks of `defChecks` that set an upper bound, each paired with it. */
|
|
554
|
+
export function sizeCaps(defChecks) {
|
|
555
|
+
const caps = [];
|
|
556
|
+
for (const ch of defChecks ?? []) {
|
|
557
|
+
const d = ch._zod.def;
|
|
558
|
+
// a later check may rewrite the value
|
|
559
|
+
if (!/_(length|size)$|_equals$/.test(d.check))
|
|
560
|
+
break;
|
|
561
|
+
const max = d.maximum ?? d.length ?? d.size;
|
|
562
|
+
if (max >= 0)
|
|
563
|
+
caps.push([max, ch]);
|
|
564
|
+
}
|
|
565
|
+
return caps;
|
|
566
|
+
}
|
|
553
567
|
export function attachSchema(issues, start, inst) {
|
|
554
568
|
var _a;
|
|
555
569
|
for (let i = start; i < issues.length; i++) {
|