const fs = require("fs");
const SAFE_BIN_RE = /^[A-Za-z0-9_./-]+$/;
function isValidBin(bin) {
return typeof bin === "string" && SAFE_BIN_RE.test(bin);
}
function isValidBinWithDiagnostic(bin) {
if (typeof bin !== "string") return false;
if (!SAFE_BIN_RE.test(bin)) {
console.error("[reliary-sift] rejected binary path (contains unsafe chars):", bin);
return false;
}
return true;
}
function findReliary() {
if (process.env.RELIARY_BIN_PATH) {
const p = process.env.RELIARY_BIN_PATH.trim();
if (!isValidBinWithDiagnostic(p)) return null;
try { fs.accessSync(p, fs.constants.X_OK); return p; } catch { return null; }
}
const pathDirs = (process.env.PATH || "").split(":");
for (const name of ["reliary", "reliary-agent"]) {
for (const dir of pathDirs) {
const candidate = dir ? dir + "/" + name : name;
if (!isValidBin(candidate)) continue;
try { fs.accessSync(candidate, fs.constants.X_OK); return candidate; } catch { }
}
}
return null;
}
const REWRITE_PROGRAMS = new Set([
"git", "gh",
"cargo", "npm", "yarn", "pnpm", "bun", "cargo-binstall", "rustc", "gcc", "clang",
"make", "cmake", "go", "java", "javac", "dotnet", "kotlinc", "swiftc",
"pytest", "pytest3", "jest", "vitest", "mocha", "playwright", "cypress",
"rake", "rspec", "phpunit", "tox", "nose2", "behave",
"ruff", "eslint", "prettier", "biome", "black", "isort", "flake8", "mypy",
"pylint", "shellcheck", "golangci-lint", "rubocop", "clippy-driver", "rustfmt",
"ls", "tree", "find", "fd", "rg", "ag", "grep", "ack", "delta", "bat",
"less", "more", "head", "tail", "wc", "du", "df", "stat", "file", "xxd",
"docker", "podman", "kubectl", "kubectx", "minikube", "helm",
"docker-compose", "nerdctl",
"aws", "gcloud", "az", "terraform", "pulumi", "terragrunt",
"diff", "meld", "vimdiff",
]);
function firstToken(cmd) {
const tokens = cmd.split(/\s+/);
for (const t of tokens) {
if (!/^[A-Z_][A-Z0-9_]*=/.test(t)) return t;
}
return "";
}
module.exports = function (opencode) {
const SIFT_BASH = process.env.RELIARY_SIFT_BASH !== "0"; const RELIARY_BIN = findReliary();
if (!RELIARY_BIN) {
console.error("[reliary-sift] disabled: binary not found or unsafe path");
return;
}
opencode.on("tool.execute.before", (input, output) => {
if (!SIFT_BASH) return;
if (input?.tool !== "bash" && input?.tool !== "shell") return;
const args = output?.args || {};
const cmd = args.command || "";
if (!cmd || cmd.length < 4) return;
if (cmd.includes("\n")) return;
if (cmd.includes("--no-sift")) return;
if (cmd.includes("reliary ")) return;
if (/[|<>&;]|`|\$\(/.test(cmd)) return;
const first = firstToken(cmd);
if (!REWRITE_PROGRAMS.has(first)) return;
const escaped_cmd = cmd.includes("'") ? cmd.replace(/'/g, "'\\''") : cmd;
args.command = `${RELIARY_BIN} wrap bash -c '${escaped_cmd}'`;
output.args = args;
});
};