{"record":{"id":"64581525698467d6","repo":"jackwener/OpenCLI","slug":"invalid-plugin-name-name-plugin-names-must-s","errorCode":null,"errorMessage":"Invalid plugin name \"${name}\". Plugin names must start with a lowercase letter and contain only lowercase letters, digits, and hyphens.","messagePattern":"Invalid plugin name \"(.+?)\"\\. Plugin names must start with a lowercase letter and contain only lowercase letters, digits, and hyphens\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/plugin-scaffold.ts","lineNumber":38,"sourceCode":"  /** Directory to create the plugin in. Defaults to `./<name>` */\n  dir?: string;\n  /** Plugin description */\n  description?: string;\n}\n\nexport interface ScaffoldResult {\n  name: string;\n  dir: string;\n  files: string[];\n}\n\n/**\n * Create a new plugin scaffold directory.\n */\nexport function createPluginScaffold(name: string, opts: ScaffoldOptions = {}): ScaffoldResult {\n  // Validate name\n  if (!/^[a-z][a-z0-9-]*$/.test(name)) {\n    throw new Error(\n      `Invalid plugin name \"${name}\". ` +\n      `Plugin names must start with a lowercase letter and contain only lowercase letters, digits, and hyphens.`\n    );\n  }\n\n  const targetDir = opts.dir\n    ? path.resolve(opts.dir)\n    : path.resolve(name);\n\n  if (fs.existsSync(targetDir) && fs.readdirSync(targetDir).length > 0) {\n    throw new Error(`Directory \"${targetDir}\" already exists and is not empty.`);\n  }\n\n  fs.mkdirSync(targetDir, { recursive: true });\n\n  const files: string[] = [];\n\n  // opencli-plugin.json","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/src/plugin-scaffold.ts#L20-L56","documentation":"createPluginScaffold validates the requested plugin name against /^[a-z][a-z0-9-]*$/ before creating anything. Names must start with a lowercase letter and contain only lowercase letters, digits, and hyphens; anything else (uppercase, underscores, leading digits or hyphens, spaces) throws this Error. The constraint keeps plugin names valid as npm-style package names and directory names.","triggerScenarios":"Calling createPluginScaffold with names like 'MyPlugin', 'my_plugin', '1st-plugin', '-foo', or 'my plugin'. Also triggered when the name comes from user input or a template variable that has not been normalized.","commonSituations":"Developer passes a CamelCase project name out of habit, uses underscores because other tools allow them, or interpolates an unvalidated CLI argument into the scaffold call.","solutions":["Rewrite the name in lowercase, replacing underscores with hyphens (e.g. 'My_Plugin' -> 'my-plugin')","Strip leading digits or hyphens so it starts with a lowercase letter","Pre-validate/normalize user-supplied names with the same regex before calling createPluginScaffold"],"exampleFix":"// before\ncreatePluginScaffold('My_CoolPlugin');\n// after\ncreatePluginScaffold('my-coolplugin');","handlingStrategy":"validation","validationCode":"const PLUGIN_NAME_RE = /^[a-z][a-z0-9-]*$/;\nif (!PLUGIN_NAME_RE.test(name)) throw new Error(`invalid plugin name: ${name}`);","typeGuard":"function isValidPluginName(name: string): boolean {\n  return /^[a-z][a-z0-9-]*$/.test(name);\n}","tryCatchPattern":"try {\n  createPluginScaffold(name, opts);\n} catch (e) {\n  if (e instanceof Error && e.message.startsWith('Invalid plugin name')) {\n    console.error(`\"${name}\" is invalid — use lowercase letters, digits, hyphens; start with a letter.`);\n  } else throw e;\n}","preventionTips":["Normalize names with toLowerCase().replace(/_/g, '-') before scaffolding","Keep a shared isValidPluginName helper and run it on all user input","Never pass raw CLI args or CamelCase project names straight into the scaffold","Mirror npm package-name rules when choosing plugin names"],"tags":["validation","naming","plugin","scaffold"],"backgroundTag":"invalid-identifier-name","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}