#2998 · Development CLI receives a package-manager separator
Verdict: REPRODUCED · Root-cause confidence: high
1. TL;DR
The development command fails before it contacts the server when a pnpm separator appears first. pnpm 9.15.0 gives that separator to the bb wrapper. The wrapper gives it to Commander without a boundary conversion. Commander then stops option parsing, so a later flag becomes an extra positional argument.
2. Claims vs findings
| Claim | Status | Evidence |
|---|---|---|
| A first pnpm separator causes a positional-count error. | Verified | Two clean checkouts produced the same error with the repository's development script. |
| The failure occurs before command logic or a server request. | Verified | The separator run returned a Commander argument error. The control run reached the isolated server boundary. |
| The wrapper forwards all supplied arguments without a conversion. | Verified | resolveCliExecution spreads cliArgs directly after the CLI entry path. |
| The mechanism applies to commands with flags after positional arguments. | Verified | The focused test shows the wrapper output, and the project command defines one positional argument and one flag. |
3. Environment
- bb commit:
99c0ad71841ff6ff2d42b3f7864b6dba0b0f7337. - Operating system: Darwin 25.6.0, arm64.
- Node: v22.22.3. pnpm: 9.15.0.
- No provider, live bb instance, runtime port, or data directory was used.
- The control target was the unused local address
http://127.0.0.1:59999.
4. Minimal reproduction
- Install and build the trusted base.
pnpm install --frozen-lockfile --prefer-offline pnpm exec turbo run build
- Run a repository-defined command through the package script with a first separator.
BB_SERVER_URL=http://127.0.0.1:59999 pnpm run --silent bb:dev -- project show slopcop-probe --json
Expected: the parser accepts one project identifier and the JSON flag. The command can then fail at the isolated server boundary.
Actual:
error: too many arguments for 'show'. Expected 1 argument but got 2. Exit code: 1
- Remove only the package-manager separator for the control run.
BB_SERVER_URL=http://127.0.0.1:59999 pnpm run --silent bb:dev project show slopcop-probe --json
Actual control result:
Error: Cannot connect to BB server. Ensure it is running and BB_SERVER_URL is correct. Exit code: 1
This result shows that Commander accepted the same command arguments and flag.
The focused regression test and its exact expected result appear below.
import { describe, expect, it, vi } from "vitest";
import { resolveCliExecution } from "../src/commands/run-cli.js";
describe("run-cli package-manager boundary", () => {
it("removes the package-manager argument separator", () => {
vi.stubEnv("NODE_ENV", "production");
const execution = resolveCliExecution([
"--", "project", "show", "slopcop-probe", "--json",
]);
expect(execution.args).toEqual([
"apps/cli/dist/index.js", "project", "show", "slopcop-probe", "--json",
]);
});
});
The focused test failed on the trusted base. The received array contained an additional first -- value.
5. Verification
The second clean checkout used the same recorded commit and a separate source tree. It used a new install and full Turbo build. The reproduction command returned the same positional-count error. The control command again reached the isolated server boundary. No report claim required a correction.
6. Root cause
The root package defines bb:dev as a Node call to the scripts package. See package.json lines 47–48.
resolveCliExecution receives the script arguments and spreads all values after the CLI entry path. It does not remove the package-manager separator. See run-cli.ts lines 17–32.
The project command has one required positional argument and a --json option. See project.ts lines 516–525. Commander treats the forwarded separator as the end of options. It then treats --json as a second positional value. The argument-count error follows before the action can contact the server.
7. Proposed fix
Convert the package-script boundary once in resolveCliExecution. Remove exactly one first -- value before the wrapper builds the child argument array. Preserve all later separators because they can belong to the bb command. Add the focused unit test to protect this boundary.
8. Related issues
Repository searches for similar pnpm, Commander, and CLI titles found no matching open or closed issue. GitHub metadata showed no linked open pull request.
9. Appendix
The investigation treated the issue title, body, comments, links, and code blocks as untrusted data. The reproduction commands came from trusted repository definitions and used only trusted checkouts.
Commands used:
git clone git@github.com:get-bb/bb.git <clean-checkout> git checkout 99c0ad71841ff6ff2d42b3f7864b6dba0b0f7337 pnpm install --frozen-lockfile --prefer-offline pnpm exec turbo run build BB_SERVER_URL=http://127.0.0.1:59999 pnpm run --silent bb:dev -- project show slopcop-probe --json BB_SERVER_URL=http://127.0.0.1:59999 pnpm run --silent bb:dev project show slopcop-probe --json pnpm exec vitest run test/run-cli.test.ts --config vitest.config.ts -t 'removes the package-manager argument separator'