399 Commits

Author SHA1 Message Date
Álvaro Tejero Cantero
0cc2e97338
Merge develop into iop-vc-preview
Bring iop-vc-preview up to develop 43f3bda8b5, which carries the
final squash of penpot#12420 (93d36d04d8).

iop-vc-preview carried an earlier copy of penpot#12420 (42a2e33ffe
and a6c20b3e95). Every file the early or the final copy touches was
merged three-way with a6c20b3e95 as the base, so develop's side wins
for every penpot#12420 hunk and iop-vc-preview keeps only its own
deltas. Changes from other develop PRs (#12524, #12192, #12731,
#12686, #12442) are kept.

Adaptations to develop:
- files_update.clj: apply-changes returns the triple
  [file op-changes media-index] on the #12524 auto-repair path too,
  and a repaired branch save logs the repair changes ahead of the
  client's ones.
- files.clj: absorb-library-by-file takes develop's update-file! map.
- migrations.cljc: migrate keeps its target arity and develop's
  ordered :migrations set.
- climit.edn: the branch global limits declare a queue, as #12686's
  example-config-bounds-every-wait requires.
- Tests: the repair tests destructure the triple, the branch import
  test uses the #12192 export cfg keys, and the ref-paths test
  classifies :set-own-tokens-status.
- Dashboard comments and placeholder take develop's design-system
  icons around iop-vc-preview's review list; en.po and es.po keep the
  union of both sides.

AI-assisted-by: claude-opus-5-5
Signed-off-by: Álvaro Tejero Cantero <alvorithm@teje.ro>
2026-11-03 12:47:08 +01:00
Alonso Torres
2f57d380db
✨ Allow send custom binary to the agents (#12770) 2026-11-03 09:31:59 +01:00
Miguel de Benito Delgado
723267cfdd
🐳 Expose GPU in devenv (#12726)
* ✨ Add GPU support to the devenv

AI-assisted-by: gpt-6.1-sol

* 📚 Fix broken link in dev docs
2026-10-30 15:13:29 +01:00
penpot-renovate[bot]
936371d9a6
⬆️ Update dependency pnpm to v12.16.1 (#12714)
- pnpm 12.16.1 (docker/images/Dockerfile.media-processor)
- pnpm 12.16.1 (docker/images/Dockerfile.mcp)
- pnpm 12.16.1 (docker/images/Dockerfile.exporter)
- pnpm 12.16.1 (docker/devenv/Dockerfile)
- pnpm 12.16.1 (render-wasm/package.json)
- pnpm 12.16.1 (plugins/package.json)
- pnpm 12.16.1 (plugins/libs/plugins-styles/package.json)
- pnpm 12.16.1 (plugins/libs/plugins-runtime/package.json)
- pnpm 12.16.1 (plugins/libs/plugin-types/package.json)
- pnpm 12.16.1 (plugins/apps/table-plugin/package.json)
- pnpm 12.16.1 (plugins/apps/rename-layers-plugin/package.json)
- pnpm 12.16.1 (plugins/apps/poc-tokens-plugin/package.json)
- pnpm 12.16.1 (plugins/apps/poc-state-plugin/package.json)
- pnpm 12.16.1 (plugins/apps/plugin-api-test-suite/package.json)
- pnpm 12.16.1 (plugins/apps/lorem-ipsum-plugin/package.json)
- pnpm 12.16.1 (plugins/apps/icons-plugin/package.json)
- pnpm 12.16.1 (plugins/apps/example-styles/package.json)
- pnpm 12.16.1 (plugins/apps/e2e/package.json)
- pnpm 12.16.1 (plugins/apps/create-palette-plugin/package.json)
- pnpm 12.16.1 (plugins/apps/contrast-plugin/package.json)
- pnpm 12.16.1 (plugins/apps/composable-test-suite/package.json)
- pnpm 12.16.1 (plugins/apps/colors-to-tokens-plugin/package.json)
- pnpm 12.16.1 (package.json)
- pnpm 12.16.1 (media-processor/package.json)
- pnpm 12.16.1 (mcp/packages/server/package.json)
- pnpm 12.16.1 (mcp/packages/plugin/package.json)
- pnpm 12.16.1 (mcp/packages/common/package.json)
- pnpm 12.16.1 (mcp/package.json)
- pnpm 12.16.1 (library/package.json)
- pnpm 12.16.1 (frontend/text-editor/package.json)
- pnpm 12.16.1 (frontend/packages/ui/package.json)
- pnpm 12.16.1 (frontend/packages/mousetrap/package.json)
- pnpm 12.16.1 (frontend/packages/draft-js/package.json)
- pnpm 12.16.1 (frontend/package.json)
- pnpm 12.16.1 (exporter/package.json)
- pnpm 12.16.1 (docs/package.json)
- pnpm 12.16.1 (common/package.json)
- pnpm 12.16.1 (backend/package.json)

Signed-off-by: penpot-renovate[bot] <338182062+penpot-renovate[bot]@users.noreply.github.com>
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-10-29 15:26:20 +01:00
Dr. Dominik Jain
c0f0b14540
🎉 Add direct MCP feedback channel via dedicated tool (#12551)
* ♻️ Move devenv-only tools to a separate folder

* 🎉 Add an MCP feedback channel

Add a user-approved feedback tool and an MCP-token-authenticated backend
endpoint that queues plain-text email. Enable the tool through the
configured backend URI in both local and multi-user mode.

Validate subject and feedback limits, enforce per-profile rate limits,
and document configuration. Cover authentication, queueing, tool
availability, and failure handling with backend and MCP tests.

Closes #12490

AI-assisted-by: gpt-6

* ♻️ Move MCP feedback submission into RPC

Use the standard RPC wrappers for feedback and remove the dedicated
HTTP endpoint, route wiring, and custom rate limiter.

Restrict MCP tokens to opted-in routes and commands. Add a shared RPC
call helper to the MCP backend client and adapt the existing tests.

AI-assisted-by: gpt-6

* 🐛 Harden MCP feedback auth, validation and messages

Accept MCP tokens when either the mcp or the access-tokens flag is on, so
instances that enable MCP without personal access tokens can send
feedback. Personal tokens still need access-tokens. Keep the issuer in one
constant, decode tokens without raising to reject unknown issuers, and
name the issuer and type checks.

Reject control characters in the subject, and in the feedback all but
tabs and line breaks, in both the command and the tool, so a NUL answers
400 instead of failing when the mail job is stored. Answer 403 with
profile-blocked or profile-not-active for unusable profiles, record only
who sent feedback in the audit event, and add doc metadata.

Replace on OAuth approval an MCP token issued before MCP tokens had their
own issuer, or one this instance cannot decrypt, since the backend rejects
both.

In the MCP server, mention disabled access tokens on 401, drop the unused
503 case, and say that delivery happens in the background. Document the
flags in the README.

AI-assisted-by: claude-opus-5-5

* 📚 Document the MCP feedback tool and MCP token rules

List submit_feedback among the MCP tools and add an MCP feedback section to
the configuration guide covering PENPOT_MCP_BACKEND_URI,
PENPOT_MCP_FEEDBACK_EMAIL, the flags and the email settings. Add commented
examples of both variables to the compose file.

In the agent memories, record when OAuth approval replaces an MCP token,
how the MCP server reaches the backend, and which flags, routes and
commands accept MCP tokens.

AI-assisted-by: claude-opus-5-5
2026-10-29 10:35:46 +01:00
Alejandro Alonso
4dc684dd9c Merge remote-tracking branch 'origin/staging' into develop 2026-10-28 11:50:56 +01:00
Alejandro Alonso
506923e2e9 Merge remote-tracking branch 'origin/main' into staging 2026-10-28 11:50:36 +01:00
Alejandro Alonso
a8e8a54a2b Merge remote-tracking branch 'origin/staging' into develop 2026-10-28 10:35:31 +01:00
andrés gonzález
bad673eb8d
📚 Fix the migration guide PDF link (#12656)
The Nextcloud link to the enterprise migration guide no longer works.
Point it to the new share.

The box also had a bold "Open the full guide (PDF)" line that looked
clickable but was not, with the real link below it. Keep a single
link and mark it as a PDF at the end of the text.

AI-assisted-by: claude-opus-5-5
2026-10-28 08:32:12 +01:00
Álvaro Tejero Cantero
1342b27f6f
Merge remote-tracking branch 'origin/develop' into iop-vc-preview
Merges develop at f6f9df9a1a. Twelve files conflicted; each keeps
both intents.

files_update.clj: develop's per-stage validation timings wrap the
branch save path. `update-file` keeps the branch's early timer and
passes it to `update-file*`, inside develop's try/catch timing log.
`process-changes-and-validate` times the changes application and
still returns the file, the fixed-up change vector and the media
index. The audit props carry develop's revn and modified-at plus the
branch props. The timing test destructures the new return shape.

v3.clj keeps the branch-file overwrite guard and takes develop's
`configure-import-transaction`. migrations.clj puts develop's 0155
to 0157 before the branch's 0800 to 0805, so the branch's stay the
tail of the vector.

errors.cljs checks the merged and archived branch refusals before
develop's retrying case. left_header.cljs keeps the branch wrapper,
the review badge and the branch bar on develop's markup: the status
dot without icons and the DS library icon on the shared badge.
palette.scss and assets.scss keep the branch clearance terms on
develop's logical properties. The test runners, requires and
deftests are unions.

AI-assisted-by: claude-opus-5-5
Signed-off-by: Álvaro Tejero Cantero <alvorithm@teje.ro>
2026-10-28 06:28:08 +01:00
Eva Marco
68ecfb1234
🐛 Fix default shortcuts that fail on some layouts and browsers (#12506)
Fixes the problems found after #12326 and listed in #12327.

Mousetrap now tries several names for each key press, in order, and
fires the first one with a binding: letters and digits by keyCode when
a modifier is held, punctuation by position (layout map, or a US table
when the browser has none), the typed glyph, and the typed glyph
without the Shift it needed. With AltGr the typed glyph comes before
the position. The shortcut recorder asks Mousetrap for the key it
stores, so a recorded shortcut always fires.

This makes "?" and "+" work on every layout, Shift and Ctrl+Shift with
punctuation work in Firefox and Safari, Option+letter work on macOS,
and AltGr+º hide the UI on Linux with a Spanish layout.

Chrome on Linux returns the map of the first configured layout, not
the active one. Mousetrap now drops the map when an unmodified
punctuation key types something else.

The layout twins are no longer needed and are removed: "shift+'" made
"?" zoom to the selection on Spanish layouts. The Add node shortcut is
removed too: on US layouts its key is the "+" zoom key, and on Firefox
with a Spanish layout it cannot fire. The Firefox and Safari warning
in the shortcuts settings is gone, since those shortcuts now work
there. The user guide and translations follow these changes.

AI-assisted-by: claude-opus-5-5
2026-10-26 11:56:09 +01:00
Andrey Antukh
74add05226 Merge remote-tracking branch 'origin/staging' into develop 2026-10-23 13:40:44 +02:00
Andrey Antukh
c04af5ddc5 Merge remote-tracking branch 'origin/main' into staging 2026-10-23 13:11:52 +02:00
Andrey Antukh
76a83387d9
⬆️ Update JVM, Node, pnpm and devenv dependencies (#12600)
Move the backend JDK to its latest maintenance build within Java 26 and
refresh the dependency versions pinned by hand in the development and
production images.

- Backend: Zulu JDK 26.0.2 to 26.0.2.1. The jlink module list keeps
  jdk.management, so the prometheus process metrics stay exported.
- Node.js 24.22.1 in .nvmrc, the development image tarball and the two
  plugins deploy workflows that pin it.
- pnpm 12.15.0 in the four Dockerfiles, the 34 packageManager fields and
  the eleven lockfiles.
- Development tools: clj-kondo 2026.10.20, Babashka 1.13.226, Pixi
  0.83.0, GitHub CLI 2.103.0, AWS CLI 2.38.5 and uv 0.13.5.
- Infra services: RustFS 1.0.3, Mailpit v1.32.0, and Valkey pinned to
  8.1.10 instead of the floating 8.1 tag.

Fix SERENA_UPDATE_VERSION in the compose file. A value there makes the
start script reinstall that Serena release on every start, overriding
the one baked into the image; it was replacing 1.7.0 with 1.6.1.

The hardened base image updates are left to Renovate.

Closes #12599

AI-assisted-by: deepseek-v4.1-flash

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-10-23 12:36:11 +02:00
Andrey Antukh
ba78ccb8c9
✨ Harden file data offload job with lock, summary and metrics (#12403)
Take the file row with FOR UPDATE SKIP LOCKED when the offload job
starts and skip the run when the row is locked or gone, so the job
never runs while the file is being edited. Every live hot-storage
row of the file moves to cold storage inside one all-or-nothing
transaction, and the handler answers a summary map with the
offloaded rows, bytes and per-type stats.

Add bounded metrics for the job: rows and bytes counters labeled by
row type on successful runs only, and a timing histogram with the
ok, skip and error outcomes. The job definition now requires
metrics, the recorders live in app.jobs.metrics, and the existing
ephemeral job timing histogram pins its buckets.

Cover the job with a new test namespace: the happy path, the locked
row, missing and deleted files, the rows and bytes summary with its
no-op rerun, the whole-file abort on storage failure, the metric
definitions and emissions, and the submit-time params validation.
An end-to-end suite reads, snapshots, writes, exports, imports and
deletes offloaded files; concurrency tests pin the stale-revn skip,
the blocked-edit retry and the reclaimable orphans of a partial
failure. The file-gc scheduler test pins one job per eligible file,
and the scheduler private helper drops its bang.

Document the lock invariant, the deliberate no-pacing decision and
the metric label sets in the backend storage memory and the
configuration guide.

Related to #12398.

AI-assisted-by: muse-spark-1.3-contributor
2026-10-22 15:31:16 +02:00
Elena Torró
05e1981acc
✨ Support running several exporter replicas (#12487)
* ✨ Support running several exporter replicas

* 📚 Document one exporter per machine instead of compose replicas

* 📚 Trim exporter replica docs to the essentials

* ✨ Cancel an exporter's jobs when it shuts down

* 📚 Replace exporter replica docs with a short beta note
2026-10-21 15:30:46 +02:00
Andrey Antukh
fcf9c27635 Merge remote-tracking branch 'origin/staging' into develop 2026-10-21 10:14:55 +02:00
Andrey Antukh
028547e19b Merge remote-tracking branch 'origin/main' into staging 2026-10-21 10:09:59 +02:00
Andrey Antukh
021492a577 🐛 Make migration 0156 compatible with PostgreSQL 15
`SET STORAGE DEFAULT` needs PostgreSQL 16, but the official docker
images pin `postgres:15`, so migration 0156 failed on those
deployments. The migration now uses `SET STORAGE EXTENDED`, the
storage mode of the type of every column it touches (text, text[],
jsonb and bytea), which leaves the catalog in the same state on any
supported version.

The documented PostgreSQL floor goes back to >=15, the reason for
raising it was that syntax.

Verified on the test database: the 62 columns reset and no table
column keeps the legacy EXTERNAL storage.

The backend memory now records that migrations must stay within
PostgreSQL 15 syntax.

AI-assisted-by: minimax-m3.1-flash-free
2026-10-20 20:36:24 +00:00
Andrey Antukh
fffc3ee222 Merge remote-tracking branch 'origin/staging' into develop 2026-10-19 22:18:27 +02:00
Andrey Antukh
fdd66978fd Merge branch 'main' into staging 2026-10-19 20:10:20 +02:00
Andrey Antukh
2d335e9e83 🔧 Reset explicit EXTERNAL storage to PG defaults
Drop the legacy TOAST STORAGE EXTERNAL overrides set when PostgreSQL
ran on ZFS with transparent compression. Migration 0156 restores the
type default (SET STORAGE DEFAULT) on 62 columns across 21 tables;
existing TOAST data keeps its strategy until rewritten.

Raise the documented PostgreSQL floor to >=16, required by the new
SET STORAGE DEFAULT syntax.

AI-assisted-by: muse-spark-1.3-contributor
2026-10-19 15:37:13 +00:00
Andrey Antukh
38a6961ff1
✨ Make keyboard shortcuts layout-independent (#12326)
* Revert "🐛 Fix shortcuts with modifiers on letters and digits (#12292)"

This reverts commit 21ecfb67b70ac2d6f4defb05a543f0fc18d692a2.

* 🐛 Migrate mousetrap to key with sane modifiers

Finish the half-done mousetrap migration from code/keyCode to
key: canonical lowercase tokens on both bind and event sides so
modifiers match again, US-only shift remap and keypress legacy
removed, and AltGr phantom ctrl filtered on Windows.

Record punctuation positionally through getLayoutMap (American
fallback) so Shift+Period stores shift+. on every layout, while
letters and digits stay glyph-based for AZERTY. Drop dead 219
aliases and revert the stray CamelCase escape command.

AI-assisted-by: muse-spark-1.3-contributor

* ♻️ Rewrite mousetrap as ESM class without behavior changes

Turn the 2012 constructor-plus-prototype shape into a class
with underscore-private methods, const tables and arrow
listeners. Drop dead _belongsTo, fold one-line prevent/stop
helpers into _fireCallback, and let handleKey absorb the old
_handleKey indirection. Public API and matching logic stay
identical; verified by existing tests plus a runtime smoke.

AI-assisted-by: muse-spark-1.3-contributor

* 🎉 Add node:test suite for mousetrap shortcuts

Cover canonical key normalization, modifiers with AltGr,
bind arrays plus aliases keyup reset overwrite, sequences
with fake timers, and the full stopCallback matrix, all
through isolated instances and synthetic events. Hook the
zero-dependency suite into frontend/scripts/test for CI.

AI-assisted-by: muse-spark-1.3-contributor

* 🐛 Record shortcuts by glyph instead of position

Drop the getLayoutMap positional layer and the
American fallback: punctuation now records event.key
lowercased, the same token Mousetrap dispatches, so
Shift combos match with and without a layout map.
Keeps the Numpad numN branch both sides share.
Updates the pinned positional tests and adds the
Spanish Shift-plus regression.

AI-assisted-by: muse-spark-1.3-contributor

* 🐛 Resolve shifted digits to the digit itself

Shift+DigitN now resolves to the digit on every layout, so
shift+0 fires on QWERTY ()) as well as AZERTY (0), like the
old keyCode behavior. Applies in the recorder and Mousetrap;
unshifted digits and numpad are untouched. Also stages the
layout-map suite left untracked.

AI-assisted-by: muse-spark-1.3-contributor

* 🐛 Cover punctuation defaults with layout twins

Some defaults only fired where their glyph is unshifted (+ dead
on US layouts, shift++ dead outside ES/DE, \ dead where it
needs AltGr). Bind the twin token per layout family and freeze
the display with :show-command. No tooltip or translation
changes.

AI-assisted-by: muse-spark-1.3-contributor

* ✨ Warn when the keyboard layout API is missing

Shows a warning on the shortcuts settings page in browsers
without navigator.keyboard.getLayoutMap, where Shift with
punctuation may not fire. Uses a synchronous probe, English
and Spanish strings, and documents the layout limitations in
the user guide.

AI-assisted-by: muse-spark-1.3-contributor

* 🐛 Fix hide-ui twins and qualify layout docs

The ctrl+alt+\ twin could never fire (the AltGr filter drops
Ctrl), so it goes away; alt+º covers Chrome on Spanish
layouts where AltGr+º resolves to º. The user guide now
states which claims need the layout map and which hold
everywhere.

AI-assisted-by: muse-spark-1.3-contributor

---------

Signed-off-by: Eva Marco <eva.marco@kaleidos.net>
Co-authored-by: Eva Marco <eva.marco@kaleidos.net>
2026-10-19 16:08:47 +02:00
David Barragán Merino
d6e1cb23e0
🐳 Serve Penpot and the Admin Console from a subpath (#12358)
* 🐳 Serve the frontend under the path of PENPOT_PUBLIC_URI

Requests below the path are rewritten to the root, so a reverse proxy can
forward them unchanged. The Admin Console keeps receiving the original path.

AI-assisted-by: Claude
Signed-off-by: David Barragán Merino <david.barragan@kaleidos.net>

* 🐳 Strip the public path before proxying to the Admin Console

The Admin Console is served at the root of its own server and applies the
public path at runtime, so it needs a matching Admin Console image.

AI-assisted-by: Claude
Signed-off-by: David Barragán Merino <david.barragan@kaleidos.net>

* 📚 Document subpath deployments in docker-compose.yaml

AI-assisted-by: Claude
Signed-off-by: David Barragán Merino <david.barragan@kaleidos.net>

* 📚 Describe subpath deployments without proxy rewrites

The frontend now serves the subpath itself, so the reverse proxy must
forward it unchanged.

AI-assisted-by: Claude
Signed-off-by: David Barragán Merino <david.barragan@kaleidos.net>

---------

Signed-off-by: David Barragán Merino <david.barragan@kaleidos.net>
2026-10-19 15:49:41 +02:00
Andrey Antukh
8c5113b815 Merge remote-tracking branch 'origin/staging' into develop 2026-10-17 14:44:44 +02:00
Andrey Antukh
d1aa36b814 ⬆️ Update pnpm to 12.14.0 and Node to v24.22.0
Bump the pnpm pin to 12.14.0 in the devenv and the production images
and stamp the same version into every package.json, realigning the
drift between the devenv (12.9.1) and the rest (12.6.0).

Bump Node to v24.22.0, the newest patch of the Krypton LTS line, in
.nvmrc, the devenv and image Dockerfiles and the plugins-deploy
workflows.

The pnpm arch checksums are those of the GitHub release tarballs, not
of the npm package. Lockfile changes are metadata only.

AI-assisted-by: deepseek-v4.1-flash
2026-10-17 14:00:43 +02:00
Álvaro Tejero Cantero
6ab7b3ebd6
Merge branch 'develop' into iop-vc-preview
Both conflicts are tail appends onto regions develop rewrote. In
migrations.clj keep both appended blocks, develop's two entries
first so the branch's four stay the tail of the vector. In
climit.edn take develop's rewritten entries and re-append the
branch's provisional block, moving the map's closing brace to the
last line.

AI-assisted-by: glm-5.3-flash
Signed-off-by: Álvaro Tejero Cantero <alvorithm@teje.ro>
2026-10-14 16:34:48 +02:00
Alonso Torres
286a6d5c9a
✨ Add new dashboard methods to the API (#12169)
* ✨ Add new dashboard methods to the API

* 🐛 Fix some issues with the new methods

* 🐛 Fix problem with mcp test
2026-10-14 15:24:53 +02:00
Andrey Antukh
d0f82b9979 Merge remote-tracking branch 'origin/staging' into develop 2026-10-14 14:37:58 +02:00
andrés gonzález
f40686d205
📚 Update user guide for 2.19 features (#12201)
Document stroke per side and its tokens, path editor changes, image
bounds resize, configurable shortcuts, tokens from a shared library
as tokens source, canvas background color tokens, Penpot board
presets, the 3x export scale, the text editing context menu, the
organization and team selector, the hide resolved comments option,
account security and the Check for updates option.

Fix outdated notes about WebGL exports, background blur exports,
library token import and path editor shortcuts. Add the images for
these sections and remove the ones no longer used.

AI-assisted-by: claude-opus-5-5
2026-10-14 12:51:51 +02:00
Andrey Antukh
0c0336da42 Merge remote-tracking branch 'origin/staging' into develop 2026-10-13 21:04:58 +02:00
Andrey Antukh
eafa483a18 Merge remote-tracking branch 'origin/main' into staging 2026-10-13 14:56:45 +02:00
Andrey Antukh
dd6cc835ef 🎉 Add graceful instance drain via /readyz
Add a per-process availability flag (app.health) that /readyz
reports as 503 OFFLINE while offline, so the load balancer
drains the instance and in-flight requests finish untouched.

Operator surface is app.srepl.main/set-offline and
app.srepl.main/set-online; a restart comes back online.
Covered by backend-tests.health-test; HA docs updated.

AI-assisted-by: muse-spark-1.3-contributor
2026-10-13 14:33:32 +02:00
Francis Santiago
6839b16735 📚 Document subpath configuration and migration 2026-10-09 12:26:57 +02:00
Alejandro Alonso
4eec950b96 Merge remote-tracking branch 'origin/staging' into develop 2026-10-09 10:00:13 +02:00
Alejandro Alonso
dd76faf17b Merge remote-tracking branch 'origin/main' into staging 2026-10-09 10:00:00 +02:00
Andrey Antukh
473a59b134 Merge remote-tracking branch 'origin/staging' into develop 2026-10-09 09:01:12 +02:00
Andrey Antukh
c17eb2a804
📚 Document disable-email-verification team auto-add behavior (#11425)
The configuration docs claimed it is not possible to add someone to a
team without them accepting an invitation email, but the backend
auto-adds existing profiles to the team when the email verification
is disabled (create-invitation in app.rpc.commands.teams-invitations).

Replace the incorrect sentence with an accurate exception note, add
the missing disable-email-verification entry to the "Other flags"
reference, document the CLI-created profile auto-add behavior in the
docker getting-started guide, and describe the shortcut in the
developer authentication docs.

Closes #11424

Reported in #11376

AI-assisted-by: glm-5.3-flash
2026-10-08 12:44:39 +02:00
andrés gonzález
3779dd99ae
💄 Remove the duplicated MCP Server link from Key Features (#12193)
Product already links to the same page.

Refs #12132

AI-assisted-by: claude-opus-5-5
2026-10-08 12:00:54 +02:00
andrés gonzález
df0402b626
💄 Align the Help Center footer with penpot.app (#12179)
The footer had a hardcoded 2025 copyright and links that no longer match
penpot.app. The year is now set at build time. Sections, links and
social icons follow the current penpot.app footer, and the grid wraps
into two rows to fit the new sections.

Closes #12132

AI-assisted-by: claude-opus-5-5
2026-10-08 10:59:36 +02:00
alonso.torres
dfff188409 ✨ Ask users to allow global plugins on install
A plugin with "scope": "global" keeps running across the dashboard
and files and can find and open the user's projects and files. Any
manifest could ask for this without the user being told.

Add the allow:global permission. The plugin registry adds it to
every manifest with global scope, so the install dialog lists it,
and a plugin that becomes global in a later version shows the
permissions update dialog again. The permission is valid in the
shared schema, which the backend checks when saving, and in the
runtime manifest schema. The built-in MCP plugin declares it too.

Document the scope property and the new permission for plugin
developers.
2026-10-07 14:58:32 +02:00
alonso.torres
c4d2ca9cd1 ✨ Move the dashboard MCP menu to the page headers
Show the MCP menu next to the layout toggle in the header of the
projects, files and deleted pages, instead of in the sidebar. It
uses the secondary button style there and a visible dot colour
while disconnected.

Clicking the MCP button now toggles the menu instead of only
opening it. Dashboard events report "dashboard:header" as their
origin.
2026-10-07 14:58:32 +02:00
Dominik Jain
54cce66c13 ✨ Share the MCP connection menu with the dashboard
Connection status:
- Replace the dashboard's action-only link with an explicit connected
  label and indicator, using the theme's existing accent colour.
- Reflect the actual connection state independently of connection intent.

Shared controls:
- Extract the toolbar's MCP menu and styles into a shared component used
  by both the dashboard and workspace.
- Provide connection status, session ID, copy, connect and disconnect
  actions in both locations, preserving hover and keyboard behaviour.
- Keep dashboard and toolbar event origins distinct and update the
  dashboard connection instructions.

Validation:
- Confirm dashboard disconnect/reconnect, menu opening, keyboard
  navigation and Escape dismissal in the running app.
- Pass live compilation, targeted ClojureScript and SCSS lint,
  formatting checks and git diff checks.

AI-assisted-by: gpt-6
Signed-off-by: Dominik Jain <dominik.jain@oraios-ai.de>
2026-10-07 14:58:32 +02:00
Dominik Jain
be17fabc6a 🎉 Introduce global plugins and move MCP to application scope
Global plugin lifecycle:
- Add optional manifest scope "global" for plugins that remain active
  across dashboard and workspace navigation within one browser tab.
  Existing plugins retain workspace scope by default.
- Preserve global sandboxes when a workspace ends or another plugin
  loads, including when that other plugin fails to initialize.
- Avoid duplicate instances of an already-running global plugin.
- Close global plugins on explicit closure or logout, with idempotent
  cleanup of listeners, timers and UI resources. Global scope does not
  imply automatic startup or persistence across a browser reload.

Plugin API and navigation:
- Keep a permanently live penpot facade whose getters follow the current
  workspace, while user, theme and UI facilities remain available on
  the dashboard.
- Expose penpotMgmt to global plugins with workspace metadata,
  none/loading/ready status and workspacechange subscriptions.
- Add awaitable openFile(fileId, {teamId}) navigation in the current tab,
  defaulting to the current team and resolving only once the requested
  file and its active page are ready.
- Reject invalid identifiers, failed or superseded navigation and waits
  exceeding 30 seconds; release navigation watchers on completion.
- Guard workspace-bound operations while no workspace is ready and
  return null from root, currentFile and currentPage in that state.
- Require content:read for the initial management API. Callers must
  reacquire file, page and shape references after changing files.

MCP lifecycle and connection controls:
- Make MCP a global plugin and initialize its integrated controller per
  authenticated application session instead of per workspace.
- Load the enabled integration with a valid token on the dashboard as
  well as in a file, retaining its existing hidden-iframe implementation.
- Keep enabling and connecting separate: an enabled plugin starts idle,
  and each tab connects explicitly through dashboard or workspace
  controls.
- Preserve the iframe, WebSocket, heartbeat and reconnect machinery
  during navigation; disconnect on request and close on disable/logout.

MCP sessions and execution:
- Derive the short MCP session ID solely from currentUser.sessionId,
  excluding the file ID. Retain the SHA-256-based, 50-bit Base32 encoding
  to produce a stable, copyable 10-character identifier.
- Allow sessions without an open file and update workspace metadata over
  the existing connection without replacing its routing identity.
- Refresh context after the connection handshake so initialization does
  not leave stale file metadata.
- Expose penpotMgmt to execute_code, preserve execution storage across
  navigation and skip layout waits when no workspace is ready.
- Update API types, tool guidance, documentation and the changelog.

Validation:
- Cover authenticated startup, workspace survival, logout cleanup,
  readiness, navigation failure, duplicate loads and session routing.
- Verify that short IDs remain stable across files and reconnects and
  that disconnect cancels pending asynchronous ID initialization.
- Pass 16 focused frontend tests, 73 runtime tests, 30 MCP plugin tests,
  builds, TypeScript checks and frontend/runtime lint.
- Pass all 73 MCP server tests with --test-force-exit; the normal runner
  still stays alive after assertions finish.
- Verify a live dashboard-to-file-to-dashboard round trip without a
  document or iframe reload, preserving facade identity and storage.

AI-assisted-by: gpt-6
2026-10-07 14:58:32 +02:00
Andrey Antukh
806a9ee98e
⬆️ Update dependencies (#12150) 2026-10-07 10:41:29 +02:00
penpot-renovate[bot]
a61a4fceb1 ⬆️ Update dependency pnpm to v12.8.1
- pnpm 12.8.1 (docker/images/Dockerfile.media-processor)
- pnpm 12.8.1 (docker/images/Dockerfile.mcp)
- pnpm 12.8.1 (docker/images/Dockerfile.exporter)
- pnpm 12.8.1 (render-wasm/package.json)
- pnpm 12.8.1 (plugins/package.json)
- pnpm 12.8.1 (plugins/libs/plugins-styles/package.json)
- pnpm 12.8.1 (plugins/libs/plugins-runtime/package.json)
- pnpm 12.8.1 (plugins/libs/plugin-types/package.json)
- pnpm 12.8.1 (plugins/apps/table-plugin/package.json)
- pnpm 12.8.1 (plugins/apps/rename-layers-plugin/package.json)
- pnpm 12.8.1 (plugins/apps/poc-tokens-plugin/package.json)
- pnpm 12.8.1 (plugins/apps/poc-state-plugin/package.json)
- pnpm 12.8.1 (plugins/apps/plugin-api-test-suite/package.json)
- pnpm 12.8.1 (plugins/apps/lorem-ipsum-plugin/package.json)
- pnpm 12.8.1 (plugins/apps/icons-plugin/package.json)
- pnpm 12.8.1 (plugins/apps/example-styles/package.json)
- pnpm 12.8.1 (plugins/apps/e2e/package.json)
- pnpm 12.8.1 (plugins/apps/create-palette-plugin/package.json)
- pnpm 12.8.1 (plugins/apps/contrast-plugin/package.json)
- pnpm 12.8.1 (plugins/apps/composable-test-suite/package.json)
- pnpm 12.8.1 (plugins/apps/colors-to-tokens-plugin/package.json)
- pnpm 12.8.1 (package.json)
- pnpm 12.8.1 (media-processor/package.json)
- pnpm 12.8.1 (mcp/packages/server/package.json)
- pnpm 12.8.1 (mcp/packages/plugin/package.json)
- pnpm 12.8.1 (mcp/packages/common/package.json)
- pnpm 12.8.1 (mcp/package.json)
- pnpm 12.8.1 (library/package.json)
- pnpm 12.8.1 (frontend/text-editor/package.json)
- pnpm 12.8.1 (frontend/packages/ui/package.json)
- pnpm 12.8.1 (frontend/packages/tokenscript/package.json)
- pnpm 12.8.1 (frontend/packages/mousetrap/package.json)
- pnpm 12.8.1 (frontend/packages/draft-js/package.json)
- pnpm 12.8.1 (frontend/package.json)
- pnpm 12.8.1 (exporter/package.json)
- pnpm 12.8.1 (docs/package.json)
- pnpm 12.8.1 (common/package.json)
- pnpm 12.8.1 (backend/package.json)

Signed-off-by: penpot-renovate[bot] <338182062+penpot-renovate[bot]@users.noreply.github.com>
2026-10-06 15:12:15 +02:00
Álvaro Tejero Cantero
f6dc4bed2d
📚 Replace the branching guide page with a placeholder
The page described a feature that changes daily behind the `:branching`
product flag, and every change cost two descriptions: the page and the
design notes the review reads. The page now names the featureset it
will cover, branches, pull requests, reviews and merges, and promises
its description at the point the feature is proposed for merging into
develop, written against the code that the proposal ships.

The name moves with it, because the page covers version control for
files and not one of its mechanisms.

AI-assisted-by: mimo-v2.6-pro
Signed-off-by: Álvaro Tejero Cantero <alvorithm@teje.ro>
2026-10-06 10:36:55 +02:00
Álvaro Tejero Cantero
0e51e5b3b8
🐛 Keep the conflict refusal's error page and fix the guide
The backend answers a :conflict refusal (:file-modified, :file-locked)
with HTTP 409 since the previous commit. On the frontend that type had
no ptk/handle-error method, so the version-restore flow would have
fallen to the generic toast instead of the error page the old 500
reached. errors.cljs now maps :conflict to the same exceptional-state
handler.

The technical guide's audit paragraph said rename, archive and delete
report nothing; they report a duration and an outcome. The merge step
list now records the re-validation after the repair and its refusal,
and the update section names the same refusal.

AI-assisted-by: mimo-v2.6-pro, claude-opus-5-5
2026-10-06 10:36:55 +02:00
Álvaro Tejero Cantero
16b7e64fbb
📚 Make the technical guide describe the op-log engine it ships with
The guide still opened by calling a branch an isolated copy of a file,
called the merge base a snapshot frozen at creation and the op log
append-only, and gave the creation transaction a reason for deferring
constraints that does not hold. It now says a branch copies no data,
that an update from main repositions the base and squashes or empties
the log, and that every row referencing the new file is inserted after
it.

The same pass corrects five more statements: base_branch_revn holds the
branch file's own revision; a branch kept after a merge keeps its pin;
op log rows survive a logical deletion and go with the cascade when the
file row is hard-deleted; a resolution may be a per-attribute map; and
the listing now runs through `audited`, while a refusal raised as an
error writes no audit event. The RPC table gains get-branching-limits,
the test lists name all five test namespaces, and the UI and event
lists name the limits, merge, and info dialogs.

AI-assisted-by: claude-opus-5-5
2026-10-06 10:36:55 +02:00
Álvaro Tejero Cantero
aad3719721
📚 Name the audited set, not every mutation on a branch
The sentence opened with every mutation and then listed three that are the
exception, which a reader has to reconcile. It now opens with the set that
does attach the three keys: the mutations through `audited` and a save routed
to a branch's op log.
2026-10-06 10:36:55 +02:00