fix: respect existing opencode.jsonc config files (#1056)

The installer hardcoded `opencode.json` in all OpenCode config paths,
creating a duplicate file when users already had `opencode.jsonc`.

Add `resolveOpencodeConfigPath()` helper that prefers `.jsonc` when it
exists, and use it in all three OpenCode config touchpoints: attribution
check, permission configuration, and uninstall cleanup.

Closes #1053

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
TÂCHES
2026-03-15 11:39:53 -06:00
committed by GitHub
parent e5b389cdb1
commit 637a3e720c

View File

@@ -320,6 +320,17 @@ function buildHookCommand(configDir, hookName) {
return `node "${hooksPath}"`;
}
/**
* Resolve the opencode config file path, preferring .jsonc if it exists.
*/
function resolveOpencodeConfigPath(configDir) {
const jsoncPath = path.join(configDir, 'opencode.jsonc');
if (fs.existsSync(jsoncPath)) {
return jsoncPath;
}
return path.join(configDir, 'opencode.json');
}
/**
* Read and parse settings.json, returning empty object if it doesn't exist
*/
@@ -358,7 +369,7 @@ function getCommitAttribution(runtime) {
let result;
if (runtime === 'opencode') {
const config = readSettings(path.join(getGlobalDir('opencode', null), 'opencode.json'));
const config = readSettings(resolveOpencodeConfigPath(getGlobalDir('opencode', null)));
result = config.disable_ai_attribution === true ? null : undefined;
} else if (runtime === 'gemini') {
// Gemini: check gemini settings.json for attribution config
@@ -1814,17 +1825,15 @@ function uninstall(isGlobal, runtime = 'claude') {
}
}
// 6. For OpenCode, clean up permissions from opencode.json
// 6. For OpenCode, clean up permissions from opencode.json or opencode.jsonc
if (isOpencode) {
// For local uninstalls, clean up ./.opencode/opencode.json
// For global uninstalls, clean up ~/.config/opencode/opencode.json
const opencodeConfigDir = isGlobal
? getOpencodeGlobalDir()
: path.join(process.cwd(), '.opencode');
const configPath = path.join(opencodeConfigDir, 'opencode.json');
const configPath = resolveOpencodeConfigPath(opencodeConfigDir);
if (fs.existsSync(configPath)) {
try {
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
const config = parseJsonc(fs.readFileSync(configPath, 'utf8'));
let modified = false;
// Remove GSD permission entries
@@ -1852,7 +1861,7 @@ function uninstall(isGlobal, runtime = 'claude') {
if (modified) {
fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
removedCount++;
console.log(` ${green}✓${reset} Removed GSD permissions from opencode.json`);
console.log(` ${green}✓${reset} Removed GSD permissions from ${path.basename(configPath)}`);
}
} catch (e) {
// Ignore JSON parse errors
@@ -1937,16 +1946,16 @@ function parseJsonc(content) {
* @param {boolean} isGlobal - Whether this is a global or local install
*/
function configureOpencodePermissions(isGlobal = true) {
// For local installs, use ./.opencode/opencode.json
// For global installs, use ~/.config/opencode/opencode.json
// For local installs, use ./.opencode/
// For global installs, use ~/.config/opencode/
const opencodeConfigDir = isGlobal
? getOpencodeGlobalDir()
: path.join(process.cwd(), '.opencode');
const configPath = path.join(opencodeConfigDir, 'opencode.json');
// Ensure config directory exists
fs.mkdirSync(opencodeConfigDir, { recursive: true });
const configPath = resolveOpencodeConfigPath(opencodeConfigDir);
// Read existing config or create empty object
let config = {};
if (fs.existsSync(configPath)) {
@@ -1955,7 +1964,8 @@ function configureOpencodePermissions(isGlobal = true) {
config = parseJsonc(content);
} catch (e) {
// Cannot parse - DO NOT overwrite user's config
console.log(` ${yellow}⚠${reset} Could not parse opencode.json - skipping permission config`);
const configFile = path.basename(configPath);
console.log(` ${yellow}⚠${reset} Could not parse ${configFile} - skipping permission config`);
console.log(` ${dim}Reason: ${e.message}${reset}`);
console.log(` ${dim}Your config was NOT modified. Fix the syntax manually if needed.${reset}`);
return;