Files
ponytail/hooks/ponytail-activate.js
T
Lakshya77089 a3bc7db722 fix: strip UTF-8 BOM before parsing settings.json in ponytail-activate (#148) (#151)
settings.json written by Notepad or VS Code on Windows can carry a
UTF-8 BOM. JSON.parse then throws SyntaxError, the outer catch swallows
it, hasStatusline stays false, and the statusline setup nudge is never
emitted.

Strip the leading BOM before parsing, matching the existing handling in
ponytail-mode-tracker.js. (#96 added a null guard but not BOM stripping.)
2026-06-18 22:50:10 +02:00

75 lines
2.5 KiB
JavaScript

#!/usr/bin/env node
// ponytail — Claude Code SessionStart activation hook
//
// Runs on every session start:
// 1. Writes flag file at ~/.claude/.ponytail-active (statusline reads this)
// 2. Emits ponytail ruleset as hidden SessionStart context
// 3. Detects missing statusline config and emits setup nudge
const fs = require('fs');
const path = require('path');
const { getDefaultMode, getClaudeDir } = require('./ponytail-config');
const { getPonytailInstructions } = require('./ponytail-instructions');
const {
clearMode,
isCodex,
setMode,
writeHookOutput,
} = require('./ponytail-runtime');
const claudeDir = getClaudeDir();
const settingsPath = path.join(claudeDir, 'settings.json');
const mode = getDefaultMode();
// "off" mode — skip activation entirely, don't write flag or emit rules
if (mode === 'off') {
clearMode();
writeHookOutput('SessionStart', 'off', isCodex ? '' : 'OK');
process.exit(0);
}
// 1. Write flag file
try {
setMode(mode);
} catch (e) {
// Silent fail -- flag is best-effort, don't block the hook
}
// 2. Emit the ponytail ruleset, filtered to the active intensity level.
let output = getPonytailInstructions(mode);
// 3. Detect missing statusline config — nudge Claude to help set it up
if (!isCodex) try {
let hasStatusline = false;
if (fs.existsSync(settingsPath)) {
// Strip UTF-8 BOM some editors prepend on Windows (breaks JSON.parse)
const raw = fs.readFileSync(settingsPath, 'utf8').replace(/^\uFEFF/, '');
const settings = JSON.parse(raw);
if (settings.statusLine) {
hasStatusline = true;
}
}
if (!hasStatusline) {
const isWindows = process.platform === 'win32';
const scriptName = isWindows ? 'ponytail-statusline.ps1' : 'ponytail-statusline.sh';
const scriptPath = path.join(__dirname, scriptName);
const command = isWindows
? `powershell -ExecutionPolicy Bypass -File "${scriptPath}"`
: `bash "${scriptPath}"`;
const statusLineSnippet =
'"statusLine": { "type": "command", "command": ' + JSON.stringify(command) + ' }';
output += "\n\n" +
"STATUSLINE SETUP NEEDED: The ponytail plugin includes a statusline badge showing active mode " +
"(e.g. [PONYTAIL], [PONYTAIL:ULTRA]). It is not configured yet. " +
"To enable, add this to ~/.claude/settings.json: " +
statusLineSnippet + " " +
"Proactively offer to set this up for the user on first interaction.";
}
} catch (e) {
// Silent fail — don't block session start over statusline detection
}
writeHookOutput('SessionStart', mode, output);