mirror of
https://github.com/penpot/penpot.git
synced 2026-02-12 14:42:56 +00:00
WIP
This commit is contained in:
@@ -82,6 +82,10 @@ services:
|
||||
- PENPOT_LDAP_ATTRS_FULLNAME=cn
|
||||
- PENPOT_LDAP_ATTRS_PHOTO=jpegPhoto
|
||||
|
||||
# MCP
|
||||
- PENPOT_MCP_SERVER_LISTEN_ADDRESS=0.0.0.0
|
||||
- PENPOT_MCP_SERVER_ADDRESS=0.0.0.0
|
||||
|
||||
networks:
|
||||
default:
|
||||
aliases:
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"devDependencies": {
|
||||
"@penpot/draft-js": "workspace:./packages/draft-js",
|
||||
"@penpot/mousetrap": "workspace:./packages/mousetrap",
|
||||
"@penpot/plugins-runtime": "1.4.2",
|
||||
"@penpot/plugins-runtime": "workspace:../plugins/dist/plugins-runtime",
|
||||
"@penpot/svgo": "penpot/svgo#v3.2",
|
||||
"@penpot/text-editor": "workspace:./text-editor",
|
||||
"@penpot/tokenscript": "workspace:./packages/tokenscript",
|
||||
|
||||
47
frontend/pnpm-lock.yaml
generated
47
frontend/pnpm-lock.yaml
generated
@@ -20,8 +20,8 @@ importers:
|
||||
specifier: workspace:./packages/mousetrap
|
||||
version: link:packages/mousetrap
|
||||
'@penpot/plugins-runtime':
|
||||
specifier: 1.4.2
|
||||
version: 1.4.2
|
||||
specifier: workspace:../plugins/dist/plugins-runtime
|
||||
version: link:../plugins/dist/plugins-runtime
|
||||
'@penpot/svgo':
|
||||
specifier: penpot/svgo#v3.2
|
||||
version: svgo@https://codeload.github.com/penpot/svgo/tar.gz/8c9b0e32e9cb5f106085260bd9375f3c91a5010b
|
||||
@@ -581,15 +581,6 @@ packages:
|
||||
'@dabh/diagnostics@2.0.8':
|
||||
resolution: {integrity: sha512-R4MSXTVnuMzGD7bzHdW2ZhhdPC/igELENcq5IjEverBvq5hn1SXCWcsi6eSsdWP0/Ur+SItRRjAktmdoX/8R/Q==}
|
||||
|
||||
'@endo/cache-map@1.1.0':
|
||||
resolution: {integrity: sha512-owFGshs/97PDw9oguZqU/px8Lv1d0KjAUtDUiPwKHNXRVUE/jyettEbRoTbNJR1OaI8biMn6bHr9kVJsOh6dXw==}
|
||||
|
||||
'@endo/env-options@1.1.11':
|
||||
resolution: {integrity: sha512-p9OnAPsdqoX4YJsE98e3NBVhIr2iW9gNZxHhAI2/Ul5TdRfoOViItzHzTqrgUVopw6XxA1u1uS6CykLMDUxarA==}
|
||||
|
||||
'@endo/immutable-arraybuffer@1.1.2':
|
||||
resolution: {integrity: sha512-u+NaYB2aqEugQ3u7w3c5QNkPogf8q/xGgsPaqdY6pUiGWtYiTiFspKFcha6+oeZhWXWQ23rf0KrUq0kfuzqYyQ==}
|
||||
|
||||
'@esbuild/aix-ppc64@0.21.5':
|
||||
resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -1258,12 +1249,6 @@ packages:
|
||||
resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==}
|
||||
engines: {node: '>= 10.0.0'}
|
||||
|
||||
'@penpot/plugin-types@1.4.2':
|
||||
resolution: {integrity: sha512-O8wU6RSYE8bIVU7g8cSTYi32ppxs3R13dq7X3Nn9tmDaJjBOKOBpVLuoRPIp3fJC65fv8/7om0sdrtFoL5v19g==}
|
||||
|
||||
'@penpot/plugins-runtime@1.4.2':
|
||||
resolution: {integrity: sha512-y9TDZOnb96JBW9E33dHKpmTMeAPXLtHDIZruUVjtM8hBJWZK7RCv+vAGDGxeoZJC/OB2YAHrCZG+mukePBzcuQ==}
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
|
||||
engines: {node: '>=14'}
|
||||
@@ -4636,9 +4621,6 @@ packages:
|
||||
resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==}
|
||||
engines: {node: '>= 18'}
|
||||
|
||||
ses@1.14.0:
|
||||
resolution: {integrity: sha512-T07hNgOfVRTLZGwSS50RnhqrG3foWP+rM+Q5Du4KUQyMLFI3A8YA4RKl0jjZzhihC1ZvDGrWi/JMn4vqbgr/Jg==}
|
||||
|
||||
set-function-length@1.2.2:
|
||||
resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==}
|
||||
engines: {node: '>= 0.4'}
|
||||
@@ -5499,9 +5481,6 @@ packages:
|
||||
peerDependencies:
|
||||
zod: ^3.25.0 || ^4.0.0
|
||||
|
||||
zod@3.25.76:
|
||||
resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==}
|
||||
|
||||
zod@4.3.6:
|
||||
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
||||
|
||||
@@ -5775,12 +5754,6 @@ snapshots:
|
||||
enabled: 2.0.0
|
||||
kuler: 2.0.0
|
||||
|
||||
'@endo/cache-map@1.1.0': {}
|
||||
|
||||
'@endo/env-options@1.1.11': {}
|
||||
|
||||
'@endo/immutable-arraybuffer@1.1.2': {}
|
||||
|
||||
'@esbuild/aix-ppc64@0.21.5':
|
||||
optional: true
|
||||
|
||||
@@ -6297,14 +6270,6 @@ snapshots:
|
||||
'@parcel/watcher-win32-x64': 2.5.6
|
||||
optional: true
|
||||
|
||||
'@penpot/plugin-types@1.4.2': {}
|
||||
|
||||
'@penpot/plugins-runtime@1.4.2':
|
||||
dependencies:
|
||||
'@penpot/plugin-types': 1.4.2
|
||||
ses: 1.14.0
|
||||
zod: 3.25.76
|
||||
|
||||
'@pkgjs/parseargs@0.11.0':
|
||||
optional: true
|
||||
|
||||
@@ -10000,12 +9965,6 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
ses@1.14.0:
|
||||
dependencies:
|
||||
'@endo/cache-map': 1.1.0
|
||||
'@endo/env-options': 1.1.11
|
||||
'@endo/immutable-arraybuffer': 1.1.2
|
||||
|
||||
set-function-length@1.2.2:
|
||||
dependencies:
|
||||
define-data-property: 1.1.4
|
||||
@@ -10974,6 +10933,4 @@ snapshots:
|
||||
dependencies:
|
||||
zod: 4.3.6
|
||||
|
||||
zod@3.25.76: {}
|
||||
|
||||
zod@4.3.6: {}
|
||||
|
||||
@@ -119,6 +119,10 @@
|
||||
(normalize-uri (or (obj/get global "penpotPublicURI")
|
||||
(obj/get location "origin"))))
|
||||
|
||||
(def mcp-server-uri
|
||||
(normalize-uri (or (obj/get global "penpotMcpServerURI")
|
||||
(str "ws://" (obj/get location "hostname")":4402" ))))
|
||||
|
||||
(def rasterizer-uri
|
||||
(or (some-> (obj/get global "penpotRasterizerURI") normalize-uri)
|
||||
public-uri))
|
||||
|
||||
@@ -65,8 +65,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)
|
||||
(reset-plugin-flags plugin-id))
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
[app.common.types.components-list :as ctkl]
|
||||
[app.common.types.shape :as cts]
|
||||
[app.common.types.variant :as ctv]
|
||||
[app.common.uri :as u]
|
||||
[app.common.uuid :as uuid]
|
||||
[app.config :as cf]
|
||||
[app.main.data.changes :as dch]
|
||||
@@ -212,7 +213,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 (str (u/join cf/public-uri "plugins/mcp/manifest.json"))
|
||||
:code "plugin.js"
|
||||
:host (str (u/join cf/public-uri "plugins/mcp/"))
|
||||
: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}]
|
||||
|
||||
@@ -230,7 +230,9 @@
|
||||
:aria-pressed (contains? layout :debug-panel)
|
||||
:aria-label (tr "workspace.toolbar.debug")
|
||||
: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")
|
||||
|
||||
346
mcp/package-lock.json
generated
Normal file
346
mcp/package-lock.json
generated
Normal file
@@ -0,0 +1,346 @@
|
||||
{
|
||||
"name": "mcp-meta",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "mcp-meta",
|
||||
"version": "1.0.0",
|
||||
"devDependencies": {
|
||||
"concurrently": "^9.2.1",
|
||||
"prettier": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
"integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk/node_modules/supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concurrently": {
|
||||
"version": "9.2.1",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.1.tgz",
|
||||
"integrity": "sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "4.1.2",
|
||||
"rxjs": "7.8.2",
|
||||
"shell-quote": "1.8.3",
|
||||
"supports-color": "8.1.1",
|
||||
"tree-kill": "1.2.2",
|
||||
"yargs": "17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
"conc": "dist/bin/concurrently.js",
|
||||
"concurrently": "dist/bin/concurrently.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/prettier": {
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
|
||||
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"prettier": "bin/prettier.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/shell-quote": {
|
||||
"version": "1.8.3",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz",
|
||||
"integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz",
|
||||
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-kill": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
|
||||
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"tree-kill": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"dev": true,
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
|
||||
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
1422
mcp/packages/plugin/package-lock.json
generated
Normal file
1422
mcp/packages/plugin/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
5
mcp/packages/plugin/src/index.d.ts
vendored
Normal file
5
mcp/packages/plugin/src/index.d.ts
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
declare global {
|
||||
const mcp: any;
|
||||
}
|
||||
|
||||
export {};
|
||||
@@ -19,12 +19,19 @@ const statusElement = document.getElementById("connection-status");
|
||||
* @param isConnectedState - whether the connection is in a connected state (affects color)
|
||||
* @param message - optional additional message to append to the status
|
||||
*/
|
||||
function updateConnectionStatus(status: string, isConnectedState: boolean, message?: string): void {
|
||||
function updateConnectionStatus(code: string, status: string, isConnectedState: boolean, message?: string): void {
|
||||
if (statusElement) {
|
||||
const displayText = message ? `${status}: ${message}` : status;
|
||||
statusElement.textContent = displayText;
|
||||
statusElement.style.color = isConnectedState ? "var(--accent-primary)" : "var(--error-700)";
|
||||
}
|
||||
parent.postMessage(
|
||||
{
|
||||
type: "update-connection-status",
|
||||
status: code,
|
||||
},
|
||||
"*"
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,25 +51,23 @@ function sendTaskResponse(response: any): void {
|
||||
/**
|
||||
* Establishes a WebSocket connection to the MCP server.
|
||||
*/
|
||||
function connectToMcpServer(): void {
|
||||
function connectToMcpServer(url: string, token: string): void {
|
||||
if (ws?.readyState === WebSocket.OPEN) {
|
||||
updateConnectionStatus("Already connected", true);
|
||||
updateConnectionStatus("connected", "Already connected", true);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
let wsUrl = PENPOT_MCP_WEBSOCKET_URL;
|
||||
if (isMultiUserMode) {
|
||||
// TODO obtain proper userToken from penpot
|
||||
const userToken = "dummyToken";
|
||||
wsUrl += `?userToken=${encodeURIComponent(userToken)}`;
|
||||
url += `?userToken=${encodeURIComponent(token)}`;
|
||||
}
|
||||
ws = new WebSocket(wsUrl);
|
||||
updateConnectionStatus("Connecting...", false);
|
||||
|
||||
ws = new WebSocket(url);
|
||||
updateConnectionStatus("connecting", "Connecting...", false);
|
||||
|
||||
ws.onopen = () => {
|
||||
console.log("Connected to MCP server");
|
||||
updateConnectionStatus("Connected to MCP server", true);
|
||||
updateConnectionStatus("connected", "Connected to MCP server", true);
|
||||
};
|
||||
|
||||
ws.onmessage = (event) => {
|
||||
@@ -79,32 +84,37 @@ function connectToMcpServer(): void {
|
||||
ws.onclose = (event: CloseEvent) => {
|
||||
console.log("Disconnected from MCP server");
|
||||
const message = event.reason || undefined;
|
||||
updateConnectionStatus("Disconnected", false, message);
|
||||
updateConnectionStatus("disconnected", "Disconnected", false, message);
|
||||
ws = null;
|
||||
};
|
||||
|
||||
ws.onerror = (error) => {
|
||||
console.error("WebSocket error:", error);
|
||||
// note: WebSocket error events typically don't contain detailed error messages
|
||||
updateConnectionStatus("Connection error", false);
|
||||
updateConnectionStatus("error", "Connection error", false);
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Failed to connect to MCP server:", error);
|
||||
const message = error instanceof Error ? error.message : undefined;
|
||||
updateConnectionStatus("Connection failed", false, message);
|
||||
updateConnectionStatus("error", "Connection failed", false, message);
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelector("[data-handler='connect-mcp']")?.addEventListener("click", () => {
|
||||
connectToMcpServer();
|
||||
});
|
||||
// document.querySelector("[data-handler='connect-mcp']")?.addEventListener("click", () => {
|
||||
// connectToMcpServer();
|
||||
// });
|
||||
|
||||
// Listen plugin.ts messages
|
||||
window.addEventListener("message", (event) => {
|
||||
if (event.data.source === "penpot") {
|
||||
console.log("event", event.data);
|
||||
if (event.data.type === "init-server") {
|
||||
connectToMcpServer(event.data.url, event.data.token);
|
||||
} else if (event.data.source === "penpot") {
|
||||
document.body.dataset.theme = event.data.theme;
|
||||
} else if (event.data.type === "task-response") {
|
||||
// Forward task response back to MCP server
|
||||
sendTaskResponse(event.data.response);
|
||||
}
|
||||
});
|
||||
|
||||
parent.postMessage({ type: "ui-initialized" }, "*");
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { ExecuteCodeTaskHandler } from "./task-handlers/ExecuteCodeTaskHandler";
|
||||
import { Task, TaskHandler } from "./TaskHandler";
|
||||
|
||||
console.log("TOKEN", mcp.getToken());
|
||||
console.log("SERVER", mcp.getServerUrl());
|
||||
|
||||
mcp.setMcpStatus("connecting");
|
||||
|
||||
/**
|
||||
* Registry of all available task handlers.
|
||||
*/
|
||||
@@ -11,12 +16,26 @@ declare const IS_MULTI_USER_MODE: boolean;
|
||||
const isMultiUserMode = typeof IS_MULTI_USER_MODE !== "undefined" ? IS_MULTI_USER_MODE : false;
|
||||
|
||||
// Open the plugin UI (main.ts)
|
||||
penpot.ui.open("Penpot MCP Plugin", `?theme=${penpot.theme}&multiUser=${isMultiUserMode}`, { width: 158, height: 200 });
|
||||
(penpot.ui as any).open("Penpot MCP Plugin", `?theme=${penpot.theme}&multiUser=${isMultiUserMode}`, {
|
||||
width: 158,
|
||||
height: 200,
|
||||
hidden: true,
|
||||
});
|
||||
|
||||
// Handle messages
|
||||
penpot.ui.onMessage<string | { id: string; task: string; params: any }>((message) => {
|
||||
penpot.ui.onMessage<string | { id: string; type?: string; status?: string; task: string; params: any }>((message) => {
|
||||
// Handle plugin task requests
|
||||
if (typeof message === "object" && message.task && message.id) {
|
||||
console.log(message);
|
||||
if (typeof message === "object" && message.type === "ui-initialized") {
|
||||
console.log("send message");
|
||||
penpot.ui.sendMessage({
|
||||
type: "init-server",
|
||||
url: mcp.getServerUrl(),
|
||||
token: mcp.getToken(),
|
||||
});
|
||||
} else if (typeof message === "object" && message.type === "update-connection-status") {
|
||||
mcp.setMcpStatus(message.status);
|
||||
} else if (typeof message === "object" && message.task && message.id) {
|
||||
handlePluginTaskRequest(message).catch((error) => {
|
||||
console.error("Error in handlePluginTaskRequest:", error);
|
||||
});
|
||||
@@ -67,3 +86,11 @@ penpot.on("themechange", (theme) => {
|
||||
theme,
|
||||
});
|
||||
});
|
||||
|
||||
// console.log("send message");
|
||||
// penpot.ui.sendMessage({
|
||||
// source: "penpot",
|
||||
// type: "init-server",
|
||||
// url: mcp.getServerUrl(),
|
||||
// token: mcp.getToken(),
|
||||
// })
|
||||
|
||||
@@ -4,7 +4,6 @@ import baseConfig from "./vite.config";
|
||||
export default mergeConfig(
|
||||
baseConfig,
|
||||
defineConfig({
|
||||
base: "./",
|
||||
plugins: [],
|
||||
})
|
||||
);
|
||||
|
||||
9
plugins/libs/plugin-types/index.d.ts
vendored
9
plugins/libs/plugin-types/index.d.ts
vendored
@@ -1,3 +1,10 @@
|
||||
|
||||
export interface OpenModalOptions {
|
||||
width: number;
|
||||
height: number;
|
||||
hidden: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* These are methods and properties available on the `penpot` global object.
|
||||
*
|
||||
@@ -23,7 +30,7 @@ export interface Penpot extends Omit<
|
||||
open: (
|
||||
name: string,
|
||||
url: string,
|
||||
options?: { width: number; height: number },
|
||||
options?: UIOptions,
|
||||
) => void;
|
||||
|
||||
size: {
|
||||
|
||||
@@ -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`,
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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,10 @@ export function createSandbox(
|
||||
structuredClone: ses.harden(window.structuredClone),
|
||||
};
|
||||
|
||||
if (apiExtensions) {
|
||||
publicPluginApi = Object.assign(publicPluginApi, apiExtensions);
|
||||
}
|
||||
|
||||
const compartment = ses.createCompartment(publicPluginApi);
|
||||
|
||||
return {
|
||||
|
||||
@@ -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);
|
||||
@@ -58,6 +61,7 @@ export const loadPlugin = async function (
|
||||
closeCallback();
|
||||
}
|
||||
},
|
||||
apiExtensions,
|
||||
);
|
||||
|
||||
plugins.push(plugin);
|
||||
@@ -70,8 +74,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) {
|
||||
|
||||
@@ -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(),
|
||||
});
|
||||
|
||||
873
plugins/pnpm-lock.yaml
generated
873
plugins/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user