{"record":{"id":"1ab38f9260197b91","repo":"can1357/oh-my-pi","slug":"invalid-source-args-source-expected-one-of","errorCode":null,"errorMessage":"Invalid --source: ${args.source}. Expected one of: ${TTSR_SOURCES.join(\", \")}","messagePattern":"Invalid --source: (.+?)\\. Expected one of: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/cli/ttsr-cli.ts","lineNumber":338,"sourceCode":"\t\tbuiltinRules: true,\n\t\tdisabledRules: [],\n\t});\n\tif (!manager.addRule(rule)) {\n\t\tthrow new Error(\n\t\t\t`Rule \"${rule.name}\" has no usable TTSR condition. Add a \\`condition\\` (regex) or \\`astCondition\\` (ast-grep pattern) to its frontmatter.`,\n\t\t);\n\t}\n\treturn { rules: manager.getRules(), manager };\n}\n\nasync function loadIsolatedScanRule(rulePath: string): Promise<Rule[]> {\n\tconst rule = await readIsolatedRule(rulePath);\n\treturn filterTtsrRulesForScan([rule]);\n}\n\nasync function runTest(args: TtsrTestArgs, json: boolean, cwd: string): Promise<void> {\n\tif (args.source && !TTSR_SOURCES.includes(args.source)) {\n\t\tthrow new Error(`Invalid --source: ${args.source}. Expected one of: ${TTSR_SOURCES.join(\", \")}`);\n\t}\n\n\tconst snippet = await readSnippet(args);\n\n\t// Infer match context: when the user points --file at a source file and\n\t// doesn't pick a source, default to tool/edit with that path so tool-scoped\n\t// rules (the common case, e.g. tool:edit(*.ts)) match like they would live.\n\tconst filePath = args.filePath ?? (args.file && args.file !== STDIN_MARKER ? path.resolve(args.file) : undefined);\n\tconst source: TtsrMatchSource =\n\t\targs.source ?? (filePath && SOURCE_FILE_EXT.test(path.extname(filePath)) ? \"tool\" : \"text\");\n\tconst tool = args.tool ?? (source === \"tool\" ? \"edit\" : undefined);\n\n\t// A supplied source file whose extension is unknown falls through to the\n\t// text (prose) context, where tool-scoped rules can never match. Surface\n\t// that so a false negative reads as a context mismatch, not a bad regex.\n\tconst inferenceNote =\n\t\t!args.source && filePath && source === \"text\"\n\t\t\t? `inferred --source text from '${path.extname(filePath) || filePath}' (not in the source-file extension set); pass --source tool --tool edit to evaluate tool-scoped rules`","sourceCodeStart":320,"sourceCodeEnd":356,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/cli/ttsr-cli.ts#L320-L356","documentation":"`omp ttsr test` accepts `--source` to set the match context origin, which must be one of the enumerated TTSR_SOURCES values: text, thinking, or tool. runTest validates the raw string before use; anything else throws this error listing the allowed values. This is an argument-validation guard so an invalid source never silently alters rule scoping.","triggerScenarios":"Running `omp ttsr test ... --source <value>` where value is not exactly `text`, `thinking`, or `tool` — typos like `tools`, `Text` (case-sensitive), `editor`, or passing a tool name to --source instead of --tool.","commonSituations":"Confusing --source with --tool (e.g. `--source edit` instead of `--tool edit`); autocomplete/history from a different command's flag values; shell variable interpolation injecting an unexpected value.","solutions":["Use one of: `--source text`, `--source thinking`, or `--source tool`.","If you meant to name a tool like edit/write, pass it via `--tool` together with `--source tool`.","Mind case sensitivity — values are lowercase.","Omit --source entirely to let the CLI infer it from --file (tool for source files, text otherwise)."],"exampleFix":"// before\nomp ttsr test --snippet \"...\" --source edit --tool edit\n// after\nomp ttsr test --snippet \"...\" --source tool --tool edit","handlingStrategy":"validation","validationCode":"const SOURCES = [\"text\", \"thinking\", \"tool\"] as const;\nif (args.source && !SOURCES.includes(args.source)) {\n  throw new Error(`--source must be one of ${SOURCES.join(\"|\")}`);\n}","typeGuard":"function isTtsrSource(v: string): v is TtsrMatchSource {\n  return (TTSR_SOURCES as readonly string[]).includes(v);\n}","tryCatchPattern":"try {\n  await runTtsrCommand(args);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"Invalid --source:\")) {\n    console.error(`${err.message} (values are lowercase)`);\n    process.exitCode = 2;\n  } else throw err;\n}","preventionTips":["Remember the valid set: text | thinking | tool (lowercase, case-sensitive).","Use --tool for tool names like edit/write; --source only takes the three enum values.","Omit --source to let the CLI infer from --file.","Add shell completion or a wrapper script that validates the value."],"tags":["cli","validation","invalid-argument","enum"],"backgroundTag":"invalid-argument-value","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}