Compare commits

...

1 Commits

Author SHA1 Message Date
alonso.torres
f39dc3675f WIP 2026-01-14 16:36:08 +01:00
12 changed files with 82 additions and 20 deletions

View File

@@ -54,7 +54,7 @@
"devDependencies": {
"@penpot/draft-js": "portal:./packages/draft-js",
"@penpot/mousetrap": "portal:./packages/mousetrap",
"@penpot/plugins-runtime": "1.3.2",
"@penpot/plugins-runtime": "portal:../plugins/dist/plugins-runtime",
"@penpot/svgo": "penpot/svgo#v3.2",
"@penpot/text-editor": "portal:./text-editor",
"@playwright/test": "1.57.0",

View File

@@ -51,8 +51,23 @@
(update [_ state]
(update-in state [:workspace-local :open-plugins] (fnil disj #{}) id))))
(defn start-plugin!
[{:keys [plugin-id name description host code icon permissions allow-background]} ^js extensions]
(.ɵloadPlugin
^js ug/global
#js {:pluginId plugin-id
:name name
:description description
:host host
:code code
:icon icon
:allowBackground (boolean allow-background)
:permissions (apply array permissions)}
nil
extensions))
(defn- load-plugin!
[{:keys [plugin-id name description host code icon permissions]}]
[{:keys [plugin-id name description host code icon permissions] :as params}]
(try
(st/emit! (save-current-plugin plugin-id))
(.ɵloadPlugin

View File

@@ -210,7 +210,34 @@
ptk/WatchEvent
(watch [_ _ _]
(rx/of (dp/check-open-plugin)
(fdf/fix-deleted-fonts-for-local-library file-id)))))
(fdf/fix-deleted-fonts-for-local-library file-id)))
ptk/EffectEvent
(effect [_ _ _]
(dp/start-plugin!
{:url "http://localhost:4400/manifest.json"
:code "plugin.js"
:host "http://localhost:4400"
:name "Penpot MCP Plugin"
:plugin-id "96dfa740-005d-8020-8007-55ede24a2bae"
:description "This plugin enables interaction with the Penpot MCP server"
:allow-background true
:permissions
#{"library:read"
"library:write"
"comment:read"
"content:write"
"comment:write"
"content:read"}}
#js
{:mcp
#js
{:getToken (fn [] "xxxxx")
:getServerUrl (fn [] "ws://localhost:4402")
:setMcpStatus (fn [status]
(when-let [node (.getElementById ^js js/document "mcp-status")]
(set! (.-textContent node) status)))}}))))
(defn- bundle-fetched
[{:keys [file file-id thumbnails] :as bundle}]

View File

@@ -230,7 +230,9 @@
:aria-pressed (contains? layout :debug-panel)
:aria-label "Debugging tool"
:tooltip-placement "bottom"
:on-click toggle-debug-panel}]])]]
:on-click toggle-debug-panel}]])
[:span {:id "mcp-status"} "disconnected"]]]
[:button {:title (tr "workspace.toolbar.toggle-toolbar")
:aria-label (tr "workspace.toolbar.toggle-toolbar")

View File

@@ -1198,16 +1198,15 @@ __metadata:
languageName: node
linkType: hard
"@penpot/plugins-runtime@npm:1.3.2":
version: 1.3.2
resolution: "@penpot/plugins-runtime@npm:1.3.2"
"@penpot/plugins-runtime@portal:../plugins/dist/plugins-runtime::locator=frontend%40workspace%3A.":
version: 0.0.0-use.local
resolution: "@penpot/plugins-runtime@portal:../plugins/dist/plugins-runtime::locator=frontend%40workspace%3A."
dependencies:
"@penpot/plugin-types": "npm:^1.3.2"
ses: "npm:^1.1.0"
zod: "npm:^3.22.4"
checksum: 10c0/b6d2cb3a57bcbe58232db52b8224d1817495e96b34997bfa72421629b5f34a8c9cc71357c315dcab9d52ea036ed632a5efe0ac50f52e730901c02d498dfa1313
languageName: node
linkType: hard
linkType: soft
"@penpot/svgo@penpot/svgo#v3.2":
version: 4.0.0
@@ -4176,7 +4175,7 @@ __metadata:
dependencies:
"@penpot/draft-js": "portal:./packages/draft-js"
"@penpot/mousetrap": "portal:./packages/mousetrap"
"@penpot/plugins-runtime": "npm:1.3.2"
"@penpot/plugins-runtime": "portal:../plugins/dist/plugins-runtime"
"@penpot/svgo": "penpot/svgo#v3.2"
"@penpot/text-editor": "portal:./text-editor"
"@playwright/test": "npm:1.57.0"

View File

@@ -1,14 +1,14 @@
{
"name": "@penpot/plugins-runtime",
"version": "0.12.0",
"version": "1.3.2",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@penpot/plugins-runtime",
"version": "0.12.0",
"version": "1.3.2",
"dependencies": {
"@penpot/plugin-types": "^0.12.0",
"@penpot/plugin-types": "^1.3.2",
"ses": "^1.1.0",
"zod": "^3.22.4"
}
@@ -19,9 +19,9 @@
"integrity": "sha512-Uqy94PwLTco90Yfign43muvDtjsYTbL6Ck4W5sSWQUqJiFOL+YP8kiBOoGyQynDsGTY0MCQvMxEPfphaJKnzlQ=="
},
"node_modules/@penpot/plugin-types": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/@penpot/plugin-types/-/plugin-types-0.12.0.tgz",
"integrity": "sha512-rtSJ8memBAWxRBEx+S47NFDJN5VIvY0J7QzwTBer45Ls3BjLCaWXCnfFEcRn4SzY+Th01tmop0pwdvN5YDxkBw=="
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@penpot/plugin-types/-/plugin-types-1.3.2.tgz",
"integrity": "sha512-f0kmmZaFNs9sGtSmqmSJQYCs5Qt+KYgTD8RneUjL+Dv+zfNQnd5e4L+iHSYFJ4HWvcDvTiK7F/gya7PwMTu7WA=="
},
"node_modules/ses": {
"version": "1.8.0",

View File

@@ -24,6 +24,10 @@ export function createModal(
inlineStart: window.innerWidth - width - 290,
};
if ((options as any)?.hidden) {
modal.style.setProperty('display', 'none');
}
modal.style.setProperty(
'--modal-block-start',
`${initialPosition.blockStart}px`,

View File

@@ -7,6 +7,7 @@ export async function createPlugin(
context: Context,
manifest: Manifest,
onCloseCallback: () => void,
apiExtensions?: Object,
) {
const evaluateSandbox = async () => {
try {
@@ -30,7 +31,7 @@ export async function createPlugin(
},
);
const sandbox = createSandbox(plugin);
const sandbox = createSandbox(plugin, apiExtensions);
evaluateSandbox();

View File

@@ -2,8 +2,10 @@ import type { Penpot } from '@penpot/plugin-types';
import type { createPluginManager } from './plugin-manager';
import { createApi } from './api';
import { ses } from './ses.js';
export function createSandbox(
plugin: Awaited<ReturnType<typeof createPluginManager>>,
apiExtensions?: Object,
) {
ses.hardenIntrinsics();
@@ -51,7 +53,7 @@ export function createSandbox(
});
};
const publicPluginApi = {
let publicPluginApi = {
penpot: proxyApi,
fetch: ses.harden(safeFetch),
setTimeout: ses.harden(
@@ -123,6 +125,11 @@ export function createSandbox(
structuredClone: ses.harden(window.structuredClone),
};
if (apiExtensions) {
publicPluginApi = Object.assign(publicPluginApi, apiExtensions);
}
const compartment = ses.createCompartment(publicPluginApi);
return {

View File

@@ -19,7 +19,9 @@ export const getPlugins = () => plugins;
const closeAllPlugins = () => {
plugins.forEach((pluginApi) => {
pluginApi.plugin.close();
if (!(pluginApi.manifest as any).allowBackground) {
pluginApi.plugin.close();
}
});
plugins = [];
@@ -38,6 +40,7 @@ window.addEventListener('message', (event) => {
export const loadPlugin = async function (
manifest: Manifest,
closeCallback?: () => void,
apiExtensions?: Object,
) {
try {
const context = contextBuilder && contextBuilder(manifest.pluginId);
@@ -55,6 +58,7 @@ export const loadPlugin = async function (
plugins = plugins.filter((api) => api !== plugin);
closeCallback && closeCallback();
},
apiExtensions,
);
plugins.push(plugin);
@@ -67,8 +71,9 @@ export const loadPlugin = async function (
export const ɵloadPlugin = async function (
manifest: Manifest,
closeCallback?: () => void,
apiExtensions?: Object
) {
loadPlugin(manifest, closeCallback);
loadPlugin(manifest, closeCallback, apiExtensions);
};
export const ɵloadPluginByUrl = async function (manifestUrl: string) {

View File

@@ -3,4 +3,5 @@ import { z } from 'zod';
export const openUISchema = z.object({
width: z.number().positive(),
height: z.number().positive(),
hidden: z.boolean().optional(),
});

View File

@@ -40,6 +40,7 @@
"@commitlint/cli": "^18.6.0",
"@commitlint/config-conventional": "^18.6.0",
"@eslint/eslintrc": "^2.1.1",
"@eslint/js": "8.57.0",
"@nx/angular": "20.3.2",
"@nx/esbuild": "20.3.2",
"@nx/eslint": "20.3.2",