{"record":{"id":"7a27e0a98d38d505","repo":"can1357/oh-my-pi","slug":"message-7a27e0","errorCode":null,"errorMessage":"${message}","messagePattern":"\\$\\{message\\}","errorType":"exception","errorClass":"CliError","httpStatus":null,"severity":"error","filePath":"packages/mnemopi/src/cli.ts","lineNumber":50,"sourceCode":"\t}\n}\n\ntype CommandHandler = (args: readonly string[], context?: CliContext) => number | Promise<number>;\n\nfunction out(context: CliContext | undefined, text = \"\"): void {\n\t(context?.stdout ?? Bun.stdout).write(`${text}\\n`);\n}\n\nfunction err(context: CliContext | undefined, text = \"\"): void {\n\t(context?.stderr ?? Bun.stderr).write(`${text}\\n`);\n}\n\nfunction fail(message: string, exitCode = 2): never {\n\tthrow new CliError(`Error: ${message}`, exitCode);\n}\n\nfunction usage(message: string): never {\n\tthrow new CliError(message, 2);\n}\n\nfunction parseFloatArg(value: string, name: string): number {\n\tconst parsed = Number(value);\n\tif (!Number.isFinite(parsed)) fail(`${name} must be a number: ${value}`);\n\treturn parsed;\n}\n\nfunction parseIntArg(value: string, name: string): number {\n\tif (!/^[+-]?\\d+$/.test(value)) fail(`${name} must be an integer: ${value}`);\n\tconst parsed = Number(value);\n\tif (!Number.isSafeInteger(parsed)) fail(`${name} must be an integer: ${value}`);\n\treturn parsed;\n}\n\nfunction resolveDataDir(context?: CliContext): string {\n\treturn context?.dataDir ?? configuredDataDir();\n}","sourceCodeStart":32,"sourceCodeEnd":68,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/mnemopi/src/cli.ts#L32-L68","documentation":"`usage()` is the CLI argument-parsing failure path in the mnemopi CLI. It throws a `CliError` with exit code 2 whenever the command line is malformed — bad subcommand, missing/extra arguments, or invalid flag values. The error message is printed by the top-level CLI handler instead of a stack trace.","triggerScenarios":"Running the CLI with an unknown subcommand, a missing required argument, an unrecognized flag, or an argument that fails parsing (e.g. `parseFloatArg` companion `fail()` is used for non-numeric numeric options).","commonSituations":"Typo'd subcommands in shell scripts or CI pipelines, calling the CLI with Python-style flag names or old syntax after an upgrade, forgetting required positional args, passing a non-numeric value to a numeric option.","solutions":["Run the CLI with `--help` (or no args) and use the documented syntax for the subcommand.","Check the exact argument name and order expected by the subcommand in the CLI source (`packages/mnemopi/src/cli.ts`).","In scripts, quote/validate values before passing them (e.g. ensure numeric args are finite numbers).","Update any wrapper scripts that target a deprecated or renamed subcommand."],"exampleFix":"// before\nbun cli annotate --bank my bank --score ten\n// after\nbun cli annotate --bank my-bank --score 10","handlingStrategy":"validation","validationCode":"const args = process.argv.slice(2);\nconst VALID = new Set([\"annotate\", \"search\", \"bank\", \"import\", \"export\"]);\nif (!VALID.has(args[0])) {\n  console.error(`Unknown subcommand: ${args[0]}. Run with --help.`);\n  process.exit(2);\n}","typeGuard":"null","tryCatchPattern":"try {\n  runCli(argv);\n} catch (err) {\n  if (err instanceof CliError) {\n    console.error(err.message);\n    process.exit(err.exitCode);\n  }\n  throw err;\n}","preventionTips":["Run `--help` before scripting an unfamiliar subcommand.","Validate/quote shell variables passed as CLI args.","Pin the CLI version in CI so flag syntax doesn't drift.","Assert arg count/types before spawning the CLI."],"tags":["cli","argument-parsing","usage"],"backgroundTag":"cli-usage-error","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}