cms.c2sgmbh/.claude/hooks/statusline.js
Martin Porwoll 77f70876f4 chore: add Claude Code config, prompts, and tenant setup scripts
- Add .claude/ configuration (agents, commands, hooks, get-shit-done workflows)
- Add prompts/ directory with development planning documents
- Add scripts/setup-tenants/ with tenant configuration
- Add docs/screenshots/
- Remove obsolete phase2.2-corrections-report.md
- Update pnpm-lock.yaml
- Update detect-secrets.sh to ignore setup.sh (env var usage, not secrets)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-18 10:18:05 +00:00

84 lines
2.8 KiB
JavaScript
Executable file

#!/usr/bin/env node
// Claude Code Statusline - GSD Edition
// Shows: model | current task | directory | context usage
const fs = require('fs');
const path = require('path');
const os = require('os');
// Read JSON from stdin
let input = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', chunk => input += chunk);
process.stdin.on('end', () => {
try {
const data = JSON.parse(input);
const model = data.model?.display_name || 'Claude';
const dir = data.workspace?.current_dir || process.cwd();
const session = data.session_id || '';
const remaining = data.context_window?.remaining_percentage;
// Context window display (shows USED percentage)
let ctx = '';
if (remaining != null) {
const rem = Math.round(remaining);
const used = 100 - rem;
// Build progress bar (10 segments)
const filled = Math.floor(used / 10);
const bar = '█'.repeat(filled) + '░'.repeat(10 - filled);
// Color based on usage
if (used < 50) {
ctx = ` \x1b[32m${bar} ${used}%\x1b[0m`;
} else if (used < 65) {
ctx = ` \x1b[33m${bar} ${used}%\x1b[0m`;
} else if (used < 80) {
ctx = ` \x1b[38;5;208m${bar} ${used}%\x1b[0m`;
} else {
ctx = ` \x1b[5;31m💀 ${bar} ${used}%\x1b[0m`;
}
}
// Current task from todos
let task = '';
const homeDir = os.homedir();
const todosDir = path.join(homeDir, '.claude', 'todos');
if (session && fs.existsSync(todosDir)) {
const files = fs.readdirSync(todosDir)
.filter(f => f.startsWith(session) && f.includes('-agent-') && f.endsWith('.json'))
.map(f => ({ name: f, mtime: fs.statSync(path.join(todosDir, f)).mtime }))
.sort((a, b) => b.mtime - a.mtime);
if (files.length > 0) {
try {
const todos = JSON.parse(fs.readFileSync(path.join(todosDir, files[0].name), 'utf8'));
const inProgress = todos.find(t => t.status === 'in_progress');
if (inProgress) task = inProgress.activeForm || '';
} catch (e) {}
}
}
// GSD update available?
let gsdUpdate = '';
const cacheFile = path.join(homeDir, '.claude', 'cache', 'gsd-update-check.json');
if (fs.existsSync(cacheFile)) {
try {
const cache = JSON.parse(fs.readFileSync(cacheFile, 'utf8'));
if (cache.update_available) {
gsdUpdate = '\x1b[33m⬆ /gsd:update\x1b[0m │ ';
}
} catch (e) {}
}
// Output
const dirname = path.basename(dir);
if (task) {
process.stdout.write(`${gsdUpdate}\x1b[2m${model}\x1b[0m │ \x1b[1m${task}\x1b[0m │ \x1b[2m${dirname}\x1b[0m${ctx}`);
} else {
process.stdout.write(`${gsdUpdate}\x1b[2m${model}\x1b[0m │ \x1b[2m${dirname}\x1b[0m${ctx}`);
}
} catch (e) {
// Silent fail - don't break statusline on parse errors
}
});