* refactor(#56): retire legacy runtime directory helpers into runtime-homes projection Consolidate per-runtime global config-dir resolution onto the single canonical projection runtime-homes:getGlobalConfigDir. Extend it with the explicitDir override (CLI --config-dir) and the opencode/kilo OPENCODE_CONFIG/KILO_CONFIG file-path precedence the installer helpers had, making it byte-for-behavior equivalent to the old getGlobalDir across all 15 install runtimes. Delete bin/install.js's getGlobalDir/getOpencodeGlobalDir/getKiloGlobalDir (and the orphaned local expandTilde), repoint all 9 call-sites, and remove getGlobalDir from module.exports (net -242 lines in the installer). Migrate the 5 test importers to the canonical projection; harden default/XDG assertions against ambient *_CONFIG env vars. getAgentsDir now respects OPENCODE_CONFIG/KILO_CONFIG consistently with the installer (intentional convergence). Update CONTEXT.md Installer Module entry. Completes the installer-refactor chain #58 -> #60 -> #56. Closes #56 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(#56): add changeset for runtime directory helper retirement Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -65,7 +65,8 @@ describe('bug #3126: runtime-homes getGlobalConfigDir — defaults', () => {
|
||||
const envKeys = ['CLAUDE_CONFIG_DIR','CURSOR_CONFIG_DIR','GEMINI_CONFIG_DIR',
|
||||
'CODEX_HOME','COPILOT_CONFIG_DIR','ANTIGRAVITY_CONFIG_DIR','WINDSURF_CONFIG_DIR',
|
||||
'AUGMENT_CONFIG_DIR','TRAE_CONFIG_DIR','QWEN_CONFIG_DIR','HERMES_HOME',
|
||||
'CODEBUDDY_CONFIG_DIR','CLINE_CONFIG_DIR','OPENCODE_CONFIG_DIR','KILO_CONFIG_DIR',
|
||||
'CODEBUDDY_CONFIG_DIR','CLINE_CONFIG_DIR','OPENCODE_CONFIG_DIR','OPENCODE_CONFIG',
|
||||
'KILO_CONFIG_DIR','KILO_CONFIG',
|
||||
'XDG_CONFIG_HOME'];
|
||||
const saved = {};
|
||||
for (const k of envKeys) { saved[k] = process.env[k]; delete process.env[k]; }
|
||||
@@ -105,15 +106,19 @@ describe('bug #3126: runtime-homes env-var overrides', () => {
|
||||
});
|
||||
test('opencode uses XDG_CONFIG_HOME when OPENCODE_CONFIG_DIR absent', () => {
|
||||
withEnv('OPENCODE_CONFIG_DIR', undefined, () => {
|
||||
withEnv('XDG_CONFIG_HOME', '/xdg', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('opencode'), path.join('/xdg', 'opencode'));
|
||||
withEnv('OPENCODE_CONFIG', undefined, () => {
|
||||
withEnv('XDG_CONFIG_HOME', '/xdg', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('opencode'), path.join('/xdg', 'opencode'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
test('kilo uses XDG_CONFIG_HOME when KILO_CONFIG_DIR absent', () => {
|
||||
withEnv('KILO_CONFIG_DIR', undefined, () => {
|
||||
withEnv('XDG_CONFIG_HOME', '/xdg', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('kilo'), path.join('/xdg', 'kilo'));
|
||||
withEnv('KILO_CONFIG', undefined, () => {
|
||||
withEnv('XDG_CONFIG_HOME', '/xdg', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('kilo'), path.join('/xdg', 'kilo'));
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -186,6 +191,110 @@ describe('bug #3126: runtime-homes getGlobalSkillDir', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGlobalConfigDir — explicitDir override and opencode/kilo file-path precedence', () => {
|
||||
// ── explicitDir override ──────────────────────────────────────────────────
|
||||
test('explicitDir absolute path is returned as-is (claude)', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('claude', '/tmp/x'), '/tmp/x');
|
||||
});
|
||||
|
||||
test('explicitDir with tilde is expanded (opencode)', () => {
|
||||
assert.strictEqual(
|
||||
getGlobalConfigDir('opencode', '~/foo'),
|
||||
path.join(os.homedir(), 'foo'),
|
||||
);
|
||||
});
|
||||
|
||||
test('explicitDir wins even when OPENCODE_CONFIG_DIR is also set', () => {
|
||||
withEnv('OPENCODE_CONFIG_DIR', '/should/not/win', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('opencode', '/explicit/wins'), '/explicit/wins');
|
||||
});
|
||||
});
|
||||
|
||||
// ── opencode: OPENCODE_CONFIG file-path step ──────────────────────────────
|
||||
test('opencode: OPENCODE_CONFIG → path.dirname(expandTilde(value))', () => {
|
||||
withEnv('OPENCODE_CONFIG_DIR', undefined, () => {
|
||||
withEnv('XDG_CONFIG_HOME', undefined, () => {
|
||||
withEnv('OPENCODE_CONFIG', '/home/u/cfg/opencode.json', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('opencode'), '/home/u/cfg');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('opencode: OPENCODE_CONFIG_DIR takes precedence over OPENCODE_CONFIG', () => {
|
||||
withEnv('OPENCODE_CONFIG_DIR', '/dir/wins', () => {
|
||||
withEnv('OPENCODE_CONFIG', '/file/loses.json', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('opencode'), '/dir/wins');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('opencode: OPENCODE_CONFIG takes precedence over XDG_CONFIG_HOME', () => {
|
||||
withEnv('OPENCODE_CONFIG_DIR', undefined, () => {
|
||||
withEnv('OPENCODE_CONFIG', '/cfg/opencode.json', () => {
|
||||
withEnv('XDG_CONFIG_HOME', '/xdg/should/lose', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('opencode'), '/cfg');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('opencode: default ~/.config/opencode when no env vars set', () => {
|
||||
withEnv('OPENCODE_CONFIG_DIR', undefined, () => {
|
||||
withEnv('OPENCODE_CONFIG', undefined, () => {
|
||||
withEnv('XDG_CONFIG_HOME', undefined, () => {
|
||||
assert.strictEqual(
|
||||
getGlobalConfigDir('opencode'),
|
||||
path.join(os.homedir(), '.config', 'opencode'),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ── kilo: KILO_CONFIG file-path step ─────────────────────────────────────
|
||||
test('kilo: KILO_CONFIG → path.dirname(expandTilde(value))', () => {
|
||||
withEnv('KILO_CONFIG_DIR', undefined, () => {
|
||||
withEnv('XDG_CONFIG_HOME', undefined, () => {
|
||||
withEnv('KILO_CONFIG', '/home/u/cfg/kilo.json', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('kilo'), '/home/u/cfg');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('kilo: KILO_CONFIG_DIR takes precedence over KILO_CONFIG', () => {
|
||||
withEnv('KILO_CONFIG_DIR', '/dir/wins', () => {
|
||||
withEnv('KILO_CONFIG', '/file/loses.json', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('kilo'), '/dir/wins');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('kilo: KILO_CONFIG takes precedence over XDG_CONFIG_HOME', () => {
|
||||
withEnv('KILO_CONFIG_DIR', undefined, () => {
|
||||
withEnv('KILO_CONFIG', '/cfg/kilo.json', () => {
|
||||
withEnv('XDG_CONFIG_HOME', '/xdg/should/lose', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('kilo'), '/cfg');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test('kilo: default ~/.config/kilo when no env vars set', () => {
|
||||
withEnv('KILO_CONFIG_DIR', undefined, () => {
|
||||
withEnv('KILO_CONFIG', undefined, () => {
|
||||
withEnv('XDG_CONFIG_HOME', undefined, () => {
|
||||
assert.strictEqual(
|
||||
getGlobalConfigDir('kilo'),
|
||||
path.join(os.homedir(), '.config', 'kilo'),
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('bug #3126: init.cjs uses runtime-homes not hardcoded .claude', () => {
|
||||
test('init.cjs has no hardcoded globalSkillsBase assignment to ~/.claude/skills', () => {
|
||||
const fs = require('node:fs');
|
||||
|
||||
@@ -30,20 +30,21 @@ const { createTempDir, cleanup } = require('./helpers.cjs');
|
||||
|
||||
const {
|
||||
getDirName,
|
||||
getGlobalDir,
|
||||
getConfigDirFromHome,
|
||||
convertClaudeToCliineMarkdown,
|
||||
install,
|
||||
finishInstall,
|
||||
} = require('../bin/install.js');
|
||||
|
||||
const { getGlobalConfigDir } = require('../gsd-core/bin/lib/runtime-homes.cjs');
|
||||
|
||||
describe('Cline runtime directory mapping', () => {
|
||||
test('getDirName returns .cline for local installs', () => {
|
||||
assert.strictEqual(getDirName('cline'), '.cline');
|
||||
});
|
||||
|
||||
test('getGlobalDir returns ~/.cline for global installs', () => {
|
||||
assert.strictEqual(getGlobalDir('cline'), path.join(os.homedir(), '.cline'));
|
||||
test('getGlobalConfigDir returns ~/.cline for global installs', () => {
|
||||
assert.strictEqual(getGlobalConfigDir('cline'), path.join(os.homedir(), '.cline'));
|
||||
});
|
||||
|
||||
test('getConfigDirFromHome returns .cline fragment', () => {
|
||||
@@ -52,7 +53,7 @@ describe('Cline runtime directory mapping', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGlobalDir (Cline)', () => {
|
||||
describe('getGlobalConfigDir (Cline)', () => {
|
||||
let originalClineConfigDir;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -69,30 +70,30 @@ describe('getGlobalDir (Cline)', () => {
|
||||
|
||||
test('returns ~/.cline with no env var or explicit dir', () => {
|
||||
delete process.env.CLINE_CONFIG_DIR;
|
||||
const result = getGlobalDir('cline');
|
||||
const result = getGlobalConfigDir('cline');
|
||||
assert.strictEqual(result, path.join(os.homedir(), '.cline'));
|
||||
});
|
||||
|
||||
test('returns explicit dir when provided', () => {
|
||||
const result = getGlobalDir('cline', '/custom/cline-path');
|
||||
const result = getGlobalConfigDir('cline', '/custom/cline-path');
|
||||
assert.strictEqual(result, '/custom/cline-path');
|
||||
});
|
||||
|
||||
test('respects CLINE_CONFIG_DIR env var', () => {
|
||||
process.env.CLINE_CONFIG_DIR = '~/custom-cline';
|
||||
const result = getGlobalDir('cline');
|
||||
const result = getGlobalConfigDir('cline');
|
||||
assert.strictEqual(result, path.join(os.homedir(), 'custom-cline'));
|
||||
});
|
||||
|
||||
test('explicit dir takes priority over CLINE_CONFIG_DIR', () => {
|
||||
process.env.CLINE_CONFIG_DIR = '~/from-env';
|
||||
const result = getGlobalDir('cline', '/explicit/path');
|
||||
const result = getGlobalConfigDir('cline', '/explicit/path');
|
||||
assert.strictEqual(result, '/explicit/path');
|
||||
});
|
||||
|
||||
test('does not break other runtimes', () => {
|
||||
assert.strictEqual(getGlobalDir('claude'), path.join(os.homedir(), '.claude'));
|
||||
assert.strictEqual(getGlobalDir('codex'), path.join(os.homedir(), '.codex'));
|
||||
assert.strictEqual(getGlobalConfigDir('claude'), path.join(os.homedir(), '.claude'));
|
||||
assert.strictEqual(getGlobalConfigDir('codex'), path.join(os.homedir(), '.codex'));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -14,7 +14,6 @@ const { createTempDir, cleanup } = require('./helpers.cjs');
|
||||
|
||||
const {
|
||||
getDirName,
|
||||
getGlobalDir,
|
||||
getConfigDirFromHome,
|
||||
convertClaudeToCodebuddyMarkdown,
|
||||
convertClaudeCommandToCodebuddySkill,
|
||||
@@ -25,6 +24,8 @@ const {
|
||||
installRuntimeArtifacts,
|
||||
} = require('../bin/install.js');
|
||||
|
||||
const { getGlobalConfigDir } = require('../gsd-core/bin/lib/runtime-homes.cjs');
|
||||
|
||||
// ─── Profile resolution for installRuntimeArtifacts tests ────────────────────
|
||||
const _gsdLibDir = path.join(__dirname, '..', 'gsd-core', 'bin', 'lib');
|
||||
const { loadSkillsManifest, resolveProfile } = require(path.join(_gsdLibDir, 'install-profiles.cjs'));
|
||||
@@ -37,7 +38,7 @@ describe('CodeBuddy runtime directory mapping', () => {
|
||||
});
|
||||
|
||||
test('maps CodeBuddy to ~/.codebuddy for global installs', () => {
|
||||
assert.strictEqual(getGlobalDir('codebuddy'), path.join(os.homedir(), '.codebuddy'));
|
||||
assert.strictEqual(getGlobalConfigDir('codebuddy'), path.join(os.homedir(), '.codebuddy'));
|
||||
});
|
||||
|
||||
test('returns .codebuddy config fragments for local and global installs', () => {
|
||||
@@ -46,7 +47,7 @@ describe('CodeBuddy runtime directory mapping', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGlobalDir (CodeBuddy)', () => {
|
||||
describe('getGlobalConfigDir (CodeBuddy)', () => {
|
||||
let originalCodebuddyConfigDir;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -63,30 +64,30 @@ describe('getGlobalDir (CodeBuddy)', () => {
|
||||
|
||||
test('returns ~/.codebuddy with no env var or explicit dir', () => {
|
||||
delete process.env.CODEBUDDY_CONFIG_DIR;
|
||||
const result = getGlobalDir('codebuddy');
|
||||
const result = getGlobalConfigDir('codebuddy');
|
||||
assert.strictEqual(result, path.join(os.homedir(), '.codebuddy'));
|
||||
});
|
||||
|
||||
test('returns explicit dir when provided', () => {
|
||||
const result = getGlobalDir('codebuddy', '/custom/codebuddy-path');
|
||||
const result = getGlobalConfigDir('codebuddy', '/custom/codebuddy-path');
|
||||
assert.strictEqual(result, '/custom/codebuddy-path');
|
||||
});
|
||||
|
||||
test('respects CODEBUDDY_CONFIG_DIR env var', () => {
|
||||
process.env.CODEBUDDY_CONFIG_DIR = '~/custom-codebuddy';
|
||||
const result = getGlobalDir('codebuddy');
|
||||
const result = getGlobalConfigDir('codebuddy');
|
||||
assert.strictEqual(result, path.join(os.homedir(), 'custom-codebuddy'));
|
||||
});
|
||||
|
||||
test('explicit dir takes priority over CODEBUDDY_CONFIG_DIR', () => {
|
||||
process.env.CODEBUDDY_CONFIG_DIR = '~/from-env';
|
||||
const result = getGlobalDir('codebuddy', '/explicit/path');
|
||||
const result = getGlobalConfigDir('codebuddy', '/explicit/path');
|
||||
assert.strictEqual(result, '/explicit/path');
|
||||
});
|
||||
|
||||
test('does not break other runtimes', () => {
|
||||
assert.strictEqual(getGlobalDir('claude'), path.join(os.homedir(), '.claude'));
|
||||
assert.strictEqual(getGlobalDir('codex'), path.join(os.homedir(), '.codex'));
|
||||
assert.strictEqual(getGlobalConfigDir('claude'), path.join(os.homedir(), '.claude'));
|
||||
assert.strictEqual(getGlobalConfigDir('codex'), path.join(os.homedir(), '.codex'));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ const { parseFrontmatter, createTempDir, cleanup } = require('./helpers.cjs');
|
||||
|
||||
const {
|
||||
getDirName,
|
||||
getGlobalDir,
|
||||
getConfigDirFromHome,
|
||||
claudeToCopilotTools,
|
||||
convertCopilotToolName,
|
||||
@@ -48,6 +47,8 @@ const {
|
||||
buildRuntimePromptText,
|
||||
} = require('../bin/install.js');
|
||||
|
||||
const { getGlobalConfigDir } = require('../gsd-core/bin/lib/runtime-homes.cjs');
|
||||
|
||||
// ─── Profile resolution for installRuntimeArtifacts tests ────────────────────
|
||||
const _gsdLibDir = path.join(__dirname, '..', 'gsd-core', 'bin', 'lib');
|
||||
const { loadSkillsManifest, resolveProfile } = require(path.join(_gsdLibDir, 'install-profiles.cjs'));
|
||||
@@ -70,9 +71,9 @@ describe('getDirName (Copilot)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ─── getGlobalDir ───────────────────────────────────────────────────────────────
|
||||
// ─── getGlobalConfigDir ──────────────────────────────────────────────────────────
|
||||
|
||||
describe('getGlobalDir (Copilot)', () => {
|
||||
describe('getGlobalConfigDir (Copilot)', () => {
|
||||
let originalCopilotConfigDir;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -89,30 +90,30 @@ describe('getGlobalDir (Copilot)', () => {
|
||||
|
||||
test('returns ~/.copilot with no env var or explicit dir', () => {
|
||||
delete process.env.COPILOT_CONFIG_DIR;
|
||||
const result = getGlobalDir('copilot');
|
||||
const result = getGlobalConfigDir('copilot');
|
||||
assert.strictEqual(result, path.join(os.homedir(), '.copilot'));
|
||||
});
|
||||
|
||||
test('returns explicit dir when provided', () => {
|
||||
const result = getGlobalDir('copilot', '/custom/path');
|
||||
const result = getGlobalConfigDir('copilot', '/custom/path');
|
||||
assert.strictEqual(result, '/custom/path');
|
||||
});
|
||||
|
||||
test('respects COPILOT_CONFIG_DIR env var', () => {
|
||||
process.env.COPILOT_CONFIG_DIR = '~/custom-copilot';
|
||||
const result = getGlobalDir('copilot');
|
||||
const result = getGlobalConfigDir('copilot');
|
||||
assert.strictEqual(result, path.join(os.homedir(), 'custom-copilot'));
|
||||
});
|
||||
|
||||
test('explicit dir takes priority over COPILOT_CONFIG_DIR', () => {
|
||||
process.env.COPILOT_CONFIG_DIR = '~/env-path';
|
||||
const result = getGlobalDir('copilot', '/explicit/path');
|
||||
const result = getGlobalConfigDir('copilot', '/explicit/path');
|
||||
assert.strictEqual(result, '/explicit/path');
|
||||
});
|
||||
|
||||
test('does not break existing runtimes', () => {
|
||||
assert.strictEqual(getGlobalDir('claude'), path.join(os.homedir(), '.claude'));
|
||||
assert.strictEqual(getGlobalDir('codex'), path.join(os.homedir(), '.codex'));
|
||||
assert.strictEqual(getGlobalConfigDir('claude'), path.join(os.homedir(), '.claude'));
|
||||
assert.strictEqual(getGlobalConfigDir('codex'), path.join(os.homedir(), '.codex'));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
/**
|
||||
* Installer Module — Sections 1–5.
|
||||
*
|
||||
* Covers: getDirName/getGlobalDir/getConfigDirFromHome, per-runtime
|
||||
* Covers: getDirName/getGlobalConfigDir/getConfigDirFromHome, per-runtime
|
||||
* install/uninstall spot-checks (hermes/qwen/trae), uninstall skills
|
||||
* cleanup, Claude-reference leak tests, and Kilo-specific helpers.
|
||||
*
|
||||
@@ -34,7 +34,6 @@ const pkg = require('../package.json');
|
||||
|
||||
const {
|
||||
getDirName,
|
||||
getGlobalDir,
|
||||
getConfigDirFromHome,
|
||||
install,
|
||||
uninstall,
|
||||
@@ -46,13 +45,15 @@ const {
|
||||
configureKiloPermissions,
|
||||
} = require('../bin/install.js');
|
||||
|
||||
const { getGlobalConfigDir } = require('../gsd-core/bin/lib/runtime-homes.cjs');
|
||||
|
||||
const {
|
||||
RUNTIME_META,
|
||||
stripAnsi,
|
||||
walk,
|
||||
} = require('./helpers/install-shared.cjs');
|
||||
|
||||
// ─── Section 1: getDirName / getGlobalDir / getConfigDirFromHome ──────────────
|
||||
// ─── Section 1: getDirName / getGlobalConfigDir / getConfigDirFromHome ──────────
|
||||
|
||||
describe('getDirName — all runtimes', () => {
|
||||
for (const runtime of allRuntimes) {
|
||||
@@ -64,11 +65,14 @@ describe('getDirName — all runtimes', () => {
|
||||
}
|
||||
});
|
||||
|
||||
describe('getGlobalDir — all runtimes default paths', () => {
|
||||
describe('getGlobalConfigDir — all runtimes default paths', () => {
|
||||
// Test the default (no env var, no explicit dir) for each runtime
|
||||
const ENV_KEYS = [
|
||||
'HERMES_HOME', 'QWEN_CONFIG_DIR', 'TRAE_CONFIG_DIR', 'ANTIGRAVITY_CONFIG_DIR',
|
||||
'KILO_CONFIG_DIR', 'KILO_CONFIG', 'XDG_CONFIG_HOME',
|
||||
'CLAUDE_CONFIG_DIR', 'CURSOR_CONFIG_DIR', 'GEMINI_CONFIG_DIR', 'CODEX_HOME',
|
||||
'GROK_AGENTS_HOME', 'COPILOT_CONFIG_DIR', 'WINDSURF_CONFIG_DIR', 'AUGMENT_CONFIG_DIR',
|
||||
'TRAE_CONFIG_DIR', 'QWEN_CONFIG_DIR', 'HERMES_HOME', 'CODEBUDDY_CONFIG_DIR',
|
||||
'CLINE_CONFIG_DIR', 'OPENCODE_CONFIG_DIR', 'OPENCODE_CONFIG', 'KILO_CONFIG_DIR',
|
||||
'KILO_CONFIG', 'ANTIGRAVITY_CONFIG_DIR', 'XDG_CONFIG_HOME',
|
||||
];
|
||||
let savedEnv = {};
|
||||
|
||||
@@ -87,14 +91,14 @@ describe('getGlobalDir — all runtimes default paths', () => {
|
||||
});
|
||||
|
||||
for (const runtime of allRuntimes) {
|
||||
test(`getGlobalDir('${runtime}') returns expected home-relative path`, () => {
|
||||
test(`getGlobalConfigDir('${runtime}') returns expected home-relative path`, () => {
|
||||
const expected = path.join(os.homedir(), RUNTIME_META[runtime].globalSuffix);
|
||||
assert.strictEqual(getGlobalDir(runtime), expected);
|
||||
assert.strictEqual(getGlobalConfigDir(runtime), expected);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
describe('getGlobalDir/getConfigDirFromHome — antigravity 2.x layout detection', () => {
|
||||
describe('getGlobalConfigDir/getConfigDirFromHome — antigravity 2.x layout detection', () => {
|
||||
const saved = {};
|
||||
beforeEach(() => {
|
||||
saved.HOME = process.env.HOME;
|
||||
@@ -118,7 +122,7 @@ describe('getGlobalDir/getConfigDirFromHome — antigravity 2.x layout detection
|
||||
process.env.HOME = home;
|
||||
process.env.USERPROFILE = home;
|
||||
assert.strictEqual(
|
||||
getGlobalDir('antigravity'),
|
||||
getGlobalConfigDir('antigravity'),
|
||||
path.join(home, '.gemini', 'antigravity-ide'),
|
||||
);
|
||||
assert.strictEqual(
|
||||
@@ -137,7 +141,7 @@ describe('getGlobalDir/getConfigDirFromHome — antigravity 2.x layout detection
|
||||
process.env.HOME = home;
|
||||
process.env.USERPROFILE = home;
|
||||
assert.strictEqual(
|
||||
getGlobalDir('antigravity'),
|
||||
getGlobalConfigDir('antigravity'),
|
||||
path.join(home, '.gemini', 'antigravity-cli'),
|
||||
);
|
||||
assert.strictEqual(
|
||||
@@ -150,12 +154,12 @@ describe('getGlobalDir/getConfigDirFromHome — antigravity 2.x layout detection
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGlobalDir — explicit configDir overrides env for all runtimes', () => {
|
||||
describe('getGlobalConfigDir — explicit configDir overrides env for all runtimes', () => {
|
||||
test('explicit dir overrides any env var for hermes', () => {
|
||||
const savedHome = process.env.HERMES_HOME;
|
||||
process.env.HERMES_HOME = '~/from-env';
|
||||
try {
|
||||
assert.strictEqual(getGlobalDir('hermes', '/explicit/hermes'), '/explicit/hermes');
|
||||
assert.strictEqual(getGlobalConfigDir('hermes', '/explicit/hermes'), '/explicit/hermes');
|
||||
} finally {
|
||||
if (savedHome !== undefined) process.env.HERMES_HOME = savedHome;
|
||||
else delete process.env.HERMES_HOME;
|
||||
@@ -166,7 +170,7 @@ describe('getGlobalDir — explicit configDir overrides env for all runtimes', (
|
||||
const saved = process.env.KILO_CONFIG_DIR;
|
||||
process.env.KILO_CONFIG_DIR = '~/from-env';
|
||||
try {
|
||||
assert.strictEqual(getGlobalDir('kilo', '/explicit/kilo'), '/explicit/kilo');
|
||||
assert.strictEqual(getGlobalConfigDir('kilo', '/explicit/kilo'), '/explicit/kilo');
|
||||
} finally {
|
||||
if (saved !== undefined) process.env.KILO_CONFIG_DIR = saved;
|
||||
else delete process.env.KILO_CONFIG_DIR;
|
||||
@@ -174,7 +178,7 @@ describe('getGlobalDir — explicit configDir overrides env for all runtimes', (
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGlobalDir — HERMES_HOME env var', () => {
|
||||
describe('getGlobalConfigDir — HERMES_HOME env var', () => {
|
||||
let saved;
|
||||
beforeEach(() => { saved = process.env.HERMES_HOME; });
|
||||
afterEach(() => {
|
||||
@@ -184,11 +188,11 @@ describe('getGlobalDir — HERMES_HOME env var', () => {
|
||||
|
||||
test('respects HERMES_HOME env var (tilde-expanded)', () => {
|
||||
process.env.HERMES_HOME = '~/custom-hermes';
|
||||
assert.strictEqual(getGlobalDir('hermes'), path.join(os.homedir(), 'custom-hermes'));
|
||||
assert.strictEqual(getGlobalConfigDir('hermes'), path.join(os.homedir(), 'custom-hermes'));
|
||||
});
|
||||
});
|
||||
|
||||
describe('getGlobalDir — Kilo env var priority', () => {
|
||||
describe('getGlobalConfigDir — Kilo env var priority', () => {
|
||||
let savedEnv;
|
||||
beforeEach(() => {
|
||||
savedEnv = {
|
||||
@@ -209,23 +213,23 @@ describe('getGlobalDir — Kilo env var priority', () => {
|
||||
|
||||
test('respects KILO_CONFIG_DIR', () => {
|
||||
process.env.KILO_CONFIG_DIR = '~/custom-kilo';
|
||||
assert.strictEqual(getGlobalDir('kilo'), path.join(os.homedir(), 'custom-kilo'));
|
||||
assert.strictEqual(getGlobalConfigDir('kilo'), path.join(os.homedir(), 'custom-kilo'));
|
||||
});
|
||||
|
||||
test('falls back to XDG_CONFIG_HOME/kilo', () => {
|
||||
process.env.XDG_CONFIG_HOME = '~/xdg-config';
|
||||
assert.strictEqual(getGlobalDir('kilo'), path.join(os.homedir(), 'xdg-config', 'kilo'));
|
||||
assert.strictEqual(getGlobalConfigDir('kilo'), path.join(os.homedir(), 'xdg-config', 'kilo'));
|
||||
});
|
||||
|
||||
test('uses dirname(KILO_CONFIG) when KILO_CONFIG_DIR unset', () => {
|
||||
process.env.KILO_CONFIG = '~/profiles/work/kilo.jsonc';
|
||||
assert.strictEqual(getGlobalDir('kilo'), path.join(os.homedir(), 'profiles', 'work'));
|
||||
assert.strictEqual(getGlobalConfigDir('kilo'), path.join(os.homedir(), 'profiles', 'work'));
|
||||
});
|
||||
|
||||
test('KILO_CONFIG_DIR takes precedence over KILO_CONFIG', () => {
|
||||
process.env.KILO_CONFIG_DIR = '~/custom-kilo';
|
||||
process.env.KILO_CONFIG = '~/profiles/work/kilo.jsonc';
|
||||
assert.strictEqual(getGlobalDir('kilo'), path.join(os.homedir(), 'custom-kilo'));
|
||||
assert.strictEqual(getGlobalConfigDir('kilo'), path.join(os.homedir(), 'custom-kilo'));
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ const assert = require('node:assert/strict');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
const { getGlobalDir } = require('../bin/install.js');
|
||||
const { getGlobalConfigDir } = require('../gsd-core/bin/lib/runtime-homes.cjs');
|
||||
|
||||
describe('getGlobalDir (Windsurf)', () => {
|
||||
describe('getGlobalConfigDir (Windsurf)', () => {
|
||||
let originalWindsurfConfigDir;
|
||||
|
||||
beforeEach(() => {
|
||||
@@ -24,29 +24,29 @@ describe('getGlobalDir (Windsurf)', () => {
|
||||
});
|
||||
|
||||
test('returns ~/.codeium/windsurf with no env var or explicit dir', () => {
|
||||
const result = getGlobalDir('windsurf');
|
||||
const result = getGlobalConfigDir('windsurf');
|
||||
assert.strictEqual(result, path.join(os.homedir(), '.codeium', 'windsurf'));
|
||||
});
|
||||
|
||||
test('returns explicit dir when provided', () => {
|
||||
const result = getGlobalDir('windsurf', '/custom/windsurf-path');
|
||||
const result = getGlobalConfigDir('windsurf', '/custom/windsurf-path');
|
||||
assert.strictEqual(result, '/custom/windsurf-path');
|
||||
});
|
||||
|
||||
test('respects WINDSURF_CONFIG_DIR env var', () => {
|
||||
process.env.WINDSURF_CONFIG_DIR = '~/custom-windsurf';
|
||||
const result = getGlobalDir('windsurf');
|
||||
const result = getGlobalConfigDir('windsurf');
|
||||
assert.strictEqual(result, path.join(os.homedir(), 'custom-windsurf'));
|
||||
});
|
||||
|
||||
test('explicit dir takes priority over WINDSURF_CONFIG_DIR', () => {
|
||||
process.env.WINDSURF_CONFIG_DIR = '~/from-env';
|
||||
const result = getGlobalDir('windsurf', '/explicit/path');
|
||||
const result = getGlobalConfigDir('windsurf', '/explicit/path');
|
||||
assert.strictEqual(result, '/explicit/path');
|
||||
});
|
||||
|
||||
test('does not break other runtimes', () => {
|
||||
assert.strictEqual(getGlobalDir('claude'), path.join(os.homedir(), '.claude'));
|
||||
assert.strictEqual(getGlobalDir('codex'), path.join(os.homedir(), '.codex'));
|
||||
assert.strictEqual(getGlobalConfigDir('claude'), path.join(os.homedir(), '.claude'));
|
||||
assert.strictEqual(getGlobalConfigDir('codex'), path.join(os.homedir(), '.codex'));
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user