{"record":{"id":"05f5acdfae8610e3","repo":"EveryInc/compound-engineering-plugin","slug":"skipping-targetpath-existing-user-managed-syml-05f5ac","errorCode":null,"errorMessage":"Skipping ${targetPath}: existing user-managed symlink (not overwritten)","messagePattern":"Skipping (.+?): existing user-managed symlink \\(not overwritten\\)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"src/targets/opencode.ts","lineNumber":37,"sourceCode":"  writeManagedInstallManifest,\n} from \"./managed-artifacts\"\n\n// Returns true when the existing path was preserved (skip cleanup AND the\n// subsequent write -- writing through a preserved symlink would clobber the\n// user's fork, which is worse than not overwriting at all). All four\n// OpenCode artifact kinds (agents, commands, plugins, skills) are tracked in\n// the install manifest's `groups` map, so the same ownership rule applies\n// uniformly here rather than a symlink-only guard.\nasync function cleanupCurrentManagedFile(\n  targetPath: string,\n  manifest: ManagedInstallManifest | null,\n  group: string,\n  entryName: string,\n): Promise<boolean> {\n  const stat = await lstatOrNull(targetPath)\n  if (!stat) return false\n  if (stat.isSymbolicLink()) {\n    console.warn(`Skipping ${targetPath}: existing user-managed symlink (not overwritten)`)\n    return true\n  }\n  if (!manifest?.groups[group]?.includes(entryName)) {\n    console.warn(`Skipping ${targetPath}: existing unmanaged file (not overwritten)`)\n    return true\n  }\n  return false\n}\n\nasync function mergeOpenCodeConfig(\n  configPath: string,\n  incoming: OpenCodeConfig,\n): Promise<OpenCodeConfig> {\n  if (!(await pathExists(configPath))) return incoming\n\n  let existing: OpenCodeConfig\n  try {\n    existing = await readJson<OpenCodeConfig>(configPath)","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/EveryInc/compound-engineering-plugin/blob/c9c10f8c75412c7232cb2bd663e5fd1cea98d84e/src/targets/opencode.ts#L19-L55","documentation":"cleanupCurrentManagedFile in src/targets/opencode.ts is the preserve-check for OpenCode managed files during cleanup. It returns true (skip) when the target path is a symlink — treated as user-managed and never overwritten. This is the OpenCode analogue of the shared isPreservedSymlink guard and protects user links from being deleted or replaced by install/cleanup runs.","triggerScenarios":"Running an OpenCode bundle write/cleanup when the managed file path (e.g. .opencode/agents/<name>.md) exists and lstat reports it is a symbolic link; cleanupCurrentManagedFile is reached via the `preserved` path of the cleanup routine.","commonSituations":"Dotfiles-managed .opencode directories (stow/chezmoi symlinking each file), users linking an agent file to a shared or customized copy, or prior tooling that replaced managed files with links.","solutions":["If the symlink is intentional, nothing to do — the file is preserved as-is.","Remove the symlink (rm the link only) and re-run the install to get the generated file in place.","If the link target holds customizations you want, merge them into your own copy or into the plugin source, then delete the link and reinstall.","Verify with `ls -la .opencode/agents/` which entries are links before re-running."],"exampleFix":"// before\nls -la .opencode/agents/review.md  # -> ~/shared/agents/review.md\n// after\nrm .opencode/agents/review.md\nbun run convert --to opencode","handlingStrategy":"validation","validationCode":"import { lstat } from 'node:fs/promises'\nasync function pathIsSymlink(p: string): Promise<boolean> {\n  try { return (await lstat(p)).isSymbolicLink() } catch { return false }\n}\n// before install: if (await pathIsSymlink('.opencode/agents/<name>.md')) resolve manually","typeGuard":"function isSymlinkStat(stat: { isSymbolicLink(): boolean } | undefined): boolean {\n  return stat?.isSymbolicLink() === true\n}","tryCatchPattern":null,"preventionTips":["Do not place personal symlinks inside .opencode managed groups","Inventory `.opencode` for symlinks before each install","Keep manual customizations outside the managed file names (use distinct filenames)"],"tags":["symlink","opencode","install","filesystem-safety"],"backgroundTag":"user-managed-symlink-skipped","analyzedSha":"c9c10f8c75412c7232cb2bd663e5fd1cea98d84e","analyzedAt":"2026-08-31T15:18:07.959Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}