{"record":{"id":"3a5c840417cbcc23","repo":"tinyhumansai/openhuman","slug":"unknown-argument-arg","errorCode":null,"errorMessage":"unknown argument: ${arg}","messagePattern":"unknown argument: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/prune-dev-keychain.mjs","lineNumber":52,"sourceCode":"import os from \"node:os\";\nimport path from \"node:path\";\n\n/** `tempfile`'s default TempDir basename: `.tmp` + 6 random alphanumerics. */\nconst LEAKED_USER_ID = /^\\.tmp[A-Za-z0-9]{6}$/;\n\nfunction parseArgs(argv) {\n  const args = { apply: false, file: null };\n  for (let i = 0; i < argv.length; i += 1) {\n    const arg = argv[i];\n    if (arg === \"--apply\") {\n      args.apply = true;\n    } else if (arg === \"--file\") {\n      args.file = argv[i + 1];\n      i += 1;\n    } else if (arg === \"--help\" || arg === \"-h\") {\n      args.help = true;\n    } else {\n      throw new Error(`unknown argument: ${arg}`);\n    }\n  }\n  return args;\n}\n\nfunction defaultKeychainPath() {\n  const workspace = process.env.OPENHUMAN_WORKSPACE?.trim();\n  if (workspace) return path.join(workspace, \"dev-keychain.json\");\n  const dir =\n    process.env.OPENHUMAN_APP_ENV === \"staging\"\n      ? \".openhuman-staging\"\n      : \".openhuman\";\n  return path.join(os.homedir(), dir, \"dev-keychain.json\");\n}\n\n/** An entry is leaked when its user-id segment is a dead TempDir basename. */\nfunction isLeaked(key) {\n  const separator = key.indexOf(\":\");","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/tinyhumansai/openhuman/blob/a221052e0df5b1f7598fceba7329fd1af95d6699/scripts/prune-dev-keychain.mjs#L34-L70","documentation":"prune-dev-keychain.mjs uses a strict hand-rolled parser: the only accepted arguments are `--apply` (switch from default dry-run to real run), `--file <path>` (keychain file, defaulting to $OPENHUMAN_WORKSPACE/dev-keychain.json or .openhuman[-staging]/dev-keychain.json), and `--help`/`-h`. Any other token throws `unknown argument` before anything is read or pruned.","triggerScenarios":"Passing `--force`, `-y`, or a bare positional path (`node scripts/prune-dev-keychain.mjs ~/kc.json`); assuming flags from a sibling script exist here.","commonSituations":"Muscle memory from other repo scripts; trying to skip the dry-run with `-y` instead of `--apply`.","solutions":["Run `node scripts/prune-dev-keychain.mjs --help` to see the supported flags","Use `--apply` for a real run and `--file <path>` to select a non-default keychain file","Pass the keychain path only via `--file`, never as a positional argument"],"exampleFix":"# before\nnode scripts/prune-dev-keychain.mjs ~/tmp/dev-keychain.json --force\n# → Error: unknown argument: ~/tmp/dev-keychain.json\n\n# after\nnode scripts/prune-dev-keychain.mjs --file ~/tmp/dev-keychain.json --apply","handlingStrategy":"validation","validationCode":"const ALLOWED = new Set(['--apply', '--file', '--help', '-h']);\nconst bad = process.argv.slice(2).filter(a => !a.startsWith('-') === false && !ALLOWED.has(a) && !ALLOWED.has(process.argv[process.argv.indexOf(a) - 1]));\n// simpler: whitelist-check every dash-token before delegating\nconst tokens = process.argv.slice(2);\nconst known = new Set(['--apply', '--file', '--help', '-h']);\nif (tokens.some(t => t.startsWith('-') && !known.has(t))) {\n  console.error('Unsupported flag — supported: --apply, --file <path>, --help');\n  process.exit(2);\n}","typeGuard":null,"tryCatchPattern":"try {\n  const args = parseArgs(process.argv.slice(2));\n} catch (err) {\n  if (err.message.startsWith('unknown argument')) {\n    printUsage(); // supported flags: --apply, --file <path>, --help/-h\n    process.exit(2);\n  }\n  throw err;\n}","preventionTips":["Remember the contract: prune runs in dry-run by default; the only switches are --apply, --file <path>, --help","Wrap repo CLIs with a usage-on-error handler so an unknown flag prints help instead of a bare stack trace"],"tags":["cli","validation","developer-tooling"],"backgroundTag":null,"analyzedSha":"a221052e0df5b1f7598fceba7329fd1af95d6699","analyzedAt":"2026-08-16T12:47:06.542Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}