blob: 08d57a7e2827c05126968404296fba903f353c11 [file]
#!/usr/bin/env node
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { spawn } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { createRequire } from 'node:module';
import { dirname, join } from 'node:path';
const require = createRequire(import.meta.url);
const manifest = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8'));
try {
const platform = process.platform;
if (platform === 'linux' && !process.report.getReport().header.glibcVersionRuntime) {
throw new Error('This Maka release requires glibc on Linux.');
}
const target = `${platform}-${process.arch}${platform === 'linux' ? '-gnu' : ''}`;
const name = `@maka-agent/cli-${target}`;
if (manifest.optionalDependencies?.[name] !== manifest.version) {
throw new Error(`This Maka release does not include ${target}.`);
}
let packagePath;
try {
packagePath = require.resolve(`${name}/package.json`);
} catch {
throw new Error(
`Missing ${name}@${manifest.version}. Reinstall with: npm install --global --include=optional @maka-agent/cli@${manifest.version}`,
);
}
const native = JSON.parse(readFileSync(packagePath, 'utf8'));
const executable = platform === 'win32' ? 'maka.exe' : 'maka';
if (
native.name !== name ||
native.version !== manifest.version ||
native.bin?.maka !== `bin/${executable}`
) {
throw new Error('The installed native Maka package does not match this launcher.');
}
const child = spawn(join(dirname(packagePath), 'bin', executable), process.argv.slice(2), {
stdio: 'inherit',
});
const signals = ['SIGINT', 'SIGTERM', 'SIGHUP', ...(platform === 'win32' ? ['SIGBREAK'] : [])];
const handlers = new Map(
signals.map((signal) => [
signal,
() => {
// Windows already broadcasts Ctrl+C/Break to the native child. kill(SIGINT)
// would forcibly terminate it before its terminal cleanup can finish.
if (platform !== 'win32' || (signal !== 'SIGINT' && signal !== 'SIGBREAK'))
child.kill(signal);
},
]),
);
const cleanup = () => {
for (const [signal, handler] of handlers) process.off(signal, handler);
};
for (const [signal, handler] of handlers) process.on(signal, handler);
child.once('error', (error) => {
cleanup();
console.error(`maka: ${error.message}`);
process.exitCode = 1;
});
child.once('exit', (code, signal) => {
cleanup();
if (signal) process.kill(process.pid, signal);
else process.exitCode = code ?? 1;
});
} catch (error) {
console.error(`maka: ${error.message}`);
process.exitCode = 1;
}