From 1ec5b328c63fa8d5ffb11241ca33e2943120c1b1 Mon Sep 17 00:00:00 2001 From: haelyra <49814733+haelyra@users.noreply.github.com> Date: Sun, 11 Oct 2026 12:05:00 -0400 Subject: [PATCH] fix: normalize root overrides and report unverified snapshot staging --- .opencode/commands/instinct-status.md | 2 +- commands/auto-update.md | 2 +- commands/instinct-status.md | 2 +- commands/skill-health.md | 6 +-- commands/skill-host-compat.md | 4 +- docs/ja-JP/commands/auto-update.md | 2 +- docs/ja-JP/commands/instinct-status.md | 2 +- docs/ja-JP/commands/skill-health.md | 6 +-- docs/tr/commands/instinct-status.md | 2 +- docs/zh-CN/commands/auto-update.md | 2 +- docs/zh-CN/commands/instinct-status.md | 2 +- docs/zh-CN/commands/skill-health.md | 6 +-- scripts/lib/skill-evolution/versioning.js | 18 +++++++-- tests/lib/command-plugin-root.test.js | 2 +- tests/lib/skill-evolution-storage.test.js | 48 ++++++++++++++++++++--- 15 files changed, 78 insertions(+), 28 deletions(-) diff --git a/.opencode/commands/instinct-status.md b/.opencode/commands/instinct-status.md index c6e2e0b12..cd0dffa55 100644 --- a/.opencode/commands/instinct-status.md +++ b/.opencode/commands/instinct-status.md @@ -16,7 +16,7 @@ fallback), then run the instinct CLI. This avoids reading a stale legacy active under `~/.claude/plugins/cache/...` (#2037). ```bash -ECC_ROOT="${CLAUDE_PLUGIN_ROOT:-$(node -e "var r=(function(){var p=require('path'),f=require('fs'),o=require('os');var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var d=p.join(o.homedir(),'.claude');function L(x){try{return require(p.join(x,'scripts','lib','resolve-ecc-root')).resolveEccRoot()}catch(_){return null}}var r=L(d);if(r)return r;var s=['ecc','ecc@ecc','marketplaces/ecc','everything-claude-code','everything-claude-code@everything-claude-code','marketplaces/everything-claude-code'];for(var i=0;i versioning.createVersion(skillDir), /snapshot version range is exhausted/); - assert.deepEqual(fs.readdirSync(versionsDir), [`v${Number.MAX_SAFE_INTEGER}.md`]); + assert.deepEqual(fs.readdirSync(versionsDir).sort(), [`v${Number.MAX_SAFE_INTEGER}.md`]); assert.equal(fs.readFileSync(last, 'utf8'), 'preserve'); assert.equal(fs.existsSync(versioning.getEvolutionDir(skillDir)), false); }); @@ -149,7 +149,7 @@ test('rollback initialization failure preserves unsnapshotted live bytes and the assert.throws(() => versioning.rollbackTo(skillDir, 1), error => Boolean(error.code)); assert.equal(fs.readFileSync(path.join(skillDir, 'SKILL.md'), 'utf8'), '# Original\n'); assert.equal(fs.readFileSync(target, 'utf8'), '# Saved target\n'); - assert.deepEqual(fs.readdirSync(versionsDir), ['v1.md']); + assert.deepEqual(fs.readdirSync(versionsDir).sort(), ['v1.md']); assert.equal(fs.readFileSync(versioning.getEvolutionDir(skillDir), 'utf8'), 'owned blocker'); }); @@ -172,7 +172,7 @@ test('rollback exclusive publication failure preserves live bytes and permits a } assert.equal(fs.readFileSync(path.join(skillDir, 'SKILL.md'), 'utf8'), '# Unsnapshotted work\n'); assert.equal(fs.readFileSync(path.join(versionsDir, 'v1.md'), 'utf8'), '# Original\n'); - assert.deepEqual(fs.readdirSync(versionsDir), ['v1.md']); + assert.deepEqual(fs.readdirSync(versionsDir).sort(), ['v1.md']); assert.equal(fs.readFileSync(amendmentPath, 'utf8'), priorLog); const restored = versioning.rollbackTo(skillDir, 1); assert.equal(restored.version, 2); @@ -199,7 +199,7 @@ test('failed live rollback write preserves version and applied history, then ret fs.writeFileSync = writeFileSync; } assert.equal(fs.readFileSync(path.join(skillDir, 'SKILL.md'), 'utf8'), '# Unsnapshotted work\n'); - assert.deepEqual(fs.readdirSync(versionsDir), ['v1.md']); + assert.deepEqual(fs.readdirSync(versionsDir).sort(), ['v1.md']); assert.equal(versioning.getCurrentVersion(skillDir), 1); assert.equal(fs.readFileSync(logPath, 'utf8'), priorLog); const report = health.collectSkillHealth({ skillsRoot: path.join(root, 'skills'), homeDir: root }); @@ -280,7 +280,7 @@ test('exclusive snapshot publication preserves a path occupied after allocation' } assert.equal(fs.readFileSync(path.join(skillDir, 'SKILL.md'), 'utf8'), '# Unsnapshotted work\n'); assert.equal(fs.readFileSync(target, 'utf8'), '# Foreign snapshot\n'); - assert.deepEqual(fs.readdirSync(versionsDir), ['v1.md', 'v2.md']); + assert.deepEqual(fs.readdirSync(versionsDir).sort(), ['v1.md', 'v2.md']); assert.equal(versioning.getEvolutionLog(skillDir, 'amendments').filter(row => row.event === 'rollback').length, 0); }); @@ -312,6 +312,44 @@ test('snapshot staging cleanup preserves foreign entries and permits a clean lat assert.equal(fs.readFileSync(foreignPath, 'utf8'), 'foreign work'); }); +for (const foreign of [false, true]) { +test(`unverified staging directory identity preserves ${foreign ? 'foreign contents' : 'empty directory'} with a pending diagnostic`, fixture => { + const { skillDir, versionsDir } = fixture; + versioning.createVersion(skillDir); + fs.writeFileSync(path.join(skillDir, 'SKILL.md'), '# Unsnapshotted work\n'); + const logPath = versioning.getEvolutionLogPath(skillDir, 'amendments'); + const priorLog = fs.readFileSync(logPath, 'utf8'); + const lstatSync = fs.lstatSync; + let stagingDir; + const primary = Object.assign(new Error('Injected staging identity failure'), { code: 'EIO' }); + fs.lstatSync = (file, ...args) => { + if (path.basename(file).startsWith('.snapshot-')) { + stagingDir = file; + if (foreign) fs.writeFileSync(path.join(file, 'foreign-owned.txt'), 'preserve'); + throw primary; + } + return lstatSync(file, ...args); + }; + try { + assert.throws(() => versioning.rollbackTo(skillDir, 1), error => + error.primaryError === primary && /identity could not be verified/.test(error.message) && /recovery is pending/.test(error.message)); + } finally { + fs.lstatSync = lstatSync; + } + if (foreign) assert.equal(fs.readFileSync(path.join(stagingDir, 'foreign-owned.txt'), 'utf8'), 'preserve'); + else assert.deepEqual(fs.readdirSync(stagingDir), []); + assert.equal(fs.readFileSync(path.join(skillDir, 'SKILL.md'), 'utf8'), '# Unsnapshotted work\n'); + assert.equal(fs.existsSync(path.join(versionsDir, 'v2.md')), false); + assert.equal(versioning.getCurrentVersion(skillDir), 1); + assert.equal(fs.readFileSync(logPath, 'utf8'), priorLog); + const restored = versioning.rollbackTo(skillDir, 1); + assert.equal(restored.version, 2); + if (foreign) assert.equal(fs.readFileSync(path.join(stagingDir, 'foreign-owned.txt'), 'utf8'), 'preserve'); + else assert.deepEqual(fs.readdirSync(stagingDir), []); +}); + +} + test('successful rollback snapshots restored content and retains earlier targets for another rollback', fixture => { const { skillDir } = fixture; versioning.createVersion(skillDir);