{"record":{"id":"a2e89dd9a8bf8002","repo":"Hmbown/CodeWhale","slug":"unknown-command-cmd","errorCode":null,"errorMessage":"unknown command ${cmd}","messagePattern":"unknown command (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/scripts/facts-publish.mjs","lineNumber":620,"sourceCode":"    const channel = String(flags.channel ?? \"\");\n    const version = Number(flags.version);\n    const reason = String(flags.reason ?? \"\");\n    if (!CHANNEL_RE.test(channel) || !Number.isSafeInteger(version) || version <= 0 || !reason) throw new Error(\"--channel, --version and --reason are required\");\n    if (flags[\"dry-run\"]) {\n      console.log(JSON.stringify({ dry_run: true, channel, facts_version: version, status: \"revoked\", revoke_reason: reason }, null, 2));\n      return 0;\n    }\n    const channels = await postgrest(`facts_channel?scope=eq.global&slug=eq.${encodeURIComponent(channel)}&select=id`);\n    if (!channels?.length) throw new Error(`channel ${channel} does not exist`);\n    const updated = await postgrest(`facts_release?channel_id=eq.${channels[0].id}&facts_version=eq.${version}`, {\n      method: \"PATCH\",\n      body: { status: \"revoked\", revoked_at: nowIso(), revoke_reason: reason },\n      prefer: \"return=representation\",\n    });\n    console.log(JSON.stringify({ revoked: updated?.length ?? 0, channel, facts_version: version }, null, 2));\n    return 0;\n  }\n  throw new Error(`unknown command ${cmd}`);\n}\n\nconst invokedDirectly = process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url);\nif (invokedDirectly) {\n  main(process.argv.slice(2)).then((code) => process.exit(code)).catch((err) => {\n    console.error(`facts-publish: ${err.message}`);\n    process.exit(1);\n  });\n}\n","sourceCodeStart":602,"sourceCodeEnd":630,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/web/scripts/facts-publish.mjs#L602-L630","documentation":"Command dispatch guard in facts-publish.mjs: the first CLI argument (cmd) is not one of the script's known subcommands (e.g. publish/revoke-style operations). It fires before any PostgREST/network work, telling the operator the requested operation does not exist rather than guessing an intent.","triggerScenarios":"Calling the script with a typo'd or unsupported first argument, e.g. `facts-publish pulish`, `facts-publish list`, or no subcommand logic matching the given cmd.","commonSituations":"Shell alias mistakes, following outdated docs that reference a removed subcommand, forgetting the subcommand entirely so an empty/odd cmd reaches dispatch.","solutions":["Run the script with one of the supported subcommands (e.g. publish, revoke)","Check `node web/scripts/facts-publish.mjs` usage/header comments for valid subcommands","Quote-check for typos in the subcommand name"],"exampleFix":"// before\nnode web/scripts/facts-publish.mjs push --channel stable\n// after\nnode web/scripts/facts-publish.mjs publish --channel stable","handlingStrategy":"validation","validationCode":"const VALID = new Set([\"publish\", \"revoke\"]); // extend per script\nif (!VALID.has(cmd)) {\n  throw new Error(`unknown subcommand: ${cmd}; expected one of ${[...VALID]}`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await run([\"node\", \"web/scripts/facts-publish.mjs\", ...args]);\n} catch (e) {\n  if (e.message.startsWith(\"unknown command\")) {\n    console.error(`${e.message} — see script header for supported subcommands`);\n  }\n}","preventionTips":["Keep the subcommand name from the current docs/script source","Validate args in wrapper scripts before invoking","Run with no args or check usage to list valid commands"],"tags":["cli","arguments","unknown-command"],"backgroundTag":"invalid-cli-argument","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}