From e04a0cd2fb9ee5f1920ec32466e35dddca43c948 Mon Sep 17 00:00:00 2001 From: aiirvizionz Date: Sat, 18 Jul 2026 16:38:48 -0600 Subject: [PATCH] fix(tui): reject unknown run options --- src/tui.mjs | 3 +++ test/tui.test.mjs | 25 +++++++++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/tui.mjs b/src/tui.mjs index 289629f..eb574a0 100644 --- a/src/tui.mjs +++ b/src/tui.mjs @@ -277,6 +277,9 @@ async function runFile(args) { max = v; } else if (a === "--dry-run") { dryRun = true; + } else if (a.startsWith("-") && !file) { + console.log(err(`unknown option ${a}`)); + return; } else if (!file) { file = a; } diff --git a/test/tui.test.mjs b/test/tui.test.mjs index cce4552..b030e2a 100644 --- a/test/tui.test.mjs +++ b/test/tui.test.mjs @@ -1,8 +1,25 @@ import assert from "node:assert/strict"; +import { spawn } from "node:child_process"; import test from "node:test"; +import { fileURLToPath } from "node:url"; import { splitCommandLine } from "../src/tui.mjs"; +const BIN = fileURLToPath(new URL("../bin/moshcode.mjs", import.meta.url)); + +function runTui(input) { + return new Promise((resolve, reject) => { + const child = spawn(process.execPath, [BIN], { stdio: ["pipe", "pipe", "pipe"] }); + let stdout = ""; + let stderr = ""; + child.stdout.on("data", (chunk) => { stdout += chunk; }); + child.stderr.on("data", (chunk) => { stderr += chunk; }); + child.on("error", reject); + child.on("close", (status, signal) => resolve({ status, signal, stdout, stderr })); + child.stdin.end(input); + }); +} + test("TUI command parsing preserves quoted native CLI arguments", () => { assert.deepEqual( splitCommandLine('/coinpay card pay --description "Fix the build" --note \'ship it\''), @@ -23,3 +40,11 @@ test("TUI command parsing rejects incomplete quoting", () => { assert.throws(() => splitCommandLine('/coinpay --description "unfinished'), /unterminated/); assert.throws(() => splitCommandLine("/ugig trailing\\"), /trailing escape/); }); + +test("TUI /run rejects unknown options before reading a script file", async () => { + const result = await runTui("/run --dryrun\n/quit\n"); + + assert.equal(result.status, 0); + assert.match(result.stdout, /unknown option --dryrun/); + assert.doesNotMatch(result.stdout, /can't read --dryrun/); +});