diff --git a/.agents/skills/code-review-criteria/SKILL.md b/.agents/skills/code-review-criteria/SKILL.md index 59abf1c21e..398aa440ee 100644 --- a/.agents/skills/code-review-criteria/SKILL.md +++ b/.agents/skills/code-review-criteria/SKILL.md @@ -105,7 +105,7 @@ For detailed security guidance, see `security-and-hardening`. | **Low:** | Minor, optional | Author may ignore — formatting, style preferences | | **Suggestion:** | Worth considering | Not required, but improves the code | -**Unique finding IDs.** Assign every finding a stable identifier: `F1`, `F2`, `F3`, … numbered in order of severity (Critical first, then High, Medium, Low, Suggestion). Use the ID everywhere the finding is mentioned — in section headers, in the verdict, in follow-up discussion. Never renumber within a review. Example: `**F3 (High)** — `app/validate.cljs:42` — duplicate branch logic…`. +**Finding IDs.** Assign every finding a stable identifier by severity class: `R1`, `R2`, … for required findings (Critical, High), `M1`, `M2`, … for minor findings (Medium, Low), and `S1`, `S2`, … for suggestions. Number within each class in review order. Use the ID everywhere the finding is mentioned — in section headers, in the verdict, in follow-up discussion. Never renumber within a review. Example: `**R2** — `app/validate.cljs:42` — duplicate branch logic…`. For each finding, describe the circumstances under which it could fail: specific inputs, load conditions, timing, or user actions that trigger the problem. "This crashes when input is null" is actionable; "this might crash" is not. @@ -123,11 +123,11 @@ Briefly explain what the code does and give an overall assessment. ### Critical and High-Priority Issues -List problems that could cause security incidents, data loss, crashes, incorrect behavior, or major performance degradation. Each finding gets its unique ID (`F1`, `F2`, …). For each: state the severity, identify the file/function/code section, explain why it's a problem, describe failure circumstances, and provide a concrete improvement with corrected code when useful. +List problems that could cause security incidents, data loss, crashes, incorrect behavior, or major performance degradation. Each finding gets its unique ID (`R1`, `R2`, …). For each: state the severity, identify the file/function/code section, explain why it's a problem, describe failure circumstances, and provide a concrete improvement with corrected code when useful. ### Other Findings -List medium- and low-priority issues, including maintainability and design concerns. Continue the ID sequence started above (`F3`, `F4`, …). +List medium- and low-priority issues, including maintainability and design concerns. Use `M1`, `M2`, … for Medium/Low and `S1`, `S2`, … for Suggestions. ### Suggested Refactoring @@ -149,7 +149,7 @@ Choose one: - **Approve with minor changes** — Good to merge after addressing low/medium issues - **Request changes** — Critical or high issues must be resolved before merge -List the finding IDs the verdict depends on (e.g. "Request changes: F1, F4"). +List the finding IDs the verdict depends on (e.g. "Request changes: R1, R2"). ## Change Sizing diff --git a/.agents/skills/review-code/SKILL.md b/.agents/skills/review-code/SKILL.md index 613aae072e..21e7a7c7fd 100644 --- a/.agents/skills/review-code/SKILL.md +++ b/.agents/skills/review-code/SKILL.md @@ -67,6 +67,26 @@ agent again. 6. Skip generated files, lockfile-only changes, and unrelated modifications unless they introduce security risks. +## Posting as a GitHub comment + +Only post the review as a comment when the user asks for it explicitly. Keep +it in the session otherwise. + +When posting: PR comments go in English, with this minimal structure: + +1. **Intro line** — one sentence: what was found and the overall tone. No + greetings. +2. **`## Main issues`** — one subsection per required finding: what breaks, + the failure circumstances, and the minimal fix (code snippet when useful). + A missing test belongs here, not under minor suggestions. +3. **`## Minor suggestions`** — one bullet per minor finding or suggestion: + file/function, problem, concrete remedy. +4. **Closing** — optional and short. Cut it when it adds nothing. + +Reference every finding by its ID (`R1`, `M1`, `S1`, … from +`code-review-criteria`) so follow-up replies can point to findings +unambiguously. + ## User input, overrides and additional context $ARGUMENTS diff --git a/.serena/memories/mcp/core.md b/.serena/memories/mcp/core.md index feb218b5d3..04bfef910e 100644 --- a/.serena/memories/mcp/core.md +++ b/.serena/memories/mcp/core.md @@ -85,6 +85,21 @@ From the `mcp/` directory, run * `pnpm run build` to test the build of all packages * `pnpm run fmt` to apply the auto-formatter +* `pnpm run test` runs the tests of `plugin` (node test runner) and `server` (tsx). + The committed `typescript` version is 6.x: the 7.x line ships only a version stub + at the `typescript` entry point, and its synchronous compiler API is gone, so + `ts.transpileModule` (used by the plugin tests to compile `main.ts`/`plugin.ts` + into a sandboxed browser-like context) fails there. +* `packages/server` type-checks against the built `dist` of `@penpot/mcp-common`; + a stale `packages/common/dist` makes `types:check` fail with missing exports + (e.g. `PenpotSession`). Run `pnpm --filter mcp-common run build` first. +* The server logger (`packages/server/src/logger.ts`) uses pino transports only + outside `node:test` (`logTransportTargets`). A transport spawns a worker thread + whose message port stays referenced once a line is in flight, so the test child + process keeps running after the tests finish and the suite hangs intermittently + (node reports `Promise resolution is still pending but the event loop has + already resolved` for the file's root test). Inside tests the logger writes to + stdout directly. `NODE_TEST_CONTEXT` is the env var `node --test` sets. * Cross-cutting testing principles and anti-patterns: `mem:testing`. ## Devenv plugin/server wiring diff --git a/.serena/memories/workflow/creating-issues.md b/.serena/memories/workflow/creating-issues.md index 1032606ef4..dbe55c9241 100644 --- a/.serena/memories/workflow/creating-issues.md +++ b/.serena/memories/workflow/creating-issues.md @@ -263,6 +263,16 @@ AUTHOR=$(gh pr view --repo penpot/penpot --json author --jq '.author gh issue edit --repo penpot/penpot --add-assignee "$AUTHOR" ``` +GitHub only allows assigning users with write permission, org members, or +users who have already commented on the issue. Assigning an outside +contributor fails with `422 ... assignees ... invalid`, and `gh issue edit` +still exits 0 and prints the issue URL. Verify the result and, when the list +stays empty, skip the assignment: + +```bash +gh api repos/penpot/penpot/issues/ --jq '[.assignees[].login]' +``` + ### Set Issue Type and verify See the **Setting the Issue Type** and **Verification** sections above — the diff --git a/docker/devenv/Dockerfile b/docker/devenv/Dockerfile index a3456d5341..101438f4d8 100644 --- a/docker/devenv/Dockerfile +++ b/docker/devenv/Dockerfile @@ -112,18 +112,18 @@ RUN set -eux; \ FROM base AS setup-opencode -ENV OPENCODE_VERSION=2.0.25 +ENV OPENCODE_VERSION=2.0.26 RUN set -eux; \ ARCH="$(dpkg --print-architecture)"; \ case "${ARCH}" in \ aarch64|arm64) \ BINARY_URL="https://registry.npmjs.org/@opencode/cli-linux-arm64/-/cli-linux-arm64-${OPENCODE_VERSION}.tgz"; \ - ESUM='92ce31022cd32f57ac3ccc775ba3a96f6aa36128a176aea0c7ef266986047537'; \ + ESUM='1d7117dbb31968456f89537b562fb5e20e48d9e9ef0325fc8845abdda6ef4842'; \ ;; \ amd64|x86_64) \ BINARY_URL="https://registry.npmjs.org/@opencode/cli-linux-x64/-/cli-linux-x64-${OPENCODE_VERSION}.tgz"; \ - ESUM='5b3e50ad1c06214aaf1c26eb30f90a15f66975a6e3e48fef5a31c34466e37b5a'; \ + ESUM='0a116e033a02804741d4644337d012bdf5a24aac33a34c0c96534d2d53961119'; \ ;; \ *) \ echo "Unsupported arch: ${ARCH}"; exit 1; \ diff --git a/frontend/src/app/main/data/exports/wasm.cljs b/frontend/src/app/main/data/exports/wasm.cljs index d2258b5e85..ff56fd5796 100644 --- a/frontend/src/app/main/data/exports/wasm.cljs +++ b/frontend/src/app/main/data/exports/wasm.cljs @@ -22,11 +22,10 @@ (wapi/create-uri blob))) (defn export-image - [{:keys [type suffix name] :as params}] + [{:keys [type name] :as params}] (let [url (export-image-uri params) - mtype (format->mtype type) - filename (str name (or suffix ""))] - (dom/trigger-download-uri filename mtype url) + mtype (format->mtype type)] + (dom/trigger-download-uri name mtype url) (wapi/revoke-uri url) nil)) @@ -37,9 +36,9 @@ (wapi/create-uri blob))) (defn export-pdf - [{:keys [suffix name] :as params}] + [{:keys [name] :as params}] (let [url (export-pdf-uri params) - filename (str name (or suffix "") ".pdf")] + filename (str name ".pdf")] (dom/trigger-download-uri filename "application/pdf" url) (js/queueMicrotask #(wapi/revoke-uri url)) nil)) @@ -51,9 +50,9 @@ (wapi/create-uri blob))) (defn export-svg - [{:keys [suffix name] :as params}] + [{:keys [name] :as params}] (let [url (export-svg-uri params) - filename (str name (or suffix "") ".svg")] + filename (str name ".svg")] (dom/trigger-download-uri filename "image/svg+xml" url) (js/queueMicrotask #(wapi/revoke-uri url)) nil)) diff --git a/frontend/src/app/main/data/workspace/texts.cljs b/frontend/src/app/main/data/workspace/texts.cljs index 1040ec1fd6..faa68099fc 100644 --- a/frontend/src/app/main/data/workspace/texts.cljs +++ b/frontend/src/app/main/data/workspace/texts.cljs @@ -904,6 +904,40 @@ new-shape) shape)) +(defn merge-live-text-dimensions + "Pick displayed width/height while editing auto-grow text. + + Geometry commits are finalize-only (see `v2-update-text-shape-content`), so the + Design tab and edition outline read live WASM layout for growing axes: + - `:auto-width` → live width and height + - `:auto-height` → selrect width, live height + - `:fixed` → selrect for both + + Nil or non-positive live axes fall back to the committed selrect so a missing + WASM measure never flashes `0`." + [grow-type {:keys [width height]} live] + (let [lw (when (map? live) (:width live)) + lh (when (map? live) (:height live))] + {:width (if (and (= grow-type :auto-width) (number? lw) (pos? lw)) lw width) + :height (if (and (not= grow-type :fixed) (number? lh) (pos? lh)) lh height)})) + +(defn shape-with-live-text-dimensions + "Display-only patch of shape selrect (and :width/:height) from live WASM text + layout. Does not write to the store. Returns `shape` unchanged when WASM is + unavailable or dimensions do not change." + [shape] + (let [selrect (:selrect shape) + live (when (wasm.api/initialized?) + (wasm.api/get-text-dimensions (:id shape))) + {:keys [width height]} (merge-live-text-dimensions (:grow-type shape) selrect live)] + (if (and (mth/close? width (:width selrect)) + (mth/close? height (:height selrect))) + shape + (-> shape + (assoc :selrect (grc/make-rect (:x selrect) (:y selrect) width height)) + (cond-> (contains? shape :width) (assoc :width width)) + (cond-> (contains? shape :height) (assoc :height height)))))) + (defn commit-update-text-modifier [] (ptk/reify ::commit-update-text-modifier diff --git a/frontend/src/app/main/ui/workspace/libraries.cljs b/frontend/src/app/main/ui/workspace/libraries.cljs index 05da244e5b..ca7d530203 100644 --- a/frontend/src/app/main/ui/workspace/libraries.cljs +++ b/frontend/src/app/main/ui/workspace/libraries.cljs @@ -819,7 +819,7 @@ [:div {:class (stl/css :lib-section)} [:> title-bar* {:collapsable false - :title "ASSETS IN THIS FILE" + :title (tr "workspace.libraries.assets-in-this-file") :class (stl/css :title-spacing-lib)}] [:div {:class (stl/css :section-list)} [:div {:class (stl/css :section-list-publish)} @@ -916,7 +916,7 @@ (tr "workspace.libraries.empty.no-connected-libraries")] [:button {:class (stl/css :go-to-shared-button) :on-click go-to-shared} - "Add a shared library"]])]]])) + (tr "workspace.libraries.add-shared-library")]])]]])) (defn- extract-assets @@ -1154,7 +1154,7 @@ tabs (mf/with-memo [token-lib-sync?] (if token-lib-sync? - [{:label "This file" + [{:label (tr "workspace.libraries.this-file") :id "file"} {:label (tr "workspace.libraries.libraries") :id "libraries"} diff --git a/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs b/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs index 93e7562438..43d2b492d0 100644 --- a/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs +++ b/frontend/src/app/main/ui/workspace/shapes/text/text_edition_outline.cljs @@ -22,17 +22,15 @@ [selrect transform] (dsh/get-selrect selrect-transform shape) ;; While editing, the committed selrect lags the text (geometry is - ;; finalize-only), so measure the live WASM text for the growing axes: - ;; width grows on auto-width, height on auto-width/auto-height. - grow-type (:grow-type shape) - {live-width :width live-height :height} (wasm.api/get-text-dimensions (:id shape)) - sr-width (if (= grow-type :auto-width) live-width (:width selrect)) - sr-height (if (= grow-type :fixed) (:height selrect) live-height)] + ;; finalize-only), so measure the live WASM text for the growing axes. + live (wasm.api/get-text-dimensions (:id shape)) + {:keys [width height]} (dwt/merge-live-text-dimensions + (:grow-type shape) selrect live)] [:rect.main.viewport-selrect {:x (:x selrect) :y (:y selrect) - :width sr-width - :height sr-height + :width width + :height height :transform transform :style {:stroke "var(--color-accent-tertiary)" :stroke-width (/ 1 zoom) diff --git a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs index 3158f59be2..dd2c9dc102 100644 --- a/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs +++ b/frontend/src/app/main/ui/workspace/sidebar/options/shapes/text.cljs @@ -31,8 +31,19 @@ (mf/defc options* [{:keys [shape libraries file-id page-id]}] - (let [id (dm/get-prop shape :id) - type (dm/get-prop shape :type) + (let [id (dm/get-prop shape :id) + type (dm/get-prop shape :type) + edition (mf/deref refs/selected-edition) + ;; While editing auto-grow text, committed selrect lags (finalize-only + ;; geometry). Patch display size from live WASM so Design W/H match the + ;; viewport outline without writing to the store. + shape + (cond-> shape + (and (= id edition) + (not= :fixed (:grow-type shape)) + (features/active-feature? @st/state "render-wasm/v1")) + (dwt/shape-with-live-text-dimensions)) + ids (mf/with-memo [id] [id]) shapes (mf/with-memo [shape] [shape]) diff --git a/frontend/src/app/main/ui/workspace/tokens/themes.cljs b/frontend/src/app/main/ui/workspace/tokens/themes.cljs index 5c116ca4ad..81ad0d033f 100644 --- a/frontend/src/app/main/ui/workspace/tokens/themes.cljs +++ b/frontend/src/app/main/ui/workspace/tokens/themes.cljs @@ -23,6 +23,9 @@ (let [ordered-themes (mf/deref refs/workspace-token-themes-no-hidden) + can-edit-file? + (mf/use-ctx ctx/can-edit?) + can-edit-tokens? (mf/use-ctx ctx/can-edit-tokens?) @@ -50,6 +53,6 @@ :class (stl/css :edit-theme-button) :on-click open-modal} (tr "labels.edit")]] - [:div {:title (when-not can-edit-tokens? + [:div {:title (when-not can-edit-file? (tr "workspace.tokens.no-permission-themes"))} [:> theme-selector* {:tokens-source tokens-source}]]))])) diff --git a/frontend/src/app/render_wasm/text_editor.cljs b/frontend/src/app/render_wasm/text_editor.cljs index eff80ba610..c7e529ec6f 100644 --- a/frontend/src/app/render_wasm/text_editor.cljs +++ b/frontend/src/app/render_wasm/text_editor.cljs @@ -840,11 +840,17 @@ (defn- clean-styles "Drop nil-valued attrs (unlike the DOM path, our merge would keep them and fail - the backend schema); a per-span fn is passed through untouched." + the backend schema); a per-span fn is passed through untouched. A nil + `:text-decoration` is the panel's toggle-off, so it becomes \"none\"." [styles] (if (fn? styles) styles - (into {} (remove (comp nil? val)) styles))) + (into {} + (keep (fn [[k v]] + (cond + (some? v) [k v] + (= k :text-decoration) [k "none"]))) + styles))) (defn apply-styles-to-selection "Apply `styles` (attrs map, or a fn per span) to the selected spans; `:with-fills?` also returns `:fills`." diff --git a/frontend/test/frontend_tests/data/workspace_texts_test.cljs b/frontend/test/frontend_tests/data/workspace_texts_test.cljs index 14eef12d50..9fe41428e7 100644 --- a/frontend/test/frontend_tests/data/workspace_texts_test.cljs +++ b/frontend/test/frontend_tests/data/workspace_texts_test.cljs @@ -581,3 +581,48 @@ (t/testing "a non-root content (e.g. paragraph) is left alone" (let [node {:type "paragraph" :children []}] (t/is (= node (dwt/ensure-valid-text-content node)))))) + +;; --------------------------------------------------------------------------- +;; Tests: merge-live-text-dimensions (Design tab / edition outline) +;; --------------------------------------------------------------------------- + +(t/deftest merge-live-text-dimensions-auto-width-uses-live-axes + (t/testing "auto-width takes live width and height" + (let [selrect {:width 0.01 :height 0.01} + live {:width 70 :height 17} + result (dwt/merge-live-text-dimensions :auto-width selrect live)] + (t/is (= 70 (:width result))) + (t/is (= 17 (:height result)))))) + +(t/deftest merge-live-text-dimensions-auto-height-keeps-width + (t/testing "auto-height keeps selrect width and takes live height" + (let [selrect {:width 300 :height 40} + live {:width 120 :height 80} + result (dwt/merge-live-text-dimensions :auto-height selrect live)] + (t/is (= 300 (:width result))) + (t/is (= 80 (:height result)))))) + +(t/deftest merge-live-text-dimensions-fixed-keeps-selrect + (t/testing "fixed keeps both selrect axes" + (let [selrect {:width 300 :height 60} + live {:width 90 :height 20} + result (dwt/merge-live-text-dimensions :fixed selrect live)] + (t/is (= 300 (:width result))) + (t/is (= 60 (:height result)))))) + +(t/deftest merge-live-text-dimensions-nil-live-falls-back + (t/testing "nil live map falls back to selrect" + (let [selrect {:width 50 :height 25} + result (dwt/merge-live-text-dimensions :auto-width selrect nil)] + (t/is (= 50 (:width result))) + (t/is (= 25 (:height result))))) + (t/testing "nil live axes fall back per axis" + (let [selrect {:width 50 :height 25} + result (dwt/merge-live-text-dimensions :auto-width selrect {:width nil :height nil})] + (t/is (= 50 (:width result))) + (t/is (= 25 (:height result))))) + (t/testing "non-positive live axes do not wipe selrect" + (let [selrect {:width 50 :height 25} + result (dwt/merge-live-text-dimensions :auto-width selrect {:width 0 :height 0})] + (t/is (= 50 (:width result))) + (t/is (= 25 (:height result)))))) diff --git a/frontend/translations/en.po b/frontend/translations/en.po index c08ac11b60..0be9173e33 100644 --- a/frontend/translations/en.po +++ b/frontend/translations/en.po @@ -6741,6 +6741,14 @@ msgstr "Locate" msgid "workspace.layout-grid.editor.top-bar.locate.tooltip" msgstr "Locate grid layout" +#: src/app/main/ui/workspace/libraries.cljs:898 +msgid "workspace.libraries.add-shared-library" +msgstr "Add a shared library" + +#: src/app/main/ui/workspace/libraries.cljs:801 +msgid "workspace.libraries.assets-in-this-file" +msgstr "ASSETS IN THIS FILE" + #: src/app/main/ui/workspace/libraries.cljs:126, src/app/main/ui/workspace/libraries.cljs:155, src/app/main/ui/workspace/libraries.cljs:199 msgid "workspace.libraries.colors" msgid_plural "workspace.libraries.colors" @@ -6895,6 +6903,10 @@ msgstr "Unlink all assets" msgid "workspace.libraries.text.multiple-token-tooltip" msgstr "Detach all tokens" +#: src/app/main/ui/workspace/libraries.cljs:1136 +msgid "workspace.libraries.this-file" +msgstr "This file" + #: src/app/main/ui/workspace/libraries.cljs:167, src/app/main/ui/workspace/libraries.cljs:211 msgid "workspace.libraries.token-sets" msgid_plural "workspace.libraries.token-sets" diff --git a/frontend/translations/es.po b/frontend/translations/es.po index 717ef8179a..5715b6bba1 100644 --- a/frontend/translations/es.po +++ b/frontend/translations/es.po @@ -6830,6 +6830,14 @@ msgstr "Mostrar" msgid "workspace.layout-grid.editor.top-bar.locate.tooltip" msgstr "Mostrar grid layout" +#: src/app/main/ui/workspace/libraries.cljs:898 +msgid "workspace.libraries.add-shared-library" +msgstr "Añadir una biblioteca compartida" + +#: src/app/main/ui/workspace/libraries.cljs:801 +msgid "workspace.libraries.assets-in-this-file" +msgstr "RECURSOS EN ESTE ARCHIVO" + #: src/app/main/ui/workspace/libraries.cljs:126, src/app/main/ui/workspace/libraries.cljs:155, src/app/main/ui/workspace/libraries.cljs:199 msgid "workspace.libraries.colors" msgid_plural "workspace.libraries.colors" @@ -6984,6 +6992,10 @@ msgstr "Desvincular todos los recursos" msgid "workspace.libraries.text.multiple-token-tooltip" msgstr "Desvincular todos los tokens" +#: src/app/main/ui/workspace/libraries.cljs:1136 +msgid "workspace.libraries.this-file" +msgstr "Este archivo" + #: src/app/main/ui/workspace/libraries.cljs:167, src/app/main/ui/workspace/libraries.cljs:211 msgid "workspace.libraries.token-sets" msgid_plural "workspace.libraries.token-sets" diff --git a/mcp/packages/common/package.json b/mcp/packages/common/package.json index 6c1ef48621..e91b9ea873 100644 --- a/mcp/packages/common/package.json +++ b/mcp/packages/common/package.json @@ -12,7 +12,7 @@ "clean": "rm -rf dist/" }, "devDependencies": { - "typescript": "^7.0.2" + "typescript": "^6.0.3" }, "files": [ "dist/**/*" diff --git a/mcp/packages/plugin/package.json b/mcp/packages/plugin/package.json index 4d102f91f7..383f8cb76d 100644 --- a/mcp/packages/plugin/package.json +++ b/mcp/packages/plugin/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "cross-env": "^10.1.0", - "typescript": "^7.0.2", + "typescript": "^6.0.3", "vite": "^8.3.2", "vite-live-preview": "^0.4.0" } diff --git a/mcp/packages/server/package.json b/mcp/packages/server/package.json index b939e16c24..33a08f336c 100644 --- a/mcp/packages/server/package.json +++ b/mcp/packages/server/package.json @@ -56,7 +56,7 @@ "esbuild": "^0.28.1", "ts-node": "^10.9.2", "tsx": "^4.23.15", - "typescript": "^7.0.2" + "typescript": "^6.0.3" }, "ts-node": { "esm": true diff --git a/mcp/packages/server/src/logger.test.ts b/mcp/packages/server/src/logger.test.ts new file mode 100644 index 0000000000..ea0b6a0317 --- /dev/null +++ b/mcp/packages/server/src/logger.test.ts @@ -0,0 +1,14 @@ +import assert from "node:assert/strict"; +import test from "node:test"; +import { logTransportTargets } from "./logger"; + +test("test processes log to stdout instead of a transport worker thread", () => { + assert.deepEqual(logTransportTargets({ NODE_TEST_CONTEXT: "child-v8" }), []); +}); + +test("regular processes keep the configured pino transports", () => { + assert.deepEqual( + logTransportTargets({}).map((target) => target.target), + ["pino-pretty"] + ); +}); diff --git a/mcp/packages/server/src/logger.ts b/mcp/packages/server/src/logger.ts index 45cb359e90..e74f7cdda9 100644 --- a/mcp/packages/server/src/logger.ts +++ b/mcp/packages/server/src/logger.ts @@ -198,17 +198,31 @@ const transports: LogTransportProvider[] = [consoleTransport, fileTransport, lok */ export const logFilePath: string | undefined = fileTransport.getFilePath(); +/** + * The pino transport targets to configure, empty when the logger writes to stdout directly. + * + * @param env - environment to inspect, injectable for tests + * @returns the active transport targets, empty inside a node:test child process + */ +export function logTransportTargets(env: NodeJS.ProcessEnv = process.env): TransportTargetSpec[] { + if (env.NODE_TEST_CONTEXT !== undefined) { + return []; + } + return transports.map((t) => t.getTarget()).filter((target): target is TransportTargetSpec => target !== null); +} + +const transportTargets = logTransportTargets(); + /** * Logger instance configured with the active transports (console, optional file, optional Loki). + * + * Inside a node:test child process the transports are skipped and the logger writes to stdout, + * so the test process does not outlive its tests over a transport worker thread. */ export const logger = pino({ level: LOG_LEVEL, timestamp: pino.stdTimeFunctions.isoTime, - transport: { - targets: transports - .map((t) => t.getTarget()) - .filter((target): target is TransportTargetSpec => target !== null), - }, + ...(transportTargets.length > 0 ? { transport: { targets: transportTargets } } : {}), }); /** diff --git a/mcp/pnpm-lock.yaml b/mcp/pnpm-lock.yaml index 57f33744c2..9cf2bda79d 100644 --- a/mcp/pnpm-lock.yaml +++ b/mcp/pnpm-lock.yaml @@ -180,8 +180,8 @@ importers: packages/common: devDependencies: typescript: - specifier: ^7.0.2 - version: 7.0.2 + specifier: ^6.0.3 + version: 6.0.3 packages/plugin: dependencies: @@ -196,8 +196,8 @@ importers: specifier: ^10.1.0 version: 10.1.0 typescript: - specifier: ^7.0.2 - version: 7.0.2 + specifier: ^6.0.3 + version: 6.0.3 vite: specifier: ^8.3.2 version: 8.3.2(@types/node@26.6.4)(esbuild@0.28.2)(tsx@4.23.15) @@ -279,13 +279,13 @@ importers: version: 0.28.2 ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@26.6.4)(typescript@7.0.2) + version: 10.9.2(@types/node@26.6.4)(typescript@6.0.3) tsx: specifier: ^4.23.15 version: 4.23.15 typescript: - specifier: ^7.0.2 - version: 7.0.2 + specifier: ^6.0.3 + version: 6.0.3 packages: @@ -819,126 +819,6 @@ packages: '@types/ws@8.18.2': resolution: {integrity: sha512-67MQl+fpWKVTT1NYdnmo3U4sc/xPo/zQBncVnI74qmQa0z/b+1g6iYqNmGCPbxO+zz2aklb08a0oHfegiVd0/w==} - '@typescript/typescript-aix-ppc64@7.0.2': - resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} - engines: {node: '>=16.20.0'} - cpu: [ppc64] - os: [aix] - - '@typescript/typescript-darwin-arm64@7.0.2': - resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [darwin] - - '@typescript/typescript-darwin-x64@7.0.2': - resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [darwin] - - '@typescript/typescript-freebsd-arm64@7.0.2': - resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [freebsd] - - '@typescript/typescript-freebsd-x64@7.0.2': - resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [freebsd] - - '@typescript/typescript-linux-arm64@7.0.2': - resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [linux] - - '@typescript/typescript-linux-arm@7.0.2': - resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} - engines: {node: '>=16.20.0'} - cpu: [arm] - os: [linux] - - '@typescript/typescript-linux-loong64@7.0.2': - resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} - engines: {node: '>=16.20.0'} - cpu: [loong64] - os: [linux] - - '@typescript/typescript-linux-mips64el@7.0.2': - resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} - engines: {node: '>=16.20.0'} - cpu: [mips64el] - os: [linux] - - '@typescript/typescript-linux-ppc64@7.0.2': - resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} - engines: {node: '>=16.20.0'} - cpu: [ppc64] - os: [linux] - - '@typescript/typescript-linux-riscv64@7.0.2': - resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} - engines: {node: '>=16.20.0'} - cpu: [riscv64] - os: [linux] - - '@typescript/typescript-linux-s390x@7.0.2': - resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} - engines: {node: '>=16.20.0'} - cpu: [s390x] - os: [linux] - - '@typescript/typescript-linux-x64@7.0.2': - resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [linux] - - '@typescript/typescript-netbsd-arm64@7.0.2': - resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [netbsd] - - '@typescript/typescript-netbsd-x64@7.0.2': - resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [netbsd] - - '@typescript/typescript-openbsd-arm64@7.0.2': - resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [openbsd] - - '@typescript/typescript-openbsd-x64@7.0.2': - resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [openbsd] - - '@typescript/typescript-sunos-x64@7.0.2': - resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [sunos] - - '@typescript/typescript-win32-arm64@7.0.2': - resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} - engines: {node: '>=16.20.0'} - cpu: [arm64] - os: [win32] - - '@typescript/typescript-win32-x64@7.0.2': - resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} - engines: {node: '>=16.20.0'} - cpu: [x64] - os: [win32] - accepts@2.0.0: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} @@ -1614,9 +1494,9 @@ packages: resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} engines: {node: '>= 18'} - typescript@7.0.2: - resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} - engines: {node: '>=16.20.0'} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} + engines: {node: '>=14.17'} hasBin: true undici-types@8.9.0: @@ -2079,66 +1959,6 @@ snapshots: dependencies: '@types/node': 26.6.4 - '@typescript/typescript-aix-ppc64@7.0.2': - optional: true - - '@typescript/typescript-darwin-arm64@7.0.2': - optional: true - - '@typescript/typescript-darwin-x64@7.0.2': - optional: true - - '@typescript/typescript-freebsd-arm64@7.0.2': - optional: true - - '@typescript/typescript-freebsd-x64@7.0.2': - optional: true - - '@typescript/typescript-linux-arm64@7.0.2': - optional: true - - '@typescript/typescript-linux-arm@7.0.2': - optional: true - - '@typescript/typescript-linux-loong64@7.0.2': - optional: true - - '@typescript/typescript-linux-mips64el@7.0.2': - optional: true - - '@typescript/typescript-linux-ppc64@7.0.2': - optional: true - - '@typescript/typescript-linux-riscv64@7.0.2': - optional: true - - '@typescript/typescript-linux-s390x@7.0.2': - optional: true - - '@typescript/typescript-linux-x64@7.0.2': - optional: true - - '@typescript/typescript-netbsd-arm64@7.0.2': - optional: true - - '@typescript/typescript-netbsd-x64@7.0.2': - optional: true - - '@typescript/typescript-openbsd-arm64@7.0.2': - optional: true - - '@typescript/typescript-openbsd-x64@7.0.2': - optional: true - - '@typescript/typescript-sunos-x64@7.0.2': - optional: true - - '@typescript/typescript-win32-arm64@7.0.2': - optional: true - - '@typescript/typescript-win32-x64@7.0.2': - optional: true - accepts@2.0.0: dependencies: mime-types: 3.0.2 @@ -2826,7 +2646,7 @@ snapshots: tree-kill@1.2.2: {} - ts-node@10.9.2(@types/node@26.6.4)(typescript@7.0.2): + ts-node@10.9.2(@types/node@26.6.4)(typescript@6.0.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.13 @@ -2840,7 +2660,7 @@ snapshots: create-require: 1.1.1 diff: 4.0.4 make-error: 1.3.6 - typescript: 7.0.2 + typescript: 6.0.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 @@ -2858,28 +2678,7 @@ snapshots: media-typer: 1.1.1 mime-types: 3.0.2 - typescript@7.0.2: - optionalDependencies: - '@typescript/typescript-aix-ppc64': 7.0.2 - '@typescript/typescript-darwin-arm64': 7.0.2 - '@typescript/typescript-darwin-x64': 7.0.2 - '@typescript/typescript-freebsd-arm64': 7.0.2 - '@typescript/typescript-freebsd-x64': 7.0.2 - '@typescript/typescript-linux-arm': 7.0.2 - '@typescript/typescript-linux-arm64': 7.0.2 - '@typescript/typescript-linux-loong64': 7.0.2 - '@typescript/typescript-linux-mips64el': 7.0.2 - '@typescript/typescript-linux-ppc64': 7.0.2 - '@typescript/typescript-linux-riscv64': 7.0.2 - '@typescript/typescript-linux-s390x': 7.0.2 - '@typescript/typescript-linux-x64': 7.0.2 - '@typescript/typescript-netbsd-arm64': 7.0.2 - '@typescript/typescript-netbsd-x64': 7.0.2 - '@typescript/typescript-openbsd-arm64': 7.0.2 - '@typescript/typescript-openbsd-x64': 7.0.2 - '@typescript/typescript-sunos-x64': 7.0.2 - '@typescript/typescript-win32-arm64': 7.0.2 - '@typescript/typescript-win32-x64': 7.0.2 + typescript@6.0.3: {} undici-types@8.9.0: {}