{
  "version": 3,
  "sources": ["../../../src/hooks/ts/post-tool-use/whisper-reinject.ts", "../../../src/hooks/ts/lib/worker-session.ts"],
  "sourcesContent": ["#!/usr/bin/env node\n\n/**\n * whisper-reinject \u2014 put the output-shape rules back in view mid-turn.\n *\n * The whisper rules are injected once per user message, by the UserPromptSubmit\n * hook. That is the wrong place for the rules that govern how a turn is\n * *written*, because a long turn does not write its answer next to that\n * injection: it runs twenty tool calls first. Attention follows the tool\n * output, the injected block scrolls out of working memory, and by the time the\n * answer is composed the rules are gone. Nothing in the loop re-checks them, so\n * compliance decays with turn length \u2014 exactly the turns where it matters most.\n *\n * This fires after a tool call instead, so the reminder lands where the decay\n * happens. It stays quiet for short sequences (nothing has decayed yet) and\n * emits a compressed set \u2014 not all of them \u2014 every few calls after that. The\n * full rule set is deliberately not repeated: a wall of text re-read every few\n * calls is skimmed, and it costs context that the actual work needs.\n *\n * Only rules about the shape of the reply belong here. Rules about actions\n * (what may be sent, published, or committed) are enforced at the point of\n * action, not by reminding.\n */\nimport { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport { tmpdir } from \"node:os\";\nimport { isWorkerSession } from \"../lib/worker-session.js\";\n\n/** Stay silent below this many tool calls \u2014 a short turn has not drifted yet. */\nconst QUIET_BELOW = 6;\n\n/** Re-emit every N calls once past QUIET_BELOW. */\nconst EVERY = 8;\n\nfunction counterFile(sessionId: string): string {\n  const safe = sessionId.replace(/[^A-Za-z0-9_-]/g, \"\") || \"nosession\";\n  return join(tmpdir(), \"pai-whisper-reinject\", `${safe}.count`);\n}\n\nfunction bump(path: string): number {\n  try {\n    mkdirSync(dirname(path), { recursive: true });\n    const n = existsSync(path) ? Number.parseInt(readFileSync(path, \"utf-8\").trim(), 10) || 0 : 0;\n    const next = n + 1;\n    writeFileSync(path, String(next));\n    return next;\n  } catch {\n    return 0;\n  }\n}\n\nfunction localTime(): string {\n  const d = new Date();\n  const p = (n: number) => String(n).padStart(2, \"0\");\n  return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}`;\n}\n\nfunction readStdin(): string {\n  try {\n    return readFileSync(0, \"utf-8\");\n  } catch {\n    return \"\";\n  }\n}\n\nfunction main(): void {\n  let sessionId = \"\";\n  try {\n    const raw = readStdin();\n    if (raw.trim()) sessionId = (JSON.parse(raw) as { session_id?: string }).session_id ?? \"\";\n  } catch { /* no session id \u2014 fall back to a shared counter */ }\n\n  if (isWorkerSession()) return;\n\n  const n = bump(counterFile(sessionId));\n  if (n < QUIET_BELOW || n % EVERY !== 0) return;\n\n  const lines = [\n    `CURRENT LOCAL TIME: ${localTime()} \u2014 use verbatim for any [YYYY-MM-DD HH:MM] stamp. Never estimate it, never increment a previous one.`,\n    `You are ${n} tool calls into this turn. Before the next one, check:`,\n    \"- One command at a time: say what you are about to run, run it, say what came back. Do not batch several steps into one call.\",\n    \"- Report what CHANGED, not what you learned. A finding is not a deliverable.\",\n    \"- Prove it: show the reading that says it failed before and works now.\",\n    \"- Found a fault while working? Fix it. Filing it is not fixing it.\",\n    \"- Corrections stay to one line. No re-litigating your own mistakes.\",\n  ];\n\n  console.log(`<system-reminder>\\n${lines.join(\"\\n\")}\\n</system-reminder>`);\n}\n\nmain();\n", "/**\n * Worker-session detection.\n *\n * A disposable headless worker (a `claude -p` run started by an orchestrating\n * session, possibly against a different model provider with a different\n * context window) shares the project directory and the hook configuration\n * with the real session that spawned it. Left alone, the hooks treat it as a\n * session in its own right: they inject project context into it, create and\n * rename a numbered session note for it, autosave it, and enqueue a\n * model-written handover for it. Its compactions also land in the project's\n * transcript folder, where they are indistinguishable from a real session's\n * and drag the measured compaction trigger down (observed 2026-09-17: two\n * workers compacting at ~151k tokens pulled a project's trigger from ~784k\n * to ~151k, and the real session's handover fired at ~50k tokens).\n *\n * The launcher marks such sessions with `PAI_WORKER=1`. Every hook that does\n * per-session bookkeeping returns immediately when this predicate is true.\n * Deliberately NOT guarded: the security validator (a worker's shell\n * commands must still be checked) and observability capture.\n */\nexport function isWorkerSession(env: NodeJS.ProcessEnv = process.env): boolean {\n  return env.PAI_WORKER === \"1\";\n}\n"],
  "mappings": ";;;;;;AAuBA,SAAyB,YAAY,WAAW,cAAc,qBAAqB;AACnF,SAAS,SAAS,YAAY;AAC9B,SAAS,cAAc;;;ACLhB,SAAS,gBAAgB,MAAyB,QAAQ,KAAc;AAC7E,SAAO,IAAI,eAAe;AAC5B;;;ADOA,IAAM,cAAc;AAGpB,IAAM,QAAQ;AAEd,SAAS,YAAY,WAA2B;AAC9C,QAAM,OAAO,UAAU,QAAQ,mBAAmB,EAAE,KAAK;AACzD,SAAO,KAAK,OAAO,GAAG,wBAAwB,GAAG,IAAI,QAAQ;AAC/D;AAEA,SAAS,KAAK,MAAsB;AAClC,MAAI;AACF,cAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,UAAM,IAAI,WAAW,IAAI,IAAI,OAAO,SAAS,aAAa,MAAM,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,IAAI;AAC5F,UAAM,OAAO,IAAI;AACjB,kBAAc,MAAM,OAAO,IAAI,CAAC;AAChC,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,YAAoB;AAC3B,QAAM,IAAI,oBAAI,KAAK;AACnB,QAAM,IAAI,CAAC,MAAc,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AAClD,SAAO,GAAG,EAAE,YAAY,CAAC,IAAI,EAAE,EAAE,SAAS,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,CAAC,CAAC;AAC5G;AAEA,SAAS,YAAoB;AAC3B,MAAI;AACF,WAAO,aAAa,GAAG,OAAO;AAAA,EAChC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,OAAa;AACpB,MAAI,YAAY;AAChB,MAAI;AACF,UAAM,MAAM,UAAU;AACtB,QAAI,IAAI,KAAK,EAAG,aAAa,KAAK,MAAM,GAAG,EAA8B,cAAc;AAAA,EACzF,QAAQ;AAAA,EAAsD;AAE9D,MAAI,gBAAgB,EAAG;AAEvB,QAAM,IAAI,KAAK,YAAY,SAAS,CAAC;AACrC,MAAI,IAAI,eAAe,IAAI,UAAU,EAAG;AAExC,QAAM,QAAQ;AAAA,IACZ,uBAAuB,UAAU,CAAC;AAAA,IAClC,WAAW,CAAC;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAEA,UAAQ,IAAI;AAAA,EAAsB,MAAM,KAAK,IAAI,CAAC;AAAA,mBAAsB;AAC1E;AAEA,KAAK;",
  "names": []
}
