diff --git a/package.json b/package.json index b77de18..14406b3 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,11 @@ "scripts": { "install:all": "concurrently --names \"COMMON,MCP-SERVER,PLUGIN\" --prefix-colors \"green,cyan,magenta\" \"npm --prefix common install\" \"npm --prefix mcp-server install\" \"npm --prefix penpot-plugin install\"", "build:all": "concurrently --names \"COMMON,MCP-SERVER,PLUGIN\" --prefix-colors \"green,cyan,magenta\" --success first \"npm --prefix common install && npm --prefix common run build\" \"npm --prefix mcp-server run build\" \"npm --prefix penpot-plugin run build\"", + "build:all-multi-user": "concurrently --names \"COMMON,MCP-SERVER,PLUGIN\" --prefix-colors \"green,cyan,magenta\" --success first \"npm --prefix common install && npm --prefix common run build\" \"npm --prefix mcp-server run build\" \"npm --prefix penpot-plugin run build:multi-user\"", "start:all": "concurrently --names \"MCP-SERVER,PLUGIN-SERVER\" --prefix-colors \"cyan,magenta\" --kill-others-on-fail \"npm --prefix mcp-server start\" \"npm --prefix penpot-plugin run dev\"", - "start:all-multi-user": "concurrently --names \"MCP-SERVER,PLUGIN-SERVER\" --prefix-colors \"cyan,magenta\" --kill-others-on-fail \"npm --prefix mcp-server run start:multi-user\" \"npm --prefix penpot-plugin run dev\"", + "start:all-multi-user": "concurrently --names \"MCP-SERVER,PLUGIN-SERVER\" --prefix-colors \"cyan,magenta\" --kill-others-on-fail \"npm --prefix mcp-server run start:multi-user\" \"npm --prefix penpot-plugin run dev:multi-user\"", "bootstrap": "npm run install:all && npm run build:all && npm run start:all", - "bootstrap:multi-user": "npm run install:all && npm run build:all && npm run start:all-multi-user", + "bootstrap:multi-user": "npm run install:all && npm run build:all-multi-user && npm run start:all-multi-user", "format": "prettier --write .", "format:check": "prettier --check ." }, diff --git a/penpot-plugin/package-lock.json b/penpot-plugin/package-lock.json index 5fcc2fa..384ee05 100644 --- a/penpot-plugin/package-lock.json +++ b/penpot-plugin/package-lock.json @@ -1,12 +1,12 @@ { - "name": "penpot-plugin-starter-template", - "version": "0.0.0", + "name": "penpot-mcp-plugin", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "penpot-plugin-starter-template", - "version": "0.0.0", + "name": "penpot-mcp-plugin", + "version": "1.0.0", "dependencies": { "@penpot-mcp/common": "file:../common", "@penpot/plugin-styles": "1.3.2", @@ -14,6 +14,7 @@ "penpot-mcp": "file:.." }, "devDependencies": { + "cross-env": "^7.0.3", "typescript": "^5.8.3", "vite": "^7.0.5", "vite-live-preview": "^0.3.2" @@ -816,6 +817,40 @@ "node": ">=18" } }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/debug": { "version": "4.3.6", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", @@ -914,6 +949,13 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -950,6 +992,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/penpot-mcp": { "resolved": "..", "link": true @@ -1039,6 +1091,29 @@ "fsevents": "~2.3.2" } }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -1184,6 +1259,22 @@ "vite": ">=5.2.13" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/ws": { "version": "8.18.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", diff --git a/penpot-plugin/package.json b/penpot-plugin/package.json index 2176c51..cc817e9 100644 --- a/penpot-plugin/package.json +++ b/penpot-plugin/package.json @@ -1,11 +1,13 @@ { - "name": "penpot-plugin-starter-template", + "name": "penpot-mcp-plugin", "private": true, - "version": "0.0.0", + "version": "1.0.0", "type": "module", "scripts": { "dev": "vite build --watch", - "build": "tsc && vite build" + "dev:multi-user": "cross-env MULTI_USER_MODE=true vite build --watch", + "build": "tsc && vite build", + "build:multi-user": "tsc && cross-env MULTI_USER_MODE=true vite build" }, "dependencies": { "@penpot-mcp/common": "file:../common", @@ -14,6 +16,7 @@ "penpot-mcp": "file:.." }, "devDependencies": { + "cross-env": "^7.0.3", "typescript": "^5.8.3", "vite": "^7.0.5", "vite-live-preview": "^0.3.2" diff --git a/penpot-plugin/src/main.ts b/penpot-plugin/src/main.ts index e3fba42..2404346 100644 --- a/penpot-plugin/src/main.ts +++ b/penpot-plugin/src/main.ts @@ -4,6 +4,10 @@ import "./style.css"; const searchParams = new URLSearchParams(window.location.search); document.body.dataset.theme = searchParams.get("theme") ?? "light"; +// Determine whether multi-user mode is enabled based on URL parameters +const isMultiUserMode = searchParams.get("multiUser") === "true"; +console.log("Penpot MCP multi-user mode:", isMultiUserMode); + // WebSocket connection management let ws: WebSocket | null = null; const statusElement = document.getElementById("connection-status"); @@ -47,7 +51,13 @@ function connectToMcpServer(): void { } try { - ws = new WebSocket("ws://localhost:4402"); + let wsUrl = "ws://localhost:4402"; + if (isMultiUserMode) { + // TODO obtain proper userToken from penpot + const userToken = "dummyToken"; + wsUrl += `?userToken=${encodeURIComponent(userToken)}`; + } + ws = new WebSocket(wsUrl); updateConnectionStatus("Connecting...", false); ws.onopen = () => { diff --git a/penpot-plugin/src/plugin.ts b/penpot-plugin/src/plugin.ts index 6016ef3..e6a1fad 100644 --- a/penpot-plugin/src/plugin.ts +++ b/penpot-plugin/src/plugin.ts @@ -6,8 +6,12 @@ import { Task, TaskHandler } from "./TaskHandler"; */ const taskHandlers: TaskHandler[] = [new ExecuteCodeTaskHandler()]; -// Open the plugin UI -penpot.ui.open("Penpot MCP Plugin", `?theme=${penpot.theme}`, { width: 158, height: 200 }); +// Determine whether multi-user mode is enabled based on build-time configuration +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 }); // Handle messages penpot.ui.onMessage((message) => { diff --git a/penpot-plugin/vite.config.ts b/penpot-plugin/vite.config.ts index adfe58b..afa7319 100644 --- a/penpot-plugin/vite.config.ts +++ b/penpot-plugin/vite.config.ts @@ -1,6 +1,10 @@ import { defineConfig } from "vite"; import livePreview from "vite-live-preview"; +// Debug: Log the environment variable +console.log("MULTI_USER_MODE env:", process.env.MULTI_USER_MODE); +console.log("Will define IS_MULTI_USER_MODE as:", JSON.stringify(process.env.MULTI_USER_MODE === "true")); + export default defineConfig({ plugins: [ livePreview({ @@ -27,4 +31,7 @@ export default defineConfig({ port: 4400, cors: true, }, + define: { + IS_MULTI_USER_MODE: JSON.stringify(process.env.MULTI_USER_MODE === "true"), + }, });