diff --git a/bin/install.js b/bin/install.js index e1a5c08..75023fa 100755 --- a/bin/install.js +++ b/bin/install.js @@ -69,6 +69,10 @@ function parseArgs(argv) { case '--uninstall': case '-u': opts.uninstall = true; break; case '--non-interactive': opts.nonInteractive = true; break; case '-h': case '--help': opts.help = true; break; + // POSIX end-of-options marker. Older curl|bash flows pipe `-- --only foo` + // through npx; some npx versions forward the literal `--`. Accept and + // ignore so we never regress on the headline install command. + case '--': break; case '--only': { const v = argv[++i]; if (!v) die('error: --only requires an argument'); diff --git a/install.ps1 b/install.ps1 index a5fe086..d177789 100644 --- a/install.ps1 +++ b/install.ps1 @@ -55,5 +55,8 @@ if (-not $npx) { exit 1 } -& npx -y "github:$Repo" -- @Args +# Do NOT pass `--` here — npm 7+ npx already forwards trailing args to the +# package, and a literal `--` was tripping bin/install.js's parseArgs as an +# unknown flag. +& npx -y "github:$Repo" @Args exit $LASTEXITCODE diff --git a/install.sh b/install.sh index 9125bd3..87dbe4a 100755 --- a/install.sh +++ b/install.sh @@ -35,16 +35,20 @@ if [ "$NODE_MAJOR" -lt 18 ]; then fi # If we're inside the repo clone, run the local installer directly — saves -# the npx round-trip and keeps offline installs working. -here="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd)" || here="" +# the npx round-trip and keeps offline installs working. BASH_SOURCE is unset +# when bash is invoked from stdin (curl | bash), and `set -u` would trip on a +# bare reference — default to empty so the curl-pipe path falls through cleanly. +here="$(cd "$(dirname "${BASH_SOURCE[0]:-}")" 2>/dev/null && pwd)" || here="" if [ -n "$here" ] && [ -f "$here/bin/install.js" ]; then exec node "$here/bin/install.js" "$@" fi -# Curl-pipe path: delegate to npx. The `--` separates npx flags from our flags. +# Curl-pipe path: delegate to npx. We do NOT pass `--` here — npm 7+ npx +# already forwards trailing args to the package, and a literal `--` tripped +# bin/install.js's parseArgs as an unknown flag. if ! command -v npx >/dev/null 2>&1; then echo "caveman: npx required (ships with Node ≥18). Reinstall Node.js." >&2 exit 1 fi -exec npx -y "github:$REPO" -- "$@" +exec npx -y "github:$REPO" "$@" diff --git a/tests/installer/unit.argv.test.mjs b/tests/installer/unit.argv.test.mjs index 42234a1..5282a23 100644 --- a/tests/installer/unit.argv.test.mjs +++ b/tests/installer/unit.argv.test.mjs @@ -99,6 +99,13 @@ test('--config-dir expands ~ to home directory', async () => { } }); +test('bare -- (POSIX end-of-options) is accepted and ignored', () => { + // Regression: npx forwarded `--` from `curl|bash -- --only openclaw` to the + // package, and parseArgs rejected it as an unknown flag. Now we accept it. + const r = run('--', '--only', 'claude', '--non-interactive', '--dry-run', '--config-dir', '/tmp/__cm_dashdash'); + assert.equal(r.status, 0); +}); + test('--help discloses --config-dir scope', () => { const r = run('--help'); assert.equal(r.status, 0);