From 03f1c8eb437885469e3478a6982c525b4de6cb50 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Wed, 29 Jul 2026 03:45:06 +0800 Subject: [PATCH] fix(subprocess): absolutize relative PATH lookups --- packages/subprocess/subprocess-local/src/index.ts | 4 ++-- packages/subprocess/subprocess-local/tests/local.spec.ts | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/subprocess/subprocess-local/src/index.ts b/packages/subprocess/subprocess-local/src/index.ts index 40d2f52552..03755cd9ea 100644 --- a/packages/subprocess/subprocess-local/src/index.ts +++ b/packages/subprocess/subprocess-local/src/index.ts @@ -11,7 +11,7 @@ import { constants } from 'node:fs' import { mkdtempSync } from 'node:fs' import { access, rm, stat } from 'node:fs/promises' import { tmpdir } from 'node:os' -import { delimiter, extname, isAbsolute, join } from 'node:path' +import { delimiter, extname, isAbsolute, join, resolve } from 'node:path' import { Context } from 'cordis' import * as nodePty from 'node-pty' import type { IPtyForkOptions } from 'node-pty' @@ -107,7 +107,7 @@ export class LocalSubprocessService extends SubprocessService { ? (env.PATHEXT ?? '.COM;.EXE;.BAT;.CMD').split(';') : [''] return path.split(delimiter).flatMap(directory => - directory === '' ? [] : extensions.map(extension => join(directory, command + extension))) + directory === '' ? [] : extensions.map(extension => resolve(this.cwd, directory, command + extension))) } spawn(spec: SubprocessSpawnSpec): SubprocessHandle { diff --git a/packages/subprocess/subprocess-local/tests/local.spec.ts b/packages/subprocess/subprocess-local/tests/local.spec.ts index 93be25acd0..6ce3d06b8e 100644 --- a/packages/subprocess/subprocess-local/tests/local.spec.ts +++ b/packages/subprocess/subprocess-local/tests/local.spec.ts @@ -1,7 +1,7 @@ import { PassThrough } from 'node:stream' import { describe, expect, it, vi } from 'vitest' import { stat } from 'node:fs/promises' -import { basename, delimiter, dirname } from 'node:path' +import { basename, delimiter, dirname, relative } from 'node:path' import { Context } from 'cordis' import LocalSubprocessService from '@deepseek-ai/dsh-subprocess-local' import type { SubprocessSpawnSpec, SubprocessTerminalHandle, SubprocessTerminalSpawnSpec } from '@deepseek-ai/dsh-subprocess' @@ -38,6 +38,9 @@ describe('LocalSubprocessService', () => { expect(await ctx.subprocess.resolveExecutable(basename(process.execPath), { PATH: dirname(process.execPath), })).toBe(process.execPath) + expect(await ctx.subprocess.resolveExecutable(basename(process.execPath), { + PATH: relative(process.cwd(), dirname(process.execPath)) || '.', + })).toBe(process.execPath) await expect(ctx.subprocess.resolveExecutable('')).rejects.toThrow('must be non-empty') await expect(ctx.subprocess.resolveExecutable('dsh-command-that-does-not-exist', { PATH: '' })) .rejects.toThrow('was not found on PATH')