{"record":{"id":"f2518c13c26d349e","repo":"jackwener/OpenCLI","slug":"skipping-name-invalid-structure-validati","errorCode":null,"errorMessage":"Skipping \"${name}\": invalid structure — ${validation.errors.join(', ')}","messagePattern":"Skipping \"(.+?)\": invalid structure — (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/plugin.ts","lineNumber":907,"sourceCode":"      log.warn(`Skipping \"${name}\": requires opencli ${entry.opencli}`);\n      continue;\n    }\n\n    let subDir: string;\n    try {\n      subDir = resolveRepoContainedPath(repoRoot, entry.path);\n    } catch {\n      log.warn(`Skipping \"${name}\": path \"${entry.path}\" escapes repo root.`);\n      continue;\n    }\n    if (!fs.existsSync(subDir)) {\n      log.warn(`Skipping \"${name}\": path \"${entry.path}\" not found in repo.`);\n      continue;\n    }\n\n    const validation = validatePluginStructure(subDir);\n    if (!validation.valid) {\n      log.warn(`Skipping \"${name}\": invalid structure — ${validation.errors.join(', ')}`);\n      continue;\n    }\n\n    const linkPath = path.join(PLUGINS_DIR, name);\n    if (fs.existsSync(linkPath)) {\n      log.warn(`Skipping \"${name}\": already installed at ${linkPath}`);\n      continue;\n    }\n\n    eligiblePlugins.push({ name, entry });\n  }\n\n  if (eligiblePlugins.length === 0) {\n    return installedNames;\n  }\n\n  const publishPlugins = eligiblePlugins.map(({ name, entry }) => ({ name, subPath: entry.path }));\n","sourceCodeStart":889,"sourceCodeEnd":925,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/src/plugin.ts#L889-L925","documentation":"When linking/installing plugins from repo subdirectories, each candidate is validated with validatePluginStructure. Invalid plugins are skipped entirely: this warning is logged and the loop 'continue's, so the plugin is not linked into PLUGINS_DIR at all. Unlike 5376 this path aborts installation for that plugin.","triggerScenarios":"validatePluginStructure(subDir) returns invalid for a repo subdirectory — missing manifest or entry point — after confirming entry.path exists. The errors array contents are joined into the message.","commonSituations":"Pointing the installer at a repo root where sibling directories are not all plugins; a workspaces/monorepo folder lacking plugin.json; half-scaffolded plugin directories; renamed main files not updated in the manifest.","solutions":["Fix the structure errors listed (usually add/repair plugin.json and its main entry).","Exclude non-plugin directories from the install source list or move them out of the scanned path.","Finish scaffolding: many errors come from abandoned plugin templates missing required files.","Run the structure validator directly on the directory to see the full error list before re-attempting."],"exampleFix":"// before\nrepo/plugins/foo/   (missing plugin.json)\n// after\nrepo/plugins/foo/plugin.json  { \"name\": \"foo\", \"main\": \"index.js\" }\nrepo/plugins/foo/index.js","handlingStrategy":"validation","validationCode":"for (const entry of candidates) {\n  if (!fs.existsSync(entry.path)) continue;\n  const v = validatePluginStructure(entry.path);\n  if (!v.valid) { console.warn(`pre-check skip ${entry.name}: ${v.errors.join(', ')}`); continue; }\n}","typeGuard":"function looksLikePlugin(dir: string): boolean {\n  return fs.existsSync(path.join(dir, 'plugin.json')) || fs.existsSync(path.join(dir, 'package.json'));\n}","tryCatchPattern":"const validation = validatePluginStructure(subDir);\nif (!validation.valid) {\n  console.warn(`Skipping \"${name}\": ${validation.errors.join(', ')}`);\n  continue; // mirror library behavior; optionally collect names and report at the end\n}","preventionTips":["Only point bulk install at directories that are all valid plugins.","Scaffold plugins from the official template so required files exist.","Keep manifest main paths in sync when renaming entry files.","Pre-validate all candidate dirs and print a summary before linking."],"tags":["plugin","validation","structure"],"backgroundTag":"plugin-structure-invalid","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}