fix: honor CLAUDE_CONFIG_DIR in hooks (#37)

ponytail-activate.js and ponytail-runtime.js hardcoded ~/.claude for the
flag file and settings lookup, ignoring CLAUDE_CONFIG_DIR. Add a shared
getClaudeDir() to ponytail-config.js and use it in both. Regression test
added to hooks.test.js.

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
DietrichGebert
2026-06-15 00:00:01 +02:00
committed by GitHub
co-authored by Claude Opus 4.8
parent 6d990f8c54
commit 01578c0cd4
4 changed files with 35 additions and 5 deletions
+2 -3
View File
@@ -8,8 +8,7 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const os = require('os'); const { getDefaultMode, getClaudeDir } = require('./ponytail-config');
const { getDefaultMode } = require('./ponytail-config');
const { getPonytailInstructions } = require('./ponytail-instructions'); const { getPonytailInstructions } = require('./ponytail-instructions');
const { const {
clearMode, clearMode,
@@ -18,7 +17,7 @@ const {
writeHookOutput, writeHookOutput,
} = require('./ponytail-runtime'); } = require('./ponytail-runtime');
const claudeDir = path.join(os.homedir(), '.claude'); const claudeDir = getClaudeDir();
const settingsPath = path.join(claudeDir, 'settings.json'); const settingsPath = path.join(claudeDir, 'settings.json');
const mode = getDefaultMode(); const mode = getDefaultMode();
+6
View File
@@ -50,6 +50,11 @@ function getConfigPath() {
return path.join(getConfigDir(), 'config.json'); return path.join(getConfigDir(), 'config.json');
} }
function getClaudeDir() {
// ponytail: CLAUDE_CONFIG_DIR overrides ~/.claude, matching Claude Code.
return process.env.CLAUDE_CONFIG_DIR || path.join(os.homedir(), '.claude');
}
function getDefaultMode() { function getDefaultMode() {
// 1. Environment variable (highest priority) // 1. Environment variable (highest priority)
const envMode = process.env.PONYTAIL_DEFAULT_MODE; const envMode = process.env.PONYTAIL_DEFAULT_MODE;
@@ -89,6 +94,7 @@ module.exports = {
getDefaultMode, getDefaultMode,
getConfigDir, getConfigDir,
getConfigPath, getConfigPath,
getClaudeDir,
normalizeMode, normalizeMode,
normalizeConfigMode, normalizeConfigMode,
normalizePersistedMode, normalizePersistedMode,
+2 -2
View File
@@ -1,11 +1,11 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const os = require('os'); const { getClaudeDir } = require('./ponytail-config');
const isCodex = Boolean(process.env.PLUGIN_DATA); const isCodex = Boolean(process.env.PLUGIN_DATA);
const statePath = isCodex const statePath = isCodex
? path.join(process.env.PLUGIN_DATA, '.ponytail-active') ? path.join(process.env.PLUGIN_DATA, '.ponytail-active')
: path.join(os.homedir(), '.claude', '.ponytail-active'); : path.join(getClaudeDir(), '.ponytail-active');
function setMode(mode) { function setMode(mode) {
fs.mkdirSync(path.dirname(statePath), { recursive: true }); fs.mkdirSync(path.dirname(statePath), { recursive: true });
+25
View File
@@ -16,6 +16,10 @@ function run(script, env, input = '') {
}); });
} }
// Keep the base env clean so the default-dir checks are deterministic; the
// CLAUDE_CONFIG_DIR case sets it explicitly.
delete process.env.CLAUDE_CONFIG_DIR;
const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'ponytail-hooks-')); const temp = fs.mkdtempSync(path.join(os.tmpdir(), 'ponytail-hooks-'));
const home = path.join(temp, 'home'); const home = path.join(temp, 'home');
const pluginData = path.join(temp, 'plugin-data'); const pluginData = path.join(temp, 'plugin-data');
@@ -74,5 +78,26 @@ assert.equal(
'full', 'full',
); );
// CLAUDE_CONFIG_DIR overrides ~/.claude for the flag file (issue #34).
const home2 = path.join(temp, 'home2');
fs.mkdirSync(home2, { recursive: true });
const customConfigDir = path.join(temp, 'custom-claude');
result = run('ponytail-activate.js', {
HOME: home2,
USERPROFILE: home2,
CLAUDE_CONFIG_DIR: customConfigDir,
PONYTAIL_DEFAULT_MODE: 'lite',
});
assert.equal(result.status, 0, result.stderr);
assert.equal(
fs.readFileSync(path.join(customConfigDir, '.ponytail-active'), 'utf8'),
'lite',
);
assert.equal(
fs.existsSync(path.join(home2, '.claude', '.ponytail-active')),
false,
'flag must not land in ~/.claude when CLAUDE_CONFIG_DIR is set',
);
fs.rmSync(temp, { recursive: true, force: true }); fs.rmSync(temp, { recursive: true, force: true });
console.log('hook compatibility checks passed'); console.log('hook compatibility checks passed');