build: update dependencies (#873)

* build: update dependencies

Update the AI SDK providers, Vue, Reka UI, Valibot, Zod, es-toolkit,
CodeMirror, Storybook, Playwright, Hono and other dependencies to their
current releases, consistently across workspaces.

The Tauri plugin packages must match their Rust crates, and the new plugin
crates require Tauri 2.12, so Cargo.lock, @tauri-apps/api and the Tauri CLI
move to 2.12 as well.

* build(harness): update the AI SDK harness packages

@ai-sdk/harness 1.0.74 pinned ai 7.0.67, so the workspace carried a second
copy of ai next to the root one; 1.0.138 depends on the same ai release.

The Pi adapter no longer takes a model: HarnessAgent does. The settings
were spread from untyped records, so the compiler could not reject the
stale key and the chosen model would have been dropped; they are plain
literals now.

PiAuthOptions is now PiAuthenticationMode, and auth accepts an environment
record. Pass the gateway key that way instead of writing it into the
process-wide environment while a session is created. Derive the thinking
level from the adapter's settings, which adds 'max'.

* build: hold vue-tsc at 3.3.11

vue-tsc 3.3.12 no longer sees a v-slot binding inside a component that
also has an event listener, so check:vue reports "Cannot find name
'control'" in MCPConnectionEditor and ProfileEditor. 3.3.11 checks them
cleanly.

* fix(ai): keep retryability for provider errors reported mid-stream

From ai 7.0.80 a provider error after the response stream starts is a StreamProviderError rather than an APICallError, so classifyAIChatError lost its isRetryable.

* feat(desktop): accept updates only when signed for their version

Tauri CLI 2.12 records the app version in each updater signature, and
updater 2.13 checks it against the version latest.json announces. With
requireSignedVersion it also rejects signatures that carry no version, so a
tampered manifest cannot pair a newer version number with an older, still
validly signed bundle.

Release assembly now fails when a signature does not name the version
being released, instead of shipping one that installed apps would reject.

* docs: note the dependency update's security fixes in the changelog

* feat(ai): recommend the latest models

The provider packages now know Claude Sonnet 5.5 and Opus 5.5 and the GPT-6
series. Make Sonnet 5.5 and GPT-6.1 Sol the defaults, list Opus 5.5, Fable
5.1, GPT-6 Astra and GPT-6 Luna, and replace the two free OpenRouter models
that OpenRouter no longer serves.

* build: align the fig package's valibot with the workspace
This commit is contained in:
Danila Poyarkov 2026-10-04 12:48:24 +00:00 committed by GitHub
parent bb69735d27
commit daef57d52d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
30 changed files with 799 additions and 600 deletions

View file

@ -42,6 +42,8 @@
### Changed
- Recommend the latest models in the AI model picker: Claude Sonnet 5.5 (the new Anthropic and OpenRouter default), Claude Opus 5.5, GPT-6.1 Sol (the new OpenAI default), GPT-6 Astra, and GPT-6 Luna, and replace the free OpenRouter models OpenRouter retired with Qwen3.8 27B and Gemma 4 31B. Saved profiles keep the model they chose.
- The Linux AppImage no longer bundles `xdg-open`; opening links relies on the system's `xdg-utils`, as most desktop distributions provide.
- With nothing selected, the Code tab explains that it shows the selection's code and offers Write JSX for new layers, instead of showing a template frame that looked like a real layer.
- Design lint reports far fewer false positives in `openpencil lint` and the app: `no-hardcoded-colors` flags only colors that match a color variable and names it, `no-deeply-nested` flags only the layer that crosses the depth limit, `touch-target-size` checks the WCAG 2.2 AA minimum of 24 × 24 in the Recommended preset (Strict and Accessibility keep 44 × 44), matches control names as whole words (a layer named "Rectangle" is no longer a call to action) and ignores icons and controls inside other controls, `consistent-spacing` accepts multiples of 4, `color-contrast` checks text bound to color variables, and layers inside instances are checked once through their main component. The Recommended preset reports unbound colors, deep nesting, mixed text styles, and off-scale spacing as suggestions instead of warnings. Lint messages carry the measured values in `data`.
- Keep the Share button labeled Share while you are in a room, instead of turning it into a Connected status; a green dot on your avatar shows the room is live.
@ -103,6 +105,9 @@
### Security
- Update the desktop app to Tauri 2.12, which binds large IPC channel responses to the webview that requested them instead of letting another webview fetch them (GHSA-w28w-mhc8-qvjv).
- Install a desktop update only when its signature names the version the update server announces, so a tampered update manifest cannot pair a newer version number with an older signed build.
- Update `@xmldom/xmldom` to 0.9.12, which fixes quadratic-time and quadratic-memory parsing of crafted SVG and XML and reports malformed end tags instead of accepting them.
- Validate cursors, selections, and names that collaborators send before drawing them, and cap their size, so a broken or hostile peer cannot crash or flood the canvas.
- Evaluate `calc` expressions through `jsep` and an arithmetic allowlist that never compiles input into JavaScript, replacing the `expr-eval` dependency and its unpatched critical code-execution advisory (GHSA-q9v2-7m5w-4693).
- Escape layer names and other text properties in JSX and Tailwind JSX export, so text from a document can no longer add attributes or JavaScript expressions that the AI and MCP `render` and `replace` tools would execute, and names containing `&` no longer change when the JSX is rendered back.

602
bun.lock

File diff suppressed because it is too large Load diff

373
desktop/Cargo.lock generated
View file

@ -30,15 +30,15 @@ dependencies = [
[[package]]
name = "alloc-no-stdlib"
version = "2.0.4"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3"
checksum = "c2fb6cfd47bf496ff64095c20eaba0c201404ee38714d4142fcfa1dc334fcc7a"
[[package]]
name = "alloc-stdlib"
version = "0.2.4"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e76a019e91224d279006ff972f1e984179a6e9feb050adba6ce8274aef23195"
checksum = "0b5c1865780388bfa186411ab5f247819487fc4864c6e9c3106611fa347586e1"
dependencies = [
"alloc-no-stdlib",
]
@ -401,9 +401,9 @@ dependencies = [
[[package]]
name = "brotli"
version = "8.0.4"
version = "9.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cc91aac060a7a1e25823bdccbfb6af1875b88f17c6daac97894eed8207166b3"
checksum = "f8b851b75c23ca7873623d612fe49bd1989aeb03d08fb9432187eb253d3d4c6b"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@ -412,9 +412,9 @@ dependencies = [
[[package]]
name = "brotli-decompressor"
version = "5.0.3"
version = "6.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3a32acac15fe1967bc3986b2a6347dffc965602354ea6f450ad07e8bfd253583"
checksum = "941cd9bd4ddab83cb46fa5a2d428f1c857b24ac78cb876cf7beb710840934bd7"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@ -535,12 +535,13 @@ dependencies = [
[[package]]
name = "cargo_toml"
version = "0.22.3"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77"
checksum = "82f4b26e751e711a5302649417f2da046dce6391b2ea30a4820f37462314f0b9"
dependencies = [
"semver",
"serde",
"toml 0.9.12+spec-1.1.0",
"toml 1.1.4+spec-1.1.0",
]
[[package]]
@ -572,13 +573,13 @@ checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c"
[[package]]
name = "cfb"
version = "0.7.3"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d38f2da7a0a2c4ccf0065be06397cc26a81f4e528be095826eee9d4adbb8c60f"
checksum = "a347dcabdae9c31b0825fd6a8bed285ec9c2acb89c47827126d52fa4f59cece3"
dependencies = [
"byteorder",
"fnv",
"uuid",
"web-time",
]
[[package]]
@ -704,6 +705,16 @@ dependencies = [
"version_check",
]
[[package]]
name = "core-foundation"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation"
version = "0.10.1"
@ -727,7 +738,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "064badf302c3194842cf2c5d61f56cc88e54a759313879cdf03abdd27d0c3b97"
dependencies = [
"bitflags 2.13.1",
"core-foundation",
"core-foundation 0.10.1",
"core-graphics-types",
"foreign-types",
"libc",
@ -740,7 +751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb"
dependencies = [
"bitflags 2.13.1",
"core-foundation",
"core-foundation 0.10.1",
"libc",
]
@ -804,9 +815,9 @@ dependencies = [
[[package]]
name = "cssparser"
version = "0.36.0"
version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dae61cf9c0abb83bd659dab65b7e4e38d8236824c85f0f804f173567bda257d2"
checksum = "8c9cdaae01d5ed7882b04d795e7f752f46ff52d2fa3b50a20d28c464510bba98"
dependencies = [
"cssparser-macros",
"dtoa-short",
@ -817,29 +828,19 @@ dependencies = [
[[package]]
name = "cssparser-macros"
version = "0.6.1"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331"
checksum = "d045de693cb712d0b22c6a64be5b953f67b3ce00ab5ad3dd5d8b441886ab8e1a"
dependencies = [
"quote",
"syn 2.0.119",
"syn 3.0.3",
]
[[package]]
name = "ctor"
version = "0.8.0"
version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98"
dependencies = [
"ctor-proc-macro",
"dtor",
]
[[package]]
name = "ctor-proc-macro"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
checksum = "914a755b7c2d4af2bdcff7ce1739e2db9a1b81a9b07123d8015786ae03c0980d"
[[package]]
name = "darling"
@ -971,9 +972,9 @@ dependencies = [
[[package]]
name = "dirs"
version = "6.0.0"
version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e8aa94d75141228480295a7d0e7feb620b1a5ad9f12bc40be62411e38cce4e"
checksum = "8d57d423b3c82e89b9a24ca3091fee61f456a26edbd28d26c65906f4bc1dcd8f"
dependencies = [
"dirs-sys",
]
@ -1056,9 +1057,9 @@ dependencies = [
[[package]]
name = "dom_query"
version = "0.27.0"
version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521e380c0c8afb8d9a1e83a1822ee03556fc3e3e7dbc1fd30be14e37f9cb3f89"
checksum = "fac5fca71e65e94cc718a6e2af65d6e0f9c6027751c2aa562fbb5087fda639bc"
dependencies = [
"bit-set",
"cssparser",
@ -1099,21 +1100,6 @@ dependencies = [
"dtoa",
]
[[package]]
name = "dtor"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4"
dependencies = [
"dtor-proc-macro",
]
[[package]]
name = "dtor-proc-macro"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5"
[[package]]
name = "dunce"
version = "1.0.5"
@ -1975,9 +1961,9 @@ dependencies = [
[[package]]
name = "html5ever"
version = "0.38.0"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1054432bae2f14e0061e33d23402fbaa67a921d319d56adc6bcf887ddad1cbc2"
checksum = "46a1761807faccc9a19e86944bbf40610014066306f96edcdedc2fb714bcb7b8"
dependencies = [
"log",
"markup5ever",
@ -2083,9 +2069,11 @@ dependencies = [
"percent-encoding",
"pin-project-lite",
"socket2",
"system-configuration",
"tokio",
"tower-service",
"tracing",
"windows-registry",
]
[[package]]
@ -2271,9 +2259,9 @@ dependencies = [
[[package]]
name = "infer"
version = "0.19.0"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a588916bfdfd92e71cacef98a63d9b1f0d74d6599980d11894290e7ddefffcf7"
checksum = "f4200d433cbd5178df7797c9c2e75b348b728e39631cf14520d1e2fc424201f4"
dependencies = [
"cfb",
]
@ -2512,21 +2500,21 @@ dependencies = [
[[package]]
name = "json-patch"
version = "3.0.1"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08"
checksum = "7421438de105a0827e44fadd05377727847d717c80ce29a229f85fd04c427b72"
dependencies = [
"jsonptr",
"serde",
"serde_json",
"thiserror 1.0.69",
"thiserror 2.0.20",
]
[[package]]
name = "jsonptr"
version = "0.6.3"
version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70"
checksum = "a5a3cc660ba5d72bce0b3bb295bf20847ccbb40fd423f3f05b61273672e561fe"
dependencies = [
"serde",
"serde_json",
@ -2534,13 +2522,12 @@ dependencies = [
[[package]]
name = "keyboard-types"
version = "0.7.0"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b750dcadc39a09dbadd74e118f6dd6598df77fa01df0cfcdc52c28dece74528a"
checksum = "0fbe853b403ae61a04233030ae8a79d94975281ed9770a1f9e246732b534b28d"
dependencies = [
"bitflags 2.13.1",
"serde",
"unicode-segmentation",
]
[[package]]
@ -2693,9 +2680,9 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
[[package]]
name = "markup5ever"
version = "0.38.0"
version = "0.39.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8983d30f2915feeaaab2d6babdd6bc7e9ed1a00b66b5e6d74df19aa9c0e91862"
checksum = "7122d987ec5f704ee56f6e5b41a7d93722e9aae27ae07cafa4036c4d3f9757de"
dependencies = [
"log",
"tendril",
@ -2778,9 +2765,9 @@ dependencies = [
[[package]]
name = "muda"
version = "0.19.3"
version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd04e60bc0b07438a6771710ee1698f98f6ebbc7f89b61264af1563b8aeb878"
checksum = "cca139e57da4383727f189e43e66e84fa372347027fc996f9f1a007ec0a37996"
dependencies = [
"crossbeam-channel",
"dpi",
@ -2812,6 +2799,12 @@ dependencies = [
"thiserror 1.0.69",
]
[[package]]
name = "ndk-context"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b"
[[package]]
name = "ndk-sys"
version = "0.6.0+11769913"
@ -4081,7 +4074,7 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d1e2536ce4f35f4846aa13bff16bd0ff40157cdb14cc056c7b14ba41233ba0"
dependencies = [
"core-foundation",
"core-foundation 0.10.1",
"core-foundation-sys",
"jni 0.22.4",
"log",
@ -4226,7 +4219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d"
dependencies = [
"bitflags 2.13.1",
"core-foundation",
"core-foundation 0.10.1",
"core-foundation-sys",
"libc",
"security-framework-sys",
@ -4244,9 +4237,9 @@ dependencies = [
[[package]]
name = "selectors"
version = "0.36.1"
version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c5d9c0c92a92d33f08817311cf3f2c29a3538a8240e94a6a3c622ce652d7e00c"
checksum = "8adfa1c298912827b8a28b223b3b874357397ae706e6190acd9bf28cee99114d"
dependencies = [
"bitflags 2.13.1",
"cssparser",
@ -4663,9 +4656,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "swift-rs"
version = "1.0.7"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4057c98e2e852d51fdcfca832aac7b571f6b351ad159f9eda5db1655f8d0c4d7"
checksum = "e45c444e496845d3f2a351146bff59aae4975b2280238df1dfaa0c7d1846f38e"
dependencies = [
"base64 0.21.7",
"serde",
@ -4733,6 +4726,27 @@ dependencies = [
"libc",
]
[[package]]
name = "system-configuration"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b"
dependencies = [
"bitflags 2.13.1",
"core-foundation 0.9.4",
"system-configuration-sys",
]
[[package]]
name = "system-configuration-sys"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "system-deps"
version = "6.2.2"
@ -4761,13 +4775,13 @@ dependencies = [
[[package]]
name = "tao"
version = "0.35.3"
version = "0.37.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1c93047acf68669466a34690ac58cca7010bd1b201e1ec86f1fd0a75d3dd4a9"
checksum = "f37f381f4e048e6cdf038b5705f8cf14ad108279d46eb968140a7b291aba9400"
dependencies = [
"bitflags 2.13.1",
"block2",
"core-foundation",
"core-foundation 0.10.1",
"core-graphics",
"crossbeam-channel",
"dbus",
@ -4781,20 +4795,20 @@ dependencies = [
"libc",
"log",
"ndk",
"ndk-context",
"ndk-sys",
"objc2",
"objc2-app-kit",
"objc2-foundation",
"objc2-ui-kit",
"once_cell",
"parking_lot",
"percent-encoding",
"raw-window-handle",
"tao-macros",
"unicode-segmentation",
"url",
"windows 0.61.3",
"windows-core 0.61.2",
"windows 0.62.2",
"windows-core 0.62.2",
"windows-version",
"x11-dl",
]
@ -4835,9 +4849,9 @@ checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
[[package]]
name = "tauri"
version = "2.11.5"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "667b20e2726d572dea2de7370da16e188eb06008faf9a92fab7cdc46791190b5"
checksum = "ed99ee9694a2deb776d91cae48ac7411ddfc89ecae2f9b5041111d8c88f2ace9"
dependencies = [
"anyhow",
"bytes",
@ -4879,16 +4893,16 @@ dependencies = [
"tray-icon",
"url",
"webkit2gtk",
"webview2-com",
"webview2-com 0.39.1",
"window-vibrancy",
"windows 0.61.3",
"windows 0.62.2",
]
[[package]]
name = "tauri-build"
version = "2.6.3"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc9ce40b16101cb6ea63d3e221567affd1c3a9205f95d7bc574941a10636b632"
checksum = "59563ca5b331fd97f27ee9672ec8d36d33bb3c9e2c9f6710a1a5687256052e45"
dependencies = [
"anyhow",
"cargo_toml",
@ -4907,16 +4921,16 @@ dependencies = [
[[package]]
name = "tauri-codegen"
version = "2.6.3"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08279169ff42f8fc45a1dbc9dcae888893ba95288142e5880c59b93a26d2cfc5"
checksum = "e50213e463086ecc283d7e9f51c30cc0fd304ad457425158018be26dbf0d0a80"
dependencies = [
"base64 0.22.1",
"brotli",
"ico",
"json-patch",
"plist",
"png 0.17.16",
"png 0.18.1",
"proc-macro2",
"quote",
"semver",
@ -4934,9 +4948,9 @@ dependencies = [
[[package]]
name = "tauri-macros"
version = "2.6.3"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8b394794f399a421811d06966343e7933fcae92d59f5180b9388d1174497a45"
checksum = "8129fb43bb6e0d6b73ad3315cd172beaab17cd28899c594b1b32c80edbbfd99c"
dependencies = [
"heck 0.5.0",
"proc-macro2",
@ -4948,9 +4962,9 @@ dependencies = [
[[package]]
name = "tauri-plugin"
version = "2.6.3"
version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74be5dd4bed9afbd145e5716b5fa2ec28cbc29c34ffa61c258c9273d896c8020"
checksum = "1140cf34a3b3b836a13103dcab17f18831d5cc3534cbd435dc01a5c6daa65aa2"
dependencies = [
"anyhow",
"glob",
@ -4964,9 +4978,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-clipboard-manager"
version = "2.3.2"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "206dc20af4ed210748ba945c2774e60fd0acd52b9a73a028402caf809e9b6ecf"
checksum = "333d3b6beeb1c2c7fc040233d4ea7b6c03a9f8f039592b7400833c43fb5b568a"
dependencies = [
"arboard",
"log",
@ -5000,9 +5014,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-dialog"
version = "2.7.2"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2d3c1dbe38037e7f590cdf2492594d5ceebe031e7bc7e827509b22a999d2940"
checksum = "daf9a5c92e39bdd84f22f6be9230e39d0c4e140345f71ffe6058dca4f71127cf"
dependencies = [
"log",
"raw-window-handle",
@ -5018,9 +5032,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-fs"
version = "2.5.1"
version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7ecc274121aca0c036a2b42d1cbe83d368d348f54e0bb8a735c2b1548e8f371"
checksum = "466eb32466fe5021b6728b06862f9ff14a9f7e1af890047654e03a96d7c0e1bb"
dependencies = [
"anyhow",
"dunce",
@ -5044,9 +5058,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-opener"
version = "2.5.4"
version = "2.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17e1bea14edce6b793a04e2417e3fd924b9bc4faae83cdee7d714156cceeed29"
checksum = "d39404b2572927e0d3ed30a7ca226037f7508d22e79c96ee6ef0d42b6a4b3345"
dependencies = [
"dunce",
"glob",
@ -5060,7 +5074,7 @@ dependencies = [
"tauri-plugin",
"thiserror 2.0.20",
"url",
"windows 0.61.3",
"windows 0.62.2",
"zbus",
]
@ -5094,9 +5108,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-shell"
version = "2.3.5"
version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8457dbf9e2bab1edd8df22bb2c20857a59a9868e79cb3eac5ed639eec4d0c73b"
checksum = "094bdbc47e5efe36544ba21b3a53ab5c724150236cf55e6c9be46191deb6eab6"
dependencies = [
"encoding_rs",
"log",
@ -5132,9 +5146,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-updater"
version = "2.10.1"
version = "2.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "806d9dac662c2e4594ff03c647a552f2c9bd544e7d0f683ec58f872f952ce4af"
checksum = "3cb0b2ea3e85ca287990d3859a29cc5cb18024240fd78f62e027fb7963670f18"
dependencies = [
"base64 0.22.1",
"dirs",
@ -5159,7 +5173,7 @@ dependencies = [
"time",
"tokio",
"url",
"windows-sys 0.60.2",
"windows-sys 0.61.2",
"zip 4.6.1",
]
@ -5191,16 +5205,16 @@ dependencies = [
"tracing",
"uuid",
"webkit2gtk",
"webview2-com",
"webview2-com 0.38.2",
"windows 0.61.3",
"windows-core 0.61.2",
]
[[package]]
name = "tauri-runtime"
version = "2.11.3"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0b4bc95aed361b0019067d189a1174a603d460d0f6c72606512d59fc9c12ec8"
checksum = "c2a57a2a9b8c8b7fc00d35b510fe808ded7f9f1b44fc1cdda6aee38632ea5413"
dependencies = [
"cookie",
"dpi",
@ -5217,15 +5231,15 @@ dependencies = [
"thiserror 2.0.20",
"url",
"webkit2gtk",
"webview2-com",
"windows 0.61.3",
"webview2-com 0.39.1",
"windows 0.62.2",
]
[[package]]
name = "tauri-runtime-wry"
version = "2.11.4"
version = "2.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e6fac707727b7a2f48e4ded90976324267371073edbb415ffb73bb0458d203f"
checksum = "7f9e7e0c9f80a5130773cfabb6df4dc924518fb1b2c923726966804634b57d22"
dependencies = [
"gtk",
"http",
@ -5242,16 +5256,16 @@ dependencies = [
"tauri-utils",
"url",
"webkit2gtk",
"webview2-com",
"windows 0.61.3",
"webview2-com 0.39.1",
"windows 0.62.2",
"wry",
]
[[package]]
name = "tauri-utils"
version = "2.9.3"
version = "2.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3e176a18e67764923c4f1ce66f25ae4abe5f688384d5eb1a0fa6c77f3d90f887"
checksum = "2ff55a614843b9a3f010f211df637c94df2607175b8d0f6e0f4a7c19e18621ee"
dependencies = [
"anyhow",
"brotli",
@ -5497,21 +5511,6 @@ dependencies = [
"toml_edit 0.20.2",
]
[[package]]
name = "toml"
version = "0.9.12+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf92845e79fc2e2def6a5d828f0801e29a2f8acc037becc5ab08595c7d5e9863"
dependencies = [
"indexmap 2.14.0",
"serde_core",
"serde_spanned 1.1.1",
"toml_datetime 0.7.5+spec-1.1.0",
"toml_parser",
"toml_writer",
"winnow 0.7.15",
]
[[package]]
name = "toml"
version = "1.1.4+spec-1.1.0"
@ -5536,15 +5535,6 @@ dependencies = [
"serde",
]
[[package]]
name = "toml_datetime"
version = "0.7.5+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
dependencies = [
"serde_core",
]
[[package]]
name = "toml_datetime"
version = "1.1.1+spec-1.1.0"
@ -5685,9 +5675,9 @@ dependencies = [
[[package]]
name = "tray-icon"
version = "0.24.2"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "045979e3f037cd18ad1cb2a419dfda133c5c29c9f3453370079f2255d46c257e"
checksum = "b2b9c52859a94554803ccd4a24b98f74148ebc73b90676d783f3490b1bff9d72"
dependencies = [
"crossbeam-channel",
"dirs",
@ -5745,47 +5735,6 @@ dependencies = [
"windows-sys 0.61.2",
]
[[package]]
name = "unic-char-property"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
dependencies = [
"unic-char-range",
]
[[package]]
name = "unic-char-range"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
[[package]]
name = "unic-common"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
[[package]]
name = "unic-ucd-ident"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987"
dependencies = [
"unic-char-property",
"unic-char-range",
"unic-ucd-version",
]
[[package]]
name = "unic-ucd-version"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
dependencies = [
"unic-common",
]
[[package]]
name = "unicode-ident"
version = "1.0.24"
@ -5819,13 +5768,13 @@ dependencies = [
[[package]]
name = "urlpattern"
version = "0.3.0"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d"
checksum = "df16f50ef4cc145211879a3867ba757076b25dfee812040dcb0658bd9ae7904b"
dependencies = [
"icu_properties",
"regex",
"serde",
"unic-ucd-ident",
"url",
]
@ -6161,13 +6110,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7130243a7a5b33c54a444e54842e6a9e133de08b5ad7b5861cd8ed9a6a5bc96a"
dependencies = [
"webview2-com-macros",
"webview2-com-sys",
"webview2-com-sys 0.38.2",
"windows 0.61.3",
"windows-core 0.61.2",
"windows-implement",
"windows-interface",
]
[[package]]
name = "webview2-com"
version = "0.39.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f89fca7a704cee10dcb3654c1dbb8941d1783132f1917358af75bec37a7d7e6"
dependencies = [
"webview2-com-macros",
"webview2-com-sys 0.39.1",
"windows 0.62.2",
"windows-core 0.62.2",
]
[[package]]
name = "webview2-com-macros"
version = "0.8.1"
@ -6190,6 +6151,17 @@ dependencies = [
"windows-core 0.61.2",
]
[[package]]
name = "webview2-com-sys"
version = "0.39.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b3a07132775117d6065853d9d1178157b8c90e228de47129d6bce2c7edebedfb"
dependencies = [
"thiserror 2.0.20",
"windows 0.62.2",
"windows-core 0.62.2",
]
[[package]]
name = "weezl"
version = "0.1.12"
@ -6241,16 +6213,17 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "window-vibrancy"
version = "0.6.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d9bec5a31f3f9362f2258fd0e9c9dd61a9ca432e7306cc78c444258f0dce9a9c"
checksum = "111e51caca442cafd9bab396628ac4d814880eaea4e63dfd76a12e9f342b5580"
dependencies = [
"objc2",
"objc2-app-kit",
"objc2-core-foundation",
"objc2-foundation",
"objc2-quartz-core",
"raw-window-handle",
"windows-sys 0.59.0",
"windows-sys 0.61.2",
"windows-version",
]
@ -6726,12 +6699,6 @@ dependencies = [
"memchr",
]
[[package]]
name = "winnow"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945"
[[package]]
name = "winnow"
version = "1.0.4"
@ -6789,9 +6756,9 @@ checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc"
[[package]]
name = "wry"
version = "0.55.1"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186f9871daa55fd9c016578b810d149de58367113db7fb72b462d2323ce19514"
checksum = "a819957a01b3119af85e638a38d242af76dbc87d130dca67bfd0441072e21ff0"
dependencies = [
"base64 0.22.1",
"block2",
@ -6824,9 +6791,9 @@ dependencies = [
"url",
"webkit2gtk",
"webkit2gtk-sys",
"webview2-com",
"windows 0.61.3",
"windows-core 0.61.2",
"webview2-com 0.39.1",
"windows 0.62.2",
"windows-core 0.62.2",
"windows-version",
"x11-dl",
]

View file

@ -70,6 +70,7 @@
},
"updater": {
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDU4QzBCRjBFNzhFNEVEMDEKUldRQjdlUjREci9BV0hLaEJPeG5tRXdsWkhQWFdEa0VxcEtNR1o1S2VJeGlKU1VDTldQTi9wYncK",
"requireSignedVersion": true,
"endpoints": ["https://github.com/open-pencil/open-pencil/releases/latest/download/latest.json"],
"windows": {
"installMode": "passive"

View file

@ -99,25 +99,25 @@
"check:tools": "tsgo --noEmit -p tools/tsconfig.json"
},
"dependencies": {
"@ai-sdk/anthropic": "^4.0.39",
"@ai-sdk/deepseek": "^3.0.28",
"@ai-sdk/google": "^4.0.44",
"@ai-sdk/openai": "^4.0.42",
"@ai-sdk/valibot": "^3.0.27",
"@ai-sdk/vue": "^4.0.66",
"@ai-sdk/anthropic": "^4.0.71",
"@ai-sdk/deepseek": "^3.0.58",
"@ai-sdk/google": "^4.0.87",
"@ai-sdk/openai": "^4.0.83",
"@ai-sdk/valibot": "^3.0.53",
"@ai-sdk/vue": "^4.0.127",
"@atlaskit/pragmatic-drag-and-drop": "^1.8.1",
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.2.0",
"@chenglou/pretext": "^0.0.7",
"@codemirror/autocomplete": "^6.20.3",
"@codemirror/commands": "^6.11.0",
"@codemirror/commands": "^6.11.1",
"@codemirror/lang-html": "^6.4.12",
"@codemirror/lang-javascript": "^6.2.5",
"@codemirror/lang-json": "^6.0.2",
"@codemirror/language": "^6.12.4",
"@codemirror/lint": "^6.9.7",
"@codemirror/merge": "^6.12.2",
"@codemirror/search": "^6.7.1",
"@codemirror/state": "^6.7.1",
"@codemirror/search": "^6.7.2",
"@codemirror/state": "^6.7.6",
"@codemirror/view": "^6.43.9",
"@lezer/highlight": "^1.2.3",
"@nanostores/i18n": "^1.3.3",
@ -132,31 +132,31 @@
"@open-pencil/pen": "workspace:*",
"@open-pencil/scene-graph": "workspace:*",
"@open-pencil/vue": "workspace:*",
"@openrouter/ai-sdk-provider": "^3.0.0",
"@openrouter/ai-sdk-provider": "^3.1.0",
"@stream-markdown/code": "2.0.0-beta.5",
"@tailwindcss/vite": "^4.3.3",
"@tanstack/vue-table": "^8.21.3",
"@tauri-apps/api": "^2.11.1",
"@tauri-apps/plugin-clipboard-manager": "^2.3.2",
"@tauri-apps/plugin-dialog": "^2.7.2",
"@tauri-apps/plugin-fs": "^2.5.1",
"@tauri-apps/plugin-opener": "^2.5.4",
"@tauri-apps/api": "^2.12.1",
"@tauri-apps/plugin-clipboard-manager": "^2.4.1",
"@tauri-apps/plugin-dialog": "^2.8.1",
"@tauri-apps/plugin-fs": "^2.6.0",
"@tauri-apps/plugin-opener": "^2.7.0",
"@tauri-apps/plugin-os": "^2.3.2",
"@tauri-apps/plugin-process": "^2.3.1",
"@tauri-apps/plugin-shell": "^2.3.5",
"@tauri-apps/plugin-updater": "^2.10.1",
"@tauri-apps/plugin-shell": "^2.4.0",
"@tauri-apps/plugin-updater": "^2.13.1",
"@unhead/vue": "^2.1.17",
"@valibot/to-json-schema": "^1.8.0",
"@vueuse/core": "^14.4.0",
"@xmldom/xmldom": "^0.9.11",
"ai": "^7.0.66",
"@xmldom/xmldom": "^0.9.12",
"ai": "^7.0.127",
"aws4fetch": "^1.0.20",
"canvaskit-wasm": "^0.41.1",
"copy-to-clipboard": "^4.0.2",
"culori": "^4.0.2",
"dedent": "^1.7.2",
"diff": "^8.0.4",
"es-toolkit": "^1.51.0",
"es-toolkit": "^1.52.0",
"fflate": "^0.8.3",
"fuse.js": "^7.5.0",
"fzstd": "^0.1.1",
@ -165,57 +165,57 @@
"js-base64": "^3.9.3",
"jspdf": "^4.2.1",
"lib0": "^0.2.117",
"motion-v": "^2.4.0",
"nanostores": "^1.5.0",
"motion-v": "^2.5.2",
"nanostores": "^1.5.4",
"opentype.js": "^2.0.0",
"partial-json": "^0.1.7",
"reka-ui": "^2.10.3",
"svg2pdf.js": "^2.7.0",
"tailwind-merge": "^3.6.0",
"reka-ui": "^2.10.5",
"svg2pdf.js": "^2.8.1",
"tailwind-merge": "^3.7.0",
"tailwind-variants": "^3.3.1",
"tailwindcss": "^4.3.3",
"tinykeys": "^3.1.0",
"trystero": "^0.22.0",
"valibot": "^1.4.2",
"valibot": "^1.5.0",
"vee-validate": "5.0.0-beta.0",
"vue": "^3.5.41",
"vue-router": "^5.2.0",
"vue": "^3.5.43",
"vue-router": "^5.3.1",
"vue-stream-markdown": "2.0.0-beta.5",
"y-indexeddb": "^9.0.12",
"y-protocols": "^1.0.7",
"yjs": "^13.6.32",
"yoga-layout": "npm:@open-pencil/yoga-layout@3.3.0-grid.3",
"zod": "^4.4.3"
"zod": "^4.6.5"
},
"devDependencies": {
"@agentclientprotocol/sdk": "^0.14.1",
"@arethetypeswrong/cli": "0.18.4",
"@commitlint/cli": "^21.2.2",
"@commitlint/config-conventional": "^21.2.2",
"@commitlint/is-ignored": "^21.2.2",
"@commitlint/types": "^21.2.0",
"@commitlint/cli": "^21.2.3",
"@commitlint/config-conventional": "^21.2.3",
"@commitlint/is-ignored": "^21.2.3",
"@commitlint/types": "^21.2.3",
"@feature-sliced/steiger-plugin": "^0.5.8",
"@figma/plugin-typings": "^1.134.0",
"@figma/plugin-typings": "^1.140.0",
"@hono/node-server": "^1.19.17",
"@iconify-json/lucide": "^1.2.123",
"@iconify-json/lucide": "^1.2.139",
"@modelcontextprotocol/client": "^2.0.0",
"@open-pencil/brand-tools": "workspace:*",
"@open-pencil/mcp": "workspace:*",
"@oxlint/plugins": "1.57.0",
"@playwright/test": "^1.62.1",
"@storybook/addon-a11y": "^10.5.8",
"@storybook/addon-docs": "^10.5.8",
"@storybook/addon-themes": "^10.5.8",
"@storybook/vue3-vite": "^10.5.8",
"@tauri-apps/cli": "2.11.4",
"@playwright/test": "^1.63.0",
"@storybook/addon-a11y": "^10.6.1",
"@storybook/addon-docs": "^10.6.1",
"@storybook/addon-themes": "^10.6.1",
"@storybook/vue3-vite": "^10.6.1",
"@tauri-apps/cli": "2.12.1",
"@types/culori": "^4.0.1",
"@types/node": "^25.9.5",
"@types/node": "^25.9.9",
"@types/opentype.js": "^1.3.10",
"@types/ws": "^8.18.1",
"@typescript-eslint/utils": "^8.67.0",
"@typescript-eslint/utils": "^8.71.0",
"@typescript/native-preview": "^7.0.0-dev.20260707.2",
"@vitejs/plugin-vue": "^6.0.8",
"@vue/compiler-core": "^3.5.41",
"@vitejs/plugin-vue": "^6.0.9",
"@vue/compiler-core": "^3.5.43",
"@wdio/cli": "9.30.1",
"@wdio/globals": "9.29.1",
"@wdio/local-runner": "9.30.1",
@ -229,7 +229,7 @@
"expect-webdriverio": "5.7.0",
"fake-indexeddb": "^6.2.5",
"franc": "^6.2.0",
"hono": "^4.13.2",
"hono": "^4.13.13",
"jscpd": "^4.3.0",
"knip": "6.20.0",
"mdast": "^3.0.0",
@ -242,7 +242,7 @@
"publint": "0.3.20",
"sherif": "1.12.0",
"steiger": "^0.5.13",
"storybook": "^10.5.8",
"storybook": "^10.6.1",
"tsdown": "^0.22.14",
"tw-animate-css": "^1.4.0",
"typescript": "~5.8.3",
@ -253,8 +253,8 @@
"unplugin-vue-components": "^31.1.0",
"vite": "8.1.4",
"vite-plugin-pwa": "^1.3.0",
"vue-tsc": "^3.3.10",
"webmcp-types": "^0.1.7",
"vue-tsc": "3.3.11",
"webmcp-types": "^0.1.10",
"workbox-window": "^7.4.1",
"ws": "^8.21.3"
},

View file

@ -44,9 +44,9 @@
"agentfmt": "^0.1.3",
"canvaskit-wasm": "^0.41.1",
"citty": "^0.1.6",
"es-toolkit": "^1.51.0",
"es-toolkit": "^1.52.0",
"js-base64": "^3.9.3",
"valibot": "^1.4.2"
"valibot": "^1.5.0"
},
"devDependencies": {
"@types/bun": "^1.3.14"

View file

@ -173,16 +173,16 @@
"@open-pencil/kiwi": "workspace:*",
"@open-pencil/pen": "workspace:*",
"@open-pencil/scene-graph": "workspace:*",
"@tauri-apps/api": "^2.11.1",
"@tauri-apps/api": "^2.12.1",
"@valibot/to-json-schema": "^1.8.0",
"@xmldom/xmldom": "^0.9.11",
"@xmldom/xmldom": "^0.9.12",
"acorn": "^8.18.0",
"canvaskit-wasm": "^0.41.1",
"culori": "^4.0.2",
"dedent": "^1.7.2",
"destr": "^2.0.5",
"diff": "^8.0.4",
"es-toolkit": "^1.51.0",
"es-toolkit": "^1.52.0",
"fflate": "^0.8.3",
"fontoxpath": "^3.34.0",
"fzstd": "^0.1.1",
@ -198,11 +198,11 @@
"rbush": "^4.0.1",
"sucrase": "^3.35.1",
"svg-path-properties": "^2.0.2",
"svg2pdf.js": "^2.7.0",
"svg2pdf.js": "^2.8.1",
"svgpath": "^2.6.0",
"twirlwind": "^0.4.0",
"unifont": "0.7.4",
"valibot": "^1.4.2",
"valibot": "^1.5.0",
"yoga-layout": "npm:@open-pencil/yoga-layout@3.3.0-grid.3"
},
"devDependencies": {

View file

@ -252,30 +252,30 @@ export const AI_PROVIDERS: AIProviderDef[] = [
name: 'OpenRouter',
keyPlaceholder: 'sk-or-…',
keyURL: 'https://openrouter.ai/keys',
defaultModel: 'anthropic/claude-sonnet-5',
defaultModel: 'anthropic/claude-sonnet-5.5',
supportsCustomModel: true,
models: [
{
id: 'anthropic/claude-sonnet-5',
name: 'Claude Sonnet 5',
id: 'anthropic/claude-sonnet-5.5',
name: 'Claude Sonnet 5.5',
tag: 'Best for design',
capabilities: ['tools', 'vision']
},
{
id: 'anthropic/claude-opus-5',
name: 'Claude Opus 5',
tag: 'Smartest',
id: 'anthropic/claude-opus-5.5',
name: 'Claude Opus 5.5',
tag: 'Deep reasoning',
capabilities: ['tools', 'vision']
},
{
id: 'anthropic/claude-fable-5.1',
name: 'Claude Fable 5.1',
tag: 'Latest Anthropic',
tag: 'Most capable',
capabilities: ['tools', 'vision']
},
{
id: 'openai/gpt-5.6',
name: 'GPT-5.6',
id: 'openai/gpt-6.1-sol',
name: 'GPT-6.1 Sol',
tag: 'Latest OpenAI',
capabilities: ['tools', 'vision']
},
@ -298,8 +298,18 @@ export const AI_PROVIDERS: AIProviderDef[] = [
tag: 'Vision + code',
capabilities: ['tools', 'vision']
},
{ id: 'qwen/qwen3-coder:free', name: 'Qwen3 Coder', tag: 'Free' },
{ id: 'openai/gpt-oss-120b:free', name: 'GPT-OSS 120B', tag: 'Free' }
{
id: 'qwen/qwen3.8-27b:free',
name: 'Qwen3.8 27B',
tag: 'Free',
capabilities: ['tools', 'vision']
},
{
id: 'google/gemma-4-31b-it:free',
name: 'Gemma 4 31B',
tag: 'Free',
capabilities: ['tools', 'vision']
}
]
},
{
@ -307,24 +317,24 @@ export const AI_PROVIDERS: AIProviderDef[] = [
name: 'Anthropic',
keyPlaceholder: 'sk-ant-…',
keyURL: 'https://console.anthropic.com/settings/keys',
defaultModel: 'claude-sonnet-5',
defaultModel: 'claude-sonnet-5-5',
models: [
{
id: 'claude-sonnet-5',
name: 'Claude Sonnet 5',
id: 'claude-sonnet-5-5',
name: 'Claude Sonnet 5.5',
tag: 'Best for design',
capabilities: ['tools', 'vision']
},
{
id: 'claude-opus-5',
name: 'Claude Opus 5',
tag: 'Smartest',
id: 'claude-opus-5-5',
name: 'Claude Opus 5.5',
tag: 'Deep reasoning',
capabilities: ['tools', 'vision']
},
{
id: 'claude-fable-5-1',
name: 'Claude Fable 5.1',
tag: 'Latest',
tag: 'Most capable',
capabilities: ['tools', 'vision']
}
]
@ -334,12 +344,16 @@ export const AI_PROVIDERS: AIProviderDef[] = [
name: 'OpenAI',
keyPlaceholder: 'sk-…',
keyURL: 'https://platform.openai.com/api-keys',
defaultModel: 'gpt-5.6',
defaultModel: 'gpt-6.1-sol',
models: [
{ id: 'gpt-5.6', name: 'GPT-5.6', tag: 'Best', capabilities: ['tools', 'vision'] },
{ id: 'gpt-5.5', name: 'GPT-5.5', capabilities: ['tools', 'vision'] },
{ id: 'gpt-5.4-mini', name: 'GPT-5.4 mini', tag: 'Fast', capabilities: ['tools', 'vision'] },
{ id: 'gpt-5.4-nano', name: 'GPT-5.4 nano', tag: 'Cheap', capabilities: ['tools', 'vision'] }
{ id: 'gpt-6.1-sol', name: 'GPT-6.1 Sol', tag: 'Best', capabilities: ['tools', 'vision'] },
{
id: 'gpt-6-astra',
name: 'GPT-6 Astra',
tag: 'Smartest',
capabilities: ['tools', 'vision']
},
{ id: 'gpt-6-luna', name: 'GPT-6 Luna', tag: 'Fast', capabilities: ['tools', 'vision'] }
]
},
{

View file

@ -64,9 +64,9 @@
"acorn": "^8.18.0",
"dedent": "^1.7.2",
"entities": "^8.0.0",
"es-toolkit": "^1.51.0",
"es-toolkit": "^1.52.0",
"sucrase": "^3.35.1",
"valibot": "^1.4.2"
"valibot": "^1.5.0"
},
"devDependencies": {
"@types/bun": "^1.3.14",

View file

@ -20,7 +20,7 @@
"@tailwindcss/vite": "^4.3.3",
"vitepress": "^2.0.0-alpha.19",
"vitepress-plugin-llms": "1.12.2",
"vue": "^3.5.41",
"vue": "^3.5.43",
"vue-component-meta": "^3.3.10"
},
"dependencies": {

View file

@ -79,7 +79,7 @@
"@acemir/cssom": "^0.9.31",
"@open-pencil/emit": "workspace:*",
"dedent": "^1.7.2",
"es-toolkit": "^1.51.0",
"es-toolkit": "^1.52.0",
"js-base64": "^3.9.3",
"parse5": "^8.0.1",
"postcss-value-parser": "^4.2.0",

View file

@ -59,10 +59,10 @@
"typecheck": "bunx tsc --noEmit -p tsconfig.test.json"
},
"dependencies": {
"es-toolkit": "^1.51.0",
"es-toolkit": "^1.52.0",
"fflate": "^0.8.3",
"js-base64": "^3.9.3",
"valibot": "^1.4.2"
"valibot": "^1.5.0"
},
"devDependencies": {
"@types/bun": "^1.3.14",

View file

@ -33,9 +33,9 @@
},
"files": ["dist", "src", "README.md"],
"dependencies": {
"@ai-sdk/harness": "1.0.74",
"@ai-sdk/harness-pi": "1.0.76",
"@ai-sdk/sandbox-just-bash": "1.0.74"
"@ai-sdk/harness": "1.0.138",
"@ai-sdk/harness-pi": "1.0.140",
"@ai-sdk/sandbox-just-bash": "1.0.138"
},
"devDependencies": {
"@types/bun": "^1.3.14",

View file

@ -1,44 +1,17 @@
import { createPi } from '@ai-sdk/harness-pi'
import type { PiAuthOptions } from '@ai-sdk/harness-pi'
import type { PiAuthenticationMode, PiHarnessSettings } from '@ai-sdk/harness-pi'
import { HarnessAgent } from '@ai-sdk/harness/agent'
import type { HarnessAgentResumeSessionState, HarnessAgentSession } from '@ai-sdk/harness/agent'
import { createJustBashSandbox } from '@ai-sdk/sandbox-just-bash'
import type { TextStreamPart, ToolSet } from 'ai'
import type { HarnessSessionConfiguration, JSONValue } from '../protocol'
function optional<T>(key: string, value: T | undefined): Record<string, T> {
return value === undefined ? {} : { [key]: value }
}
function restoreEnvironment(previous: Map<string, string | undefined>): void {
for (const [name, value] of previous) {
if (value === undefined) Reflect.deleteProperty(process.env, name)
else process.env[name] = value
}
}
async function withEnvironment<T>(
environment: Record<string, string>,
run: () => Promise<T>
): Promise<T> {
const previous = new Map<string, string | undefined>()
for (const [name, value] of Object.entries(environment)) {
previous.set(name, process.env[name])
process.env[name] = value
}
try {
return await run()
} finally {
restoreEnvironment(previous)
}
}
import type { BackendEvent, BackendSession, HarnessBackend, HarnessResumeState } from './types'
export type PiThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh'
export type PiThinkingLevel = NonNullable<PiHarnessSettings['thinkingLevel']>
export interface PiHarnessBackendOptions {
auth?: PiAuthOptions
auth?: PiAuthenticationMode
apiKey?: string
model?: string
thinkingLevel?: PiThinkingLevel
@ -145,35 +118,35 @@ export class PiHarnessBackend implements HarnessBackend {
typeof configuration.settings?.permissionMode === 'string'
? (configuration.settings.permissionMode as PiHarnessBackendOptions['permissionMode'])
: undefined
const environment: Record<string, string> = this.defaults.apiKey
? { AI_GATEWAY_API_KEY: this.defaults.apiKey }
: {}
return withEnvironment(environment, async () => {
const harness = createPi({
...optional('auth', this.defaults.auth),
...optional('model', configuration.model),
...optional('thinkingLevel', thinkingLevel ?? this.defaults.thinkingLevel),
...optional('agentDir', this.defaults.agentDir),
...optional('mcpServers', options.configuration?.mcpServers ?? this.defaults.mcpServers)
})
const agent = new HarnessAgent({
harness,
sandbox: createJustBashSandbox({ cwd: '/workspace' }),
sandboxConfig: { workDir: 'workspace' },
...optional('instructions', configuration.instructions ?? this.defaults.instructions),
permissionMode: permissionMode ?? this.defaults.permissionMode ?? 'allow-edits'
})
const sessionOptions: {
sessionId: string
resumeFrom?: HarnessAgentResumeSessionState
abortSignal?: AbortSignal
} = { sessionId: options.sessionId }
if (options.resumeState !== undefined) {
sessionOptions.resumeFrom = options.resumeState as HarnessAgentResumeSessionState
}
if (options.signal !== undefined) sessionOptions.abortSignal = options.signal
const session = await agent.createSession(sessionOptions)
return new PiBackendSession(agent, session)
// A supplied environment authenticates this session alone, without touching process.env.
const auth =
this.defaults.auth ??
(this.defaults.apiKey ? { AI_GATEWAY_API_KEY: this.defaults.apiKey } : undefined)
// Plain literals, so the compiler rejects a setting an adapter no longer accepts.
const harness = createPi({
auth,
thinkingLevel: thinkingLevel ?? this.defaults.thinkingLevel,
agentDir: this.defaults.agentDir,
mcpServers: configuration.mcpServers ?? this.defaults.mcpServers
})
const agent = new HarnessAgent({
harness,
model: configuration.model,
sandbox: createJustBashSandbox({ cwd: '/workspace' }),
sandboxConfig: { workDir: 'workspace' },
instructions: configuration.instructions ?? this.defaults.instructions,
permissionMode: permissionMode ?? this.defaults.permissionMode ?? 'allow-edits'
})
const sessionOptions: {
sessionId: string
resumeFrom?: HarnessAgentResumeSessionState
abortSignal?: AbortSignal
} = { sessionId: options.sessionId }
if (options.resumeState !== undefined) {
sessionOptions.resumeFrom = options.resumeState as HarnessAgentResumeSessionState
}
if (options.signal !== undefined) sessionOptions.abortSignal = options.signal
const session = await agent.createSession(sessionOptions)
return new PiBackendSession(agent, session)
}
}

View file

@ -69,14 +69,14 @@
"@open-pencil/design-jsx": "workspace:*",
"@open-pencil/scene-graph": "workspace:*",
"@valibot/to-json-schema": "^1.8.0",
"hono": "^4.13.2",
"hono": "^4.13.13",
"js-base64": "^3.9.3",
"package-manager-detector": "^1.8.0",
"valibot": "^1.4.2",
"valibot": "^1.5.0",
"ws": "^8.21.3"
},
"devDependencies": {
"@types/node": "^25.9.5",
"@types/node": "^25.9.9",
"@types/ws": "^8.18.1"
}
}

View file

@ -200,7 +200,7 @@
},
"dependencies": {
"culori": "^4.0.2",
"es-toolkit": "^1.51.0",
"es-toolkit": "^1.52.0",
"nanoevents": "^9.1.0",
"svgpath": "^2.6.0"
},

View file

@ -49,8 +49,8 @@
"@tanstack/vue-table": "^8.21.3",
"@vueuse/core": "^14.4.0",
"fuse.js": "^7.5.0",
"nanostores": "^1.5.0",
"reka-ui": "^2.10.3"
"nanostores": "^1.5.4",
"reka-ui": "^2.10.5"
},
"devDependencies": {
"tsdown": "^0.22.14",

View file

@ -1,4 +1,4 @@
import { APICallError } from 'ai'
import { APICallError, StreamProviderError } from 'ai'
export type AIChatFailureReason =
| 'authentication'
@ -113,6 +113,10 @@ export function classifyAIChatError(error: unknown): AIChatFailure {
reason: failureReason(error),
detail: errorText(error),
statusCode: providerErrorStatus(error) ?? undefined,
retryable: APICallError.isInstance(error) ? error.isRetryable : undefined
// A provider error after the stream starts arrives as StreamProviderError, not APICallError.
retryable:
APICallError.isInstance(error) || StreamProviderError.isInstance(error)
? error.isRetryable
: undefined
}
}

View file

@ -6,14 +6,14 @@ import AppCombobox from './AppCombobox.vue'
const models = [
{
value: 'anthropic/claude-sonnet-5',
label: 'Claude Sonnet 5',
value: 'anthropic/claude-sonnet-5.5',
label: 'Claude Sonnet 5.5',
meta: 'Recommended',
group: 'Recommended'
},
{
value: 'openai/gpt-5.6',
label: 'GPT-5.6',
value: 'openai/gpt-6.1-sol',
label: 'GPT-6.1 Sol',
meta: 'Latest',
group: 'Latest'
},
@ -59,7 +59,7 @@ const meta = {
render: (args) => ({
components: { AppCombobox },
setup() {
const value = ref('anthropic/claude-sonnet-5')
const value = ref('anthropic/claude-sonnet-5.5')
return { args, value }
},
template: `

View file

@ -46,8 +46,8 @@ describe('models.dev catalog', () => {
catalogResponse({
openai: {
models: {
'gpt-5.6': {
name: 'GPT-5.6 from catalog',
'gpt-6.1-sol': {
name: 'GPT-6.1 Sol from catalog',
tool_call: true,
attachment: true,
release_date: '2026-07-09',
@ -81,8 +81,8 @@ describe('models.dev catalog', () => {
)
expect(models[0]).toMatchObject({
id: 'gpt-5.6',
name: 'GPT-5.6',
id: 'gpt-6.1-sol',
name: 'GPT-6.1 Sol',
tag: 'Best',
capabilities: ['tools', 'vision'],
releaseDate: '2026-07-09'
@ -99,7 +99,7 @@ describe('models.dev catalog', () => {
const failingFetch = (async () => new Response(null, { status: 503 })) as typeof fetch
const models = await listCatalogModels('anthropic', failingFetch)
expect(models[0]).toMatchObject({ id: 'claude-sonnet-5', tag: 'Best for design' })
expect(models[0]).toMatchObject({ id: 'claude-sonnet-5-5', tag: 'Best for design' })
})
test('retries a failed shared request and shares a successful request', async () => {
@ -131,7 +131,7 @@ describe('models.dev catalog', () => {
test('preserves vision support in offline curated models', async () => {
const failingFetch = (async () => new Response(null, { status: 503 })) as typeof fetch
const openai = await listCatalogModels('openai', failingFetch)
for (const id of ['gpt-5.6', 'gpt-5.5', 'gpt-5.4-mini', 'gpt-5.4-nano']) {
for (const id of ['gpt-6.1-sol', 'gpt-6-astra', 'gpt-6-luna']) {
expect(openai.find((model) => model.id === id)?.capabilities).toContain('vision')
}
const zai = await listCatalogModels('zai', failingFetch)

View file

@ -1,6 +1,6 @@
import { describe, expect, test } from 'bun:test'
import { APICallError } from 'ai'
import { APICallError, StreamProviderError } from 'ai'
import {
classifyAIChatError,
@ -50,6 +50,19 @@ describe('AI chat failures', () => {
})
})
test('classifies provider errors reported after the stream started', () => {
const streamError = new StreamProviderError({
message: 'Too many requests',
statusCode: 429,
isRetryable: true
})
expect(classifyAIChatError(streamError)).toMatchObject({
reason: 'rate-limit',
statusCode: 429,
retryable: true
})
})
test('classifies provider messages without exposing them as presentation copy', () => {
expect(classifyAIChatError(new Error('API key expired.')).reason).toBe('authentication')
expect(classifyAIChatError(new Error('Invalid API key.')).reason).toBe('authentication')

View file

@ -14,6 +14,6 @@
"dependencies": {
"@open-pencil/package-artifacts-tools": "workspace:*",
"citty": "^0.1.6",
"es-toolkit": "^1.51.0"
"es-toolkit": "^1.52.0"
}
}

View file

@ -15,14 +15,14 @@
"@open-pencil/package-artifacts-tools": "workspace:*",
"@realfavicongenerator/generate-favicon": "0.9.0",
"@realfavicongenerator/image-adapter-node": "0.9.0",
"@tauri-apps/cli": "2.11.4",
"@tauri-apps/cli": "2.12.1",
"proper-lockfile": "4.1.2",
"sharp": "0.34.5",
"valibot": "^1.4.2"
"valibot": "^1.5.0"
},
"devDependencies": {
"@types/bun": "^1.3.14",
"@types/node": "^25.9.5",
"@types/node": "^25.9.9",
"@types/proper-lockfile": "4.1.4",
"typescript": "~5.8.3"
}

View file

@ -5,6 +5,6 @@
"devDependencies": {
"@types/bun": "^1.3.14",
"@types/mdast": "^4.0.4",
"@types/node": "^25.9.5"
"@types/node": "^25.9.9"
}
}

View file

@ -17,7 +17,7 @@
"@publint/pack": "^0.1.5",
"pkg-types": "^2.3.1",
"tinyexec": "^1.3.0",
"valibot": "^1.4.2"
"valibot": "^1.5.0"
},
"devDependencies": {
"nanotar": "^0.3.0"

View file

@ -9,7 +9,7 @@
1. **Plan:** resolve the source commit and generate the native matrix from `native/catalog.ts`.
2. **Frontend:** build packages and the desktop frontend once; prepare and pack npm archives without rebuilding. Archive `dist`, desktop icons, and generated menus together and record its SHA-256.
3. **Native:** five independent jobs check out that same source, verify and extract the shared inputs, then build through Node's Tauri CLI launcher. A generated config sets only `build.beforeBuildCommand` to `null`; the checked-in local build hook is unchanged. No native job uploads release assets.
4. **Publish:** require the complete matrix with identical source/workflow/run/attempt/frontend identity. Verify file inventories, hashes, every updater signature, and exact source changelog notes. Generate the updater JSON, source/workflow manifest, and checksums; attest and verify the complete output set. Verify npm consumers and publish the original tarballs with npm provenance. Replace every expected draft asset, then download and verify all uploaded bytes.
4. **Publish:** require the complete matrix with identical source/workflow/run/attempt/frontend identity. Verify file inventories, hashes, every updater signature and the release version it records (the desktop updater sets `requireSignedVersion`), and exact source changelog notes. Generate the updater JSON, source/workflow manifest, and checksums; attest and verify the complete output set. Verify npm consumers and publish the original tarballs with npm provenance. Replace every expected draft asset, then download and verify all uploaded bytes.
Workflow tooling is checked out separately in `.pipeline` and installed from its own frozen lockfile where it runs. Application dependency installation and builds remain owned by the tagged checkout; rebuilding an older tag must not accidentally execute its older release orchestration. Dependency installation is not frontend/package compilation.

View file

@ -17,9 +17,9 @@
"@open-pencil/package-artifacts-tools": "workspace:*",
"@open-pencil/package-quality-tools": "workspace:*",
"citty": "^0.1.6",
"es-toolkit": "^1.51.0",
"es-toolkit": "^1.52.0",
"js-base64": "^3.9.3",
"valibot": "^1.4.2"
"valibot": "^1.5.0"
},
"devDependencies": {
"nanotar": "^0.3.0"

View file

@ -4,13 +4,14 @@ import { join } from 'node:path'
import { readReleaseNotes } from '#release/release-notes'
import { isEqual } from 'es-toolkit'
import { toUint8Array } from 'js-base64'
import { decode, toUint8Array } from 'js-base64'
import * as v from 'valibot'
import { desktopAssets } from './catalog.ts'
import { releaseCommands } from './commands.ts'
import { createReleaseContext } from './context.ts'
import { digestFile, validateTargetManifests } from './manifest.ts'
import { assertSignedVersion } from './signature.ts'
const { identity, repository, version, paths } = createReleaseContext()
const { verifySignature } = releaseCommands(paths.root)
@ -74,6 +75,7 @@ try {
const decoded = join(temporary, `${asset.name}.minisig`)
await writeFile(decoded, toUint8Array(signature))
await verifySignature(join(source, asset.name), publicKey, decoded)
assertSignedVersion(decode(signature), version, asset.name)
for (const platform of asset.updaterKeys) {
if (platforms[platform]) throw new Error(`Duplicate updater platform: ${platform}`)

View file

@ -0,0 +1,26 @@
const TRUSTED_COMMENT = 'trusted comment: '
/**
* The version a decoded minisign signature was made for. The Tauri CLI writes the trusted
* comment as tab-separated `key:value` fields, e.g. `timestamp:…\tfile:…\tversion:1.2.3`.
*/
export function signedVersion(minisign: string): string | null {
const comment = minisign
.split(/\r?\n/)
.find((line) => line.startsWith(TRUSTED_COMMENT))
?.slice(TRUSTED_COMMENT.length)
if (comment === undefined) return null
for (const field of comment.split('\t')) {
if (field.startsWith('version:')) return field.slice('version:'.length)
}
return null
}
/** Updaters with `requireSignedVersion` reject a signature that does not name this version. */
export function assertSignedVersion(minisign: string, version: string, asset: string): void {
const signed = signedVersion(minisign)
if (signed === null) throw new Error(`Signature for ${asset} does not record a version`)
if (signed !== version) {
throw new Error(`Signature for ${asset} is for version ${signed}, not ${version}`)
}
}

View file

@ -0,0 +1,32 @@
import { expect, test } from 'bun:test'
import { assertSignedVersion, signedVersion } from '#release/native/signature'
function minisign(trustedComment: string): string {
return [
'untrusted comment: signature from tauri secret key',
'RUQB7eR4Dr/AWAAAAA==',
`trusted comment: ${trustedComment}`,
'BBBB=='
].join('\n')
}
test('reads the version the Tauri CLI records in the trusted comment', () => {
expect(signedVersion(minisign('timestamp:1\tfile:OpenPencil.app.tar.gz\tversion:0.16.0'))).toBe(
'0.16.0'
)
expect(signedVersion(minisign('timestamp:1\tfile:OpenPencil.app.tar.gz'))).toBeNull()
})
test('accepts only a signature made for the released version', () => {
const asset = 'OpenPencil.app.tar.gz'
expect(() =>
assertSignedVersion(minisign(`timestamp:1\tfile:${asset}\tversion:0.16.0`), '0.16.0', asset)
).not.toThrow()
expect(() =>
assertSignedVersion(minisign(`timestamp:1\tfile:${asset}\tversion:0.15.1`), '0.16.0', asset)
).toThrow('is for version 0.15.1')
expect(() =>
assertSignedVersion(minisign(`timestamp:1\tfile:${asset}`), '0.16.0', asset)
).toThrow('does not record a version')
})