Commit graph

911 commits

Author SHA1 Message Date
Danila Poyarkov a29f609dd2
fix(settings): separate MCP connections from models (#522)
- Add a dedicated MCP connections destination to Settings navigation
- Keep ModelsPanel focused on model profiles and assignments
- Update documentation, changelog, and browser coverage for the new location
2026-08-14 20:39:29 +03:00
Danila Poyarkov 90f2498bcf
fix(collab): validate synchronized node data (#517)
* fix(collab): validate synchronized node data

- Exclude renderer-only text picture caches from Yjs payloads

- Normalize source metadata and geometry at the remote boundary

- Cover malformed payloads and typed geometry round trips

* fix(collab): reject malformed geometry fills

* fix(collab): validate nested fill metadata

* test(collab): preserve valid nested fill metadata
2026-08-14 20:38:46 +03:00
Danila Poyarkov 39bc4d2eb1
feat(acp): add reusable MCP connections (#516)
* feat(acp): add reusable MCP connections

- Store named Streamable HTTP connections separately from model providers
- Keep bearer tokens in the credential manager and resolve them per ACP session
- Add localized settings, validation, documentation, and focused coverage

* test(acp): harden MCP connection workflow

- Label credential inputs and confirm destructive connection removal
- Exercise MCP server delivery through an in-memory ACP session
- Extend the browser smoke test to cover accessible input and confirmation flows

* fix(acp): validate MCP connection lifecycle

- Keep non-browser storage initialization in memory and restore the German model copy
- Reject persisted name collisions and invalid draft IDs
- Preserve connections on credential failures and require credentials before enablement
2026-08-14 20:08:45 +03:00
Danila Poyarkov b93ffea073
feat: add Figma-style variants and component libraries (#512)
Closes #239
2026-08-14 19:31:41 +03:00
Danila Poyarkov 16e7707d7a Merge remote-tracking branch 'origin/master' into reference-image-chat 2026-08-14 14:47:03 +03:00
Danila Poyarkov 5f0b673a07 fix(ai): harden image attachment lifecycle
- Prevent overlapping submissions while image analysis is running

- Guard browser image APIs and object URL cleanup

- Restore compound-control and keyboard-focus styling
2026-08-14 14:31:59 +03:00
Danila Poyarkov d90e640e89
perf(app): defer inactive Code panel generation (#514)
* perf(app): defer inactive Code panel generation

- Skip JSX serialization and syntax highlighting while the Code tab is hidden

- Restore code generation when desktop or mobile users activate the tab

- Cover large Design-tab selections without hidden Code-panel work

* test(app): cover deferred Code panel updates

- Keep mobile JSX generation inactive while the drawer is closed

- Measure the complete two-frame inactive selection flow

- Verify mobile Code output refreshes when the drawer reopens
2026-08-14 14:24:10 +03:00
Danila Poyarkov 7b67bd8658 feat(ai): support multiple image attachments
- Show complete user messages with every image immediately after sending

- Analyze up to four bounded images without adding pixels to Design context

- Organize image handling under the extensible attachment domain
2026-08-14 13:44:57 +03:00
Danila Poyarkov 2f88ef4827 refactor(ui): unify chat composer controls
- Add a canonical 24, 28, and 32 pixel control scale

- Rebuild the AI prompt as a multiline compound input

- Keep property-panel icon actions at the explicit compact size
2026-08-14 13:21:29 +03:00
Danila Poyarkov 62f3594819 feat(ai): add visual reference attachments 2026-08-14 12:46:29 +03:00
Danila Poyarkov 631fc25ee6
fix(app): retain recovery after closing unsaved tabs (#505)
* fix(app): retain recovery after closing unsaved tabs

- Persist source-less tab snapshots before disposing editors

- Keep retained snapshots available for startup restore or explicit discard

- Cover close, reload, and restore behavior in Playwright

* fix(app): surface recovery persistence failures

- Propagate explicit close and reload snapshot failures

- Keep background debounce failures logged without unhandled rejections

- Exercise close-time persistence in recovery coverage

* test(app): cover recovery persistence retry

* docs: restore recovery retention note
2026-08-13 21:39:35 +03:00
Danila Poyarkov 6a44aecc24 refactor(ai): isolate reasoning options 2026-08-13 21:18:10 +03:00
Danila Poyarkov 96b030699c fix(ai): apply vision reasoning settings 2026-08-13 21:15:44 +03:00
Danila Poyarkov 8294e32f33 feat(ai): add isolated visual inspection
- Route bounded selection renders through the optional Vision model

- Return compact text findings without retaining image data in Design chat history

- Bound MCP and AI image exports by their longest pixel edge
2026-08-13 21:15:44 +03:00
Danila Poyarkov 6d81d53d1d fix(tauri): preserve HTTP timeout and response semantics
- Apply validated request timeouts without overriding the shared client default

- Preserve abort behavior and null-body response statuses

Co-authored-by: Joseph Cumines <joeycumines@gmail.com>
2026-08-13 20:33:10 +03:00
Danila Poyarkov 1eb1f38c78 feat(text): surface missing font substitutions
- Track loaded font provenance and aggregate page-level face fidelity, including synthesized styles and active Inter substitutions
- Add a localized warning banner with retry and affected-layer actions
- Expose get_font_status through the Figma API and MCP tool registry
2026-08-13 18:33:10 +03:00
Danila Poyarkov f22d2c9bad fix(app): serialize document recovery lifecycle
- Await IndexedDB writes and tab recovery cleanup

- Serialize recovery backend fallback and snapshot adoption

- Preserve queued snapshots when IndexedDB falls back to memory
2026-08-13 17:22:59 +03:00
Danila Poyarkov 7b8e5fbfbe fix(app): harden document recovery lifecycle
- Serialize recovery cleanup with active snapshot writes

- Preserve version ordering across autosave, restore, and cleanup

- Fall back to memory when IndexedDB operations fail
2026-08-13 17:22:59 +03:00
Danila Poyarkov 16b74a2087 refactor(app): standardize IndexedDB access
- Migrate the local canvas store and sync outbox to the typed idb dependency

- Remove the redundant raw IndexedDB promise helpers
2026-08-13 17:22:59 +03:00
Danila Poyarkov 37912d92a7 feat(app): recover unsaved documents
- Persist debounced FIG snapshots for source-less documents in IndexedDB

- Restore or discard orphaned snapshots from the editor startup dialog

- Clear recovery data after successful saves and explicit tab closure
2026-08-13 17:22:59 +03:00
Danila Poyarkov 3a2c8afc3e fix(ai): harden failure diagnostics
- Redact and bound provider error details in copied logs

- Avoid repeat toasts after locale changes

- Show reasoning effort only for supported providers
2026-08-13 15:03:12 +03:00
Danila Poyarkov 9e93884e7f fix(ai): surface silent provider failures
- Report credit and output-limit failures through localized toasts and debug logs

- Persist optional provider-specific reasoning effort on model profiles

- Classify insufficient-credit connection tests and cover failure diagnostics
2026-08-13 15:03:12 +03:00
Danila Poyarkov a8cf8eb412
fix(tauri): prevent Windows font loading crashes (#497)
* fix(tauri): prevent Windows font loading crashes

- Return native font files over binary Tauri IPC instead of JSON byte arrays

- Resolve desktop script fallbacks without parsing large system fonts in JavaScript

* fix(core): restore quality checks

- Use the shared Vector primitive for render-bound offsets

- Remove unsupported SLICE handling from SceneGraph rescaling

- Drop an unused generated-text test binding

* chore: address font fix review

- Place the release note under the Fixed heading

- Name fallback resolution options and use the shared Tauri constant
2026-08-12 20:09:04 +03:00
Danila Poyarkov 3c016e9573
fix(mcp): close orphaned servers after app disconnects (#494)
* fix(mcp): close orphaned servers that no app ever claims

- Add ServerOptions.appAttachTimeoutMs: if no app registers within this
  window after startup, the server closes itself and removes its
  discovery file, instead of squatting the port indefinitely.
- Wire it through the openpencil-mcp-http CLI as
  OPENPENCIL_MCP_APP_TIMEOUT_MS (opt-in, unset/0 disables it — a bare
  CLI invocation for manual testing should not self-terminate).
- The desktop app opts in with a 30s timeout when it spawns the server.

Without this, a server that outlives its spawning app (renderer crash,
forced reload) keeps holding its port with a stale discovery file. The
app's liveness check only asks whether something answers /health, not
whether an app has ever registered (see /health's no_app status) — so
every later launch finds the orphan already listening and defers to
it, and MCP tool calls fail with "app is not connected" until someone
manually kills the orphaned process. Closing self-caused orphans at
the source means the next launch finds no discovery file and takes
the normal fresh-spawn path.

Fixes #488

* fix(mcp): clean up servers after app disconnects

- Re-arm the orphan watchdog when the registered app disconnects

- Cancel pending shutdown when the app reconnects within the grace period

- Reject timeout values that overflow the runtime timer range

* test(mcp): make watchdog reconnect coverage deterministic

- Wait for the disconnected health state before reconnecting

- Report distinct safe-integer and timer-range validation errors

---------

Co-authored-by: swe-sanad <sanad.arousi@export119.com>
2026-08-12 18:44:31 +03:00
Danila Poyarkov d4fedcb6ed
fix(storage): polish workspace and connection feedback (#492)
* fix(storage): polish workspace and connection feedback

- Move Refresh into the Storage Workspace header and keep shell theme actions available outside the editor route
- Split native shell and editor menu listeners behind the app shell
- Replace permanent CORS controls and inline connection results with standard toasts and clearer browser guidance

* fix(app): harden native menu routing

- Dispose menu listeners that finish registering after their Vue scope closes
- Mark shell-owned actions in the shared menu schema instead of duplicating IDs
- Cover route-neutral shell action classification
2026-08-12 16:06:10 +03:00
Danila Poyarkov 00f0d3902a fix(app): destructure font picker props 2026-08-12 12:39:38 +03:00
Danila Poyarkov 97bfedda1d chore: format mobile drawer navigation 2026-08-12 12:27:47 +03:00
Danila Poyarkov 0de5685074 fix(tauri): restore native text clipboard actions
- Use macOS predefined copy, cut, and paste menu items so WebKit routes accelerators to focused editing controls\n- Keep canvas clipboard events handled by OpenPencil and recognize composed contenteditable targets\n- Cover editable input and nested contenteditable event paths
2026-08-12 07:37:11 +03:00
Danila Poyarkov 51ab21571a fix(i18n): translate remaining app surfaces
- Localize import, collaboration, settings, color, font, and accessibility text across supported locales

- Synchronize the document language through reactive Unhead attributes

- Translate connection failures, browser fallbacks, notifications, and save prompts
2026-08-11 22:19:40 +03:00
Danila Poyarkov 8f35746060 fix(app): keep desktop startup console clean
- Load Prism JSX only after exposing the Prism runtime

- Treat unavailable MCP automation as optional during startup

- Connect the desktop automation bridge only after MCP is ready
2026-08-11 13:56:04 +03:00
Danila Poyarkov a6842fde47 fix(vue): discard stale workspace results 2026-08-10 22:47:00 +03:00
Danila Poyarkov b21509cc8d fix(storage): isolate workspace refresh state
- Discard stale provider refreshes and queued previews

- Guard malformed deflate data and listener failures

- Start periodic refresh without an immediate callback
2026-08-10 22:30:54 +03:00
Danila Poyarkov 4fe27dd1e6 fix(storage): harden workspace previews
- Validate ranged thumbnail payloads and S3 bounds

- Invalidate stale previews and expose loading errors

- Document the public document workspace composable
2026-08-10 20:02:58 +03:00
Danila Poyarkov dde7376bd3 feat(storage): show workspace document previews
- Load embedded Figma thumbnails through bounded S3 byte-range requests

- Add a headless Vue workspace composable with lazy previews and refresh lifecycle

- Cache local previews and refresh the workspace after saves and synchronization
2026-08-10 17:21:36 +03:00
Danila Poyarkov 55b368dc4a fix: complete acronym casing follow-ups
- Cover UI identifiers in the acronym guardrail
- Preserve FIG thumbnail and metadata values through archive parsing
- Use Vue-compatible acronym prop attributes
2026-08-10 16:38:17 +03:00
Danila Poyarkov 7f91594d0c refactor: standardize acronym casing
- Rename first-party API, RPC, JSON, CORS, SVG, JSX, and related identifiers to preserve acronym casing
- Keep upstream and serialized boundary names unchanged
- Add a lint guardrail and migration notes for exported APIs
2026-08-10 15:48:16 +03:00
Danila Poyarkov 4986fb8b54 fix(ai): simplify model configuration
- Separate model, connection, and advanced settings

- Resolve capabilities and output limits from provider catalogs

- Keep custom model compatibility declarations explicit
2026-08-10 12:55:35 +03:00
Danila Poyarkov 854e1642d8 feat(fig): prototype lazy population worker
- Populate subsequent lazy pages in a development-only persistent worker
- Journal created, updated, and deleted graph state as field deltas
- Invalidate stale worker replicas after authoritative graph mutations
- Fall back to synchronous population when the worker is unavailable
2026-08-07 09:27:54 +03:00
Danila Poyarkov 005f1bcdfa
Merge branch 'master' into polish-pr-455 2026-08-05 17:03:52 +03:00
Danila Poyarkov 3353c747af fix(ai): preserve valid design assignment
- Reject removing the active Design profile when no tools-capable fallback exists

- Cover text-only fallback handling
2026-08-05 17:03:37 +03:00
Danila Poyarkov 7a3a8bf53f refactor(chat): polish model profile switching
- Centralize design-profile eligibility for the selector, role assignment, fallback, and tests
- Keep built-in provider model selection intact while switching saved custom profiles
- Add localized accessible labeling and constrain long profile names
2026-08-05 15:44:27 +03:00
Rob Coenen 4bdaeb6d6e feat(chat): switch models from the chat panel
The chat model chip is a dropdown for built-in providers but a static label
for OpenAI-compatible and custom-model setups, so anyone using a custom
endpoint had to open Settings to change models -- even with several models
already configured.

Add a profile switcher that reassigns the design role from the chat panel.
It lists saved profiles that can use tools, shows the profile name rather
than the raw model ID, and badges the vision-capable ones. It writes the
same assignments.design field the Settings dropdown does, so the two stay in
sync.

Only renders when more than one tools-capable profile exists; a single
profile keeps the existing label. Built-in providers keep ProviderModelSelect
unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-05 15:28:31 +03:00
Danila Poyarkov 79aa6ba5dd refactor(app): move storage workspace navigation into File menu
- Replace the full-width editor header action with a shared browser and native menu command
- Localize the destination and cover menu schema and browser navigation
2026-08-03 17:42:39 +03:00
Rob Coenen d85e2ec5e1 feat(app): add a Back to workspace button to the editor header
Once a document is opened from the storage workspace there is no way back
to it: the only in-app route is Settings -> Cloud storage -> Open workspace,
and the desktop shell has no browser back at all.

Add an explicit button in the shared header row (rendered on both web and
Tauri, unlike the File/Edit menubar below it) that routes to /storage. It is
a fixed destination rather than history navigation, so it behaves the same
on both platforms.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 17:18:16 +03:00
Danila Poyarkov de8578c435
feat(app): expand Figma menu and selection parity (#459)
- Add Figma-style object, component, selection, view, settings, and browser Move to Page actions
- Add undoable z-order, transformed distribution, inverse selection, and single/bulk rename behavior
- Keep browser and native menus, shortcuts, generated schema, localization, and documentation aligned
2026-08-03 00:23:05 +03:00
rcoenen ff31f90de9
fix(ai): opt into Anthropic direct browser access (#438)
Anthropic omits Access-Control-Allow-Origin unless the caller sends
anthropic-dangerous-direct-browser-access, so the web build failed with an
opaque "Could not reach this endpoint from the browser" for the anthropic
provider. @ai-sdk/anthropic does not send the header and neither did our
adapter.

Send it from the browser only. The desktop build routes through tauriFetch
and is not subject to CORS, so it does not need to advertise browser access.

Fixes #436

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 20:22:45 +03:00
Danila Poyarkov cb2c4aa3d3 fix(vector): edit vectors from opened files
- Resolve the active graph at action time and map edit geometry through full world transforms
- Regenerate live path fills and discard stale imported stroke outlines after edits
- Preserve fill and stroke geometry through resize previews, undo, and redo
- Cover graph replacement, nested transforms, edit history, resizing, and CanvasKit output

Co-authored-by: Rob Coenen <753704+rcoenen@users.noreply.github.com>
2026-07-28 12:30:21 +03:00
tae.virus 679ee9f98f
feat(export): add editable PPTX export (#416)
- Export text and basic shapes as editable PowerPoint elements
- Rasterize unsupported geometry, effects, masks, and clipped content for fidelity
- Support app and CLI exports across multiple pages

Co-authored-by: TKman <102001532+greekr4@users.noreply.github.com>
2026-07-28 10:12:41 +03:00
Danila Poyarkov 1415640718 refactor(core): centralize Base64 encoding
- Add portable byte and Unicode Base64 helpers backed by js-base64

- Replace manual binary-string, Buffer, and unsupported typed-array conversions

- Cover binary, Unicode, URL-safe, malformed, and large inputs
2026-07-28 08:27:22 +03:00
Danila Poyarkov a7a44e90b2 fix(settings): remember browser credentials by default
- Default fresh browser sessions to encrypted credential persistence with an explicit session-only opt-out

- Keep API-key links left-aligned, legible, and limited to their text click target

- Update credential guidance and browser coverage
2026-07-27 19:21:19 +03:00