Files
hermes-agent/apps/desktop/scripts/dmgbuild-diagnostics.cjs
ethernet 2efa4ff94f refactor(desktop): prepare dependencies before saving build caches
Dependency acquisition during packaging left native wheels and packager
inputs outside the pre-build cache save. Compose PM and existing providers
into a preparation phase, then require builds to consume admitted inputs.

Share native preparation with PM Bundle. Keep path-bound environments and
signing outputs separate from reusable caches. Use read-only cache tokens
for commit builds and preserve the one-command local build path.

Verify pinned tools through PM, probe PTYs under the prepared Electron,
and supply dmgbuild through a build-only PM package. Resolve bundled tool
stores from their payload manifest so relocation preserves discovery.

Validation: focused Python and JS tests, checkJs, Ruff, Windows checks,
anti-slop, cache relocation, and network-denied Linux AppImage builds.
Relocated runtime smoke passed with NixOS host libraries supplied.
Native Windows/macOS signing and live GitHub cache behavior remain untested.
2026-09-13 14:28:31 -04:00

63 lines
2.1 KiB
JavaScript

'use strict'
const childProcess = require('node:child_process')
const { syncBuiltinESMExports } = require('node:module')
const path = require('node:path')
const { promisify } = require('node:util')
/** @param {typeof import("node:child_process").execFile} execFile @param {(chunk: Buffer) => void} [write] @returns {typeof import("node:child_process").execFile} */
function wrapDmgbuildExecFile(execFile, write = chunk => process.stderr.write(chunk)) {
function wrapped(file, args, options, callback) {
if (
typeof file !== 'string' ||
path.basename(file) !== 'dmgbuild' ||
!Array.isArray(args) ||
typeof options !== 'object' ||
((options?.env?.CUSTOM_DMGBUILD_PATH || process.env.CUSTOM_DMGBUILD_PATH)?.trim() &&
!(options?.env?.HERMES_PREPARED_PACKAGING || process.env.HERMES_PREPARED_PACKAGING))
) {
return execFile.apply(this, arguments)
}
// Use the interpreter and module path from the supplier's launcher.
// A PATH shim cannot intercept dmgbuild's absolute /usr/bin/hdiutil call.
const vendor = path.dirname(file)
const diagnostic = path.resolve(__dirname, '../../../scripts/bundles/dmgbuild_diagnostics.py')
const child = execFile.call(
this,
path.join(vendor, 'python', 'bin', 'python3'),
[diagnostic, ...args],
{
...options,
env: { ...(options?.env || process.env), PYTHONPATH: path.join(vendor, 'python', 'lib') }
},
callback
)
// execFile buffers stderr. Tee it so a later successful retry cannot hide it.
child.stderr?.on('data', write)
return child
}
wrapped[promisify.custom] = (...args) => {
const { promise, resolve, reject } = Promise.withResolvers()
promise.child = wrapped(...args, (error, stdout, stderr) => {
if (error) {
error.stdout = stdout
error.stderr = stderr
reject(error)
} else {
resolve({ stdout, stderr })
}
})
return promise
}
return wrapped
}
module.exports = { wrapDmgbuildExecFile }
if (process.platform === 'darwin') {
childProcess.execFile = wrapDmgbuildExecFile(childProcess.execFile)
syncBuiltinESMExports()
}