mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 08:03:22 +00:00
174 lines
6.1 KiB
JavaScript
174 lines
6.1 KiB
JavaScript
import { createHash } from 'node:crypto'
|
|
import { spawnSync } from 'node:child_process'
|
|
import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
|
import { createRequire } from 'node:module'
|
|
import { tmpdir } from 'node:os'
|
|
import { dirname, join, resolve } from 'node:path'
|
|
import { runInNewContext } from 'node:vm'
|
|
import { describe, expect, it } from 'vitest'
|
|
|
|
const projectRoot = resolve(import.meta.dirname, '../..')
|
|
const require = createRequire(import.meta.url)
|
|
const patchName = 'node-pty-windows-pre-ready-shutdown-patch.cjs'
|
|
const vanillaWindowsTerminal = `'use strict';
|
|
function WindowsTerminal() {}
|
|
WindowsTerminal.prototype.destroy = function () {
|
|
var _this = this;
|
|
this._deferNoArgs(function () {
|
|
_this.kill();
|
|
});
|
|
};
|
|
WindowsTerminal.prototype.kill = function (signal) {
|
|
var _this = this;
|
|
this._deferNoArgs(function () {
|
|
if (signal) {
|
|
throw new Error('Signals not supported on windows.');
|
|
}
|
|
_this._close();
|
|
_this._agent.kill();
|
|
});
|
|
};
|
|
WindowsTerminal.prototype._deferNoArgs = function (deferredFn) {
|
|
var _this = this;
|
|
if (this._isReady) {
|
|
deferredFn.call(this);
|
|
return;
|
|
}
|
|
this._deferreds.push({ run: function () { return deferredFn.call(_this); } });
|
|
};
|
|
exports.WindowsTerminal = WindowsTerminal;
|
|
`
|
|
const vanillaConptyConsoleListAgent = `'use strict';
|
|
var utils_1 = require("./utils");
|
|
var getConsoleProcessList = utils_1.loadNativeModule('conpty_console_list').module.getConsoleProcessList;
|
|
var shellPid = parseInt(process.argv[2], 10);
|
|
var consoleProcessList = getConsoleProcessList(shellPid);
|
|
process.send({ consoleProcessList: consoleProcessList });
|
|
process.exit(0);
|
|
`
|
|
|
|
function loadHarness(modulePath) {
|
|
delete require.cache[require.resolve(modulePath)]
|
|
const { WindowsTerminal } = require(modulePath)
|
|
const terminal = Object.create(WindowsTerminal.prototype)
|
|
let closeCount = 0
|
|
let nativeKillCount = 0
|
|
terminal._isReady = false
|
|
terminal._deferreds = []
|
|
terminal._close = () => closeCount++
|
|
terminal._agent = { kill: () => nativeKillCount++ }
|
|
terminal.kill()
|
|
return {
|
|
closeCount,
|
|
nativeKillCount,
|
|
deferredCount: terminal._deferreds.length
|
|
}
|
|
}
|
|
|
|
describe('packaged Windows SSH relay node-pty patch', () => {
|
|
it('hashes, ships, and executes the pre-ready shutdown fix', () => {
|
|
const build = spawnSync(process.execPath, ['config/scripts/build-relay.mjs'], {
|
|
cwd: projectRoot,
|
|
encoding: 'utf8'
|
|
})
|
|
expect(build.status, `${build.stdout}\n${build.stderr}`).toBe(0)
|
|
|
|
for (const platform of ['win32-x64', 'win32-arm64']) {
|
|
const relayDir = join(projectRoot, 'out', 'relay', platform)
|
|
const relayContent = readFileSync(join(relayDir, 'relay.js'))
|
|
const watcherContent = readFileSync(join(relayDir, 'relay-watcher.js'))
|
|
const patchContent = readFileSync(join(relayDir, patchName))
|
|
const expectedHash = createHash('sha256')
|
|
.update(relayContent)
|
|
.update(watcherContent)
|
|
.update(patchContent)
|
|
.digest('hex')
|
|
.slice(0, 12)
|
|
expect(readFileSync(join(relayDir, '.version'), 'utf8')).toBe(`0.1.0+${expectedHash}`)
|
|
}
|
|
|
|
for (const platform of ['linux-x64', 'darwin-arm64']) {
|
|
expect(existsSync(join(projectRoot, 'out', 'relay', platform, patchName))).toBe(false)
|
|
}
|
|
|
|
const packageConfig = require('../electron-builder.config.cjs')
|
|
for (const platform of ['win', 'mac', 'linux']) {
|
|
expect(packageConfig[platform].extraResources).toContainEqual({
|
|
from: 'out/relay',
|
|
to: 'relay'
|
|
})
|
|
}
|
|
|
|
const tempRoot = mkdtempSync(join(tmpdir(), 'orca-relay-node-pty-'))
|
|
try {
|
|
const modulePath = join(tempRoot, 'node_modules', 'node-pty', 'lib', 'windowsTerminal.js')
|
|
const watcherPath = join(tempRoot, 'node_modules', '@parcel', 'watcher', 'index.js')
|
|
const consoleListPath = join(
|
|
tempRoot,
|
|
'node_modules',
|
|
'node-pty',
|
|
'lib',
|
|
'conpty_console_list_agent.js'
|
|
)
|
|
mkdirSync(dirname(modulePath), { recursive: true })
|
|
mkdirSync(dirname(watcherPath), { recursive: true })
|
|
writeFileSync(modulePath, vanillaWindowsTerminal, 'utf8')
|
|
writeFileSync(consoleListPath, vanillaConptyConsoleListAgent, 'utf8')
|
|
writeFileSync(watcherPath, 'module.exports = {}\n', 'utf8')
|
|
|
|
expect(loadHarness(modulePath)).toEqual({
|
|
closeCount: 0,
|
|
nativeKillCount: 0,
|
|
deferredCount: 1
|
|
})
|
|
const patch = spawnSync(
|
|
process.execPath,
|
|
[join(projectRoot, 'out', 'relay', 'win32-x64', patchName), '--apply', tempRoot],
|
|
{ cwd: tempRoot, encoding: 'utf8' }
|
|
)
|
|
expect(patch.status, patch.stderr).toBe(0)
|
|
expect(patch.stdout).toContain('ORCA-NPTY-WINDOWS-PATCH-OK')
|
|
expect(loadHarness(modulePath)).toEqual({
|
|
closeCount: 1,
|
|
nativeKillCount: 1,
|
|
deferredCount: 0
|
|
})
|
|
const sent = []
|
|
runInNewContext(readFileSync(consoleListPath, 'utf8'), {
|
|
require: () => ({
|
|
loadNativeModule: () => ({
|
|
module: {
|
|
getConsoleProcessList: () => {
|
|
throw new Error('AttachConsole failed')
|
|
}
|
|
}
|
|
})
|
|
}),
|
|
process: {
|
|
argv: ['node', consoleListPath, '42'],
|
|
exit: () => {},
|
|
send: (message) => sent.push(message)
|
|
}
|
|
})
|
|
expect(sent).toEqual([{ consoleProcessList: [42] }])
|
|
|
|
const secondPatch = spawnSync(
|
|
process.execPath,
|
|
[join(projectRoot, 'out', 'relay', 'win32-x64', patchName), '--apply', tempRoot],
|
|
{ cwd: tempRoot, encoding: 'utf8' }
|
|
)
|
|
expect(secondPatch.status, secondPatch.stderr).toBe(0)
|
|
|
|
const check = spawnSync(
|
|
process.execPath,
|
|
[join(projectRoot, 'out', 'relay', 'win32-x64', patchName), '--check', tempRoot],
|
|
{ cwd: tempRoot, encoding: 'utf8' }
|
|
)
|
|
expect(check.status, check.stderr).toBe(0)
|
|
expect(check.stdout).toContain('ORCA-NATIVE-DEPS-OK')
|
|
} finally {
|
|
rmSync(tempRoot, { recursive: true, force: true })
|
|
}
|
|
})
|
|
})
|