feat: complete WorkBuddy parity and Windows release workflow

This commit is contained in:
xiaohan.yuan committed 2026-10-18 12:45:21 +08:00
1 parent 143516b3a8
commit d5512df549
434 files changed
+54977 -1854

No files matched your search

+70
View File
@@ -0,0 +1,70 @@
'use strict'
// Explicit preload for synchronous subprocess capture in Windows AppContainers.
// Every subprocess still uses Node's own spawn and inherits the existing token/Job.
const fs = require('node:fs')
const path = require('node:path')
const cp = require('node:child_process')
const { syncBuiltinESMExports } = require('node:module')
const originals = { spawnSync: cp.spawnSync, execFileSync: cp.execFileSync, execSync: cp.execSync }
const maximum = 16 * 1024 * 1024
function captured(method, file, args, options, spawn) {
if (options.stdio !== undefined && options.stdio !== 'pipe') return method()
const limit = options.maxBuffer === undefined ? 1024 * 1024 : options.maxBuffer
if (!Number.isSafeInteger(limit) || limit < 0 || limit > maximum) throw new RangeError('Sandbox process adapter maxBuffer must be between 0 and 16 MiB')
const input = options.input === undefined ? Buffer.alloc(0) : typeof options.input === 'string'
? Buffer.from(options.input, options.encoding && options.encoding !== 'buffer' ? options.encoding : 'utf8')
: ArrayBuffer.isView(options.input) ? Buffer.from(options.input.buffer, options.input.byteOffset, options.input.byteLength) : null
if (!input) throw new TypeError('Sandbox process adapter input must be a string, Buffer or ArrayBuffer view')
if (input.length > maximum) throw new RangeError('Sandbox process adapter input exceeds 16 MiB')
const directory = fs.mkdtempSync(path.join(process.env.TEMP, 'ycode-process-'))
const files = ['stdin', 'stdout', 'stderr'].map(name => path.join(directory, name)), handles = []
const encode = bytes => options.encoding && options.encoding !== 'buffer' ? bytes.toString(options.encoding) : bytes
let answer, failure
try {
fs.writeFileSync(files[0], input, { flag: 'wx', mode: 0o600 })
handles.push(fs.openSync(files[0], 'r'))
handles.push(fs.openSync(files[1], 'wx+'))
handles.push(fs.openSync(files[2], 'wx+'))
const forwarded = { ...options, stdio: handles }; delete forwarded.input
try { answer = method(forwarded) } catch (error) { failure = error }
const read = index => {
const buffer = Buffer.alloc(Math.min(fs.fstatSync(handles[index]).size, limit + 1))
let length = 0
while (length < buffer.length) { const count = fs.readSync(handles[index], buffer, length, buffer.length - length, length); if (!count) break; length += count }
return { bytes: buffer.subarray(0, Math.min(length, limit)), overflow: length > limit }
}
const out = read(1), err = read(2), stdout = encode(out.bytes), stderr = encode(err.bytes)
if (out.overflow || err.overflow) failure = Object.assign(new Error('Sandbox subprocess output exceeds maxBuffer'), { code: 'ENOBUFS', syscall: 'spawnSync', path: file, spawnargs: args })
if (spawn) {
if (failure && !answer) throw failure
return { ...answer, stdout, stderr, output: [null, stdout, stderr], ...(failure ? { error: failure } : {}) }
}
if (failure) {
failure.stdout = stdout; failure.stderr = stderr; failure.output = [null, stdout, stderr]
throw failure
}
return stdout
} finally {
for (const handle of handles) try { fs.closeSync(handle) } catch {}
for (const file of files) try { fs.unlinkSync(file) } catch {}
try { fs.rmdirSync(directory) } catch {}
}
}
function argumentsOf(args, options) {
return Array.isArray(args) ? { args, options: options || {} } : { args: [], options: args == null ? options || {} : args }
}
function spawnSync(file, args, options) {
const normalized = argumentsOf(args, options)
return captured(forwarded => originals.spawnSync(file, normalized.args, forwarded || normalized.options), file, normalized.args, normalized.options, true)
}
function execFileSync(file, args, options) {
const normalized = argumentsOf(args, options)
return captured(forwarded => originals.execFileSync(file, normalized.args, forwarded || normalized.options), file, normalized.args, normalized.options, false)
}
function execSync(command, options = {}) {
return captured(forwarded => originals.execSync(command, forwarded || options), command, [], options, false)
}
if (process.env.YCODE_SANDBOX !== 'appcontainer') throw new Error('The subprocess adapter is for the isolated YCode Node runtime')
Object.assign(cp, { spawnSync, execFileSync, execSync })
syncBuiltinESMExports()
module.exports = { spawnSync, execFileSync, execSync }