diff --git a/bin/install.js b/bin/install.js index e1020afbc..779a1ae55 100755 --- a/bin/install.js +++ b/bin/install.js @@ -8268,11 +8268,13 @@ function buildRuntimePromptText() { function parseRuntimeInput(answer) { const input = (answer == null ? '' : String(answer)).trim() || '1'; - if (input === ALL_RUNTIMES_OPTION) { + // Tokenize first so the all-runtimes shortcut also fires for inputs the + // prompt encourages — "16,", "16 1", etc. — not just the bare "16". + const choices = input.split(/[\s,]+/).filter(Boolean); + if (choices.includes(ALL_RUNTIMES_OPTION)) { return allRuntimes.slice(); } - const choices = input.split(/[\s,]+/).filter(Boolean); const selected = []; for (const c of choices) { const runtime = runtimeMap[c]; diff --git a/tests/hermes-install.test.cjs b/tests/hermes-install.test.cjs index 3724e4d0c..13d2395a5 100644 --- a/tests/hermes-install.test.cjs +++ b/tests/hermes-install.test.cjs @@ -23,7 +23,16 @@ describe('Hermes Agent runtime directory mapping', () => { }); test('maps Hermes to ~/.hermes for global installs', () => { - assert.strictEqual(getGlobalDir('hermes'), path.join(os.homedir(), '.hermes')); + // Isolate from any HERMES_HOME exported on the developer's machine — + // otherwise this test asserts the env-derived path, not the default. + const originalHermesHome = process.env.HERMES_HOME; + delete process.env.HERMES_HOME; + try { + assert.strictEqual(getGlobalDir('hermes'), path.join(os.homedir(), '.hermes')); + } finally { + if (originalHermesHome === undefined) delete process.env.HERMES_HOME; + else process.env.HERMES_HOME = originalHermesHome; + } }); test('returns .hermes config fragments for local and global installs', () => { diff --git a/tests/multi-runtime-select.test.cjs b/tests/multi-runtime-select.test.cjs index e7f760dc1..1e15d046b 100644 --- a/tests/multi-runtime-select.test.cjs +++ b/tests/multi-runtime-select.test.cjs @@ -84,6 +84,17 @@ describe('multi-runtime selection parsing', () => { assert.deepStrictEqual(parseRuntimeInput('16'), allRuntimes); }); + test('choice 16 returns all runtimes when mixed with separators or other tokens', () => { + // CR feedback: tokenized inputs that include 16 (e.g. trailing comma, or + // alongside other choices) must still expand to all-runtimes — previously + // only the bare "16" matched, so "16," or "16 1" silently installed a + // subset. + assert.deepStrictEqual(parseRuntimeInput('16,'), allRuntimes); + assert.deepStrictEqual(parseRuntimeInput('16 1'), allRuntimes); + assert.deepStrictEqual(parseRuntimeInput('1,16'), allRuntimes); + assert.deepStrictEqual(parseRuntimeInput(' 16 '), allRuntimes); + }); + test('empty input defaults to claude', () => { assert.deepStrictEqual(parseRuntimeInput(''), ['claude']); assert.deepStrictEqual(parseRuntimeInput(' '), ['claude']);