jay-code
Version:
Streamlined AI CLI orchestration engine with mathematical rigor and enterprise-grade reliability
287 lines (256 loc) • 6.22 kB
JavaScript
/**
* Runtime Environment Detection
* Cross-platform detection and compatibility layer for Node.js and Deno
*/
// Runtime detection
const isNode = typeof process !== 'undefined' && process.versions && process.versions.node;
const isDeno = typeof Deno !== 'undefined';
// Environment-specific imports
let runtime;
let stdin, stdout, stderr;
let TextEncoder, TextDecoder;
let exit, pid, addSignalListener;
if (isDeno) {
// Deno environment
runtime = 'deno';
stdin = Deno.stdin;
stdout = Deno.stdout;
stderr = Deno.stderr;
TextEncoder = globalThis.TextEncoder;
TextDecoder = globalThis.TextDecoder;
exit = Deno.exit;
pid = Deno.pid;
addSignalListener = Deno.addSignalListener;
} else if (isNode) {
// Node.js environment
runtime = 'node';
stdin = process.stdin;
stdout = process.stdout;
stderr = process.stderr;
TextEncoder = globalThis.TextEncoder || require('util').TextEncoder;
TextDecoder = globalThis.TextDecoder || require('util').TextDecoder;
exit = process.exit;
pid = process.pid;
addSignalListener = (signal, handler) => {
process.on(signal, handler);
};
} else {
throw new Error('Unsupported runtime environment');
}
/**
* Cross-platform terminal I/O layer
*/
export class UnifiedTerminalIO {
constructor() {
this.decoder = new TextDecoder();
this.encoder = new TextEncoder();
this.runtime = runtime;
}
/**
* Write to stdout
*/
async write(data) {
if (typeof data === 'string') {
data = this.encoder.encode(data);
}
if (runtime === 'deno') {
await stdout.write(data);
} else {
return new Promise((resolve) => {
stdout.write(data, resolve);
});
}
}
/**
* Read from stdin
*/
async read(buffer) {
if (runtime === 'deno') {
return await stdin.read(buffer);
} else {
return new Promise((resolve) => {
let data = '';
const onData = (chunk) => {
data += chunk;
if (data.includes('\n')) {
stdin.removeListener('data', onData);
const encoded = this.encoder.encode(data);
const bytesToCopy = Math.min(encoded.length, buffer.length);
buffer.set(encoded.slice(0, bytesToCopy));
resolve(bytesToCopy);
}
};
// Only set raw mode if available (terminal environments)
if (stdin.setRawMode && typeof stdin.setRawMode === 'function') {
try {
stdin.setRawMode(true);
} catch (err) {
// Ignore errors if not in a TTY
}
}
if (stdin.resume && typeof stdin.resume === 'function') {
stdin.resume();
}
stdin.on('data', onData);
});
}
}
/**
* Set up signal handlers
*/
onSignal(signal, handler) {
if (runtime === 'deno') {
addSignalListener(signal, handler);
} else {
process.on(signal, handler);
}
}
/**
* Exit the process
*/
exit(code = 0) {
exit(code);
}
/**
* Get process ID
*/
getPid() {
return pid;
}
/**
* Set raw mode for stdin (Node.js only)
*/
setRawMode(enabled) {
if (runtime === 'node' && stdin.setRawMode && typeof stdin.setRawMode === 'function') {
try {
stdin.setRawMode(enabled);
} catch (err) {
// Ignore errors if not in a TTY
}
}
}
/**
* Resume stdin (Node.js only)
*/
resume() {
if (runtime === 'node' && stdin.resume) {
stdin.resume();
}
}
/**
* Pause stdin (Node.js only)
*/
pause() {
if (runtime === 'node' && stdin.pause) {
stdin.pause();
}
}
}
/**
* Environment detection utilities
*/
export const RuntimeDetector = {
isNode: () => isNode,
isDeno: () => isDeno,
getRuntime: () => runtime,
/**
* Get platform-specific information
*/
getPlatform: () => {
if (runtime === 'deno') {
return {
os: Deno.build.os,
arch: Deno.build.arch,
target: Deno.build.target,
};
} else {
return {
os:
process.platform === 'win32'
? 'windows'
: process.platform === 'darwin'
? 'darwin'
: process.platform === 'linux'
? 'linux'
: process.platform,
arch: process.arch,
target: `${process.arch}-${process.platform}`,
};
}
},
/**
* Check if API is available
*/
hasAPI: (apiName) => {
switch (apiName) {
case 'deno':
return isDeno;
case 'node':
return isNode;
case 'fs':
return runtime === 'node' || (runtime === 'deno' && typeof Deno.readFile !== 'undefined');
case 'process':
return runtime === 'node' || (runtime === 'deno' && typeof Deno.run !== 'undefined');
default:
return false;
}
},
/**
* Get environment variables
*/
getEnv: (key) => {
if (runtime === 'deno') {
return process.env[key];
} else {
return process.env[key];
}
},
/**
* Set environment variables
*/
setEnv: (key, value) => {
if (runtime === 'deno') {
process.env[key] = value;
} else {
process.env[key] = value;
}
},
};
/**
* Cross-platform compatibility layer
*/
export const createCompatibilityLayer = () => {
return {
runtime,
terminal: new UnifiedTerminalIO(),
detector: RuntimeDetector,
// Unified APIs
TextEncoder,
TextDecoder,
// Platform info
platform: RuntimeDetector.getPlatform(),
// Environment
getEnv: RuntimeDetector.getEnv,
setEnv: RuntimeDetector.setEnv,
// Process control
exit,
pid,
// Graceful degradation helpers
safeCall: async (fn, fallback = null) => {
try {
return await fn();
} catch (error) {
console.warn(`Runtime compatibility warning: ${error.message}`);
return fallback;
}
},
// Feature detection
hasFeature: (feature) => {
return RuntimeDetector.hasAPI(feature);
},
};
};
// Export the compatibility layer instance
export const compat = createCompatibilityLayer();
// Export runtime detection results
export { runtime, isNode, isDeno };