From d7b98a72b4aa6303b179edead3dfa0b1ba73ebc3 Mon Sep 17 00:00:00 2001 From: online5880 Date: Mon, 9 Mar 2026 21:52:06 +0900 Subject: [PATCH 1/4] fix: support Windows command wrappers for local adapters --- package.json | 3 +- packages/adapter-utils/src/server-utils.ts | 247 +++++++++++------- pnpm-lock.yaml | 53 ++-- server/package.json | 2 +- .../codex-local-adapter-environment.test.ts | 43 +++ 5 files changed, 217 insertions(+), 131 deletions(-) diff --git a/package.json b/package.json index 45c02b8b..8b35d0ba 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "type": "module", "scripts": { "dev": "node scripts/dev-runner.mjs watch", - "dev:watch": "PAPERCLIP_MIGRATION_PROMPT=never node scripts/dev-runner.mjs watch", + "dev:watch": "cross-env PAPERCLIP_MIGRATION_PROMPT=never node scripts/dev-runner.mjs watch", "dev:once": "node scripts/dev-runner.mjs dev", "dev:server": "pnpm --filter @paperclipai/server dev", "dev:ui": "pnpm --filter @paperclipai/ui dev", @@ -29,6 +29,7 @@ }, "devDependencies": { "@changesets/cli": "^2.30.0", + "cross-env": "^10.1.0", "esbuild": "^0.27.3", "typescript": "^5.7.3", "vitest": "^3.0.5" diff --git a/packages/adapter-utils/src/server-utils.ts b/packages/adapter-utils/src/server-utils.ts index 76efba86..8a296191 100644 --- a/packages/adapter-utils/src/server-utils.ts +++ b/packages/adapter-utils/src/server-utils.ts @@ -15,6 +15,11 @@ interface RunningProcess { graceSec: number; } +interface SpawnTarget { + command: string; + args: string[]; +} + type ChildProcessWithEvents = ChildProcess & { on(event: "error", listener: (err: Error) => void): ChildProcess; on( @@ -125,6 +130,78 @@ export function defaultPathForPlatform() { return "/usr/local/bin:/opt/homebrew/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin"; } +function windowsPathExts(env: NodeJS.ProcessEnv): string[] { + return (env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";").filter(Boolean); +} + +async function pathExists(candidate: string) { + try { + await fs.access(candidate, fsConstants.X_OK); + return true; + } catch { + return false; + } +} + +async function resolveCommandPath(command: string, cwd: string, env: NodeJS.ProcessEnv): Promise { + const hasPathSeparator = command.includes("/") || command.includes("\\"); + if (hasPathSeparator) { + const absolute = path.isAbsolute(command) ? command : path.resolve(cwd, command); + return (await pathExists(absolute)) ? absolute : null; + } + + const pathValue = env.PATH ?? env.Path ?? ""; + const delimiter = process.platform === "win32" ? ";" : ":"; + const dirs = pathValue.split(delimiter).filter(Boolean); + const exts = process.platform === "win32" ? windowsPathExts(env) : [""]; + const hasExtension = process.platform === "win32" && path.extname(command).length > 0; + + for (const dir of dirs) { + const candidates = + process.platform === "win32" + ? hasExtension + ? [path.join(dir, command)] + : exts.map((ext) => path.join(dir, `${command}${ext}`)) + : [path.join(dir, command)]; + for (const candidate of candidates) { + if (await pathExists(candidate)) return candidate; + } + } + + return null; +} + +function quoteForCmd(arg: string) { + if (!arg.length) return '""'; + const escaped = arg.replace(/"/g, '""').replace(/%/g, "%%"); + return /[\s"&<>|^()]/.test(escaped) ? `"${escaped}"` : escaped; +} + +async function resolveSpawnTarget( + command: string, + args: string[], + cwd: string, + env: NodeJS.ProcessEnv, +): Promise { + const resolved = await resolveCommandPath(command, cwd, env); + const executable = resolved ?? command; + + if (process.platform !== "win32") { + return { command: executable, args }; + } + + if (/\.(cmd|bat)$/i.test(executable)) { + const shell = env.ComSpec || process.env.ComSpec || "cmd.exe"; + const commandLine = [quoteForCmd(executable), ...args.map(quoteForCmd)].join(" "); + return { + command: shell, + args: ["/d", "/s", "/c", commandLine], + }; + } + + return { command: executable, args }; +} + export function ensurePathInEnv(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv { if (typeof env.PATH === "string" && env.PATH.length > 0) return env; if (typeof env.Path === "string" && env.Path.length > 0) return env; @@ -169,36 +246,12 @@ export async function ensureAbsoluteDirectory( } export async function ensureCommandResolvable(command: string, cwd: string, env: NodeJS.ProcessEnv) { - const hasPathSeparator = command.includes("/") || command.includes("\\"); - if (hasPathSeparator) { + const resolved = await resolveCommandPath(command, cwd, env); + if (resolved) return; + if (command.includes("/") || command.includes("\\")) { const absolute = path.isAbsolute(command) ? command : path.resolve(cwd, command); - try { - await fs.access(absolute, fsConstants.X_OK); - } catch { - throw new Error(`Command is not executable: "${command}" (resolved: "${absolute}")`); - } - return; + throw new Error(`Command is not executable: "${command}" (resolved: "${absolute}")`); } - - const pathValue = env.PATH ?? env.Path ?? ""; - const delimiter = process.platform === "win32" ? ";" : ":"; - const dirs = pathValue.split(delimiter).filter(Boolean); - const windowsExt = process.platform === "win32" - ? (env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM").split(";") - : [""]; - - for (const dir of dirs) { - for (const ext of windowsExt) { - const candidate = path.join(dir, process.platform === "win32" ? `${command}${ext}` : command); - try { - await fs.access(candidate, fsConstants.X_OK); - return; - } catch { - // continue scanning PATH - } - } - } - throw new Error(`Command not found in PATH: "${command}"`); } @@ -220,78 +273,82 @@ export async function runChildProcess( return new Promise((resolve, reject) => { const mergedEnv = ensurePathInEnv({ ...process.env, ...opts.env }); - const child = spawn(command, args, { - cwd: opts.cwd, - env: mergedEnv, - shell: false, - stdio: [opts.stdin != null ? "pipe" : "ignore", "pipe", "pipe"], - }) as ChildProcessWithEvents; + void resolveSpawnTarget(command, args, opts.cwd, mergedEnv) + .then((target) => { + const child = spawn(target.command, target.args, { + cwd: opts.cwd, + env: mergedEnv, + shell: false, + stdio: [opts.stdin != null ? "pipe" : "ignore", "pipe", "pipe"], + }) as ChildProcessWithEvents; - if (opts.stdin != null && child.stdin) { - child.stdin.write(opts.stdin); - child.stdin.end(); - } + if (opts.stdin != null && child.stdin) { + child.stdin.write(opts.stdin); + child.stdin.end(); + } - runningProcesses.set(runId, { child, graceSec: opts.graceSec }); + runningProcesses.set(runId, { child, graceSec: opts.graceSec }); - let timedOut = false; - let stdout = ""; - let stderr = ""; - let logChain: Promise = Promise.resolve(); + let timedOut = false; + let stdout = ""; + let stderr = ""; + let logChain: Promise = Promise.resolve(); - const timeout = - opts.timeoutSec > 0 - ? setTimeout(() => { - timedOut = true; - child.kill("SIGTERM"); - setTimeout(() => { - if (!child.killed) { - child.kill("SIGKILL"); - } - }, Math.max(1, opts.graceSec) * 1000); - }, opts.timeoutSec * 1000) - : null; + const timeout = + opts.timeoutSec > 0 + ? setTimeout(() => { + timedOut = true; + child.kill("SIGTERM"); + setTimeout(() => { + if (!child.killed) { + child.kill("SIGKILL"); + } + }, Math.max(1, opts.graceSec) * 1000); + }, opts.timeoutSec * 1000) + : null; - child.stdout?.on("data", (chunk: unknown) => { - const text = String(chunk); - stdout = appendWithCap(stdout, text); - logChain = logChain - .then(() => opts.onLog("stdout", text)) - .catch((err) => onLogError(err, runId, "failed to append stdout log chunk")); - }); - - child.stderr?.on("data", (chunk: unknown) => { - const text = String(chunk); - stderr = appendWithCap(stderr, text); - logChain = logChain - .then(() => opts.onLog("stderr", text)) - .catch((err) => onLogError(err, runId, "failed to append stderr log chunk")); - }); - - child.on("error", (err: Error) => { - if (timeout) clearTimeout(timeout); - runningProcesses.delete(runId); - const errno = (err as NodeJS.ErrnoException).code; - const pathValue = mergedEnv.PATH ?? mergedEnv.Path ?? ""; - const msg = - errno === "ENOENT" - ? `Failed to start command "${command}" in "${opts.cwd}". Verify adapter command, working directory, and PATH (${pathValue}).` - : `Failed to start command "${command}" in "${opts.cwd}": ${err.message}`; - reject(new Error(msg)); - }); - - child.on("close", (code: number | null, signal: NodeJS.Signals | null) => { - if (timeout) clearTimeout(timeout); - runningProcesses.delete(runId); - void logChain.finally(() => { - resolve({ - exitCode: code, - signal, - timedOut, - stdout, - stderr, + child.stdout?.on("data", (chunk: unknown) => { + const text = String(chunk); + stdout = appendWithCap(stdout, text); + logChain = logChain + .then(() => opts.onLog("stdout", text)) + .catch((err) => onLogError(err, runId, "failed to append stdout log chunk")); }); - }); - }); + + child.stderr?.on("data", (chunk: unknown) => { + const text = String(chunk); + stderr = appendWithCap(stderr, text); + logChain = logChain + .then(() => opts.onLog("stderr", text)) + .catch((err) => onLogError(err, runId, "failed to append stderr log chunk")); + }); + + child.on("error", (err: Error) => { + if (timeout) clearTimeout(timeout); + runningProcesses.delete(runId); + const errno = (err as NodeJS.ErrnoException).code; + const pathValue = mergedEnv.PATH ?? mergedEnv.Path ?? ""; + const msg = + errno === "ENOENT" + ? `Failed to start command "${command}" in "${opts.cwd}". Verify adapter command, working directory, and PATH (${pathValue}).` + : `Failed to start command "${command}" in "${opts.cwd}": ${err.message}`; + reject(new Error(msg)); + }); + + child.on("close", (code: number | null, signal: NodeJS.Signals | null) => { + if (timeout) clearTimeout(timeout); + runningProcesses.delete(runId); + void logChain.finally(() => { + resolve({ + exitCode: code, + signal, + timedOut, + stdout, + stderr, + }); + }); + }); + }) + .catch(reject); }); } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ff4f3e35..80270207 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,6 +11,9 @@ importers: '@changesets/cli': specifier: ^2.30.0 version: 2.30.0(@types/node@25.2.3) + cross-env: + specifier: ^10.1.0 + version: 10.1.0 esbuild: specifier: ^0.27.3 version: 0.27.3 @@ -35,9 +38,6 @@ importers: '@paperclipai/adapter-cursor-local': specifier: workspace:* version: link:../packages/adapters/cursor-local - '@paperclipai/adapter-openclaw': - specifier: workspace:* - version: link:../packages/adapters/openclaw '@paperclipai/adapter-openclaw-gateway': specifier: workspace:* version: link:../packages/adapters/openclaw-gateway @@ -139,22 +139,6 @@ importers: specifier: ^5.7.3 version: 5.9.3 - packages/adapters/openclaw: - dependencies: - '@paperclipai/adapter-utils': - specifier: workspace:* - version: link:../../adapter-utils - picocolors: - specifier: ^1.1.1 - version: 1.1.1 - devDependencies: - '@types/node': - specifier: ^24.6.0 - version: 24.12.0 - typescript: - specifier: ^5.7.3 - version: 5.9.3 - packages/adapters/openclaw-gateway: dependencies: '@paperclipai/adapter-utils': @@ -261,9 +245,6 @@ importers: '@paperclipai/adapter-cursor-local': specifier: workspace:* version: link:../packages/adapters/cursor-local - '@paperclipai/adapter-openclaw': - specifier: workspace:* - version: link:../packages/adapters/openclaw '@paperclipai/adapter-openclaw-gateway': specifier: workspace:* version: link:../packages/adapters/openclaw-gateway @@ -379,9 +360,6 @@ importers: '@paperclipai/adapter-cursor-local': specifier: workspace:* version: link:../packages/adapters/cursor-local - '@paperclipai/adapter-openclaw': - specifier: workspace:* - version: link:../packages/adapters/openclaw '@paperclipai/adapter-openclaw-gateway': specifier: workspace:* version: link:../packages/adapters/openclaw-gateway @@ -1011,6 +989,9 @@ packages: cpu: [x64] os: [win32] + '@epic-web/invariant@1.0.0': + resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} + '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.is' @@ -3441,6 +3422,11 @@ packages: crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} + cross-env@10.1.0: + resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==} + engines: {node: '>=20'} + hasBin: true + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -6743,6 +6729,8 @@ snapshots: '@embedded-postgres/windows-x64@18.1.0-beta.16': optional: true + '@epic-web/invariant@1.0.0': {} + '@esbuild-kit/core-utils@3.3.2': dependencies: esbuild: 0.18.20 @@ -8942,14 +8930,6 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))': - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))': dependencies: '@vitest/spy': 3.2.4 @@ -9253,6 +9233,11 @@ snapshots: crelt@1.0.6: {} + cross-env@10.1.0: + dependencies: + '@epic-web/invariant': 1.0.0 + cross-spawn: 7.0.6 + cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -11722,7 +11707,7 @@ snapshots: dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) + '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 diff --git a/server/package.json b/server/package.json index 3e74286b..2b3e1ed0 100644 --- a/server/package.json +++ b/server/package.json @@ -23,7 +23,7 @@ ], "scripts": { "dev": "tsx src/index.ts", - "dev:watch": "PAPERCLIP_MIGRATION_PROMPT=never tsx watch --ignore ../ui/node_modules --ignore ../ui/.vite --ignore ../ui/dist src/index.ts", + "dev:watch": "cross-env PAPERCLIP_MIGRATION_PROMPT=never tsx watch --ignore ../ui/node_modules --ignore ../ui/.vite --ignore ../ui/dist src/index.ts", "build": "tsc", "clean": "rm -rf dist", "start": "node dist/index.js", diff --git a/server/src/__tests__/codex-local-adapter-environment.test.ts b/server/src/__tests__/codex-local-adapter-environment.test.ts index 9814334d..bf42e47d 100644 --- a/server/src/__tests__/codex-local-adapter-environment.test.ts +++ b/server/src/__tests__/codex-local-adapter-environment.test.ts @@ -29,4 +29,47 @@ describe("codex_local environment diagnostics", () => { expect(stats.isDirectory()).toBe(true); await fs.rm(path.dirname(cwd), { recursive: true, force: true }); }); + + it("runs the hello probe when Codex is available via a Windows .cmd wrapper", async () => { + if (process.platform !== "win32") return; + + const root = path.join( + os.tmpdir(), + `paperclip-codex-local-probe-${Date.now()}-${Math.random().toString(16).slice(2)}`, + ); + const binDir = path.join(root, "bin"); + const cwd = path.join(root, "workspace"); + const fakeCodex = path.join(binDir, "codex.cmd"); + const script = [ + "@echo off", + "echo {\"type\":\"thread.started\",\"thread_id\":\"test-thread\"}", + "echo {\"type\":\"item.completed\",\"item\":{\"type\":\"agent_message\",\"text\":\"hello\"}}", + "echo {\"type\":\"turn.completed\",\"usage\":{\"input_tokens\":1,\"cached_input_tokens\":0,\"output_tokens\":1}}", + "exit /b 0", + "", + ].join("\r\n"); + + try { + await fs.mkdir(binDir, { recursive: true }); + await fs.writeFile(fakeCodex, script, "utf8"); + + const result = await testEnvironment({ + companyId: "company-1", + adapterType: "codex_local", + config: { + command: "codex", + cwd, + env: { + OPENAI_API_KEY: "test-key", + PATH: `${binDir}${path.delimiter}${process.env.PATH ?? ""}`, + }, + }, + }); + + expect(result.status).toBe("pass"); + expect(result.checks.some((check) => check.code === "codex_hello_probe_passed")).toBe(true); + } finally { + await fs.rm(root, { recursive: true, force: true }); + } + }); }); From f4a9788f2d5c69b14ba0a646ac68a5078fc338db Mon Sep 17 00:00:00 2001 From: online5880 Date: Mon, 9 Mar 2026 22:08:50 +0900 Subject: [PATCH 2/4] fix: tighten Windows adapter command handling --- packages/adapter-utils/src/server-utils.ts | 4 ++-- pnpm-lock.yaml | 13 ++++++++++++- server/package.json | 1 + .../codex-local-adapter-environment.test.ts | 6 +++--- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/adapter-utils/src/server-utils.ts b/packages/adapter-utils/src/server-utils.ts index 8a296191..3d273cd9 100644 --- a/packages/adapter-utils/src/server-utils.ts +++ b/packages/adapter-utils/src/server-utils.ts @@ -136,7 +136,7 @@ function windowsPathExts(env: NodeJS.ProcessEnv): string[] { async function pathExists(candidate: string) { try { - await fs.access(candidate, fsConstants.X_OK); + await fs.access(candidate, process.platform === "win32" ? fsConstants.F_OK : fsConstants.X_OK); return true; } catch { return false; @@ -173,7 +173,7 @@ async function resolveCommandPath(command: string, cwd: string, env: NodeJS.Proc function quoteForCmd(arg: string) { if (!arg.length) return '""'; - const escaped = arg.replace(/"/g, '""').replace(/%/g, "%%"); + const escaped = arg.replace(/"/g, '""'); return /[\s"&<>|^()]/.test(escaped) ? `"${escaped}"` : escaped; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 80270207..ff1442a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -321,6 +321,9 @@ importers: '@types/ws': specifier: ^8.18.1 version: 8.18.1 + cross-env: + specifier: ^10.1.0 + version: 10.1.0 supertest: specifier: ^7.0.0 version: 7.2.2 @@ -8930,6 +8933,14 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 + '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0) + '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0))': dependencies: '@vitest/spy': 3.2.4 @@ -11707,7 +11718,7 @@ snapshots: dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.2.3)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) + '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@24.12.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.21.0)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 diff --git a/server/package.json b/server/package.json index 2b3e1ed0..73fda4bd 100644 --- a/server/package.json +++ b/server/package.json @@ -61,6 +61,7 @@ "@types/node": "^24.6.0", "@types/supertest": "^6.0.2", "@types/ws": "^8.18.1", + "cross-env": "^10.1.0", "supertest": "^7.0.0", "tsx": "^4.19.2", "typescript": "^5.7.3", diff --git a/server/src/__tests__/codex-local-adapter-environment.test.ts b/server/src/__tests__/codex-local-adapter-environment.test.ts index bf42e47d..a9201c98 100644 --- a/server/src/__tests__/codex-local-adapter-environment.test.ts +++ b/server/src/__tests__/codex-local-adapter-environment.test.ts @@ -4,6 +4,8 @@ import os from "node:os"; import path from "node:path"; import { testEnvironment } from "@paperclipai/adapter-codex-local/server"; +const itWindows = process.platform === "win32" ? it : it.skip; + describe("codex_local environment diagnostics", () => { it("creates a missing working directory when cwd is absolute", async () => { const cwd = path.join( @@ -30,9 +32,7 @@ describe("codex_local environment diagnostics", () => { await fs.rm(path.dirname(cwd), { recursive: true, force: true }); }); - it("runs the hello probe when Codex is available via a Windows .cmd wrapper", async () => { - if (process.platform !== "win32") return; - + itWindows("runs the hello probe when Codex is available via a Windows .cmd wrapper", async () => { const root = path.join( os.tmpdir(), `paperclip-codex-local-probe-${Date.now()}-${Math.random().toString(16).slice(2)}`, From a4181060054433f5337e6e5e1b375ccb4accc656 Mon Sep 17 00:00:00 2001 From: online5880 Date: Tue, 10 Mar 2026 01:43:45 +0900 Subject: [PATCH 3/4] fix: restore cross-env in server dev watch --- server/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/package.json b/server/package.json index 32cc9cd5..8c442e25 100644 --- a/server/package.json +++ b/server/package.json @@ -23,7 +23,7 @@ ], "scripts": { "dev": "tsx src/index.ts", - "dev:watch": "PAPERCLIP_MIGRATION_PROMPT=never tsx watch --ignore ../ui/node_modules --ignore ../ui/.vite --ignore ../ui/dist src/index.ts", + "dev:watch": "cross-env PAPERCLIP_MIGRATION_PROMPT=never tsx watch --ignore ../ui/node_modules --ignore ../ui/.vite --ignore ../ui/dist src/index.ts", "prepare:ui-dist": "bash ../scripts/prepare-server-ui-dist.sh", "build": "tsc", "prepack": "pnpm run prepare:ui-dist", From 756ddb6cf7f3e84ed1267c414a0dc5ee50be8f90 Mon Sep 17 00:00:00 2001 From: online5880 Date: Tue, 10 Mar 2026 02:34:52 +0900 Subject: [PATCH 4/4] fix: remove lockfile changes from PR --- pnpm-lock.yaml | 21 --------------------- 1 file changed, 21 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 36aa29a9..d1dd1ddc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,9 +14,6 @@ importers: '@playwright/test': specifier: ^1.58.2 version: 1.58.2 - cross-env: - specifier: ^10.1.0 - version: 10.1.0 esbuild: specifier: ^0.27.3 version: 0.27.3 @@ -324,9 +321,6 @@ importers: '@types/ws': specifier: ^8.18.1 version: 8.18.1 - cross-env: - specifier: ^10.1.0 - version: 10.1.0 supertest: specifier: ^7.0.0 version: 7.2.2 @@ -995,9 +989,6 @@ packages: cpu: [x64] os: [win32] - '@epic-web/invariant@1.0.0': - resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} - '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} deprecated: 'Merged into tsx: https://tsx.is' @@ -3433,11 +3424,6 @@ packages: crelt@1.0.6: resolution: {integrity: sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==} - cross-env@10.1.0: - resolution: {integrity: sha512-GsYosgnACZTADcmEyJctkJIoqAhHjttw7RsFrVoJNXbsWWqaq6Ym+7kZjq6mS45O0jij6vtiReppKQEtqWy6Dw==} - engines: {node: '>=20'} - hasBin: true - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -6755,8 +6741,6 @@ snapshots: '@embedded-postgres/windows-x64@18.1.0-beta.16': optional: true - '@epic-web/invariant@1.0.0': {} - '@esbuild-kit/core-utils@3.3.2': dependencies: esbuild: 0.18.20 @@ -9271,11 +9255,6 @@ snapshots: crelt@1.0.6: {} - cross-env@10.1.0: - dependencies: - '@epic-web/invariant': 1.0.0 - cross-spawn: 7.0.6 - cross-spawn@7.0.6: dependencies: path-key: 3.1.1