mirror of
https://github.com/JuliusBrussee/caveman.git
synced 2026-08-11 13:21:09 +02:00
feat: make default caveman mode configurable
Add caveman-config.js shared config resolver. Default mode resolves via: CAVEMAN_DEFAULT_MODE env var > XDG config file > 'full'. Updated all install/uninstall scripts (bash + PowerShell) and tests. Closes #86 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
24e6ee9ea8
commit
ea89000141
@@ -9,6 +9,7 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const { getDefaultMode } = require('./caveman-config');
|
||||
|
||||
const claudeDir = path.join(os.homedir(), '.claude');
|
||||
const flagPath = path.join(claudeDir, '.caveman-active');
|
||||
@@ -17,7 +18,7 @@ const settingsPath = path.join(claudeDir, 'settings.json');
|
||||
// 1. Write flag file
|
||||
try {
|
||||
fs.mkdirSync(path.dirname(flagPath), { recursive: true });
|
||||
fs.writeFileSync(flagPath, 'full');
|
||||
fs.writeFileSync(flagPath, getDefaultMode());
|
||||
} catch (e) {
|
||||
// Silent fail -- flag is best-effort, don't block the hook
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/usr/bin/env node
|
||||
// caveman — shared configuration resolver
|
||||
//
|
||||
// Resolution order for default mode:
|
||||
// 1. CAVEMAN_DEFAULT_MODE environment variable
|
||||
// 2. Config file defaultMode field:
|
||||
// - $XDG_CONFIG_HOME/caveman/config.json (any platform, if set)
|
||||
// - ~/.config/caveman/config.json (macOS / Linux fallback)
|
||||
// - %APPDATA%\caveman\config.json (Windows fallback)
|
||||
// 3. 'full'
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
|
||||
const VALID_MODES = [
|
||||
'lite', 'full', 'ultra',
|
||||
'wenyan-lite', 'wenyan', 'wenyan-full', 'wenyan-ultra',
|
||||
'commit', 'review', 'compress'
|
||||
];
|
||||
|
||||
function getConfigDir() {
|
||||
if (process.env.XDG_CONFIG_HOME) {
|
||||
return path.join(process.env.XDG_CONFIG_HOME, 'caveman');
|
||||
}
|
||||
if (process.platform === 'win32') {
|
||||
return path.join(
|
||||
process.env.APPDATA || path.join(os.homedir(), 'AppData', 'Roaming'),
|
||||
'caveman'
|
||||
);
|
||||
}
|
||||
return path.join(os.homedir(), '.config', 'caveman');
|
||||
}
|
||||
|
||||
function getConfigPath() {
|
||||
return path.join(getConfigDir(), 'config.json');
|
||||
}
|
||||
|
||||
function getDefaultMode() {
|
||||
// 1. Environment variable (highest priority)
|
||||
const envMode = process.env.CAVEMAN_DEFAULT_MODE;
|
||||
if (envMode && VALID_MODES.includes(envMode.toLowerCase())) {
|
||||
return envMode.toLowerCase();
|
||||
}
|
||||
|
||||
// 2. Config file
|
||||
try {
|
||||
const configPath = getConfigPath();
|
||||
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
||||
if (config.defaultMode && VALID_MODES.includes(config.defaultMode.toLowerCase())) {
|
||||
return config.defaultMode.toLowerCase();
|
||||
}
|
||||
} catch (e) {
|
||||
// Config file doesn't exist or is invalid — fall through
|
||||
}
|
||||
|
||||
// 3. Default
|
||||
return 'full';
|
||||
}
|
||||
|
||||
module.exports = { getDefaultMode, getConfigDir, getConfigPath, VALID_MODES };
|
||||
@@ -5,6 +5,7 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
const { getDefaultMode } = require('./caveman-config');
|
||||
|
||||
const flagPath = path.join(os.homedir(), '.claude', '.caveman-active');
|
||||
|
||||
@@ -35,7 +36,7 @@ process.stdin.on('end', () => {
|
||||
else if (arg === 'wenyan-lite') mode = 'wenyan-lite';
|
||||
else if (arg === 'wenyan' || arg === 'wenyan-full') mode = 'wenyan';
|
||||
else if (arg === 'wenyan-ultra') mode = 'wenyan-ultra';
|
||||
else mode = 'full';
|
||||
else mode = getDefaultMode();
|
||||
}
|
||||
|
||||
if (mode) {
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ $HooksDir = Join-Path $ClaudeDir "hooks"
|
||||
$Settings = Join-Path $ClaudeDir "settings.json"
|
||||
$RepoUrl = "https://raw.githubusercontent.com/JuliusBrussee/caveman/main/hooks"
|
||||
|
||||
$HookFiles = @("caveman-activate.js", "caveman-mode-tracker.js", "caveman-statusline.sh", "caveman-statusline.ps1")
|
||||
$HookFiles = @("caveman-config.js", "caveman-activate.js", "caveman-mode-tracker.js", "caveman-statusline.sh", "caveman-statusline.ps1")
|
||||
|
||||
# Resolve source — works from repo clone or remote
|
||||
$ScriptDir = if ($PSScriptRoot) { $PSScriptRoot } else { $null }
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ HOOKS_DIR="$CLAUDE_DIR/hooks"
|
||||
SETTINGS="$CLAUDE_DIR/settings.json"
|
||||
REPO_URL="https://raw.githubusercontent.com/JuliusBrussee/caveman/main/hooks"
|
||||
|
||||
HOOK_FILES=("caveman-activate.js" "caveman-mode-tracker.js" "caveman-statusline.sh")
|
||||
HOOK_FILES=("caveman-config.js" "caveman-activate.js" "caveman-mode-tracker.js" "caveman-statusline.sh")
|
||||
|
||||
# Resolve source — works from repo clone or curl pipe
|
||||
SCRIPT_DIR=""
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ $HooksDir = Join-Path $ClaudeDir "hooks"
|
||||
$Settings = Join-Path $ClaudeDir "settings.json"
|
||||
$FlagFile = Join-Path $ClaudeDir ".caveman-active"
|
||||
|
||||
$HookFiles = @("caveman-activate.js", "caveman-mode-tracker.js", "caveman-statusline.sh", "caveman-statusline.ps1")
|
||||
$HookFiles = @("caveman-config.js", "caveman-activate.js", "caveman-mode-tracker.js", "caveman-statusline.sh", "caveman-statusline.ps1")
|
||||
|
||||
# Detect if caveman is installed as a plugin
|
||||
$PluginInstalled = $false
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ HOOKS_DIR="$CLAUDE_DIR/hooks"
|
||||
SETTINGS="$CLAUDE_DIR/settings.json"
|
||||
FLAG_FILE="$CLAUDE_DIR/.caveman-active"
|
||||
|
||||
HOOK_FILES=("caveman-activate.js" "caveman-mode-tracker.js" "caveman-statusline.sh")
|
||||
HOOK_FILES=("caveman-config.js" "caveman-activate.js" "caveman-mode-tracker.js" "caveman-statusline.sh")
|
||||
|
||||
# Detect if caveman is installed as a plugin (check plugin cache)
|
||||
PLUGIN_INSTALLED=0
|
||||
|
||||
@@ -105,12 +105,19 @@ def verify_manifests_and_syntax() -> None:
|
||||
for path in manifest_paths:
|
||||
read_json(path)
|
||||
|
||||
run(["node", "--check", "hooks/caveman-config.js"])
|
||||
run(["node", "--check", "hooks/caveman-activate.js"])
|
||||
run(["node", "--check", "hooks/caveman-mode-tracker.js"])
|
||||
run(["bash", "-n", "hooks/install.sh"])
|
||||
run(["bash", "-n", "hooks/uninstall.sh"])
|
||||
run(["bash", "-n", "hooks/caveman-statusline.sh"])
|
||||
|
||||
# Ensure install/uninstall scripts include caveman-config.js
|
||||
install_sh = (ROOT / "hooks/install.sh").read_text()
|
||||
uninstall_sh = (ROOT / "hooks/uninstall.sh").read_text()
|
||||
ensure("caveman-config.js" in install_sh, "install.sh missing caveman-config.js")
|
||||
ensure("caveman-config.js" in uninstall_sh, "uninstall.sh missing caveman-config.js")
|
||||
|
||||
print("JSON manifests and JS/bash syntax OK")
|
||||
|
||||
|
||||
@@ -120,6 +127,8 @@ def verify_powershell_static() -> None:
|
||||
uninstall_text = (ROOT / "hooks/uninstall.ps1").read_text()
|
||||
statusline_text = (ROOT / "hooks/caveman-statusline.ps1").read_text()
|
||||
|
||||
ensure("caveman-config.js" in install_text, "install.ps1 missing caveman-config.js")
|
||||
ensure("caveman-config.js" in uninstall_text, "uninstall.ps1 missing caveman-config.js")
|
||||
ensure("caveman-statusline.ps1" in install_text, "install.ps1 missing statusline.ps1")
|
||||
ensure("caveman-statusline.ps1" in uninstall_text, "uninstall.ps1 missing statusline.ps1")
|
||||
ensure("-AsHashtable" not in install_text, "install.ps1 should stay compatible with Windows PowerShell 5.1")
|
||||
@@ -220,6 +229,16 @@ def verify_hook_install_flow() -> None:
|
||||
ensure("STATUSLINE SETUP NEEDED" not in activate.stdout, "activation should stay quiet when custom statusline exists")
|
||||
ensure((claude_dir / ".caveman-active").read_text() == "full", "activation flag should default to full")
|
||||
|
||||
# Test configurable default mode via CAVEMAN_DEFAULT_MODE env var
|
||||
activate_custom = run(
|
||||
["node", "hooks/caveman-activate.js"],
|
||||
env={"HOME": str(home), "CAVEMAN_DEFAULT_MODE": "ultra"},
|
||||
)
|
||||
ensure("CAVEMAN MODE ACTIVE." in activate_custom.stdout, "activation with custom default missing banner")
|
||||
ensure((claude_dir / ".caveman-active").read_text() == "ultra", "CAVEMAN_DEFAULT_MODE=ultra should set flag to ultra")
|
||||
# Reset back to full for subsequent tests
|
||||
(claude_dir / ".caveman-active").write_text("full")
|
||||
|
||||
run(
|
||||
["node", "hooks/caveman-mode-tracker.js"],
|
||||
env={"HOME": str(home)},
|
||||
|
||||
Reference in New Issue
Block a user