#!/usr/bin/env node /** * token-saver-bash-limiter.js · TSE Layer 3 · 2026-04-27 * PreToolUse (Bash) · 查看型命令自动截断输出 * 仅截断 cat/find/tree/journalctl 等查看命令, 不动 build/git/ssh 执行命令 * 行为: fail-open, 通过 updatedInput 追加 | head -N */ 'use strict'; const readStdin = require('./lib/read-stdin.js'); const VIEW_RE = [ /\bcat\s+\S+/, /\bdocker\s+logs\b/, /\bjournalctl\b/, /\bdmesg\b/, /\bps\s+aux/, /\bfind\s+\//, /\bls\s+-[^\s]*R/, /\btree\b/, /\bsqlite3\b.*\.dump/, /\bnpm\s+ls\b/, /\bpip\s+(list|freeze)\b/, /\bdpkg\s+-l/, /\bsystemctl\s+list/, ]; const SKIP_RE = [ /\|\s*head\b/, /\|\s*tail\b/, /\|\s*grep\b/, /\|\s*awk\b/, /\|\s*sed\b/, /\|\s*wc\b/, /[>]/, /\bgit\s+(push|pull|fetch|clone|rebase|merge|commit)/, /\bnpm\s+(install|run|build|test)/, /\bpnpm\s/, /\bdocker\s+(build|run|push|compose)/, /\bssh\b/, /\bscp\b/, /\bcurl\b/, /\bwget\b/, /\bmake\b/, /\bcargo\b/, /\bgo\s+(build|run|test)/, ]; (async () => { try { const hookData = await readStdin(); if (hookData.tool_name !== 'Bash') process.exit(0); const cmd = (hookData.tool_input || {}).command || ''; if (!cmd || cmd.length < 5) process.exit(0); for (const re of SKIP_RE) { if (re.test(cmd)) process.exit(0); } let match = false; for (const re of VIEW_RE) { if (re.test(cmd)) { match = true; break; } } if (!match) process.exit(0); const limit = /\bfind\s+\/|journalctl|tree\s+\/|\.dump/.test(cmd) ? 80 : 150; const newCmd = cmd + ' 2>&1 | head -' + limit; process.stdout.write(JSON.stringify({ continue: true, hookSpecificOutput: { hookEventName: 'PreToolUse', updatedInput: { command: newCmd, description: (hookData.tool_input || {}).description }, additionalContext: '[TSE·BASH_LIMITER] 输出已截断至 ' + limit + ' 行。需完整输出请 > file 重定向。' } })); process.exit(0); } catch { process.exit(0); } })();