diff --git a/core/README.md b/core/README.md index a4a7387..a881270 100644 --- a/core/README.md +++ b/core/README.md @@ -277,7 +277,10 @@ resolve: { dedupe: ['react', 'react-dom'] }, optimizeDeps: { exclude: ['prism-te `react`, `node-pty` and `@xterm/*` must stay at compatible versions in both apps so npm keeps ONE copy of each; the core is verified against Prism Terminal's -lockfile but ships against Prism's. +lockfile but ships against Prism's. Both apps pin `node-pty` to EXACTLY +`1.2.0-beta.15` (1.1.0's quit crash, #127/#159). The core's peer names that +build (`^1.1.0 || 1.2.0-beta.15`): a bare `^1.1.0` matches no prerelease, so npm +refused the pin in Prism. ## Releasing the core diff --git a/core/package.json b/core/package.json index 1e67f97..092d71d 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "prism-term-core", - "version": "0.28.1", + "version": "0.28.2", "description": "What Prism Terminal and Prism share: the terminal (pty, shells, agent detection and indicator, themes, links, the panel, dictation) and the update chip with its window. TypeScript source, compiled by the host.", "license": "MIT", "private": true, @@ -40,7 +40,7 @@ "@xterm/addon-unicode11": "^0.9.0", "@xterm/addon-web-links": "^0.12.0", "@xterm/xterm": "^6.0.0", - "node-pty": "^1.1.0", + "node-pty": "^1.1.0 || 1.2.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" } diff --git a/docs/regression-rules.md b/docs/regression-rules.md index ca44b6b..78836ae 100644 --- a/docs/regression-rules.md +++ b/docs/regression-rules.md @@ -49,6 +49,8 @@ one-liner in `CLAUDE.md` only if it is among the most important. `ThreadSafeFunction::CallJS` -> abort). So every kill goes through `killPty` and `will-quit` holds the quit on `shellsGone` (3 s cap). It waits for the agent's `exitCode`, set by the native callback, not the exit EVENT, which lags 1-2.7 s for a pwsh killed mid-start (a warm shell). `quitManyShells`. + The pin was LOST once (#159, 2026-10-10): an icon PR's merge put `^1.1.0` back and the dialog + returned for the owner. `src/main/nodePtyPin.test.ts` now fails on any build without the pin. - **`titleBarStyle: 'hidden'`, never `frame: false`**: DWM will not composite acrylic behind a frameless window. - **Material before colour** (`material.ts`, measured on Electron 43): `setBackgroundMaterial('none')` diff --git a/package-lock.json b/package-lock.json index ec04151..f2ecb57 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "prism-terminal", - "version": "0.35.1", + "version": "0.35.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "prism-terminal", - "version": "0.35.1", + "version": "0.35.2", "license": "MIT", "dependencies": { "@xterm/addon-fit": "^0.11.0", @@ -14,7 +14,7 @@ "@xterm/addon-unicode11": "^0.9.0", "@xterm/addon-web-links": "^0.12.0", "@xterm/xterm": "^6.0.0", - "node-pty": "^1.1.0", + "node-pty": "1.2.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, @@ -2204,6 +2204,72 @@ "node": ">=14.0.0" } }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/core": { + "version": "1.11.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/runtime": { + "version": "1.11.1", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "dev": true, + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi/node_modules/tslib": { + "version": "2.8.1", + "dev": true, + "inBundle": true, + "license": "0BSD", + "optional": true + }, "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", @@ -6107,9 +6173,9 @@ "license": "MIT" }, "node_modules/node-pty": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.1.0.tgz", - "integrity": "sha512-20JqtutY6JPXTUnL0ij1uad7Qe1baT46lyolh2sSENDd4sTzKZ4nmAFkeAARDKwmlLjPx6XKRlwRUxwjOy+lUg==", + "version": "1.2.0-beta.15", + "resolved": "https://registry.npmjs.org/node-pty/-/node-pty-1.2.0-beta.15.tgz", + "integrity": "sha512-vORSzHXi4Ofl7HemVWpuudLqCPdaQb4LfpRCUpE5HPxhp4JYscl8zZwxh11p26v2wvW24WMwnMfLjhRLixrfxA==", "hasInstallScript": true, "license": "MIT", "dependencies": { diff --git a/package.json b/package.json index 1dcd21a..f93f5f0 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "prism-terminal", "productName": "Prism Terminal", - "version": "0.35.1", + "version": "0.35.2", "description": "A tabbed Windows terminal for AI CLIs.", "main": "./out/main/index.js", "author": "Max", @@ -29,7 +29,7 @@ "@xterm/addon-unicode11": "^0.9.0", "@xterm/addon-web-links": "^0.12.0", "@xterm/xterm": "^6.0.0", - "node-pty": "^1.1.0", + "node-pty": "1.2.0-beta.15", "react": "^19.2.7", "react-dom": "^19.2.7" }, @@ -57,6 +57,6 @@ "vitest": "^3.2.7" }, "allowScripts": { - "node-pty@1.1.0": true + "node-pty@1.2.0-beta.15": true } } diff --git a/src/main/nodePtyPin.test.ts b/src/main/nodePtyPin.test.ts new file mode 100644 index 0000000..167b63d --- /dev/null +++ b/src/main/nodePtyPin.test.ts @@ -0,0 +1,35 @@ +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { describe, expect, it } from 'vitest' + +// #127/#128 pinned node-pty to 1.2.0-beta.15: 1.1.0's exit threads race on an +// unlocked vector and its prebuild asserts ("Assertion failed! remove_pty_baton"), +// a modal dialog that holds the app open. #130 (an icon PR) put ^1.1.0 back in a +// merge and nothing noticed until the owner saw the dialog again (#159). The +// quit e2e only catches the race sometimes; this catches the pin every run. +const PIN = '1.2.0-beta.15' +const root = join(__dirname, '..', '..') +interface Pkg { + dependencies: Record + peerDependencies: Record + packages: Record +} +const json = (f: string): Pkg => JSON.parse(readFileSync(join(root, f), 'utf8')) as Pkg + +describe('node-pty pin (#159)', () => { + it('package.json asks for exactly the pinned build', () => { + const pkg = json('package.json') + expect(pkg.dependencies['node-pty']).toBe(PIN) + expect(JSON.stringify(pkg)).not.toContain('node-pty@1.1.0') + }) + + // A `^1.1.0` peer matches no prerelease, so Prism's npm refused the pin. It + // still allows 1.1.0 so Prism's core bump installs before Prism's own pin lands. + it('the core lets its hosts take the pinned build', () => { + expect(json('core/package.json').peerDependencies['node-pty'].split(' || ')).toContain(PIN) + }) + + it('the lockfile resolves it', () => { + expect(json('package-lock.json').packages['node_modules/node-pty'].version).toBe(PIN) + }) +})