@mesh-tech/mesh-cli
Version:
CLI for Mesh platform development utilities
165 lines (161 loc) • 6.28 kB
JavaScript
import { execFileSync } from "child_process";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import { logError, logInfo, logSuccess, logWarn } from "../utils/log.js";
export function shimScript() {
return `#!/bin/sh
# mesh — canonical launcher shim (installed by \`mesh install-shim\`).
# Walks up from the current directory to the nearest workspace mesh CLI and runs
# it. That resolves to bin/mesh.mjs, which runs the CLI from TypeScript source —
# so this always runs the LOCAL source of whatever worktree/app you are in, with
# no build step. Nothing here is version-pinned; do not edit by hand.
#
# Outside a workspace it hands off to a globally installed mesh CLI.
# Without that hand-off the shim shadows \`npm i -g @mesh-tech/mesh-cli\` on the
# PATH and \`mesh login\` is unreachable from the home directory — which is the
# very first thing a new developer runs.
# True when $1 is another copy of this shim. Reads the marker line with the
# shell alone — no head/grep — so a stripped PATH cannot break the check.
_mesh_is_shim() {
_n=0
while [ "$_n" -lt 6 ] && IFS= read -r _line; do
case $_line in *"canonical launcher shim"*) return 0 ;; esac
_n=$((_n + 1))
done < "$1"
return 1
}
# Walk up to the nearest workspace CLI. Parameter expansion, not \`dirname\`:
# an unavailable dirname used to leave $dir empty and spin this loop forever.
dir=$(pwd)
while [ -n "$dir" ]; do
if [ -x "$dir/node_modules/.bin/mesh" ]; then
exec "$dir/node_modules/.bin/mesh" "$@"
fi
[ "$dir" = "/" ] && break
parent=\${dir%/*}
[ -n "$parent" ] || parent=/
dir=$parent
done
# Not in a workspace: exec the next \`mesh\` on PATH that is not another copy of
# this shim (matched on the marker line above, so we can never exec ourselves).
self_dir=\${0%/*}
[ "$self_dir" = "$0" ] && self_dir=.
self_dir=$(CDPATH= cd -- "$self_dir" 2>/dev/null && pwd -P)
saved_ifs=$IFS
IFS=:
set -f
for entry in $PATH; do
IFS=$saved_ifs
set +f
[ -n "$entry" ] || entry=.
candidate=$entry/mesh
# -f as well as -x: [ -x ] is true for a DIRECTORY named mesh, which would be
# taken for the CLI and exec'd into a bare 126 without ever reaching the real
# one further down PATH. A shell's own PATH search skips directories.
if [ -f "$candidate" ] && [ -x "$candidate" ]; then
entry_dir=$(CDPATH= cd -- "$entry" 2>/dev/null && pwd -P)
if [ -n "$entry_dir" ] && [ "$entry_dir" != "$self_dir" ] && ! _mesh_is_shim "$candidate"; then
exec "$candidate" "$@"
fi
fi
IFS=:
set -f
done
IFS=$saved_ifs
set +f
echo "mesh: not inside a Mesh workspace (no node_modules/.bin/mesh found)," >&2
echo " and no global mesh CLI found on PATH." >&2
echo " Install it: npm i -g @mesh-tech/mesh-cli" >&2
echo " Or cd into your app/repo (after 'pnpm install') and use 'pnpm exec mesh'." >&2
exit 1
`;
}
export function defaultShimDir() {
return path.join(os.homedir(), ".local", "bin");
}
export function dirOnPath(dir, pathEnv) {
if (!pathEnv)
return false;
return pathEnv.split(path.delimiter).some((p) => p === dir);
}
export function registerInstallShimCommand(program) {
program
.command("install-shim")
.description("Install a build-free `mesh` shim on your PATH so bare `mesh` runs the local source")
.option("--dir <dir>", "Directory to install into (must be on your PATH)", defaultShimDir())
.option("-f, --force", "Overwrite an existing file at the target path", false)
.action((opts) => {
const dir = path.resolve(opts.dir);
const target = path.join(dir, "mesh");
if (fs.existsSync(target) && !opts.force) {
logWarn(`A file already exists at ${target}.`);
logInfo("Re-run with --force to overwrite it, or pass --dir <other-path-on-PATH>.");
return;
}
try {
fs.mkdirSync(dir, { recursive: true });
fs.writeFileSync(target, shimScript(), { mode: 0o755 });
fs.chmodSync(target, 0o755);
}
catch (err) {
logError(`Could not write the shim to ${target}: ${err.message}`);
process.exitCode = 1;
return;
}
logSuccess(`Installed mesh shim → ${target}`);
if (!dirOnPath(dir, process.env.PATH)) {
logWarn(`${dir} is not on your PATH.`);
logInfo(`Add it, e.g.: echo 'export PATH="${dir}:$PATH"' >> ~/.zshrc && source ~/.zshrc`);
}
else {
logInfo("Bare `mesh <cmd>` now runs the local source of whatever workspace you're in.");
}
const diagPath = path.join(os.tmpdir(), "mesh-shim-selftest.log");
let stdout = "";
let stderr = "";
let status = 0;
let ok = true;
try {
stdout = execFileSync(target, ["--help"], {
cwd: process.cwd(),
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"],
});
}
catch (err) {
ok = false;
const e = err;
status = typeof e.status === "number" ? e.status : 1;
stdout = e.stdout?.toString?.() ?? "";
stderr = e.stderr?.toString?.() ?? String(e.message ?? err);
}
const diag = [
`mesh install-shim self-test — ${new Date().toISOString()}`,
`cwd: ${process.cwd()}`,
`shim: ${target}`,
`node: ${process.execPath} (${process.version})`,
`PATH: ${process.env.PATH ?? ""}`,
`command: mesh --help`,
`exit: ${status}`,
`--- stdout (${stdout.length} bytes) ---`,
stdout,
`--- stderr (${stderr.length} bytes) ---`,
stderr,
"",
].join("\n");
try {
fs.writeFileSync(diagPath, diag);
}
catch {
}
if (ok && /Commands:|Usage:/.test(stdout)) {
logSuccess(`Self-test passed: \`mesh --help\` ran cleanly. Diagnostic: ${diagPath}`);
}
else {
logError(`Self-test FAILED (exit ${status}). Full diagnostic written to:`);
logError(` ${diagPath}`);
process.exitCode = 1;
}
});
}