naisys
Version:
NAISYS - Autonomous AI agent runner with built-in context management and cost tracking
133 lines • 5.81 kB
JavaScript
/**
* Platform abstraction layer for shell operations
* Encapsulates platform-specific shell behavior for Windows (PowerShell) and Linux (bash)
*/
import { execSync } from "child_process";
import * as os from "os";
const nsCommandHandlerMessage = "is a NAISYS command and must be run on its own line, not combined with shell commands.";
function getWindowsConfig() {
return {
platform: "windows",
shellCommand: "powershell.exe",
shellArgs: [
"-NoProfile",
"-NoLogo",
"-NonInteractive",
"-ExecutionPolicy",
"Bypass",
],
echoDelimiter: (delimiter) => `Write-Host "${delimiter}"`,
pwdCommand: "(Get-Location).Path",
mkdirCommand: (path) => `New-Item -ItemType Directory -Force -Path "${path}" | Out-Null`,
cdCommand: (path) => `Set-Location "${path}"`,
scriptExtension: ".ps1",
scriptHeader: "# PowerShell script",
scriptSetError: "$ErrorActionPreference = 'Stop'",
pathSeparator: ";",
sourceScript: (scriptPath) => `. "${scriptPath}"`,
exportEnvCommand: (key, value) =>
// Backtick-escape `$` and `"` so PS doesn't expand or terminate the literal
`$env:${key} = "${value.replace(/`/g, "``").replace(/\$/g, "`$").replace(/"/g, '`"')}"`,
// Empty CommandScriptBlock + StopSearch suppresses PS's native "not
// recognized" block so the LLM only sees our single clean message.
// Cost: $? stays True, so PS7 &&/|| chains continue past an ns-* line
// rather than short-circuiting. Acceptable — LLMs read the message.
nsCommandNotFoundHandler: `$ExecutionContext.InvokeCommand.CommandNotFoundAction = { param($n, $e) if ($n -like 'ns-*') { Write-Host "NAISYS: '$n' ${nsCommandHandlerMessage}"; $e.CommandScriptBlock = { }; $e.StopSearch = $true } }`,
displayName: "WINDOWS",
shellName: "PowerShell",
commandNotFoundSuffix: "is not recognized",
invalidCommandMessage: "Please enter a valid PowerShell or NAISYS command after the prompt. Use the 'ns-comment' command for thoughts.",
promptSuffix: ">",
promptDivider: " ",
adminPromptSuffix: "#",
};
}
function getLinuxConfig() {
return {
platform: "linux",
shellCommand: "bash",
shellArgs: [],
echoDelimiter: (delimiter) => `echo "${delimiter}"`,
pwdCommand: "pwd",
mkdirCommand: (path) => `mkdir -p "${path}"`,
cdCommand: (path) => `cd "${path}"`,
scriptExtension: ".sh",
scriptHeader: "#!/bin/bash",
scriptSetError: `__naisys_prev_errexit=0
case $- in *e*) __naisys_prev_errexit=1 ;; esac
__naisys_prev_err_trap=$(trap -p ERR)
__naisys_prev_return_trap=$(trap -p RETURN)
trap '__naisys_rc=$?
trap - ERR
trap - RETURN
if [ -n "$__naisys_prev_err_trap" ]; then eval "$__naisys_prev_err_trap"; fi
if [ -n "$__naisys_prev_return_trap" ]; then eval "$__naisys_prev_return_trap"; fi
if [ "$__naisys_prev_errexit" = "1" ]; then set -e; else set +e; fi
unset __naisys_prev_errexit __naisys_prev_err_trap __naisys_prev_return_trap __naisys_rc' RETURN
trap '__naisys_rc=$?
set +e
echo "[NAISYS: script halted at exit $__naisys_rc on: $BASH_COMMAND]" >&2
trap - ERR
trap - RETURN
if [ -n "$__naisys_prev_err_trap" ]; then eval "$__naisys_prev_err_trap"; fi
if [ -n "$__naisys_prev_return_trap" ]; then eval "$__naisys_prev_return_trap"; fi
if [ "$__naisys_prev_errexit" = "1" ]; then set -e; else set +e; fi
eval "unset __naisys_prev_errexit __naisys_prev_err_trap __naisys_prev_return_trap __naisys_rc; return $__naisys_rc 2>/dev/null || exit $__naisys_rc"' ERR
set -e`,
pathSeparator: ":",
sourceScript: (scriptPath) => `source "${scriptPath}"`,
exportEnvCommand: (key, value) =>
// Single-quote the value so bash treats it literally; escape embedded
// single quotes by closing → escaped quote → reopening.
`export ${key}='${value.replace(/'/g, "'\\''")}'`,
nsCommandNotFoundHandler: `command_not_found_handle() { case "$1" in ns-*) echo "NAISYS: '$1' ${nsCommandHandlerMessage}" >&2; return 127 ;; *) echo "bash: $1: command not found" >&2; return 127 ;; esac; }`,
displayName: "LINUX",
shellName: "bash",
commandNotFoundSuffix: "command not found",
invalidCommandMessage: "Please enter a valid Linux or NAISYS command after the prompt. Use the 'ns-comment' command for thoughts.",
promptSuffix: "$",
promptDivider: ":",
adminPromptSuffix: "#",
};
}
/** Determine if we should use native Windows mode */
export function useNativeWindows() {
// On Windows, use native PowerShell instead of WSL
return os.platform() === "win32";
}
/** Get the platform configuration for the current OS */
export function getPlatformConfig() {
if (useNativeWindows()) {
return getWindowsConfig();
}
return getLinuxConfig();
}
/** Get a specific platform configuration */
export function getPlatformConfigFor(platform) {
if (platform === "windows") {
return getWindowsConfig();
}
return getLinuxConfig();
}
/** Cached result of elevation check (doesn't change during process lifetime) */
let elevatedCache;
/** Check if the process is running as root (Linux) or admin (Windows) */
export function isElevated() {
if (elevatedCache !== undefined) {
return elevatedCache;
}
if (os.platform() === "win32") {
try {
execSync("net session", { stdio: "ignore" });
elevatedCache = true;
}
catch {
elevatedCache = false;
}
}
else {
elevatedCache = process.getuid?.() === 0;
}
return elevatedCache;
}
//# sourceMappingURL=shellPlatform.js.map