Skip to content

Commit 110f333

Browse files
pranavcodeantclaude
andcommitted
Parse numeric CLI options in base 10
Commander passes an option's default as the parser's second argument, so the bare parseInt parsers used it as the radix: `scans results --limit` (default 100) was always NaN and fell back to 100, and `--limit 30` with a default of 20 became 60. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent c5749d9 commit 110f333

3 files changed

Lines changed: 24 additions & 16 deletions

File tree

‎changelog.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
- SCA severity is read from the advisory rating instead of defaulting to medium
99
- Extra dead-code file paths no longer end in the result file name
1010
- Removed a debug dump of full scan responses to stderr
11+
- Fixed numeric options with defaults (`scans results --limit`, `scans history --limit`, PR comment `--limit`) being parsed in the wrong radix
1112

1213
## [0.5.7] - 28/09/2026
1314
- Login tokens are prefixed with `cli___` so CLI logins show up as CLI on the IDE users page

‎src/commands/scans/index.js‎

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import { runStartScan } from './start-scan.js';
88
import { setQuiet, setNoColor } from './lib/log.js';
99
import { setNoColor as tableSetNoColor } from './formatters/table.js';
1010

11+
// Commander passes the default as the parser's second argument; keep it out of the radix.
12+
const toInt = (value) => Number.parseInt(value, 10);
13+
1114
/**
1215
* Register all `codeant scans <verb>` subcommands.
1316
*
@@ -37,7 +40,7 @@ export default function registerScansCommands(program, { runCmd }) {
3740
.requiredOption('--repo <repo>', 'Repository (owner/repo)')
3841
.option('--branch <name>', 'Filter by branch name')
3942
.option('--since <iso>', 'Show scans since ISO date')
40-
.option('--limit <n>', 'Max results (default: 20)', parseInt, 20)
43+
.option('--limit <n>', 'Max results (default: 20)', toInt, 20)
4144
.action((opts) =>
4245
runCmd(() => runHistory({ repo: opts.repo, branch: opts.branch, since: opts.since, limit: opts.limit }))
4346
);
@@ -76,8 +79,8 @@ export default function registerScansCommands(program, { runCmd }) {
7679
.option('--format <fmt>', 'Output format: json|sarif|csv|md|table (default: json)', 'json')
7780
.option('--output <path>', 'Write output to file instead of stdout')
7881
.option('--fields <list>', 'Project findings to subset of fields (comma-separated)')
79-
.option('--limit <n>', 'Max findings per page (default: 100)', parseInt, 100)
80-
.option('--offset <n>', 'Pagination offset (default: 0)', parseInt, 0)
82+
.option('--limit <n>', 'Max findings per page (default: 100)', toInt, 100)
83+
.option('--offset <n>', 'Pagination offset (default: 0)', toInt, 0)
8184
.option('--fail-fast', 'Exit 3 on first category fetch failure')
8285
.option('--no-color', 'Disable ANSI color (auto-disabled when not a TTY)')
8386
.option('--quiet', 'Suppress progress output on stderr')

‎src/index.js‎

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ import registerFindingsCommands from './commands/findings/index.js';
3131
const require = createRequire(import.meta.url);
3232
const pkg = require('../package.json');
3333

34+
// Commander passes an option's default as the parser's second argument, so a
35+
// bare `parseInt` would use it as the radix (`--limit 30` with default 20 → 60).
36+
const toInt = (value) => Number.parseInt(value, 10);
37+
3438
// Split comma-separated globs while preserving commas inside {} brace expansions (e.g. "*.{js,ts}")
3539
function splitGlobs(input) {
3640
const parts = [];
@@ -67,7 +71,7 @@ program
6771
.option('--uncommitted', 'Scan only uncommitted changes (staged + unstaged + untracked)')
6872
.option('--staged', 'Scan only staged files')
6973
.option('--last-commit', 'Scan last commit')
70-
.option('--last-n-commits <n>', 'Scan last n commits (max 5)', parseInt)
74+
.option('--last-n-commits <n>', 'Scan last n commits (max 5)', toInt)
7175
.option('--base <branch>', 'Compare against a specific base branch (e.g. --base develop)')
7276
.option('--base-commit <commit>', 'Compare against a specific commit (e.g. --base-commit HEAD~3)')
7377
.option('--include <paths>', 'Comma-separated list of file paths glob patterns to include')
@@ -118,7 +122,7 @@ program
118122
.option('--uncommitted', 'Review only uncommitted changes (staged + unstaged + untracked)')
119123
.option('--staged', 'Review only staged files')
120124
.option('--last-commit', 'Review last commit')
121-
.option('--last-n-commits <n>', 'Review last n commits (max 5)', parseInt)
125+
.option('--last-n-commits <n>', 'Review last n commits (max 5)', toInt)
122126
.option('--base <branch>', 'Compare against a specific base branch (e.g. --base develop)')
123127
.option('--base-commit <commit>', 'Compare against a specific commit (e.g. --base-commit HEAD~3)')
124128
.option('--fail-on <level>', 'Fail on issues at or above this level: BLOCKER, CRITICAL, MAJOR, MINOR, INFO (default: CRITICAL)', 'CRITICAL')
@@ -299,8 +303,8 @@ program
299303
.option('--source-branch <branch>', 'Filter by source branch (partial match)')
300304
.option('--author <login>', 'Filter by author (fuzzy match)')
301305
.option('--state <state>', 'open or closed (default: open)', 'open')
302-
.option('--limit <n>', 'Max results (default: 20, max: 100)', parseInt, 20)
303-
.option('--offset <n>', 'Pagination offset', parseInt, 0)
306+
.option('--limit <n>', 'Max results (default: 20, max: 100)', toInt, 20)
307+
.option('--offset <n>', 'Pagination offset', toInt, 0)
304308
.action((options) => {
305309
const opts = resolveRepoOpts(options);
306310
runCmd(() => scm.listPullRequests({
@@ -315,7 +319,7 @@ program
315319
.option('--name <repo>', 'Repository (owner/repo)')
316320
.option('--remote <provider>', 'github, gitlab, bitbucket, azure')
317321
.option('--default-branch <branch>', 'Default branch name')
318-
.requiredOption('--pr-number <n>', 'PR number', parseInt)
322+
.requiredOption('--pr-number <n>', 'PR number', toInt)
319323
.action((options) => {
320324
const opts = resolveRepoOpts(options);
321325
runCmd(() => scm.getPullRequest({
@@ -329,7 +333,7 @@ program
329333
.option('--name <repo>', 'Repository (owner/repo)')
330334
.option('--remote <provider>', 'github, gitlab, bitbucket, azure')
331335
.option('--default-branch <branch>', 'Default branch name')
332-
.requiredOption('--pr-number <n>', 'PR number', parseInt)
336+
.requiredOption('--pr-number <n>', 'PR number', toInt)
333337
.option('--codeant-generated <bool>', 'Filter by CodeAnt authorship (true/false)', (v) => v === 'true')
334338
.option('--addressed', 'Filter by addressed/resolved status')
335339
.option('--created-after <date>', 'ISO 8601 date filter')
@@ -347,8 +351,8 @@ program
347351
.description('Resolve a conversation/comment thread on a PR')
348352
.option('--name <repo>', 'Repository (owner/repo)')
349353
.option('--remote <provider>', 'github, gitlab, bitbucket, azure')
350-
.requiredOption('--pr-number <n>', 'PR number', parseInt)
351-
.option('--comment-id <id>', 'Comment ID (GitHub, Bitbucket)', parseInt)
354+
.requiredOption('--pr-number <n>', 'PR number', toInt)
355+
.option('--comment-id <id>', 'Comment ID (GitHub, Bitbucket)', toInt)
352356
.option('--thread-id <id>', 'Thread/node ID (GitHub GraphQL, Azure)')
353357
.option('--discussion-id <id>', 'Discussion ID (GitLab)')
354358
.action((options) => {
@@ -370,10 +374,10 @@ program
370374
.option('--name <repo>', 'Repository (owner/repo)')
371375
.option('--remote <provider>', 'github, gitlab, bitbucket, azure')
372376
.option('--default-branch <branch>', 'Default branch name')
373-
.option('--pr-number <n>', 'Filter by PR number', parseInt)
377+
.option('--pr-number <n>', 'Filter by PR number', toInt)
374378
.option('--status <status>', 'Filter by status (PENDING, COMPLETED, FAILED, etc.)')
375-
.option('--limit <n>', 'Max results (default: 20)', parseInt, 20)
376-
.option('--offset <n>', 'Pagination offset', parseInt, 0)
379+
.option('--limit <n>', 'Max results (default: 20)', toInt, 20)
380+
.option('--offset <n>', 'Pagination offset', toInt, 0)
377381
.action((options) => {
378382
const opts = resolveRepoOpts(options);
379383
runCmd(() => scm.listCodeReviews({
@@ -387,7 +391,7 @@ program
387391
.description('Get detailed information for a specific code review')
388392
.option('--name <repo>', 'Repository (owner/repo)')
389393
.option('--remote <provider>', 'github, gitlab, bitbucket, azure')
390-
.requiredOption('--pr-number <n>', 'PR number', parseInt)
394+
.requiredOption('--pr-number <n>', 'PR number', toInt)
391395
.requiredOption('--review-id <id>', 'Code review ID')
392396
.action((options) => {
393397
const opts = resolveRepoOpts(options);
@@ -405,7 +409,7 @@ program
405409
.option('--name <repo>', 'Repository (owner/repo)')
406410
.option('--remote <provider>', 'github, gitlab, bitbucket, azure')
407411
.requiredOption('--query <term>', 'Search term')
408-
.option('--limit <n>', 'Max results (default: 10, max: 50)', parseInt, 10)
412+
.option('--limit <n>', 'Max results (default: 10, max: 50)', toInt, 10)
409413
.option('--include-addressed', 'Include resolved comments (default: false)')
410414
.option('--created-after <date>', 'ISO 8601 date filter')
411415
.action((options) => {

0 commit comments

Comments
 (0)