From dac154eff67232d40f8d6481fac0ff23b5f695a2 Mon Sep 17 00:00:00 2001 From: haelyra <49814733+haelyra@users.noreply.github.com> Date: Mon, 24 Aug 2026 21:18:54 -0400 Subject: [PATCH] test(opencode): cover override lifecycle routing --- .../install-claude-skill-migration.test.js | 21 +++-- tests/lib/install-lifecycle.test.js | 81 +++++++++++++++++++ 2 files changed, 96 insertions(+), 6 deletions(-) diff --git a/tests/lib/install-claude-skill-migration.test.js b/tests/lib/install-claude-skill-migration.test.js index a60253349..cf1a9a352 100644 --- a/tests/lib/install-claude-skill-migration.test.js +++ b/tests/lib/install-claude-skill-migration.test.js @@ -1,6 +1,7 @@ 'use strict'; const assert = require('assert'); +const crypto = require('crypto'); const fs = require('fs'); const os = require('os'); const path = require('path'); @@ -136,6 +137,9 @@ function seedLegacyInstall(fixture, options = {}) { ? operation.sourceRelativePath.split(path.sep).join('\\') : operation.sourceRelativePath, destinationPath, + contentSha256: crypto.createHash('sha256') + .update(fs.readFileSync(destinationPath)) + .digest('hex'), }; }); @@ -239,12 +243,17 @@ function runTests() { fs.mkdirSync(path.dirname(otherLegacyPath), { recursive: true }); fs.writeFileSync(otherSourcePath, '# Other source\n'); fs.writeFileSync(otherLegacyPath, '# Other legacy managed skill\n'); - const otherLegacyOperation = createOperation( - 'other-module', - fixture.sourceRoot, - otherSourceRelativePath, - otherLegacyPath - ); + const otherLegacyOperation = { + ...createOperation( + 'other-module', + fixture.sourceRoot, + otherSourceRelativePath, + otherLegacyPath + ), + contentSha256: crypto.createHash('sha256') + .update(fs.readFileSync(otherLegacyPath)) + .digest('hex'), + }; writeInstallState(fixture.installStatePath, { ...fixture.plan.statePreview, operations: [...legacyOperations, otherLegacyOperation], diff --git a/tests/lib/install-lifecycle.test.js b/tests/lib/install-lifecycle.test.js index 02b246987..e4852da42 100644 --- a/tests/lib/install-lifecycle.test.js +++ b/tests/lib/install-lifecycle.test.js @@ -357,6 +357,87 @@ function runTests() { } })) passed++; else failed++; + if (test('OpenCode discovery, doctor, and uninstall honor the explicit config root', () => { + const homeDir = createTempDir('install-lifecycle-opencode-home-'); + const projectRoot = createTempDir('install-lifecycle-opencode-project-'); + const targetRoot = path.join(homeDir, 'custom-opencode'); + const installStatePath = path.join(targetRoot, 'ecc-install-state.json'); + const sourceRelativePath = path.join('rules', 'common', 'coding-style.md'); + const sourcePath = path.join(REPO_ROOT, sourceRelativePath); + const destinationPath = path.join(targetRoot, 'rules', 'common', 'coding-style.md'); + const env = { OPENCODE_CONFIG_DIR: targetRoot }; + + try { + fs.mkdirSync(path.dirname(destinationPath), { recursive: true }); + fs.copyFileSync(sourcePath, destinationPath); + writeState(installStatePath, { + adapter: { id: 'opencode-home', target: 'opencode', kind: 'home' }, + targetRoot, + installStatePath, + request: { + profile: null, + modules: [], + includeComponents: [], + excludeComponents: [], + legacyLanguages: [], + legacyMode: false, + }, + resolution: { selectedModules: [], skippedModules: [] }, + operations: [{ + kind: 'copy-file', + moduleId: 'rules-core', + sourcePath, + sourceRelativePath, + destinationPath, + strategy: 'preserve-relative-path', + ownership: 'managed', + scaffoldOnly: false, + contentSha256: crypto.createHash('sha256') + .update(fs.readFileSync(destinationPath)) + .digest('hex'), + }], + source: { + repoVersion: CURRENT_PACKAGE_VERSION, + repoCommit: null, + manifestVersion: CURRENT_MANIFEST_VERSION, + }, + }); + + const records = discoverInstalledStates({ + homeDir, + projectRoot, + targets: ['opencode'], + env, + }); + assert.strictEqual(records.length, 1); + assert.strictEqual(records[0].exists, true); + assert.strictEqual(records[0].installStatePath, installStatePath); + + const doctor = buildDoctorReport({ + repoRoot: REPO_ROOT, + homeDir, + projectRoot, + targets: ['opencode'], + env, + }); + assert.strictEqual(doctor.results.length, 1); + assert.strictEqual(doctor.results[0].installStatePath, installStatePath); + + const uninstall = uninstallInstalledStates({ + homeDir, + projectRoot, + targets: ['opencode'], + env, + }); + assert.strictEqual(uninstall.results[0].status, 'uninstalled'); + assert.ok(!fs.existsSync(destinationPath)); + assert.ok(!fs.existsSync(installStatePath)); + } finally { + cleanup(homeDir); + cleanup(projectRoot); + } + })) passed++; else failed++; + if (test('doctor reports missing managed files as an error', () => { const homeDir = createTempDir('install-lifecycle-home-'); const projectRoot = createTempDir('install-lifecycle-project-');