mirror of
https://github.com/pbakaus/impeccable.git
synced 2026-09-16 08:06:24 +03:00
Guard the OpenCode legacy migration against symlinks and home-rooted repos
Both review bots caught real hazards in the migration: a symlinked ~/.opencode/skills (shared skill storage) would have its target emptied through the link, and in a home-rooted repo that path is a live project-scope install, not a stranded pre-#406 global copy. The migration now requires a real directory (lstat), compares the just-written dir by realpath instead of string, and skips entirely when the home dir is itself a repo. Two regression tests cover the symlink and dotfiles-repo shapes. Prepared with AI assistance (Claude Code), directed by @pbakaus. Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Code
parent
caef4b8e4c
commit
cda1c572d9
@@ -1162,9 +1162,21 @@ function copyProviderSkills(bundleDir, root, targets, { scope } = {}) {
|
||||
// location OpenCode never reads. Now that the real copy sits in the
|
||||
// config dir, drop exactly the skills just written from the stranded
|
||||
// location; sibling skills and everything else in ~/.opencode stay.
|
||||
// Guards (both flagged in review): a symlinked skills dir is shared
|
||||
// storage whose target must not be emptied through the link, the
|
||||
// just-written dir must be compared by realpath rather than string,
|
||||
// and a home-rooted repo makes `.opencode/skills` a live
|
||||
// project-scope install rather than a stranded global one.
|
||||
if (scope === 'user' && provider === '.opencode') {
|
||||
const legacyDir = join(root, '.opencode', 'skills');
|
||||
if (legacyDir !== localSkillsDir && existsSync(legacyDir)) {
|
||||
let migratable = false;
|
||||
try {
|
||||
migratable = existsSync(legacyDir)
|
||||
&& !lstatSync(legacyDir).isSymbolicLink()
|
||||
&& realpathSync(legacyDir) !== realpathSync(localSkillsDir)
|
||||
&& !existsSync(join(root, '.git'));
|
||||
} catch { migratable = false; }
|
||||
if (migratable) {
|
||||
for (const skill of readdirSync(srcDir, { withFileTypes: true })) {
|
||||
if (!skill.isDirectory()) continue;
|
||||
rmSync(join(legacyDir, skill.name), { recursive: true, force: true });
|
||||
|
||||
Reference in New Issue
Block a user