From b60bbdd052dc90e50902adda3d275e974bdde78f Mon Sep 17 00:00:00 2001 From: "Tommy D. Rossi" Date: Wed, 11 Feb 2026 16:51:47 +0100 Subject: [PATCH] release: playwriter@0.0.58 --- playwriter/CHANGELOG.md | 11 ++ playwriter/package.json | 5 +- playwriter/src/cli.ts | 4 +- playwriter/src/kill-port.ts | 167 +++++++++++++++++++++++++++++++ playwriter/src/relay-client.ts | 4 +- playwriter/src/test-utils.ts | 4 +- playwriter/test/security.test.ts | 4 +- pnpm-lock.yaml | 138 ++----------------------- 8 files changed, 198 insertions(+), 139 deletions(-) create mode 100644 playwriter/src/kill-port.ts diff --git a/playwriter/CHANGELOG.md b/playwriter/CHANGELOG.md index 46c1054..b5a325b 100644 --- a/playwriter/CHANGELOG.md +++ b/playwriter/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## 0.0.58 + +### Bug Fixes + +- **Fix `bunx playwriter@latest` relay restarts**: Replaced `kill-port-process` with a vendored cross-platform port killer to avoid runtime crashes during version-mismatch restart flows. +- **Harden relay port cleanup behavior**: Unified relay/test/serve port termination through local `killPortProcess({ port })` helper with Windows/macOS/Linux support. + +### Internal + +- **Removed `kill-port-process` dependency**: Dropped external dependency and updated lockfile to reduce transitive process-management packages. + ## 0.0.57 ### Features diff --git a/playwriter/package.json b/playwriter/package.json index f84a640..94625d8 100644 --- a/playwriter/package.json +++ b/playwriter/package.json @@ -1,7 +1,7 @@ { "name": "playwriter", "description": "", - "version": "0.0.57", + "version": "0.0.58", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", @@ -46,14 +46,13 @@ "@hono/node-ws": "^1.2.0", "@modelcontextprotocol/sdk": "^1.25.2", "@xmorse/cac": "^6.0.7", + "@xmorse/playwright-core": "workspace:*", "acorn": "^8.15.0", "async-sema": "^3.1.1", "diff": "^8.0.2", "dom-accessibility-api": "^0.7.1", "hono": "^4.10.6", - "kill-port-process": "^3.2.1", "picocolors": "^1.1.1", - "@xmorse/playwright-core": "workspace:*", "posthtml": "^0.16.7", "posthtml-beautify": "^0.7.0", "string-dedent": "^3.0.2", diff --git a/playwriter/src/cli.ts b/playwriter/src/cli.ts index 8586bb8..2089564 100644 --- a/playwriter/src/cli.ts +++ b/playwriter/src/cli.ts @@ -4,6 +4,7 @@ import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' import { cac } from '@xmorse/cac' +import { killPortProcess } from './kill-port.js' import { VERSION, LOG_FILE_PATH, LOG_CDP_FILE_PATH } from './utils.js' import { ensureRelayServer, RELAY_PORT, waitForExtension } from './relay-client.js' @@ -433,8 +434,7 @@ cli // Kill existing process on the port console.log(`Killing existing server on port ${RELAY_PORT}...`) - const { killPortProcess } = await import('kill-port-process') - await killPortProcess(RELAY_PORT) + await killPortProcess({ port: RELAY_PORT }) } // Lazy-load heavy dependencies only when serve command is used diff --git a/playwriter/src/kill-port.ts b/playwriter/src/kill-port.ts new file mode 100644 index 0000000..e4488e7 --- /dev/null +++ b/playwriter/src/kill-port.ts @@ -0,0 +1,167 @@ +/** + * Cross-platform process termination for a TCP port. + * Replaces external kill-port-process dependency for bunx/runtime stability. + */ + +import { execFile } from 'node:child_process' +import os from 'node:os' +import { promisify } from 'node:util' + +const execFileAsync = promisify(execFile) + +function isValidPort(port: number): boolean { + return Number.isInteger(port) && port > 0 && port <= 65535 +} + +function parsePids(output: string): number[] { + const pids = output + .split(/\r?\n/g) + .map((line) => { + return line.trim() + }) + .filter((line) => { + return Boolean(line) + }) + .map((line) => { + return Number(line) + }) + .filter((pid) => { + return Number.isInteger(pid) && pid > 0 + }) + + return [...new Set(pids)] +} + +function parseWindowsNetstatPids(output: string, port: number): number[] { + const rows = output + .split(/\r?\n/g) + .map((line) => { + return line.trim() + }) + .filter((line) => { + return line.startsWith('TCP') + }) + + const pids = rows + .map((row) => { + const columns = row.split(/\s+/g) + const localAddress = columns[1] || '' + const state = columns[3] || '' + const pid = columns[4] || '' + const endsWithPort = localAddress.endsWith(`:${port}`) + if (!endsWithPort || state !== 'LISTENING') { + return NaN + } + return Number(pid) + }) + .filter((pid) => { + return Number.isInteger(pid) && pid > 0 + }) + + return [...new Set(pids)] +} + +async function getPidsForPortWindows(port: number): Promise { + const powerShellScript = [ + "$ErrorActionPreference='SilentlyContinue'", + `@(Get-NetTCPConnection -LocalPort ${port} -State Listen | Select-Object -ExpandProperty OwningProcess -Unique) -join [Environment]::NewLine`, + ].join('; ') + + try { + const { stdout } = await execFileAsync('powershell', ['-NoProfile', '-Command', powerShellScript]) + const pids = parsePids(stdout) + if (pids.length > 0) { + return pids + } + } catch {} + + try { + const { stdout } = await execFileAsync('cmd', ['/d', '/s', '/c', 'netstat -ano -p tcp']) + return parseWindowsNetstatPids(stdout, port) + } catch { + return [] + } +} + +async function getPidsForPortUnix(port: number): Promise { + try { + const { stdout } = await execFileAsync('lsof', ['-nP', '-iTCP:' + String(port), '-sTCP:LISTEN', '-t']) + const pids = parsePids(stdout) + if (pids.length > 0) { + return pids + } + } catch {} + + try { + const { stdout } = await execFileAsync('fuser', [`${port}/tcp`]) + return parsePids(stdout) + } catch { + return [] + } +} + +function sleep(ms: number): Promise { + return new Promise((resolve) => { + setTimeout(resolve, ms) + }) +} + +function isProcessAlive(pid: number): boolean { + try { + process.kill(pid, 0) + return true + } catch { + return false + } +} + +async function terminatePidWindows(pid: number): Promise { + try { + await execFileAsync('taskkill', ['/PID', String(pid), '/T', '/F']) + } catch {} +} + +async function terminatePidUnix(pid: number): Promise { + try { + process.kill(pid, 'SIGTERM') + } catch { + return + } + + await sleep(200) + if (!isProcessAlive(pid)) { + return + } + + try { + process.kill(pid, 'SIGKILL') + } catch {} +} + +/** + * Kill any listening process bound to the provided TCP port. + */ +export async function killPortProcess({ port }: { port: number }): Promise { + if (!isValidPort(port)) { + throw new Error(`Invalid port: ${port}`) + } + + const pids = os.platform() === 'win32' + ? await getPidsForPortWindows(port) + : await getPidsForPortUnix(port) + + const currentPid = process.pid + const targetPids = pids.filter((pid) => { + return pid !== currentPid + }) + + await Promise.all( + targetPids.map(async (pid) => { + if (os.platform() === 'win32') { + await terminatePidWindows(pid) + return + } + await terminatePidUnix(pid) + }), + ) +} diff --git a/playwriter/src/relay-client.ts b/playwriter/src/relay-client.ts index c605edd..6d25edf 100644 --- a/playwriter/src/relay-client.ts +++ b/playwriter/src/relay-client.ts @@ -6,8 +6,8 @@ import { spawn } from 'node:child_process' import path from 'node:path' import { fileURLToPath } from 'node:url' -import { killPortProcess } from 'kill-port-process' import pc from 'picocolors' +import { killPortProcess } from './kill-port.js' import { VERSION, sleep, LOG_FILE_PATH } from './utils.js' const __filename = fileURLToPath(import.meta.url) @@ -73,7 +73,7 @@ export async function waitForExtension(options: { async function killRelayServer(port: number): Promise { try { - await killPortProcess(port) + await killPortProcess({ port }) await sleep(500) } catch {} } diff --git a/playwriter/src/test-utils.ts b/playwriter/src/test-utils.ts index 37bd64b..887664f 100644 --- a/playwriter/src/test-utils.ts +++ b/playwriter/src/test-utils.ts @@ -8,7 +8,7 @@ import fs from 'node:fs' import os from 'node:os' import { startPlayWriterCDPRelayServer, type RelayServer } from './cdp-relay.js' import { createFileLogger } from './create-logger.js' -import { killPortProcess } from 'kill-port-process' +import { killPortProcess } from './kill-port.js' const execAsync = promisify(exec) const extensionBuildQueues: Map> = new Map() @@ -67,7 +67,7 @@ export async function setupTestContext({ /** Create initial page and toggle extension on it */ toggleExtension?: boolean }): Promise { - await killPortProcess(port).catch(() => {}) + await killPortProcess({ port }).catch(() => {}) // Use a port-scoped dist folder so parallel tests don't replace each other's extension builds. const distDir = `dist-${port}` diff --git a/playwriter/test/security.test.ts b/playwriter/test/security.test.ts index dedf23a..48f97b7 100644 --- a/playwriter/test/security.test.ts +++ b/playwriter/test/security.test.ts @@ -2,14 +2,14 @@ import { describe, it, expect, afterEach } from 'vitest' import { startPlayWriterCDPRelayServer } from '../src/cdp-relay.js' import { WebSocket } from 'ws' -import { killPortProcess } from 'kill-port-process' import { createFileLogger } from '../src/create-logger.js' +import { killPortProcess } from '../src/kill-port.js' const TEST_PORT = 19999 async function killProcessOnPort(port: number): Promise { try { - await killPortProcess(port) + await killPortProcess({ port }) } catch (err) { // Ignore if no process is running } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7bba633..368282a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -332,9 +332,6 @@ importers: hono: specifier: ^4.10.6 version: 4.10.6 - kill-port-process: - specifier: ^3.2.1 - version: 3.2.1 picocolors: specifier: ^1.1.1 version: 1.1.1 @@ -3489,9 +3486,6 @@ packages: engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} hasBin: true - cross-spawn@5.1.0: - resolution: {integrity: sha512-pTgQJ5KC0d2hcY8eyL1IzlBPYjTkyH72XRZPnLyKus2mBfNjQs3klqbJU2VILqZryAZUt9JOb3h/mWMy23/f5A==} - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -3978,10 +3972,6 @@ packages: resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} engines: {node: '>=18.0.0'} - execa@0.9.0: - resolution: {integrity: sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==} - engines: {node: '>=4'} - exit-hook@2.2.1: resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} engines: {node: '>=6'} @@ -4227,10 +4217,6 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-stream@3.0.0: - resolution: {integrity: sha512-GlhdIUuVakc8SJ6kK0zAFbiGzRFzNnY4jUuEbV9UROo4Y+0Ny4fjvcZFVTeDA4odpFyOQzaw6hXukJSq/f28sQ==} - engines: {node: '>=4'} - get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -4243,9 +4229,6 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-them-args@1.3.2: - resolution: {integrity: sha512-LRn8Jlk+DwZE4GTlDbT3Hikd1wSHgLMme/+7ddlqKd7ldwR6LjJgTVWzBnR01wnYGe4KgrXjg287RaI22UHmAw==} - get-tsconfig@4.13.0: resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} @@ -4573,10 +4556,6 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} - is-stream@1.1.0: - resolution: {integrity: sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==} - engines: {node: '>=0.10.0'} - is-stream@4.0.1: resolution: {integrity: sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==} engines: {node: '>=18'} @@ -4743,11 +4722,6 @@ packages: keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - kill-port-process@3.2.1: - resolution: {integrity: sha512-9rRL5uivhIaW82ES0xTeciG5dfHUVQ0MqUycyf6Y1GBzDNB/fHxKStFUqnL4hCwGp89AcrKIjJWEVZHhSUi9LQ==} - engines: {node: '>=14'} - hasBin: true - langsmith@0.3.82: resolution: {integrity: sha512-RTcxtRm0zp2lV+pMesMW7EZSsIlqN7OmR2F6sZ/sOFQwmcLVl+VErMPV4VkX4Sycs4/EIAFT5hpr36EqiHoikQ==} peerDependencies: @@ -4882,9 +4856,6 @@ packages: resolution: {integrity: sha512-vFrFJkWtJvJnD5hg+hJvVE8Lh/TcMzKnTgCWmtBipwI5yLX/iX+5UB2tfuyODF5E7k9xEzMdYgGqaSb1c0c5Yw==} engines: {node: 20 || >=22} - lru-cache@4.1.5: - resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} - lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -5114,10 +5085,6 @@ packages: npm-normalize-package-bin@1.0.1: resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} - npm-run-path@2.0.2: - resolution: {integrity: sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==} - engines: {node: '>=4'} - object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -5322,10 +5289,6 @@ packages: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} - path-key@2.0.1: - resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==} - engines: {node: '>=4'} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -5378,10 +5341,6 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - pid-from-port@1.1.3: - resolution: {integrity: sha512-OlE82n3yMOE5dY9RMOwxhoWefeMlxwk5IVxoj0sSzSFIlmvhN4obzTvO3s/d/b5JhcgXikjaspsy/HuUDTqbBg==} - engines: {node: '>=4'} - pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} @@ -5523,9 +5482,6 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - pseudomap@1.0.2: - resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} - pump@3.0.3: resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} @@ -5821,18 +5777,10 @@ packages: resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - shebang-command@1.2.0: - resolution: {integrity: sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==} - engines: {node: '>=0.10.0'} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} - shebang-regex@1.0.0: - resolution: {integrity: sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==} - engines: {node: '>=0.10.0'} - shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} @@ -5863,9 +5811,6 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -6010,10 +5955,6 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - strip-eof@1.0.0: - resolution: {integrity: sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==} - engines: {node: '>=0.10.0'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -6625,10 +6566,6 @@ packages: resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} engines: {node: '>= 0.4'} - which@1.3.1: - resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==} - hasBin: true - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -6713,9 +6650,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yallist@2.1.2: - resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} - yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -9530,6 +9464,14 @@ snapshots: optionalDependencies: vite: 7.3.0(@types/node@25.0.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.6.0) + '@vitest/mocker@4.0.8(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.6.0))': + dependencies: + '@vitest/spy': 4.0.8 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.2.2(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.6.0) + '@vitest/mocker@4.0.8(vite@7.2.2(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.6.0))': dependencies: '@vitest/spy': 4.0.8 @@ -9581,7 +9523,7 @@ snapshots: sirv: 3.0.2 tinyglobby: 0.2.15 tinyrainbow: 3.0.3 - vitest: 4.0.8(@types/node@25.2.0)(@vitest/ui@4.0.8)(jiti@2.6.1)(jsdom@27.2.0(bufferutil@4.0.9))(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.6.0) + vitest: 4.0.8(@types/node@24.10.1)(@vitest/ui@4.0.8)(jiti@2.6.1)(jsdom@27.2.0(bufferutil@4.0.9))(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.6.0) '@vitest/utils@4.0.16': dependencies: @@ -10189,12 +10131,6 @@ snapshots: dependencies: cross-spawn: 7.0.6 - cross-spawn@5.1.0: - dependencies: - lru-cache: 4.1.5 - shebang-command: 1.2.0 - which: 1.3.1 - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -10831,16 +10767,6 @@ snapshots: dependencies: eventsource-parser: 3.0.6 - execa@0.9.0: - dependencies: - cross-spawn: 5.1.0 - get-stream: 3.0.0 - is-stream: 1.1.0 - npm-run-path: 2.0.2 - p-finally: 1.0.0 - signal-exit: 3.0.7 - strip-eof: 1.0.0 - exit-hook@2.2.1: {} expect-type@1.2.2: {} @@ -11182,8 +11108,6 @@ snapshots: dunder-proto: 1.0.1 es-object-atoms: 1.1.1 - get-stream@3.0.0: {} - get-stream@5.2.0: dependencies: pump: 3.0.3 @@ -11199,8 +11123,6 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-them-args@1.3.2: {} - get-tsconfig@4.13.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -11580,8 +11502,6 @@ snapshots: dependencies: call-bound: 1.0.4 - is-stream@1.1.0: {} - is-stream@4.0.1: {} is-string@1.1.1: @@ -11768,11 +11688,6 @@ snapshots: dependencies: json-buffer: 3.0.1 - kill-port-process@3.2.1: - dependencies: - get-them-args: 1.3.2 - pid-from-port: 1.1.3 - langsmith@0.3.82(@opentelemetry/api@1.9.0)(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(openai@4.104.0(ws@8.19.0(bufferutil@4.0.9))(zod@4.3.5)): dependencies: '@types/uuid': 10.0.0 @@ -11892,11 +11807,6 @@ snapshots: lru-cache@11.2.5: optional: true - lru-cache@4.1.5: - dependencies: - pseudomap: 1.0.2 - yallist: 2.1.2 - lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -12068,10 +11978,6 @@ snapshots: npm-normalize-package-bin@1.0.1: {} - npm-run-path@2.0.2: - dependencies: - path-key: 2.0.1 - object-assign@4.1.1: {} object-inspect@1.13.4: {} @@ -12301,8 +12207,6 @@ snapshots: path-is-absolute@1.0.1: {} - path-key@2.0.1: {} - path-key@3.1.1: {} path-parse@1.0.7: {} @@ -12342,10 +12246,6 @@ snapshots: picomatch@4.0.3: {} - pid-from-port@1.1.3: - dependencies: - execa: 0.9.0 - pify@4.0.1: {} pino-abstract-transport@2.0.0: @@ -12500,8 +12400,6 @@ snapshots: proxy-from-env@1.1.0: {} - pseudomap@1.0.2: {} - pump@3.0.3: dependencies: end-of-stream: 1.4.5 @@ -12952,16 +12850,10 @@ snapshots: '@img/sharp-win32-x64': 0.34.5 optional: true - shebang-command@1.2.0: - dependencies: - shebang-regex: 1.0.0 - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - shebang-regex@1.0.0: {} - shebang-regex@3.0.0: {} shell-quote@1.8.3: {} @@ -12998,8 +12890,6 @@ snapshots: siginfo@2.0.0: {} - signal-exit@3.0.7: {} - signal-exit@4.1.0: {} simple-wcswidth@1.1.2: {} @@ -13175,8 +13065,6 @@ snapshots: strip-bom@3.0.0: {} - strip-eof@1.0.0: {} - strip-json-comments@3.1.1: {} strip-json-comments@5.0.3: {} @@ -13670,7 +13558,7 @@ snapshots: vitest@4.0.8(@types/node@24.10.1)(@vitest/ui@4.0.8)(jiti@2.6.1)(jsdom@27.2.0(bufferutil@4.0.9))(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.6.0): dependencies: '@vitest/expect': 4.0.8 - '@vitest/mocker': 4.0.8(vite@7.2.2(@types/node@25.2.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.6.0)) + '@vitest/mocker': 4.0.8(vite@7.2.2(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.6)(yaml@2.6.0)) '@vitest/pretty-format': 4.0.8 '@vitest/runner': 4.0.8 '@vitest/snapshot': 4.0.8 @@ -13826,10 +13714,6 @@ snapshots: gopd: 1.2.0 has-tostringtag: 1.0.2 - which@1.3.1: - dependencies: - isexe: 2.0.0 - which@2.0.2: dependencies: isexe: 2.0.0 @@ -13884,8 +13768,6 @@ snapshots: y18n@5.0.8: {} - yallist@2.1.2: {} - yallist@3.1.1: {} yaml@2.6.0: {}