diff --git a/CHANGES.md b/CHANGES.md index 6da1e66c2d..ac091ef363 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -120,6 +120,19 @@ - Delete selected path handles with Backspace or Delete [#11858](https://github.com/penpot/penpot/issues/11858) (PR: [#11896](https://github.com/penpot/penpot/pull/11896)) - Use the tooltip component in the token pill info [#11886](https://github.com/penpot/penpot/issues/11886) (PR: [#11900](https://github.com/penpot/penpot/pull/11900)) - Hide the duplicate cursor when alt-dragging a shape that cannot be duplicated (by @0xTHAC0) [#11905](https://github.com/penpot/penpot/issues/11905) (PR: [#11195](https://github.com/penpot/penpot/pull/11195)) + +## 2.18.6 + +### :bug: Bugs fixed + +- Fix upload endpoints storing server files when the path points outside the temp dir [#12771](https://github.com/penpot/penpot/issues/12771) (PR: [#12772](https://github.com/penpot/penpot/pull/12772)) + +## 2.18.5 + +### :bug: Bugs fixed + +- Fix the Admin Console failing on every URL on Docker deployments by reverting the subpath support [#12358](https://github.com/penpot/penpot/pull/12358) + ## 2.18.4 ### :bug: Bugs fixed diff --git a/mcp/README.md b/mcp/README.md index 632abf4254..2f1636d24a 100644 --- a/mcp/README.md +++ b/mcp/README.md @@ -361,9 +361,10 @@ Some of the aforementioned configuration options control these modes. * Auto-formatting: Use `pnpm run fmt` * Generating API type data: See [types-generator/README.md](types-generator/README.md) * Versioning: Use `bash scripts/set-version` to set the version for the MCP package (in `package.json`). - - Ensure that at least the major, minor and patch components of the version are always up-to-date. - - The MCP plugin assumes that a mismatch between the MCP version and the Penpot version (as returned by the API) - indicates incompatibility, resulting in the display of a warning message in the plugin UI. + - Ensure that at least the major and minor components of the version are always up-to-date. + - The MCP plugin assumes that a mismatch between the major.minor components of the MCP version and the Penpot + version (as returned by the API) indicates incompatibility, resulting in the display of a warning message in + the plugin UI. Patch releases are treated as compatible. * Packaging and publishing: 1. Ensure that the API type data is up-to-date (see above). 2. Ensure release version is set correctly in package.json (call `bash scripts/set-version` to update it automatically) diff --git a/mcp/packages/plugin/src/VersionCompatibility.test.ts b/mcp/packages/plugin/src/VersionCompatibility.test.ts new file mode 100644 index 0000000000..2e40bb7cf0 --- /dev/null +++ b/mcp/packages/plugin/src/VersionCompatibility.test.ts @@ -0,0 +1,28 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { extractMinorVersion, isCompatibleVersion } from "./VersionCompatibility.ts"; + +test("extracts major.minor from release and pre-release versions", () => { + assert.equal(extractMinorVersion("2.18.1"), "2.18"); + assert.equal(extractMinorVersion("2.17.0"), "2.17"); + assert.equal(extractMinorVersion("2.15.0-rc.1.116"), "2.15"); + assert.equal(extractMinorVersion("2.18.1-dev.140"), "2.18"); + assert.equal(extractMinorVersion("2.18"), "2.18"); +}); + +test("returns non-matching versions unchanged", () => { + assert.equal(extractMinorVersion("<2.15"), "<2.15"); + assert.equal(extractMinorVersion("develop"), "develop"); +}); + +test("treats patch releases of the same minor version as compatible", () => { + assert.equal(isCompatibleVersion(extractMinorVersion("2.17.2"), extractMinorVersion("2.17.0")), true); +}); + +test("reports a different minor version as incompatible", () => { + assert.equal(isCompatibleVersion(extractMinorVersion("2.18.1"), extractMinorVersion("2.17.0")), false); +}); + +test("treats local development builds of Penpot as compatible", () => { + assert.equal(isCompatibleVersion(extractMinorVersion("0.0.0"), extractMinorVersion("2.17.0")), true); +}); diff --git a/mcp/packages/plugin/src/VersionCompatibility.ts b/mcp/packages/plugin/src/VersionCompatibility.ts new file mode 100644 index 0000000000..f529491ea3 --- /dev/null +++ b/mcp/packages/plugin/src/VersionCompatibility.ts @@ -0,0 +1,27 @@ +/** + * Extracts the major.minor prefix from a version string. + * + * Patch releases of Penpot do not change the plugin API the MCP server is + * written against, and the MCP package version is only set per minor + * release, so the patch component is not part of the compatibility check. + * + * @param version - a version string starting with major.minor (e.g. "2.18.1") + * @returns the major.minor prefix, or the original string if it does not match + */ +export function extractMinorVersion(version: string): string { + const match = version.match(/^(\d+\.\d+)(?:\.|$)/); + return match ? match[1] : version; +} + +/** + * Returns whether an MCP build is intended for the running Penpot version. + * + * Local development builds of Penpot report "0.0.0" and are always treated + * as compatible. + * + * @param penpotVersion - the running Penpot version, as major.minor prefix + * @param mcpVersion - the version the MCP build targets, as major.minor prefix + */ +export function isCompatibleVersion(penpotVersion: string, mcpVersion: string): boolean { + return penpotVersion === "0.0" || penpotVersion === mcpVersion; +} diff --git a/mcp/packages/plugin/src/plugin.ts b/mcp/packages/plugin/src/plugin.ts index 025354df74..cb2576178e 100644 --- a/mcp/packages/plugin/src/plugin.ts +++ b/mcp/packages/plugin/src/plugin.ts @@ -1,6 +1,7 @@ import { ExecuteCodeTaskHandler } from "./task-handlers/ExecuteCodeTaskHandler"; import { Task, TaskHandler } from "./TaskHandler"; import { formatTaskError } from "./ErrorUtils"; +import { extractMinorVersion, isCompatibleVersion } from "./VersionCompatibility"; import type { PluginConnectionInit } from "../../common/src"; import type { WorkspaceContext } from "@penpot/plugin-types"; @@ -16,17 +17,6 @@ const isIntegratedRemoteMcp = !!mcp; */ const management = typeof penpotMgmt === "undefined" ? null : penpotMgmt; -/** - * Extracts the major.minor.patch prefix from a version string. - * - * @param version - a version string starting with major.minor.patch - * @returns the major.minor.patch prefix, or the original string if it does not match - */ -function extractVersionPrefix(version: string): string { - const match = version.match(/^(\d+\.\d+\.\d+)/); - return match ? match[1] : version; -} - let uiInitialized = false; /** @@ -53,11 +43,10 @@ penpot.ui.onMessage< integratedRemoteMcp: isIntegratedRemoteMcp, }); // Check Penpot version compatibility - const penpotVersionPrefix = penpot.version ? extractVersionPrefix(penpot.version) : "<2.15"; // pre-2.15 versions don't have version info - const mcpVersionPrefix = extractVersionPrefix(PENPOT_MCP_VERSION); + const penpotVersionPrefix = penpot.version ? extractMinorVersion(penpot.version) : "<2.15"; // pre-2.15 versions don't have version info + const mcpVersionPrefix = extractMinorVersion(PENPOT_MCP_VERSION); console.log(`Penpot version: ${penpotVersionPrefix}, MCP version: ${mcpVersionPrefix}`); - const isLocalPenpotVersion = penpotVersionPrefix == "0.0.0"; - if (penpotVersionPrefix !== mcpVersionPrefix && !isLocalPenpotVersion) { + if (!isCompatibleVersion(penpotVersionPrefix, mcpVersionPrefix)) { penpot.ui.sendMessage({ type: "version-mismatch", mcpVersion: mcpVersionPrefix,