* 🐛 Remove cursor CSS for all inputs
- Restore the default cursor for the dashboard inputs.
- Make the numeric-input component from DS to work as expected.
* 🐛 Fix remove drag-to-change behaviour from old numeric-input
* 🐛 Fix library updates reappear after file is reloaded
Summary
Migrate synced_at timestamps to a standalone file_library_sync table to ensure sync state is tracked for both direct and transitive libraries.
Problem
Transitive libraries (libraries imported by other libraries) are not stored as direct rows in file_library_rel. Because the system previously coupled synced_at directly to the file_library_rel schema, transitive libraries lacked a persistent location for their sync timestamps. This caused sync states to be lost or incorrectly reported for nested dependencies.
Changes
Schema Migration: Created file_library_sync and migrated existing synced_at values from file_library_rel.
Decoupling: Removed tight Foreign Key coupling to allow sync rows to exist independently of specific relationship records.
Persistent Writes: Added upsert-file-library-sync! helper. Updated all import, duplication, and RPC write paths (v1/v2/v3 importers, link-file-library) to ensure every write persists a sync row.
Unified Reads: Updated both direct and recursive/transitive library queries to fetch synced_at from the new table.
Testing: Added regression tests to verify that sync rows are correctly created/updated even when a transitive relation is absent in file_library_rel.
Impact
This fix ensures that the system accurately records and retrieves sync states for the entire library dependency tree, resolving the bug where nested libraries appeared out of sync.
* ✨ MR review
* ✨ Add additional logging and validation for image upload
* 🎉 Add chunked upload support for font variants
Extend the font variant upload flow across frontend, backend, and common
to support the standardized chunked upload protocol.
**Backend:**
- Add \`:font-max-file-size\` config default (30 MiB) and schema entry
- Add \`validate-font-size!\` in \`media.clj\` (mirrors
\`validate-media-size!\`, raises \`:font-max-file-size-reached\`)
- Extend \`schema:create-font-variant\` to accept either \`:data\`
(legacy bytes or chunk-vector) or \`:uploads\` (new chunked session
map), with a validator requiring exactly one
- Add \`prepare-font-data-from-uploads\`: assembles each chunked
session via \`cmedia/assemble-chunks\`, validates type+size
- Add \`prepare-font-data-from-legacy\`: normalises legacy byte/chunk
entries, writing to a tempfile (joining via SequenceInputStream),
validates type+size
- Add structured logging ("init"/"end") with \`:size\`, \`:mtypes\`,
and \`:elapsed\` in \`create-font-variant\`
**Frontend:**
- \`upload-blob-chunked\` accepts a per-caller \`:chunk-size\` option
- Add \`font-upload-chunk-size\` (10 MiB) and \`upload-font-variant\`
fn that uploads each mtype as a separate chunked session
- \`on-upload*\` in dashboard fonts now calls \`upload-font-variant\`
instead of issuing \`create-font-variant\` RPC directly
- \`process-upload\` stores raw ArrayBuffer instead of chunking
client-side
**Common:**
- Replace \`"font/opentype"\` with \`"font/woff2"\` in \`font-types\`
**Tests:**
- 25 tests / 224 assertions covering all three upload paths (direct
bytes, legacy chunk-vector, new chunked sessions), size validation,
and media type validation
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* 📎 Add a script for check the commit format locally
---------
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Serena provides useful tools for the agentic workflow for penpot.
The following additional extensions are added:
1. uv and Serena installation, including a suitable serena_config.yml, are added to the devenv docker image
2. Serena configuration options are set via env vars and flags in manage.sh
3. run-devenv can now take -e flags which it forwards to docker exec
GitHub #9315
Adds a new MCP tool (devenv-only) that imports .penpot files into the
running Penpot instance. The tool downloads the file from a given URL,
stages it in the frontend's static directory, and triggers the import
via the ClojureScript REPL using the frontend's web worker infrastructure.
The temporary file is cleaned up after the import completes or fails.
Registered alongside CljsReplTool, sharing the same NreplClient instance.
Github #9217
Co-authored-by: Claude <noreply@anthropic.com>
Documents how to detect, diagnose, and recover from frontend crashes
(the Internal Error page) when working through the Penpot Plugin API:
- Detect via (some? (:exception @app.main.store/state)) in the cljs REPL
- Read cause from the same map (:type, :code, :hint, :details, :uri, ...)
- Reload by listing/selecting the workspace tab in playwright and
re-navigating to its URL, then re-checking the exception is gone
Co-authored-by: Claude <noreply@anthropic.com>