Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion bin/moshcode.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,10 @@ function parseMax(value) {
// interactive. Piped / non-TTY invocations (scripts, CI, `… | moshcode run -`)
// keep the old behaviour: exit with the child's code.
function backToPit(label, code, signal) {
if (!process.stdin.isTTY) process.exit(code ?? 0);
// A nested invocation (moshscript shim, or a CLI verb called from a script)
// must hand control back to its parent, not open a second mosh pit on the
// shared TTY.
if (!process.stdin.isTTY || process.env.MOSHCODE_NESTED === "1") process.exit(code ?? 0);
const how = signal ? ` (${signal})` : code != null ? ` (code ${code})` : "";
console.log(`\n↩ ${label} exited${how} β€” back in the mosh pit. /quit to leave.\n`);
return tui();
Expand Down
5 changes: 4 additions & 1 deletion bin/moshscript.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import { fileURLToPath } from "node:url";
const BIN = fileURLToPath(new URL("moshcode.mjs", import.meta.url));
const args = process.argv.slice(2); // everything after `moshscript`

const child = spawn(process.execPath, [BIN, "run", ...args], { stdio: "inherit" });
const child = spawn(process.execPath, [BIN, "run", ...args], {
stdio: "inherit",
env: { ...process.env, MOSHCODE_NESTED: "1" },
});
child.on("error", (e) => { console.error(`moshscript: ${e.message}`); process.exit(1); });
child.on("exit", (code, signal) => {
if (signal) {
Expand Down
5 changes: 4 additions & 1 deletion src/cli.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ export function runMoshcode(cmd, args, ctx) {
}

ctx.out(` β–Ά ${printable}`);
const res = spawnSync(process.execPath, [MOSHCODE_BIN, ...argv], { stdio: "inherit" });
const res = spawnSync(process.execPath, [MOSHCODE_BIN, ...argv], {
stdio: "inherit",
env: { ...process.env, MOSHCODE_NESTED: "1" },
});
if (res.error) throw res.error; // truly fatal: spawn itself failed (ENOENT etc.)

const code = res.status ?? 1;
Expand Down
15 changes: 15 additions & 0 deletions test/run-options.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ test("run accepts equals-form max option", async () => {
assert.match(result.stdout, /1 loop\(s\)/);
});

test("run() marks the nested moshcode child as nested", async () => {
const dir = mkdtempSync(join(tmpdir(), "moshcode-nested-"));
const child = join(dir, "child.mosh");
const parent = join(dir, "parent.mosh");
writeFileSync(child, 'shell("echo NESTEDVAL=$MOSHCODE_NESTED");\n');
writeFileSync(parent, `run(${JSON.stringify(child)});\n`);

const result = await run([parent]);

assert.equal(result.status, 0);
// Without MOSHCODE_NESTED the child drops into its own TUI on a shared TTY
// instead of returning control to the parent script.
assert.match(result.stdout, /NESTEDVAL=1/);
});

test("run() includes another .mosh file, in order", async () => {
const dir = mkdtempSync(join(tmpdir(), "moshcode-include-"));
const child = join(dir, "child.mosh");
Expand Down
Loading