{"record":{"id":"8af4b21db1bb9d09","repo":"jackwener/OpenCLI","slug":"failed-to-link-host-opencli-into-plugin-geterro","errorCode":null,"errorMessage":"Failed to link host opencli into plugin: ${getErrorMessage(err)}","messagePattern":"Failed to link host opencli into plugin: (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/plugin.ts","lineNumber":1425,"sourceCode":"    const hostRoot = resolveHostOpencliRoot();\n\n    const targetLink = path.join(pluginDir, 'node_modules', '@jackwener', 'opencli');\n\n    // Remove existing (npm-installed copy or stale symlink)\n    if (fs.existsSync(targetLink)) {\n      fs.rmSync(targetLink, { recursive: true, force: true });\n    }\n\n    // Ensure parent directory exists\n    fs.mkdirSync(path.dirname(targetLink), { recursive: true });\n\n    // Use 'junction' on Windows (doesn't require admin privileges),\n    // 'dir' symlink on other platforms.\n    const linkType = isWindows ? 'junction' : 'dir';\n    fs.symlinkSync(hostRoot, targetLink, linkType);\n    log.debug(`Linked host opencli into plugin: ${targetLink} → ${hostRoot}`);\n  } catch (err) {\n    log.warn(`Failed to link host opencli into plugin: ${getErrorMessage(err)}`);\n  }\n}\n\n/**\n * Resolve the path to the esbuild CLI executable with fallback strategies.\n */\nexport function resolveEsbuildBin(): string | null {\n  const hostRoot = resolveHostOpencliRoot();\n\n  // Strategy 1 (Windows): prefer the .cmd wrapper which is executable via shell\n  if (isWindows) {\n    const cmdPath = path.join(hostRoot, 'node_modules', '.bin', 'esbuild.cmd');\n    if (fs.existsSync(cmdPath)) {\n      return cmdPath;\n    }\n  }\n\n  // Strategy 2: resolve esbuild binary via import.meta.resolve","sourceCodeStart":1407,"sourceCodeEnd":1443,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/src/plugin.ts#L1407-L1443","documentation":"To let plugins resolve the host CLI, the host root is symlinked into the plugin directory (junction on Windows, dir symlink elsewhere). If fs.symlinkSync throws — existing target, permissions, unsupported filesystem — this warning is logged and linking is abandoned without failing the overall operation.","triggerScenarios":"fs.symlinkSync(hostRoot, targetLink, linkType) throws: targetLink already exists (EEXIST), the plugin directory is read-only (EACCES), the filesystem doesn't support symlinks (e.g. FAT/exFAT, some network mounts), or on Windows without the junction type when privileges are missing (EPERM).","commonSituations":"Re-running install without cleaning up a previous link; plugins living on a synced/network drive without symlink support; Windows developer-mode disabled blocking symlink creation; CI containers running as non-root with read-only plugin dirs.","solutions":["Delete the existing link first if EEXIST: fs.rmSync(targetLink, {force:true, recursive:true}) then retry.","On Windows, keep the 'junction' type (as the code does) and/or enable Developer Mode for symlink support.","Move the plugin directory onto a local filesystem that supports symlinks (not FAT32/network shares).","Run with write permission on the plugin directory (chown/chmod or elevated shell)."],"exampleFix":"// before\nfs.symlinkSync(hostRoot, targetLink, linkType);\n// after\nif (fs.existsSync(targetLink)) fs.rmSync(targetLink, { force: true, recursive: true });\nfs.symlinkSync(hostRoot, targetLink, linkType);","handlingStrategy":"try-catch","validationCode":"if (fs.existsSync(targetLink)) fs.rmSync(targetLink, { force: true, recursive: true });\nfs.accessSync(path.dirname(targetLink), fs.constants.W_OK); // writable parent?","typeGuard":"function canSymlink(parentDir: string): boolean {\n  try { fs.accessSync(parentDir, fs.constants.W_OK); return true; } catch { return false; }\n}","tryCatchPattern":"try {\n  fs.symlinkSync(hostRoot, targetLink, isWindows ? 'junction' : 'dir');\n} catch (err) {\n  const code = (err as NodeJS.ErrnoException).code;\n  if (code === 'EEXIST') fs.rmSync(targetLink, { force: true }) || fs.symlinkSync(hostRoot, targetLink, 'junction');\n  else console.warn(`link skipped (${code}); plugin may not resolve host CLI`);\n}","preventionTips":["Remove stale links before reinstalling.","Keep plugin directories on local symlink-capable filesystems.","On Windows, use junctions and/or enable Developer Mode.","Ensure the process has write access to the plugin directory."],"tags":["filesystem","symlink","plugin"],"backgroundTag":"symlink-creation-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}