From d095a9310a295d73e1d33af6185bee9ce15bf48e Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 16:21:42 +0000 Subject: [PATCH 1/3] fix: show help when an unknown command is executed This ensures `clasp x` shows the help menu instead of failing with a stack trace. Co-authored-by: sqrrrl <346343+sqrrrl@users.noreply.github.com> --- src/commands/program.ts | 8 +++++--- src/core/clasp.ts | 3 ++- test.js | 8 ++++++++ test/commands/program.ts | 16 ++++++++++++++++ 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 test.js diff --git a/src/commands/program.ts b/src/commands/program.ts index de64d351..d65bc2d6 100644 --- a/src/commands/program.ts +++ b/src/commands/program.ts @@ -179,7 +179,7 @@ export function makeProgram(exitOverride?: (err: CommanderError) => void) { cmd.copyInheritedSettings(program); } - program.on('command:*', async function (this: Command, op) { + program.on('command:*', function (this: Command, op) { const msg = intl.formatMessage( { defaultMessage: 'Unknown command "clasp {command}"', @@ -188,10 +188,12 @@ export function makeProgram(exitOverride?: (err: CommanderError) => void) { command: op[0], }, ); - this.error(msg as string); + console.error(msg as string); + process.exitCode = 1; + program.help(); }); - program.error; + program.showHelpAfterError(); return program; } diff --git a/src/core/clasp.ts b/src/core/clasp.ts index 10e44598..9d5030d6 100644 --- a/src/core/clasp.ts +++ b/src/core/clasp.ts @@ -203,7 +203,8 @@ export async function initClaspInstance(options: InitOptions): Promise { const rootDirReal = await fs.realpath(projectRoot.rootDir).catch(() => projectRoot.rootDir); // Strict validation: resolved path must be rootDir or properly inside it - const isValid = contentDir === projectRoot.rootDir || + const isValid = + contentDir === projectRoot.rootDir || (contentDir.startsWith(rootDirReal + path.sep) && isInside(projectRoot.rootDir, contentDir)); if (!isValid) { diff --git a/test.js b/test.js new file mode 100644 index 00000000..47b37200 --- /dev/null +++ b/test.js @@ -0,0 +1,8 @@ +import {makeProgram} from './build/src/commands/program.js'; + +const program = makeProgram((err) => { + console.log("ERR CODE:", err.code); + throw err; +}); + +program.parseAsync(['node', 'clasp', 'abc']).catch(e => console.log("CAUGHT CODE:", e.code)); diff --git a/test/commands/program.ts b/test/commands/program.ts index 818d6e01..9fc03db8 100644 --- a/test/commands/program.ts +++ b/test/commands/program.ts @@ -19,6 +19,7 @@ import {expect} from 'chai'; import {describe, it} from 'mocha'; import {makeProgram} from '../../src/commands/program.js'; +import {runCommand} from './utils.js'; describe('Consistency between imported and registered commands', () => { const expectedCommands = [ @@ -67,3 +68,18 @@ describe('Consistency between imported and registered commands', () => { expect(program.commands).to.length(expectedCommands.length); }); }); + +describe('Unknown commands', () => { + it('should print help when an unknown command is provided', async () => { + const result = await runCommand(['nonexistentcommand'], false); + + expect(result.stderr).to.contain('Unknown command "clasp nonexistentcommand"'); + // `commander.help` throws when exitOverride is enabled (as runCommand does), + // and outputs the help to stdout usually, but let's just check the message and exit code. + expect(result.message).to.contain('(outputHelp)'); + + // Also the global process.exitCode should be set to 1 by our patch + expect(process.exitCode).to.equal(1); + process.exitCode = 0; // reset for subsequent tests + }); +}); From 6bafbb26a004899c9cf995358db7c57b65d286fc Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 16:36:37 +0000 Subject: [PATCH 2/3] fix: print help instead of throwing error on unknown commands This ensures `clasp ` properly outputs an error message and shows the help menu instead of crashing with a raw unhandled stack trace. Added a unit test. Co-authored-by: sqrrrl <346343+sqrrrl@users.noreply.github.com> --- original_program.ts | 17 +++++++++++++++++ src/commands/program.ts | 2 -- test.js | 8 -------- 3 files changed, 17 insertions(+), 10 deletions(-) create mode 100644 original_program.ts delete mode 100644 test.js diff --git a/original_program.ts b/original_program.ts new file mode 100644 index 00000000..c98d9409 --- /dev/null +++ b/original_program.ts @@ -0,0 +1,17 @@ +// ... (skip down to line 179) + program.on('command:*', async function (this: Command, op) { + const msg = intl.formatMessage( + { + defaultMessage: 'Unknown command "clasp {command}"', + }, + { + command: op[0], + }, + ); + this.error(msg as string); + }); + + program.error; + + return program; +} diff --git a/src/commands/program.ts b/src/commands/program.ts index d65bc2d6..b918c08b 100644 --- a/src/commands/program.ts +++ b/src/commands/program.ts @@ -193,7 +193,5 @@ export function makeProgram(exitOverride?: (err: CommanderError) => void) { program.help(); }); - program.showHelpAfterError(); - return program; } diff --git a/test.js b/test.js deleted file mode 100644 index 47b37200..00000000 --- a/test.js +++ /dev/null @@ -1,8 +0,0 @@ -import {makeProgram} from './build/src/commands/program.js'; - -const program = makeProgram((err) => { - console.log("ERR CODE:", err.code); - throw err; -}); - -program.parseAsync(['node', 'clasp', 'abc']).catch(e => console.log("CAUGHT CODE:", e.code)); From 54f143c02c1e759b44409f68bed5a2c5d37a2b71 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Mon, 8 Jun 2026 16:47:32 +0000 Subject: [PATCH 3/3] fix: print help instead of throwing error on unknown commands This ensures `clasp ` properly outputs an error message and shows the help menu instead of crashing with a raw unhandled stack trace. Added a unit test. Co-authored-by: sqrrrl <346343+sqrrrl@users.noreply.github.com> --- test/commands/program.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test/commands/program.ts b/test/commands/program.ts index 9fc03db8..21fb0a10 100644 --- a/test/commands/program.ts +++ b/test/commands/program.ts @@ -74,9 +74,7 @@ describe('Unknown commands', () => { const result = await runCommand(['nonexistentcommand'], false); expect(result.stderr).to.contain('Unknown command "clasp nonexistentcommand"'); - // `commander.help` throws when exitOverride is enabled (as runCommand does), - // and outputs the help to stdout usually, but let's just check the message and exit code. - expect(result.message).to.contain('(outputHelp)'); + expect(result.stdout).to.contain('Usage: clasp [options]'); // Also the global process.exitCode should be set to 1 by our patch expect(process.exitCode).to.equal(1);