{"record":{"id":"fabb8308c80f1ac8","repo":"santifer/career-ops","slug":"plugin-rejected-result-problems-join-n","errorCode":null,"errorMessage":"plugin rejected:\n  - ${result.problems.join('\\n  - ')}","messagePattern":"plugin rejected:\n  - (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"plugin-install.mjs","lineNumber":89,"sourceCode":"  return { ok: true, problems: [], manifest, dir };\n}\n\n/**\n * Install a community plugin from a github repo at a pinned SHA into\n * plugins.local/<id>. Returns { id, manifest, integrity, dir } WITHOUT enabling\n * it (the caller runs the consent gate). Throws on any validation failure.\n */\nexport function installFromRepo(root, { url, sha }) {\n  const { url: safeUrl, id } = parseRepoArg(url);\n  const dest = path.join(root, 'plugins.local', id);\n  if (existsSync(dest)) throw new Error(`plugins.local/${id} already exists — \\`node plugins.mjs remove ${id}\\` first`);\n  let cloned = safeClone(safeUrl, sha);\n  let result;\n  try { result = validateInstall(cloned, id); }\n  catch (e) { rmSync(cloned, { recursive: true, force: true }); throw e; }\n  if (!result.ok) {\n    rmSync(result.dir || cloned, { recursive: true, force: true });\n    throw new Error(`plugin rejected:\\n  - ${result.problems.join('\\n  - ')}`);\n  }\n  mkdirSync(path.join(root, 'plugins.local'), { recursive: true });\n  cpSync(result.dir, dest, { recursive: true });\n  rmSync(result.dir, { recursive: true, force: true });\n  const tree = hashPluginTree(dest);\n  return { id, manifest: { ...result.manifest, dir: dest }, integrity: tree.integrity, files: tree.files, repo: safeUrl, sha };\n}\n\n/**\n * Clone + statically validate a registry entry WITHOUT installing it (used by\n * the registry-validate CI). Executes NO plugin code — manifest is parsed, the\n * audit is static. Returns problems (empty = clean).\n * @returns {string[]}\n */\nexport function auditRegistryEntry(url, sha, expectId) {\n  let parsed;\n  try { parsed = parseRepoArg(url); } catch (e) { return [e.message]; }\n  if (expectId && parsed.id !== expectId) return [`repo \"${url}\" → id \"${parsed.id}\" but registry id is \"${expectId}\"`];","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/plugin-install.mjs#L71-L107","documentation":"Thrown by installFromRepo() when validateInstall() returns ok:false, collecting every static problem (missing required files manifest.json/index.mjs/README.md/LICENSE, invalid manifest JSON, manifest id mismatch, or audit findings). The cloned tree and its temp dir are cleaned up, and the problems are listed in one combined error.","triggerScenarios":"The cloned plugin is missing one of the four MIN_FILES; manifest.json is not valid JSON; the manifest's id does not match the repo-name id; plugin-audit.mjs flagged a static issue (e.g. disallowed API surface, suspicious code).","commonSituations":"Installing an incomplete/WIP plugin repo; manifest id drift between repo name and manifest field; the plugin author omitted LICENSE or README; the audit caught a risky pattern.","solutions":["Read every line under 'plugin rejected:' — each names a concrete defect.","Fix the defects in the plugin repo at the pinned SHA (or pick a corrected SHA).","Ensure manifest.json/index.mjs/README.md/LICENSE all exist and the manifest id matches the repo name suffix.","Re-run `node plugins.mjs install <repo> --sha <new-sha>` after fixes."],"exampleFix":"// before: repo missing LICENSE -> ['missing required file: LICENSE']\n// after: add LICENSE at the plugin repo, pin a new SHA, reinstall","handlingStrategy":"validation","validationCode":"// pre-flight the plugin tree before attempting install\nconst REQUIRED = ['manifest.json', 'index.mjs', 'README.md', 'LICENSE'];\nfunction hasMinFiles(treeDir) {\n  return REQUIRED.every(f => existsSync(path.join(treeDir, f)));\n}","typeGuard":"null","tryCatchPattern":"try {\n  installFromRepo(root, { url, sha });\n} catch (e) {\n  if (/plugin rejected/.test(e.message)) {\n    // parse the bullet list, surface each defect to the user\n  } else throw e;\n}","preventionTips":["Inspect the plugin repo for the four required files before pinning a SHA.","Ensure the manifest id matches the repo name suffix.","Review audit findings before retrying; don't widen permissions to silence them."],"tags":["plugins","validation","manifest","supply-chain"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}