* 🐛 Fix too much recursion when clicking shape in comments mode
Remove `deselect-all` from `handle-interrupt` in comments mode. The
`select-shape` event emits `:interrupt` which the comments stream
watcher routes to `handle-interrupt`. In comments mode, calling
`deselect-all` cleared the selection and emitted a competing
`rt/nav`, creating a synchronous recursion cycle in the potok store
that overflowed the JS call stack.
Fixes#10620
AI-assisted-by: opencode
* 🐛 Add unit tests for comments handle-interrupt
Make `handle-interrupt` public (defn- → defn) and add 4 tests covering
each branch: draft thread, open thread, comments mode, and noop.
AI-assisted-by: opencode
Guard remaining text pipeline locations that accessed :selrect directly
against nil/zero-dimension selrects by using safe-size-rect, which
provides a 4-level fallback chain (selrect -> points -> shape fields ->
empty 0.01x0.01 rect).
Fixes:
- fix-position in viewport_texts_html.cljs: replaced dm/get-prop
:selrect with ctm/safe-size-rect for both old and new shape
- assoc-position-data in modifiers.cljs: replaced (:selrect ...)
with ctm/safe-size-rect for delta computation
- change-orientation-modifiers in modifiers.cljc: replaced raw
:selrect access with safe-size-rect for scale and origin computation
Closes#10617
AI-assisted-by: mimo-v2.5-pro
* ✨ Adds static dispatch safe stubs in tests
* 🐛 Fix shapesColors metadata key to match ColorShapeInfo
* 🐛 Fix CommentThread.remove rejecting the owner's own threads
* 🐛 Fix page.removeCommentThread throwing on a spurious Promise
* ✨ Implement ShapeBase.swapComponent in the plugin API
* ✨ Expose File.revn in the plugin API
* 🐛 Fix FileVersion.createdAt calling Luxon method on a js/Date
* 🐛 Fix plugin font/typography application to text and ranges
* 🐛 Default plugin overlay interaction position for non-manual types
* 🐛 Fix plugin interaction setters passing an id-only shape
* 🐛 Fix grid addColumnAtIndex rejecting valid track types
* 🐛 Expose libraryId on library color/typography/component proxies
* ✨ Implement LibraryTypography.setFont in the plugin API
* 🐛 Fix typography.applyToTextRange reading unexposed range bounds
* 🐛 Fix utils.geometry.center argument mismatch
* 🐛 Fix localStorage.removeItem calling getItem
* 🐛 Fix shape backgroundBlur proxy key casing
* 🐛 Report boolean shape type as 'boolean' in the plugin API
* 🐛 Return the resulting paths from plugin flatten
* 🐛 Make plugin z-order methods act on the target shape
* 🐛 Make is-variant-container? return a boolean
* ✨ Implement Group.isMask in the plugin API
* 🐛 Return a shape proxy from TextRange.shape
* 🐛 Return the duplicated set from TokenSet.duplicate
* 🐛 Fix theme addSet/removeSet reading set name with a keyword
* 🐛 Accept string fontFamilies token value in the plugin API
* 🐛 Fix combineAsVariants ignoring the passed component ids
* 🐛 Fix board removeRulerGuide ignoring its argument
* 🐛 Fix board guides setter schema and parser
* 🐛 Avoid 0-byte allocation when syncing empty grid tracks
* 🐛 Validate grid track indices in the plugin API
* 🐛 Return null for empty input in group() and centerShapes()
* 🐛 Return TokenTypographyValue[] from a typography token's resolvedValue
* 🐛 Return TokenShadowValue[] from a shadow token's resolvedValue
* 🐛 Return string[] from a fontFamilies token's resolvedValue
* 🐛 Clear mutually-exclusive reps when setting LibraryColor gradient/image
* 🐛 Add readonly tags to types, deprecate Image type
* 📚 Update plugins changelog
* ♻️ Add mcp integration state management refactor (#10226)
* ♻️ Add mcp integration state management refactor
* 🐛 Fix access tokens do not appear
* ♻️ Refactor some names
* ♻️ Refactor token deletion
---------
Co-authored-by: Luis de Dios <luis.dedios@kaleidos.net>
* 🐛 Fix stale MCP token data after create/regenerate (#10280)
Fix the root cause in profile.cljs: remove the optimistic conj from
access-token-created and instead chain a fetch-access-tokens after the
create-access-token API call succeeds. This ensures all callers get a
fresh, server-consistent token list automatically.
Suggested-by: niwinz
Signed-off-by: kapilvus <kapil69265@gmail.com>
Co-authored-by: kapilvus <kapilvus@gmail.com>
* ✨ Remove non-recoverable mcp key warning from regenerated modal (#10298)
---------
Signed-off-by: kapilvus <kapil69265@gmail.com>
Co-authored-by: Luis de Dios <luis.dedios@kaleidos.net>
Co-authored-by: kapil971390 <kapil69265@gmail.com>
Co-authored-by: kapilvus <kapilvus@gmail.com>
Fix the root cause in profile.cljs: remove the optimistic conj from
access-token-created and instead chain a fetch-access-tokens after the
create-access-token API call succeeds. This ensures all callers get a
fresh, server-consistent token list automatically.
Suggested-by: niwinz
Signed-off-by: kapilvus <kapil69265@gmail.com>
Co-authored-by: kapilvus <kapilvus@gmail.com>
* 🎉 Add background blur
* 🎉 Add test
* 🎉 Add background blur info to plugins API
* 🎉 Suport in wasm for both layer and background blur
* 🐛 Fix failing test
* ♻️ Fix comments
---------
Co-authored-by: alonso.torres <alonso.torres@kaleidos.net>
* ✨ Batch multiple thumbnail deletions into a single RPC call
Replace the old per-object immediate thumbnail deletion with a
debounced batched approach. The frontend queues object-ids in state
and waits 200ms before sending a single RPC request with up to 200
object-ids. The backend deletes all matching thumbnails in one SQL
statement with a single RETURNING clause, then touches the affected
media objects.
This reduces RPC overhead when rapidly clearing thumbnails (e.g.
navigating pages) and makes deletions more efficient.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* 📎 Fix missing issues
---------
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* ✨ Add MCP connection badge to the workspace toolbar
* ✨ Add MCP status button with single-tab connection control
* ♻️ Extract component for MCP indicator in the toolbar
* ♻️ Some improvements
---------
Co-authored-by: Luis de Dios <luis.dedios@kaleidos.net>
* 🐛 Fix race condition between MCP init and plugin runtime
Add promise-based synchronization to ensure MCP initialization waits
for plugin runtime to be ready before calling global.ɵloadPlugin.
- Add runtime-ready-promise in app.plugins that resolves when
init-plugins-runtime completes
- Add wait-for-runtime function for other modules to await readiness
- MCP init now waits for runtime via rx/from before starting plugin
- Add defensive guards in start-plugin!, load-plugin!, close-plugin!
to check if plugin APIs exist before calling
- Rename init-plugins-runtime! to init-plugins-runtime
Fixes: global.ɵloadPlugin is not a function error when MCP plugin
starts before async plugin runtime initialization completes.
* 📎 Add 'create-pr' opencode skill
The `update-text-range` event's `watch` method was returning a bare
potok event object (`dwwt/resize-wasm-text-debounce id`) directly
inside `rx/concat`, instead of wrapping it in `rx/of`. This caused
RxJS to throw "You provided an invalid object where a stream was
expected" when a plugin set text fills via the Plugin API.
The fix wraps the event in `rx/of` so it becomes a valid Observable,
matching the pattern used elsewhere in the codebase (e.g.,
`clipboard.cljs` lines 1050/1082 and `texts.cljs` line 1232).
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Add guard in parse-composite-typography-value to check if the
converted value is a map before attempting map operations. When
a typography token has an array value like ["Roboto"], return
an invalid-token-value-typography error instead of crashing with
IMap.-dissoc protocol error.
Add regression test to verify the fix.
Guard against nil id and missing page in delete-page to prevent
broken changes from being sent to the server. This can happen due
to a race condition where the page is no longer present in the
pages-index. Also add assertion in changes-builder/del-page as
defense-in-depth.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Prevent navigate-to-comment-id from making an RPC call with nil
file-id when current-file-id has been cleared by finalize-workspace
during rapid workspace navigation. The deferred stream observer
(rx/observe-on :async) could fire after the workspace state was
already cleaned up, causing {:file-id nil} to become {} after
query-string nil-filtering in map->query-string.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* Revert "🐛 Detect duplicated token names in the whole library (#9034)"
This reverts commit 61cd7573553b1c5e9fc2d7300cf9b2c36b4dcbb6.
* 🔧 Preserve some enhancements and fixes that are still valid
* 🔧 Fix broken integration tests