{"record":{"id":"901dc727c867baed","repo":"can1357/oh-my-pi","slug":"rounds-must-be-a-positive-integer-901dc7","errorCode":null,"errorMessage":"--rounds must be a positive integer","messagePattern":"--rounds must be a positive integer","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/compress/index.ts","lineNumber":80,"sourceCode":"\t\t\t\tfound.add(match);\n\t\t\t\tmatched += 1;\n\t\t\t}\n\t\t\tif (matched === 0) throw new Error(`No files matched \"${pattern}\"`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst resolved = path.resolve(cwd, pattern);\n\t\tconst stat = await fs.stat(resolved).catch(() => undefined);\n\t\tif (!stat?.isFile()) throw new Error(`Not a file: ${shortenPath(resolved)}`);\n\t\tfound.add(resolved);\n\t}\n\treturn [...found].sort();\n}\n\n/** Compress every requested file through the rewrite/approve loop. */\nexport async function runCompressCommand(options: CompressCommandOptions): Promise<CompressResult> {\n\tconst maxRounds = options.maxRounds ?? DEFAULT_MAX_ROUNDS;\n\tconst concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;\n\tif (!Number.isInteger(maxRounds) || maxRounds <= 0) throw new Error(\"--rounds must be a positive integer\");\n\tif (!Number.isInteger(concurrency) || concurrency <= 0) throw new Error(\"--agents must be a positive integer\");\n\tif (options.inPlace && options.output) throw new Error(\"--in-place and --out are mutually exclusive\");\n\t// Paths and patterns follow the shell's cwd, as a file-taking CLI must; the project\n\t// dir only scopes settings discovery for the sessions.\n\tconst invocationDir = process.cwd();\n\tconst cwd = getProjectDir();\n\tconst targets = await resolveCompressTargets(options.files, invocationDir);\n\tif (targets.length === 0) throw new Error(\"No files to compress\");\n\tif (targets.length > 1 && !options.inPlace) {\n\t\tthrow new Error(`${targets.length} files matched; pass --in-place to rewrite them (--out takes a single file)`);\n\t}\n\n\tconst abortController = new AbortController();\n\tconst abort = (): void => abortController.abort(new Error(\"Compress interrupted\"));\n\tprocess.once(\"SIGINT\", abort);\n\tprocess.once(\"SIGTERM\", abort);\n\tconst progress = createProgressReporter(\"Compressing\");\n\tconst emitToStdout = targets.length === 1 && !options.inPlace && options.output === undefined;","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/compress/index.ts#L62-L98","documentation":"runCompressCommand validates CLI options before doing any work. maxRounds (from --rounds, defaulting to DEFAULT_MAX_ROUNDS) must be a positive integer; otherwise it throws. This catches non-numeric, zero, negative, or fractional round counts that would make the rewrite loop meaningless or infinite.","triggerScenarios":"Invoking the compress command with `--rounds 0`, `--rounds -1`, `--rounds abc`, `--rounds 1.5`, or programmatically passing a non-integer options.maxRounds.","commonSituations":"Shell variable interpolation producing an empty/invalid value (`--rounds $UNSET_VAR`); copy-pasted config with 0 meaning 'unlimited'; scripts constructing options objects with float or string values.","solutions":["Pass a positive integer, e.g. `--rounds 3`.","Check the script/env that supplies the value (an unset shell variable expands to empty string).","Omit the flag to use the default round count.","Fix programmatic callers to pass an integer number, not a string or float."],"exampleFix":"// before\nomp compress file.ts --rounds 0\n// after\nomp compress file.ts --rounds 3","handlingStrategy":"validation","validationCode":"function validRounds(v: unknown): v is number {\n  return typeof v === \"number\" && Number.isInteger(v) && v > 0;\n}\nif (!validRounds(maxRounds)) throw new Error(\"--rounds must be a positive integer\");","typeGuard":"function isPositiveInt(v: unknown): v is number {\n  return typeof v === \"number\" && Number.isInteger(v) && v > 0;\n}","tryCatchPattern":"try {\n  await runCompressCommand({ ...options, maxRounds });\n} catch (err) {\n  if (err instanceof Error && err.message === \"--rounds must be a positive integer\") {\n    process.stderr.write(`${err.message} (got: ${String(options.maxRounds)})\\n`);\n  } else throw err;\n}","preventionTips":["Always pass plain integers to --rounds (e.g. 1, 3, 5).","Guard shell interpolation: `--rounds \"${ROUNDS:-3}\"`.","Omit the flag to accept the default.","Validate numeric CLI inputs with Number() before constructing options objects in scripts."],"tags":["cli","argument-validation","configuration"],"backgroundTag":"invalid-cli-argument","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}