Merge pull request #2517 from deepseek-harness/xtr/node-pty-1.2-beta

chore(subprocess-local): bump node-pty beta
This commit is contained in:
_Kerman
2026-08-17 18:12:16 +08:00
committed by GitHub
11 changed files with 127 additions and 74 deletions
@@ -194,6 +194,7 @@ jobs:
*) echo "::error::Unsupported Linux runner architecture $RUNNER_ARCH"; exit 1 ;;
esac
addon_dir="$(realpath packages/subprocess/subprocess-local/node_modules/node-pty)"
(cd "$addon_dir" && npm_config_build_from_source=true pnpm run install)
addon="$addon_dir/build/Release/pty.node"
[ -f "$addon_dir/build/Makefile" ] || {
echo "::error::node-pty install did not generate $addon_dir/build/Makefile"
+1 -1
View File
@@ -93,7 +93,7 @@ External packages that a workspace package resolves at runtime. The tier covers
pnpm applies local patches to the following packages at install time, so shipped artifacts carry modified copies; each patch file is the complete record of the modification:
- `node-pty@1.1.0` — [`patches/node-pty@1.1.0.patch`](patches/node-pty@1.1.0.patch)
- `node-pty@1.2.0-beta.15` — [`patches/node-pty@1.2.0-beta.15.patch`](patches/node-pty@1.2.0-beta.15.patch)
## Official Claude Code platform payloads
@@ -42,7 +42,7 @@
"@deepseek-ai/cordis": "workspace:^"
},
"dependencies": {
"node-pty": "^1.1.0"
"node-pty": "1.2.0-beta.15"
},
"devDependencies": {
"@deepseek-ai/dsh-invariants": "workspace:^",
-62
View File
@@ -1,62 +0,0 @@
diff --git a/lib/unixTerminal.js b/lib/unixTerminal.js
index 1ec12f796a822c78fba9ad7f6448c3987e325c23..5cd6b7d635f4752be5a6c5ff9cf9edf988cf94c5 100644
--- a/lib/unixTerminal.js
+++ b/lib/unixTerminal.js
@@ -26,10 +26,23 @@ var terminal_1 = require("./terminal");
var utils_1 = require("./utils");
var native = utils_1.loadNativeModule('pty');
var pty = native.module;
-var helperPath = native.dir + '/spawn-helper';
-helperPath = path.resolve(__dirname, helperPath);
-helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
-helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');
+// A current external embedded-runtime consumer supplies a non-sibling helper.
+var helperPath = process.env.DSH_NODE_PTY_SPAWN_HELPER;
+if (helperPath) {
+ helperPath = path.resolve(helperPath);
+}
+else {
+ var executableSibling = process.execPath + '-spawn-helper';
+ if (fs.existsSync(executableSibling)) {
+ helperPath = executableSibling;
+ }
+ else {
+ helperPath = native.dir + '/spawn-helper';
+ helperPath = path.resolve(__dirname, helperPath);
+ helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
+ helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');
+ }
+}
var DEFAULT_FILE = 'sh';
var DEFAULT_NAME = 'xterm';
var DESTROY_SOCKET_TIMEOUT_MS = 200;
diff --git a/src/unixTerminal.ts b/src/unixTerminal.ts
index 98733dc0cd752b554bd94e45904ca341ad141bba..fa234291206617ae5a6d8605abf9771220392d17 100644
--- a/src/unixTerminal.ts
+++ b/src/unixTerminal.ts
@@ -14,10 +14,21 @@ import { assign, loadNativeModule } from './utils';
const native = loadNativeModule('pty');
const pty: IUnixNative = native.module;
-let helperPath = native.dir + '/spawn-helper';
-helperPath = path.resolve(__dirname, helperPath);
-helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
-helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');
+// A current external embedded-runtime consumer supplies a non-sibling helper.
+let helperPath = process.env.DSH_NODE_PTY_SPAWN_HELPER;
+if (helperPath) {
+ helperPath = path.resolve(helperPath);
+} else {
+ const executableSibling = process.execPath + '-spawn-helper';
+ if (fs.existsSync(executableSibling)) {
+ helperPath = executableSibling;
+ } else {
+ helperPath = native.dir + '/spawn-helper';
+ helperPath = path.resolve(__dirname, helperPath);
+ helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
+ helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');
+ }
+}
const DEFAULT_FILE = 'sh';
const DEFAULT_NAME = 'xterm';
+32
View File
@@ -0,0 +1,32 @@
diff --git a/lib/unixTerminal.js b/lib/unixTerminal.js
index 6966d24..18f1d25 100644
--- a/lib/unixTerminal.js
+++ b/lib/unixTerminal.js
@@ -28,10 +28,23 @@ var terminal_1 = require("./terminal");
var utils_1 = require("./utils");
var native = (0, utils_1.loadNativeModule)('pty');
var pty = native.module;
-var helperPath = native.dir + '/spawn-helper';
-helperPath = path.resolve(__dirname, helperPath);
-helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
-helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');
+// A current external embedded-runtime consumer supplies a non-sibling helper.
+var helperPath = process.env.DSH_NODE_PTY_SPAWN_HELPER;
+if (helperPath) {
+ helperPath = path.resolve(helperPath);
+}
+else {
+ var executableSibling = process.execPath + '-spawn-helper';
+ if (fs.existsSync(executableSibling)) {
+ helperPath = executableSibling;
+ }
+ else {
+ helperPath = native.dir + '/spawn-helper';
+ helperPath = path.resolve(__dirname, helperPath);
+ helperPath = helperPath.replace('app.asar', 'app.asar.unpacked');
+ helperPath = helperPath.replace('node_modules.asar', 'node_modules.asar.unpacked');
+ }
+}
var DEFAULT_FILE = 'sh';
var DEFAULT_NAME = 'xterm';
var DESTROY_SOCKET_TIMEOUT_MS = 200;
+6 -6
View File
@@ -9,7 +9,7 @@ overrides:
'@deepseek-ai/schemastery': link:vendor/schemastery
patchedDependencies:
node-pty@1.1.0: 7a0c04f1f49d798a9ffe2f7f414c01064a44ca2489772d0c3e1235ab336755e6
node-pty@1.2.0-beta.15: b40ae545608897914bd25fb009c97eeac478c34e8a910298ddcb01b746534bb0
importers:
@@ -7493,8 +7493,8 @@ importers:
packages/subprocess/subprocess-local:
dependencies:
node-pty:
specifier: ^1.1.0
version: 1.1.0(patch_hash=7a0c04f1f49d798a9ffe2f7f414c01064a44ca2489772d0c3e1235ab336755e6)
specifier: 1.2.0-beta.15
version: 1.2.0-beta.15(patch_hash=b40ae545608897914bd25fb009c97eeac478c34e8a910298ddcb01b746534bb0)
devDependencies:
'@deepseek-ai/cordis':
specifier: workspace:^
@@ -13164,8 +13164,8 @@ packages:
resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
node-pty@1.1.0:
resolution: {integrity: sha512-20JqtutY6JPXTUnL0ij1uad7Qe1baT46lyolh2sSENDd4sTzKZ4nmAFkeAARDKwmlLjPx6XKRlwRUxwjOy+lUg==}
node-pty@1.2.0-beta.15:
resolution: {integrity: sha512-vORSzHXi4Ofl7HemVWpuudLqCPdaQb4LfpRCUpE5HPxhp4JYscl8zZwxh11p26v2wvW24WMwnMfLjhRLixrfxA==}
node-releases@2.0.51:
resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==}
@@ -18588,7 +18588,7 @@ snapshots:
fetch-blob: 3.2.0
formdata-polyfill: 4.0.10
node-pty@1.1.0(patch_hash=7a0c04f1f49d798a9ffe2f7f414c01064a44ca2489772d0c3e1235ab336755e6):
node-pty@1.2.0-beta.15(patch_hash=b40ae545608897914bd25fb009c97eeac478c34e8a910298ddcb01b746534bb0):
dependencies:
node-addon-api: 7.1.1
+1 -1
View File
@@ -69,4 +69,4 @@ minimumReleaseAgeExclude:
- node-addon-require-builtin@0.1.4
patchedDependencies:
node-pty@1.1.0: patches/node-pty@1.1.0.patch
node-pty@1.2.0-beta.15: patches/node-pty@1.2.0-beta.15.patch
@@ -0,0 +1,49 @@
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { dirname, join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
import { resolveLinuxNodePtyAddon } from './build-exe-for-python-sdk-native-pty.ts'
const roots: string[] = []
afterEach(() => {
for (const root of roots.splice(0)) rmSync(root, { recursive: true, force: true })
})
describe('resolveLinuxNodePtyAddon', () => {
it('prefers the manylinux build produced by the release workflow', () => {
const root = temporaryPackage()
const built = createAddon(root, 'build', 'Release', 'pty.node')
createAddon(root, 'prebuilds', 'linux-x64', 'pty.node')
expect(resolveLinuxNodePtyAddon(root, 'x64')).toBe(built)
})
it('uses the target prebuild after an ordinary beta install', () => {
const root = temporaryPackage()
const prebuilt = createAddon(root, 'prebuilds', 'linux-arm64', 'pty.node')
expect(resolveLinuxNodePtyAddon(root, 'arm64')).toBe(prebuilt)
})
it('reports both expected locations when no addon is installed', () => {
const root = temporaryPackage()
expect(() => resolveLinuxNodePtyAddon(root, 'x64')).toThrow(
`node-pty addon is absent from both ${join(root, 'build', 'Release', 'pty.node')} and ${join(root, 'prebuilds', 'linux-x64', 'pty.node')}`,
)
})
})
function temporaryPackage(): string {
const root = mkdtempSync(join(tmpdir(), 'dsh-node-pty-addon-'))
roots.push(root)
return root
}
function createAddon(root: string, ...segments: string[]): string {
const path = join(root, ...segments)
mkdirSync(dirname(path), { recursive: true })
writeFileSync(path, '')
return path
}
@@ -0,0 +1,23 @@
/** Resolve the native node-pty input used by the Python SDK runtime builder. */
import { existsSync } from 'node:fs'
import { join } from 'node:path'
/**
* Prefer the workflow's manylinux build and fall back to node-pty's target prebuild.
* @param packageDirectory - installed node-pty package directory.
* @param arch - Linux target architecture.
* @returns the existing addon path.
*/
export function resolveLinuxNodePtyAddon(
packageDirectory: string,
arch: 'x64' | 'arm64',
): string {
const built = join(packageDirectory, 'build', 'Release', 'pty.node')
if (existsSync(built)) return built
const prebuilt = join(packageDirectory, 'prebuilds', `linux-${arch}`, 'pty.node')
if (existsSync(prebuilt)) return prebuilt
throw new Error(
`build-exe-for-python-sdk: node-pty addon is absent from both ${built} and ${prebuilt}.`,
)
}
+12 -3
View File
@@ -11,6 +11,7 @@ import { existsSync, statSync } from 'node:fs'
import { chmod, copyFile, cp, lstat, mkdir, readFile, readdir, realpath, rm, writeFile } from 'node:fs/promises'
import { basename, dirname, join, resolve, sep } from 'node:path'
import { parseArgs } from 'node:util'
import { resolveLinuxNodePtyAddon } from './build-exe-for-python-sdk-native-pty.ts'
const root = resolve(import.meta.dirname, '..')
@@ -409,8 +410,8 @@ class SingleExeBuild {
}
/**
* Put the target node-pty addon in the staged closure. Linux npm installs
* build it from source, but legacy deploy omits that side-effect directory.
* Put the target node-pty addon in the staged closure. The release workflow
* provides a manylinux build; ordinary installs use node-pty's target prebuild.
* @param target - the pkg target whose native addon is being staged.
*/
private async prepareNativePty(target: Target): Promise<void> {
@@ -418,8 +419,16 @@ class SingleExeBuild {
if (this.cli.dryRun) console.log(`build-exe-for-python-sdk: [dry-run] rm -rf ${stagedBuild}`)
else await rm(stagedBuild, { recursive: true, force: true })
if (target.platform !== 'linux') return
const source = join(root, 'packages', 'subprocess', 'subprocess-local', 'node_modules', 'node-pty', 'build', 'Release', 'pty.node')
const packageDirectory = join(
root,
'packages',
'subprocess',
'subprocess-local',
'node_modules',
'node-pty',
)
const destination = join(stagedBuild, 'Release', 'pty.node')
const source = resolveLinuxNodePtyAddon(packageDirectory, target.arch)
if (this.cli.dryRun) {
console.log(`build-exe-for-python-sdk: [dry-run] cp ${source} ${destination}`)
return
+1
View File
@@ -342,6 +342,7 @@ describe('Python release workflows', () => {
expect(manylinuxAddon).toMatchObject({ if: "runner.os == 'Linux'" })
expect(JSON.stringify(manylinuxAddon)).toContain('manylinux_2_28_x86_64')
expect(JSON.stringify(manylinuxAddon)).toContain('manylinux_2_28_aarch64')
expect(JSON.stringify(manylinuxAddon)).toContain('npm_config_build_from_source=true pnpm run install')
expect(JSON.stringify(manylinuxAddon)).toContain('$HOME/setup-pnpm:$HOME/setup-pnpm:ro')
expect(JSON.stringify(manylinuxAddon)).toContain('node-pty-glibc-versions.txt')
expect(JSON.stringify(manylinuxAddon)).toContain('le 2.28')