kerf-cli 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -8,7 +8,7 @@ import React2 from "react";
8
8
  import { render } from "ink";
9
9
 
10
10
  // src/core/parser.ts
11
- import { readFileSync, statSync } from "node:fs";
11
+ import { readFileSync, statSync, readdirSync, openSync, readSync, closeSync } from "node:fs";
12
12
  import { readdir } from "node:fs/promises";
13
13
  import { join as join2, basename } from "node:path";
14
14
  import dayjs from "dayjs";
@@ -79,6 +79,7 @@ function parseJsonlContent(content, sessionId) {
79
79
  };
80
80
  messageMap.set(id, {
81
81
  id,
82
+ sessionId,
82
83
  model: model !== "unknown" ? model : existing?.model ?? "unknown",
83
84
  timestamp,
84
85
  usage: parsedUsage,
@@ -138,6 +139,28 @@ async function findJsonlFiles(baseDir) {
138
139
  await walk(dir);
139
140
  return files;
140
141
  }
142
+ function findJsonlFilesSync(baseDir) {
143
+ const dir = baseDir ?? CLAUDE_PROJECTS_DIR;
144
+ const files = [];
145
+ function walkSync(currentDir) {
146
+ let entries;
147
+ try {
148
+ entries = readdirSync(currentDir, { withFileTypes: true });
149
+ } catch {
150
+ return;
151
+ }
152
+ for (const entry of entries) {
153
+ const fullPath = join2(currentDir, entry.name);
154
+ if (entry.isDirectory()) {
155
+ walkSync(fullPath);
156
+ } else if (entry.name.endsWith(".jsonl")) {
157
+ files.push(fullPath);
158
+ }
159
+ }
160
+ }
161
+ walkSync(dir);
162
+ return files;
163
+ }
141
164
  async function getActiveSessions(baseDir) {
142
165
  const files = await findJsonlFiles(baseDir);
143
166
  const cutoff = dayjs().subtract(BILLING_WINDOW_HOURS, "hour");
@@ -224,11 +247,11 @@ function calculateMessageCost(msg) {
224
247
  };
225
248
  }
226
249
  const pricing = resolveModelPricing(msg.model);
227
- const MILLION = 1e6;
228
- const inputCost = msg.usage.input_tokens * pricing.input / MILLION;
229
- const outputCost = msg.usage.output_tokens * pricing.output / MILLION;
230
- const cacheReadCost = msg.usage.cache_read_input_tokens * pricing.cacheRead / MILLION;
231
- const cacheCreationCost = msg.usage.cache_creation_input_tokens * pricing.cacheCreation / MILLION;
250
+ const MILLION2 = 1e6;
251
+ const inputCost = msg.usage.input_tokens * pricing.input / MILLION2;
252
+ const outputCost = msg.usage.output_tokens * pricing.output / MILLION2;
253
+ const cacheReadCost = msg.usage.cache_read_input_tokens * pricing.cacheRead / MILLION2;
254
+ const cacheCreationCost = msg.usage.cache_creation_input_tokens * pricing.cacheCreation / MILLION2;
232
255
  return {
233
256
  inputCost,
234
257
  outputCost,
@@ -269,7 +292,7 @@ function aggregateCosts(messages, period) {
269
292
  const key = getPeriodKey(msg.timestamp, period);
270
293
  const group = groups.get(key) ?? { messages: [], sessions: /* @__PURE__ */ new Set() };
271
294
  group.messages.push(msg);
272
- group.sessions.add(msg.id.split("_")[0] ?? msg.id);
295
+ group.sessions.add(msg.sessionId);
273
296
  groups.set(key, group);
274
297
  }
275
298
  return Array.from(groups.entries()).map(([key, group]) => {
@@ -690,17 +713,41 @@ var COMPLEXITY_PROFILES = {
690
713
  };
691
714
  var SIMPLE_KEYWORDS = ["typo", "rename", "fix typo", "update version", "change name", "remove unused", "delete"];
692
715
  var COMPLEX_KEYWORDS = ["refactor", "rewrite", "new module", "implement", "build", "create", "migrate", "redesign", "overhaul", "architecture"];
716
+ var TYPICAL_WINDOW_COSTS = {
717
+ sonnet: 15,
718
+ opus: 75,
719
+ haiku: 4
720
+ };
693
721
  function detectComplexity(taskDescription) {
694
722
  const lower = taskDescription.toLowerCase();
695
723
  if (SIMPLE_KEYWORDS.some((k) => lower.includes(k))) return "simple";
696
724
  if (COMPLEX_KEYWORDS.some((k) => lower.includes(k))) return "complex";
697
725
  return "medium";
698
726
  }
727
+ var MILLION = 1e6;
728
+ var CACHE_HIT_RATE = 0.9;
729
+ function estimateCostForTurns(turns, modelPricing, contextPerTurn, outputTokensPerTurn) {
730
+ let totalCost = 0;
731
+ for (let turn = 1; turn <= turns; turn++) {
732
+ const conversationGrowth = (turn - 1) * outputTokensPerTurn;
733
+ const inputTokens = contextPerTurn + conversationGrowth;
734
+ let effectiveInputCost;
735
+ if (turn <= 2) {
736
+ effectiveInputCost = inputTokens * modelPricing.input / MILLION;
737
+ } else {
738
+ const cachedTokens = inputTokens * CACHE_HIT_RATE;
739
+ const uncachedTokens = inputTokens * (1 - CACHE_HIT_RATE);
740
+ effectiveInputCost = cachedTokens * modelPricing.cacheRead / MILLION + uncachedTokens * modelPricing.input / MILLION;
741
+ }
742
+ const outputCost = outputTokensPerTurn * modelPricing.output / MILLION;
743
+ totalCost += effectiveInputCost + outputCost;
744
+ }
745
+ return totalCost;
746
+ }
699
747
  async function estimateTaskCost(taskDescription, options = {}) {
700
748
  const model = options.model ?? "sonnet";
701
749
  const cwd = options.cwd ?? process.cwd();
702
750
  const pricing = resolveModelPricing(model);
703
- const MILLION = 1e6;
704
751
  const overhead = estimateContextOverhead();
705
752
  let fileTokens = 0;
706
753
  let fileList = options.files ?? [];
@@ -724,48 +771,29 @@ async function estimateTaskCost(taskDescription, options = {}) {
724
771
  const complexity = detectComplexity(taskDescription);
725
772
  const profile = COMPLEXITY_PROFILES[complexity];
726
773
  const contextPerTurn = overhead.totalOverhead + fileTokens;
727
- const CACHE_HIT_RATE = 0.9;
728
- function estimateCostForTurns(turns) {
729
- let totalCost = 0;
730
- for (let turn = 1; turn <= turns; turn++) {
731
- const conversationGrowth = (turn - 1) * profile.outputTokensPerTurn;
732
- const inputTokens = contextPerTurn + conversationGrowth;
733
- let effectiveInputCost;
734
- if (turn <= 2) {
735
- effectiveInputCost = inputTokens * pricing.input / MILLION;
736
- } else {
737
- const cachedTokens = inputTokens * CACHE_HIT_RATE;
738
- const uncachedTokens = inputTokens * (1 - CACHE_HIT_RATE);
739
- effectiveInputCost = cachedTokens * pricing.cacheRead / MILLION + uncachedTokens * pricing.input / MILLION;
740
- }
741
- const outputCost = profile.outputTokensPerTurn * pricing.output / MILLION;
742
- totalCost += effectiveInputCost + outputCost;
743
- }
744
- return totalCost;
745
- }
746
- const lowCost = estimateCostForTurns(profile.turns.low);
747
- const expectedCost = estimateCostForTurns(profile.turns.expected);
748
- const highCost = estimateCostForTurns(profile.turns.high);
774
+ const lowCost = estimateCostForTurns(profile.turns.low, pricing, contextPerTurn, profile.outputTokensPerTurn);
775
+ const expectedCost = estimateCostForTurns(profile.turns.expected, pricing, contextPerTurn, profile.outputTokensPerTurn);
776
+ const highCost = estimateCostForTurns(profile.turns.high, pricing, contextPerTurn, profile.outputTokensPerTurn);
749
777
  const expectedInputTokens = contextPerTurn * profile.turns.expected;
750
778
  const expectedOutputTokens = profile.outputTokensPerTurn * profile.turns.expected;
751
779
  const expectedCachedTokens = expectedInputTokens * CACHE_HIT_RATE;
752
- const windowMinutes = BILLING_WINDOW_HOURS * 60;
753
- const percentOfWindow = expectedCost / (expectedCost * 3) * 100;
780
+ const typicalWindowCost = TYPICAL_WINDOW_COSTS[model] ?? TYPICAL_WINDOW_COSTS.sonnet;
781
+ const percentOfWindow = Math.min(100, Math.round(expectedCost / typicalWindowCost * 100));
754
782
  const recommendations = [];
755
783
  if (model !== "sonnet") {
756
784
  const sonnetPricing = resolveModelPricing("sonnet");
757
- const sonnetCost = estimateCostForTurns(profile.turns.expected);
758
- const ratio = pricing.output / resolveModelPricing("sonnet").output;
759
- if (ratio > 2) {
785
+ const sonnetExpected = estimateCostForTurns(profile.turns.expected, sonnetPricing, contextPerTurn, profile.outputTokensPerTurn);
786
+ const savings = expectedCost - sonnetExpected;
787
+ if (savings > 0.01) {
760
788
  recommendations.push(
761
- `Consider Sonnet to save ~${formatCost(expectedCost - expectedCost / ratio)} (${ratio.toFixed(0)}x cheaper)`
789
+ `Consider Sonnet to save ~${formatCost(savings)} (${(expectedCost / sonnetExpected).toFixed(1)}x cheaper)`
762
790
  );
763
791
  }
764
792
  }
765
793
  if (model === "sonnet") {
766
794
  const opusPricing = resolveModelPricing("opus");
767
- const ratio = opusPricing.output / pricing.output;
768
- recommendations.push(`Using Opus would cost ~${formatCost(expectedCost * ratio)} (${ratio.toFixed(0)}x more)`);
795
+ const opusExpected = estimateCostForTurns(profile.turns.expected, opusPricing, contextPerTurn, profile.outputTokensPerTurn);
796
+ recommendations.push(`Using Opus would cost ~${formatCost(opusExpected)} (${(opusExpected / expectedCost).toFixed(1)}x more)`);
769
797
  }
770
798
  if (overhead.percentUsable < 60) {
771
799
  recommendations.push(`High ghost token overhead (${(100 - overhead.percentUsable).toFixed(0)}%). Run 'kerf-cli audit' to optimize.`);
@@ -788,7 +816,7 @@ async function estimateTaskCost(taskDescription, options = {}) {
788
816
  },
789
817
  contextOverhead: overhead.totalOverhead,
790
818
  fileTokens,
791
- percentOfWindow: Math.round(percentOfWindow),
819
+ percentOfWindow,
792
820
  recommendations
793
821
  };
794
822
  }
@@ -1046,6 +1074,39 @@ var BudgetManager = class {
1046
1074
  VALUES (?, ?, ?, ?, ?, ?)`
1047
1075
  ).run(projectId, sessionId, tokensIn, tokensOut, costUsd, timestamp);
1048
1076
  }
1077
+ syncFromJsonl(projectPath) {
1078
+ const projectName = basename2(projectPath);
1079
+ const allFiles = findJsonlFilesSync();
1080
+ const encodedPath = projectPath.replace(/\//g, "-");
1081
+ const filesToProcess = allFiles.filter(
1082
+ (f) => f.includes(projectName) || f.includes(encodeURIComponent(projectPath)) || f.includes(encodedPath)
1083
+ );
1084
+ if (filesToProcess.length === 0) return 0;
1085
+ let synced = 0;
1086
+ for (const file of filesToProcess) {
1087
+ try {
1088
+ const session = parseSessionFile(file);
1089
+ for (const msg of session.messages) {
1090
+ const cost = calculateMessageCost(msg);
1091
+ try {
1092
+ this.recordUsage(
1093
+ projectPath,
1094
+ session.sessionId,
1095
+ msg.usage.input_tokens,
1096
+ msg.usage.output_tokens,
1097
+ cost.totalCost,
1098
+ msg.timestamp
1099
+ );
1100
+ synced++;
1101
+ } catch {
1102
+ }
1103
+ }
1104
+ } catch {
1105
+ continue;
1106
+ }
1107
+ }
1108
+ return synced;
1109
+ }
1049
1110
  getUsage(projectPath, period) {
1050
1111
  const project = this.db.prepare("SELECT id FROM projects WHERE path = ?").get(projectPath);
1051
1112
  if (!project) return 0;
@@ -1060,6 +1121,7 @@ var BudgetManager = class {
1060
1121
  checkBudget(projectPath) {
1061
1122
  const budgetConfig = this.getBudget(projectPath);
1062
1123
  if (!budgetConfig) return null;
1124
+ this.syncFromJsonl(projectPath);
1063
1125
  const spent = this.getUsage(projectPath, budgetConfig.period);
1064
1126
  const remaining = Math.max(0, budgetConfig.amount - spent);
1065
1127
  const percentUsed = budgetConfig.amount > 0 ? spent / budgetConfig.amount * 100 : 0;
@@ -1235,6 +1297,7 @@ function analyzeGhostTokens(claudeMdPath) {
1235
1297
  // src/audit/claudeMdLinter.ts
1236
1298
  import { readFileSync as readFileSync3, existsSync as existsSync3 } from "node:fs";
1237
1299
  import { join as join4 } from "node:path";
1300
+ import { homedir as homedir3 } from "node:os";
1238
1301
  var CRITICAL_RULE_PATTERN = /\b(NEVER|ALWAYS|MUST|IMPORTANT|CRITICAL)\b/i;
1239
1302
  var SKILL_CANDIDATES = /\b(review|deploy|release|migration|template|boilerplate|scaffold)\b/i;
1240
1303
  var LINE_LIMIT = 200;
@@ -1247,7 +1310,9 @@ function getAttentionZone(position, total) {
1247
1310
  function lintClaudeMd(filePath) {
1248
1311
  const paths = filePath ? [filePath] : [
1249
1312
  join4(process.cwd(), "CLAUDE.md"),
1250
- join4(process.cwd(), ".claude", "CLAUDE.md")
1313
+ join4(process.cwd(), ".claude", "CLAUDE.md"),
1314
+ ...findGitRootClaudeMd(),
1315
+ join4(homedir3(), ".claude", "CLAUDE.md")
1251
1316
  ];
1252
1317
  let resolvedPath = null;
1253
1318
  for (const p of paths) {
@@ -1301,7 +1366,7 @@ function lintClaudeMd(filePath) {
1301
1366
  // src/audit/mcpAnalyzer.ts
1302
1367
  import { readFileSync as readFileSync4, existsSync as existsSync4 } from "node:fs";
1303
1368
  import { join as join5 } from "node:path";
1304
- import { homedir as homedir3 } from "node:os";
1369
+ import { homedir as homedir4 } from "node:os";
1305
1370
  var CLI_ALTERNATIVES = {
1306
1371
  playwright: "Consider using the built-in Bash tool with playwright CLI instead",
1307
1372
  puppeteer: "Consider using the built-in Bash tool with puppeteer scripts",
@@ -1310,39 +1375,14 @@ var CLI_ALTERNATIVES = {
1310
1375
  slack: "Consider using 'slack' CLI or curl for API calls"
1311
1376
  };
1312
1377
  function analyzeMcp() {
1313
- const servers = [];
1314
- const configPaths = [
1315
- join5(process.cwd(), ".mcp.json"),
1316
- join5(homedir3(), ".claude.json")
1317
- ];
1318
- for (const configPath of configPaths) {
1319
- if (!existsSync4(configPath)) continue;
1320
- try {
1321
- const raw = JSON.parse(readFileSync4(configPath, "utf-8"));
1322
- const mcpServers = raw.mcpServers ?? raw.mcp_servers ?? {};
1323
- for (const [name, config] of Object.entries(mcpServers)) {
1324
- const cfg = config;
1325
- const tools = Array.isArray(cfg.tools) ? cfg.tools : [];
1326
- const toolCount = tools.length || 5;
1327
- const estimatedTokens = toolCount * MCP_TOKENS_PER_TOOL;
1328
- servers.push({
1329
- name,
1330
- toolCount,
1331
- estimatedTokens,
1332
- isHeavy: toolCount > 10
1333
- });
1334
- }
1335
- } catch {
1336
- continue;
1337
- }
1338
- }
1378
+ const servers = analyzeMcpServers();
1339
1379
  const totalTools = servers.reduce((sum, s) => sum + s.toolCount, 0);
1340
1380
  const totalTokens = servers.reduce((sum, s) => sum + s.estimatedTokens, 0);
1341
1381
  const heavyServers = servers.filter((s) => s.isHeavy);
1342
1382
  let hasToolSearch = false;
1343
1383
  const settingsPaths = [
1344
1384
  join5(process.cwd(), ".claude", "settings.json"),
1345
- join5(homedir3(), ".claude", "settings.json")
1385
+ join5(homedir4(), ".claude", "settings.json")
1346
1386
  ];
1347
1387
  for (const sp of settingsPaths) {
1348
1388
  if (!existsSync4(sp)) continue;
@@ -1558,6 +1598,44 @@ function registerAuditCommand(program2) {
1558
1598
  // src/cli/commands/report.ts
1559
1599
  import chalk4 from "chalk";
1560
1600
  import dayjs4 from "dayjs";
1601
+
1602
+ // src/core/cacheAnalyzer.ts
1603
+ function analyzeCacheUsage(messages) {
1604
+ let totalCacheReads = 0;
1605
+ let totalCacheCreations = 0;
1606
+ let totalInputTokens = 0;
1607
+ const perMessage = messages.map((msg) => {
1608
+ const cacheRead = msg.usage.cache_read_input_tokens;
1609
+ const cacheCreation = msg.usage.cache_creation_input_tokens;
1610
+ const input = msg.usage.input_tokens;
1611
+ totalCacheReads += cacheRead;
1612
+ totalCacheCreations += cacheCreation;
1613
+ totalInputTokens += input;
1614
+ const totalCacheable2 = cacheRead + cacheCreation + input;
1615
+ const hitRate = totalCacheable2 > 0 ? cacheRead / totalCacheable2 * 100 : 0;
1616
+ return {
1617
+ id: msg.id,
1618
+ cacheRead,
1619
+ cacheCreation,
1620
+ input,
1621
+ hitRate
1622
+ };
1623
+ });
1624
+ const totalCacheable = totalCacheReads + totalCacheCreations + totalInputTokens;
1625
+ const cacheHitRate = totalCacheable > 0 ? totalCacheReads / totalCacheable * 100 : 0;
1626
+ const savingsMultiplier = 0.9;
1627
+ const estimatedSavings = totalCacheReads * savingsMultiplier;
1628
+ return {
1629
+ totalCacheReads,
1630
+ totalCacheCreations,
1631
+ totalInputTokens,
1632
+ cacheHitRate,
1633
+ estimatedSavings,
1634
+ perMessageBreakdown: perMessage
1635
+ };
1636
+ }
1637
+
1638
+ // src/cli/commands/report.ts
1561
1639
  function registerReportCommand(program2) {
1562
1640
  program2.command("report").description("Historical cost reports").option("--period <period>", "Time period (today|week|month|all)", "today").option("-p, --project <path>", "Filter to specific project").option("--model", "Show per-model breakdown").option("--sessions", "Show per-session breakdown").option("--csv", "Export as CSV").option("--json", "Export as JSON").action(async (opts) => {
1563
1641
  const files = await findJsonlFiles(opts.project);
@@ -1614,15 +1692,13 @@ function registerReportCommand(program2) {
1614
1692
  let totalCost = 0;
1615
1693
  let totalInput = 0;
1616
1694
  let totalOutput = 0;
1617
- let totalCacheRead = 0;
1618
1695
  for (const msg of allMessages) {
1619
1696
  totalCost += calculateMessageCost(msg).totalCost;
1620
1697
  totalInput += msg.usage.input_tokens;
1621
1698
  totalOutput += msg.usage.output_tokens;
1622
- totalCacheRead += msg.usage.cache_read_input_tokens;
1623
1699
  }
1624
- const totalCacheable = totalInput + totalCacheRead;
1625
- const cacheHitRate = totalCacheable > 0 ? totalCacheRead / totalCacheable * 100 : 0;
1700
+ const cacheAnalysis = analyzeCacheUsage(allMessages);
1701
+ const cacheHitRate = cacheAnalysis.cacheHitRate;
1626
1702
  if (opts.json) {
1627
1703
  console.log(
1628
1704
  JSON.stringify(
@@ -1697,16 +1773,107 @@ function registerReportCommand(program2) {
1697
1773
 
1698
1774
  // src/cli/commands/init.ts
1699
1775
  import chalk5 from "chalk";
1700
- import { mkdirSync as mkdirSync2, existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync, copyFileSync } from "node:fs";
1776
+ import { mkdirSync as mkdirSync3, existsSync as existsSync6 } from "node:fs";
1777
+ import { join as join7 } from "node:path";
1778
+ import { homedir as homedir6 } from "node:os";
1779
+
1780
+ // src/hooks/installer.ts
1781
+ import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync, copyFileSync, mkdirSync as mkdirSync2 } from "node:fs";
1701
1782
  import { join as join6, dirname as dirname2 } from "node:path";
1702
- import { homedir as homedir4 } from "node:os";
1783
+ import { homedir as homedir5 } from "node:os";
1784
+ var NOTIFICATION_HOOK = `#!/bin/bash
1785
+ # kerf-cli notification hook
1786
+ KERF_LOG="\${HOME}/.kerf/session-log.jsonl"
1787
+ mkdir -p "$(dirname "$KERF_LOG")"
1788
+ INPUT=$(cat)
1789
+ TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
1790
+ SESSION_ID=$(echo "$INPUT" | grep -o '"session_id"[[:space:]]*:[[:space:]]*"[^"]*"' | head -1 | sed 's/.*: *"//;s/"//')
1791
+ echo "{\\"timestamp\\":\\"$TIMESTAMP\\",\\"session_id\\":\\"$SESSION_ID\\",\\"event\\":\\"notification\\",\\"raw\\":$INPUT}" >> "$KERF_LOG"
1792
+ `;
1793
+ var STOP_HOOK = `#!/bin/bash
1794
+ # kerf-cli stop hook \u2014 budget enforcement
1795
+ KERF_BIN=$(which kerf-cli 2>/dev/null || echo "npx kerf-cli@latest")
1796
+ BUDGET_CHECK=$($KERF_BIN budget show --json 2>/dev/null)
1797
+ if [ $? -ne 0 ] || [ -z "$BUDGET_CHECK" ]; then
1798
+ exit 0
1799
+ fi
1800
+ PERCENT_USED=$(echo "$BUDGET_CHECK" | grep -o '"percentUsed"[[:space:]]*:[[:space:]]*[0-9.]*' | head -1 | sed 's/.*: *//')
1801
+ IS_OVER=$(echo "$BUDGET_CHECK" | grep -o '"isOverBudget"[[:space:]]*:[[:space:]]*\\(true\\|false\\)' | head -1 | sed 's/.*: *//')
1802
+ if [ "$IS_OVER" = "true" ]; then
1803
+ echo '{"reason":"Budget exceeded. Run kerf-cli budget show for details."}'
1804
+ exit 0
1805
+ fi
1806
+ if [ -n "$PERCENT_USED" ]; then
1807
+ THRESHOLD=80
1808
+ OVER=$(echo "$PERCENT_USED > $THRESHOLD" | bc -l 2>/dev/null || echo "0")
1809
+ if [ "$OVER" = "1" ]; then
1810
+ echo "{\\"reason\\":\\"Budget warning: $PERCENT_USED% used. Run kerf-cli budget show for details.\\"}"
1811
+ fi
1812
+ fi
1813
+ exit 0
1814
+ `;
1815
+ function installHooks(options = {}) {
1816
+ const settingsPath = options.global ? join6(homedir5(), ".claude", "settings.json") : join6(process.cwd(), ".claude", "settings.json");
1817
+ const dir = dirname2(settingsPath);
1818
+ if (!existsSync5(dir)) {
1819
+ mkdirSync2(dir, { recursive: true });
1820
+ }
1821
+ let settings = {};
1822
+ if (existsSync5(settingsPath)) {
1823
+ const backupPath = settingsPath + ".kerf-backup";
1824
+ copyFileSync(settingsPath, backupPath);
1825
+ settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
1826
+ }
1827
+ if (!settings.hooks) {
1828
+ settings.hooks = {};
1829
+ }
1830
+ const installed = [];
1831
+ const skipped = [];
1832
+ const hooksDir = join6(homedir5(), ".kerf", "hooks");
1833
+ if (!existsSync5(hooksDir)) {
1834
+ mkdirSync2(hooksDir, { recursive: true });
1835
+ }
1836
+ const notificationPath = join6(hooksDir, "notification.sh");
1837
+ const stopPath = join6(hooksDir, "stop.sh");
1838
+ writeFileSync(notificationPath, NOTIFICATION_HOOK, { mode: 493 });
1839
+ writeFileSync(stopPath, STOP_HOOK, { mode: 493 });
1840
+ if (!hasKerfHook(settings.hooks, "Notification")) {
1841
+ addHook(settings.hooks, "Notification", notificationPath);
1842
+ installed.push("Notification");
1843
+ } else {
1844
+ skipped.push("Notification (already installed)");
1845
+ }
1846
+ if (!hasKerfHook(settings.hooks, "Stop")) {
1847
+ addHook(settings.hooks, "Stop", stopPath);
1848
+ installed.push("Stop");
1849
+ } else {
1850
+ skipped.push("Stop (already installed)");
1851
+ }
1852
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
1853
+ return { installed, skipped, settingsPath };
1854
+ }
1855
+ function hasKerfHook(hooks, event) {
1856
+ const eventHooks = hooks[event] ?? [];
1857
+ return eventHooks.some((h) => h.hooks.some((hh) => hh.command.includes("kerf")));
1858
+ }
1859
+ function addHook(hooks, event, scriptPath) {
1860
+ if (!hooks[event]) {
1861
+ hooks[event] = [];
1862
+ }
1863
+ hooks[event].push({
1864
+ matcher: "",
1865
+ hooks: [{ type: "command", command: `bash ${scriptPath}` }]
1866
+ });
1867
+ }
1868
+
1869
+ // src/cli/commands/init.ts
1703
1870
  function registerInitCommand(program2) {
1704
1871
  program2.command("init").description("Set up kerf-cli for the current project").option("--global", "Install hooks globally").option("--hooks-only", "Only install hooks").option("--no-hooks", "Skip hook installation").option("--force", "Skip confirmation prompts").action(async (opts) => {
1705
1872
  console.log(chalk5.bold.cyan("\n Welcome to kerf-cli!\n"));
1706
1873
  console.log(" Setting up cost intelligence for Claude Code...\n");
1707
- const kerfDir = join6(homedir4(), ".kerf");
1708
- if (!existsSync5(kerfDir)) {
1709
- mkdirSync2(kerfDir, { recursive: true });
1874
+ const kerfDir = join7(homedir6(), ".kerf");
1875
+ if (!existsSync6(kerfDir)) {
1876
+ mkdirSync3(kerfDir, { recursive: true });
1710
1877
  console.log(chalk5.green(" Created ~/.kerf/"));
1711
1878
  }
1712
1879
  if (!opts.hooksOnly) {
@@ -1734,15 +1901,19 @@ function registerInitCommand(program2) {
1734
1901
  } catch {
1735
1902
  }
1736
1903
  if (opts.hooks !== false) {
1737
- const settingsPath = opts.global ? join6(homedir4(), ".claude", "settings.json") : join6(process.cwd(), ".claude", "settings.json");
1738
1904
  console.log("\n Install hooks? These enable:");
1739
1905
  console.log(" - Real-time token tracking (Notification hook)");
1740
1906
  console.log(" - Budget enforcement (Stop hook)");
1741
1907
  console.log(`
1742
1908
  Hooks will be added to ${opts.global ? "~/.claude" : ".claude"}/settings.json`);
1743
1909
  try {
1744
- installHooks(settingsPath);
1745
- console.log(chalk5.green("\n Hooks installed"));
1910
+ const result = installHooks({ global: opts.global, force: opts.force });
1911
+ for (const hook of result.installed) {
1912
+ console.log(chalk5.green(` Installed ${hook} hook`));
1913
+ }
1914
+ for (const hook of result.skipped) {
1915
+ console.log(chalk5.dim(` Skipped ${hook}`));
1916
+ }
1746
1917
  } catch (err) {
1747
1918
  console.log(chalk5.yellow(`
1748
1919
  Skipped hook installation: ${err}`));
@@ -1759,31 +1930,10 @@ function registerInitCommand(program2) {
1759
1930
  console.log(chalk5.bold.cyan("\n Run 'kerf-cli watch' to start the live dashboard!\n"));
1760
1931
  });
1761
1932
  }
1762
- function installHooks(settingsPath) {
1763
- const dir = dirname2(settingsPath);
1764
- if (!existsSync5(dir)) {
1765
- mkdirSync2(dir, { recursive: true });
1766
- }
1767
- let settings = {};
1768
- if (existsSync5(settingsPath)) {
1769
- const backupPath = settingsPath + ".bak";
1770
- copyFileSync(settingsPath, backupPath);
1771
- settings = JSON.parse(readFileSync5(settingsPath, "utf-8"));
1772
- }
1773
- const hooks = settings.hooks ?? {};
1774
- if (!hooks.Notification) {
1775
- hooks.Notification = [];
1776
- }
1777
- if (!hooks.Stop) {
1778
- hooks.Stop = [];
1779
- }
1780
- settings.hooks = hooks;
1781
- writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
1782
- }
1783
1933
 
1784
1934
  // src/cli/index.ts
1785
1935
  var program = new Command();
1786
- program.name("kerf-cli").version("0.2.0").description("Cost intelligence for Claude Code. Know before you spend.");
1936
+ program.name("kerf-cli").version("0.2.1").description("Cost intelligence for Claude Code. Know before you spend.");
1787
1937
  registerWatchCommand(program);
1788
1938
  registerEstimateCommand(program);
1789
1939
  registerBudgetCommand(program);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli/index.ts","../src/cli/commands/watch.ts","../src/core/parser.ts","../src/core/config.ts","../src/cli/ui/Dashboard.tsx","../src/cli/ui/CostMeter.tsx","../src/core/costCalculator.ts","../src/cli/ui/ContextBar.tsx","../src/core/tokenCounter.ts","../src/cli/commands/estimate.ts","../src/core/estimator.ts","../src/cli/ui/EstimateCard.tsx","../src/cli/commands/budget.ts","../src/core/budgetManager.ts","../src/db/schema.ts","../src/db/migrations.ts","../src/cli/commands/audit.ts","../src/audit/ghostTokens.ts","../src/audit/claudeMdLinter.ts","../src/audit/mcpAnalyzer.ts","../src/audit/recommendations.ts","../src/cli/commands/report.ts","../src/cli/commands/init.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { registerWatchCommand } from \"./commands/watch.js\";\nimport { registerEstimateCommand } from \"./commands/estimate.js\";\nimport { registerBudgetCommand } from \"./commands/budget.js\";\nimport { registerAuditCommand } from \"./commands/audit.js\";\nimport { registerReportCommand } from \"./commands/report.js\";\nimport { registerInitCommand } from \"./commands/init.js\";\n\ndeclare const __KERF_VERSION__: string;\n\nconst program = new Command();\n\nprogram\n .name(\"kerf-cli\")\n .version(__KERF_VERSION__)\n .description(\"Cost intelligence for Claude Code. Know before you spend.\");\n\n// Register all subcommands\nregisterWatchCommand(program);\nregisterEstimateCommand(program);\nregisterBudgetCommand(program);\nregisterAuditCommand(program);\nregisterReportCommand(program);\nregisterInitCommand(program);\n\n// Default to watch if no command given\nprogram.action(async () => {\n await program.commands.find((c) => c.name() === \"watch\")?.parseAsync([], { from: \"user\" });\n});\n\nprogram.parse();\n","import React from \"react\";\nimport { render } from \"ink\";\nimport { Command } from \"commander\";\nimport { getActiveSessions } from \"../../core/parser.js\";\nimport { Dashboard } from \"../ui/Dashboard.js\";\n\nexport function registerWatchCommand(program: Command): void {\n program\n .command(\"watch\")\n .description(\"Real-time cost dashboard (default)\")\n .option(\"-s, --session <id>\", \"Watch a specific session\")\n .option(\"-p, --project <path>\", \"Watch sessions for a specific project\")\n .option(\"-i, --interval <ms>\", \"Polling interval in ms\", \"2000\")\n .option(\"--no-color\", \"Disable colors\")\n .action(async (opts) => {\n const interval = parseInt(opts.interval, 10);\n\n let sessionFilePath: string | undefined;\n\n if (opts.session) {\n const sessions = await getActiveSessions(opts.project);\n const found = sessions.find((s) => s.sessionId.startsWith(opts.session));\n sessionFilePath = found?.filePath;\n } else {\n const sessions = await getActiveSessions(opts.project);\n sessionFilePath = sessions[0]?.filePath;\n }\n\n if (!sessionFilePath) {\n console.log(\n \"No active Claude Code session found. Start Claude Code and run 'kerf-cli watch' again.\",\n );\n process.exit(0);\n }\n\n if (!process.stdin.isTTY) {\n console.log(\n \"kerf-cli watch requires an interactive terminal (TTY). Run it directly in a terminal tab, not piped.\",\n );\n process.exit(1);\n }\n\n const { waitUntilExit } = render(\n React.createElement(Dashboard, { sessionFilePath, interval }),\n );\n await waitUntilExit();\n });\n}\n","import { readFileSync, statSync } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join, basename } from \"node:path\";\nimport { createReadStream } from \"node:fs\";\nimport { createInterface } from \"node:readline\";\nimport dayjs from \"dayjs\";\nimport { watch } from \"chokidar\";\nimport { CLAUDE_PROJECTS_DIR, BILLING_WINDOW_HOURS } from \"./config.js\";\nimport type {\n RawJsonlMessage,\n ParsedMessage,\n SessionData,\n ParsedSession,\n MessageUsage,\n} from \"../types/jsonl.js\";\n\nconst DEFAULT_USAGE: MessageUsage = {\n input_tokens: 0,\n output_tokens: 0,\n cache_creation_input_tokens: 0,\n cache_read_input_tokens: 0,\n};\n\nfunction extractUsage(raw: RawJsonlMessage): Partial<MessageUsage> | null {\n return raw.message?.usage ?? raw.usage ?? raw.delta?.usage ?? null;\n}\n\nfunction extractMessageId(raw: RawJsonlMessage): string | null {\n return raw.message?.id ?? null;\n}\n\nfunction extractModel(raw: RawJsonlMessage): string | null {\n return raw.message?.model ?? null;\n}\n\nfunction extractTimestamp(raw: RawJsonlMessage): string {\n return raw.timestamp ?? dayjs().toISOString();\n}\n\nexport function parseJsonlLine(line: string): RawJsonlMessage | null {\n const trimmed = line.trim();\n if (!trimmed) return null;\n try {\n return JSON.parse(trimmed) as RawJsonlMessage;\n } catch {\n return null;\n }\n}\n\nexport function parseJsonlContent(content: string, sessionId: string): ParsedMessage[] {\n const lines = content.split(\"\\n\");\n const messageMap = new Map<string, ParsedMessage>();\n let anonymousCounter = 0;\n\n for (const line of lines) {\n const raw = parseJsonlLine(line);\n if (!raw) continue;\n\n const usage = extractUsage(raw);\n if (!usage) continue;\n\n const id = extractMessageId(raw) ?? `anon_${anonymousCounter++}`;\n const model = extractModel(raw) ?? \"unknown\";\n const timestamp = extractTimestamp(raw);\n\n const existing = messageMap.get(id);\n const parsedUsage: MessageUsage = {\n input_tokens: usage.input_tokens ?? existing?.usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? existing?.usage.output_tokens ?? 0,\n cache_creation_input_tokens:\n usage.cache_creation_input_tokens ?? existing?.usage.cache_creation_input_tokens ?? 0,\n cache_read_input_tokens:\n usage.cache_read_input_tokens ?? existing?.usage.cache_read_input_tokens ?? 0,\n };\n\n // Deduplicate by message id — take the LAST occurrence (handles streaming intermediates)\n messageMap.set(id, {\n id,\n model: model !== \"unknown\" ? model : existing?.model ?? \"unknown\",\n timestamp,\n usage: parsedUsage,\n totalCostUsd: raw.total_cost_usd ?? existing?.totalCostUsd ?? null,\n });\n }\n\n return Array.from(messageMap.values());\n}\n\nexport function parseSessionFile(filePath: string): ParsedSession {\n const content = readFileSync(filePath, \"utf-8\");\n const sessionId = basename(filePath, \".jsonl\");\n const messages = parseJsonlContent(content, sessionId);\n\n const totals = messages.reduce(\n (acc, msg) => ({\n input: acc.input + msg.usage.input_tokens,\n output: acc.output + msg.usage.output_tokens,\n cacheRead: acc.cacheRead + msg.usage.cache_read_input_tokens,\n cacheCreation: acc.cacheCreation + msg.usage.cache_creation_input_tokens,\n cost: acc.cost + (msg.totalCostUsd ?? 0),\n }),\n { input: 0, output: 0, cacheRead: 0, cacheCreation: 0, cost: 0 },\n );\n\n const timestamps = messages.map((m) => m.timestamp).sort();\n\n return {\n sessionId,\n filePath,\n messages,\n totalInputTokens: totals.input,\n totalOutputTokens: totals.output,\n totalCacheReadTokens: totals.cacheRead,\n totalCacheCreationTokens: totals.cacheCreation,\n totalCostUsd: totals.cost,\n startTime: timestamps[0] ?? \"\",\n endTime: timestamps[timestamps.length - 1] ?? \"\",\n messageCount: messages.length,\n };\n}\n\nexport async function findJsonlFiles(baseDir?: string): Promise<string[]> {\n const dir = baseDir ?? CLAUDE_PROJECTS_DIR;\n const files: string[] = [];\n\n async function walk(currentDir: string): Promise<void> {\n let entries;\n try {\n entries = await readdir(currentDir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const fullPath = join(currentDir, entry.name);\n if (entry.isDirectory()) {\n await walk(fullPath);\n } else if (entry.name.endsWith(\".jsonl\")) {\n files.push(fullPath);\n }\n }\n }\n\n await walk(dir);\n return files;\n}\n\nexport async function getActiveSessions(baseDir?: string): Promise<SessionData[]> {\n const files = await findJsonlFiles(baseDir);\n const cutoff = dayjs().subtract(BILLING_WINDOW_HOURS, \"hour\");\n const activeSessions: SessionData[] = [];\n\n for (const filePath of files) {\n try {\n const stat = statSync(filePath);\n const lastModified = dayjs(stat.mtime);\n if (lastModified.isAfter(cutoff)) {\n const content = readFileSync(filePath, \"utf-8\");\n const sessionId = basename(filePath, \".jsonl\");\n const messages = parseJsonlContent(content, sessionId);\n\n if (messages.length === 0) continue;\n\n const timestamps = messages.map((m) => m.timestamp).sort();\n activeSessions.push({\n sessionId,\n filePath,\n messages,\n startTime: timestamps[0] ?? \"\",\n endTime: timestamps[timestamps.length - 1] ?? \"\",\n lastModified: stat.mtime,\n });\n }\n } catch {\n continue;\n }\n }\n\n return activeSessions.sort(\n (a, b) => b.lastModified.getTime() - a.lastModified.getTime(),\n );\n}\n\nexport interface StreamingParser {\n onMessage: (callback: (msg: ParsedMessage) => void) => void;\n stop: () => void;\n}\n\nexport function createStreamingParser(filePath: string): StreamingParser {\n const callbacks: Array<(msg: ParsedMessage) => void> = [];\n const sessionId = basename(filePath, \".jsonl\");\n let anonymousCounter = 0;\n\n const watcher = watch(filePath, { persistent: true });\n\n watcher.on(\"change\", () => {\n const content = readFileSync(filePath, \"utf-8\");\n const lines = content.split(\"\\n\");\n // Process only the last few lines for incremental updates\n const recentLines = lines.slice(-20);\n for (const line of recentLines) {\n const raw = parseJsonlLine(line);\n if (!raw) continue;\n const usage = extractUsage(raw);\n if (!usage) continue;\n\n const id = extractMessageId(raw) ?? `anon_${anonymousCounter++}`;\n const model = extractModel(raw) ?? \"unknown\";\n const timestamp = extractTimestamp(raw);\n\n const msg: ParsedMessage = {\n id,\n model,\n timestamp,\n usage: {\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,\n cache_read_input_tokens: usage.cache_read_input_tokens ?? 0,\n },\n totalCostUsd: raw.total_cost_usd ?? null,\n };\n\n for (const cb of callbacks) {\n cb(msg);\n }\n }\n });\n\n return {\n onMessage(callback) {\n callbacks.push(callback);\n },\n stop() {\n watcher.close();\n },\n };\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { KerfConfig } from \"../types/config.js\";\n\nexport const DEFAULT_CONFIG: KerfConfig = {\n defaultModel: \"sonnet\",\n budgetWarningThreshold: 80,\n budgetBlockThreshold: 100,\n pollingInterval: 2000,\n dataDir: join(homedir(), \".kerf\"),\n enableHooks: true,\n};\n\nexport const CONTEXT_WINDOW_SIZE = 200_000;\nexport const SYSTEM_PROMPT_TOKENS = 14_328;\nexport const BUILT_IN_TOOLS_TOKENS = 15_000;\nexport const AUTOCOMPACT_BUFFER_TOKENS = 33_000;\nexport const MCP_TOKENS_PER_TOOL = 600;\nexport const BILLING_WINDOW_HOURS = 5;\n\nexport const CLAUDE_PROJECTS_DIR = join(homedir(), \".claude\", \"projects\");\nexport const CLAUDE_SETTINGS_GLOBAL = join(homedir(), \".claude\", \"settings.json\");\nexport const KERF_DB_PATH = join(homedir(), \".kerf\", \"kerf.db\");\nexport const KERF_SESSION_LOG = join(homedir(), \".kerf\", \"session-log.jsonl\");\n\nexport function getConfig(): KerfConfig {\n return { ...DEFAULT_CONFIG };\n}\n","import React, { useState, useEffect } from \"react\";\nimport { Box, Text, useInput, useApp } from \"ink\";\nimport { CostMeter } from \"./CostMeter.js\";\nimport { ContextBar } from \"./ContextBar.js\";\nimport { parseSessionFile } from \"../../core/parser.js\";\nimport {\n calculateMessageCost,\n calculateCostVelocity,\n formatCost,\n formatTokens,\n} from \"../../core/costCalculator.js\";\nimport { estimateContextOverhead } from \"../../core/tokenCounter.js\";\nimport { CONTEXT_WINDOW_SIZE, BILLING_WINDOW_HOURS } from \"../../core/config.js\";\nimport type { ParsedSession } from \"../../types/jsonl.js\";\nimport type { ContextOverhead } from \"../../types/config.js\";\n\ninterface DashboardProps {\n sessionFilePath: string;\n interval: number;\n}\n\nexport function Dashboard({ sessionFilePath, interval }: DashboardProps) {\n const { exit } = useApp();\n const [session, setSession] = useState<ParsedSession | null>(null);\n const [overhead, setOverhead] = useState<ContextOverhead>(estimateContextOverhead());\n const [showBudget, setShowBudget] = useState(false);\n\n useEffect(() => {\n function refresh() {\n try {\n const parsed = parseSessionFile(sessionFilePath);\n setSession(parsed);\n setOverhead(estimateContextOverhead());\n } catch {\n // File may be in the middle of a write\n }\n }\n\n refresh();\n const timer = setInterval(refresh, interval);\n return () => clearInterval(timer);\n }, [sessionFilePath, interval]);\n\n useInput(\n (input) => {\n if (input === \"q\") exit();\n if (input === \"b\") setShowBudget((prev) => !prev);\n },\n { isActive: process.stdin.isTTY ?? false },\n );\n\n if (!session || session.messages.length === 0) {\n return (\n <Box paddingX={1}>\n <Text dimColor>Waiting for session data...</Text>\n </Box>\n );\n }\n\n const totalCost = session.messages.reduce(\n (sum, msg) => sum + calculateMessageCost(msg).totalCost,\n 0,\n );\n const velocity = calculateCostVelocity(session.messages);\n const model = session.messages[session.messages.length - 1]?.model ?? \"unknown\";\n const windowBudget = velocity.projectedWindowCost || totalCost * 3;\n\n const totalInput = session.totalInputTokens + session.totalCacheReadTokens;\n const usedTokens = totalInput + session.totalOutputTokens;\n\n // Recent messages for the log\n const recentMessages = session.messages.slice(-8);\n\n return (\n <Box flexDirection=\"column\">\n <Box borderStyle=\"round\" borderColor=\"cyan\" paddingX={1}>\n <Text bold color=\"cyan\">\n kerf-cli watch\n </Text>\n <Text> | session: {session.sessionId.slice(0, 8)}...</Text>\n <Text> | {session.messageCount} messages</Text>\n <Text dimColor> (q=quit, b=budget)</Text>\n </Box>\n\n <CostMeter\n spent={totalCost}\n windowBudget={windowBudget}\n burnRate={velocity.dollarsPerMinute}\n minutesRemaining={velocity.minutesRemaining}\n model={model}\n />\n\n <ContextBar used={usedTokens} total={CONTEXT_WINDOW_SIZE} overhead={overhead} />\n\n <Box flexDirection=\"column\" paddingX={1} marginTop={1}>\n <Text bold>Recent Messages:</Text>\n {recentMessages.map((msg, i) => {\n const cost = calculateMessageCost(msg);\n return (\n <Text key={i}>\n <Text dimColor>{msg.timestamp.slice(11, 19)}</Text>\n <Text> {formatTokens(msg.usage.input_tokens + msg.usage.output_tokens)} tok</Text>\n <Text color=\"yellow\"> {formatCost(cost.totalCost)}</Text>\n </Text>\n );\n })}\n </Box>\n </Box>\n );\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { formatCost } from \"../../core/costCalculator.js\";\n\ninterface CostMeterProps {\n spent: number;\n windowBudget: number;\n burnRate: number;\n minutesRemaining: number;\n model: string;\n}\n\nexport function CostMeter({ spent, windowBudget, burnRate, minutesRemaining, model }: CostMeterProps) {\n const pct = windowBudget > 0 ? (spent / windowBudget) * 100 : 0;\n const color = pct < 50 ? \"green\" : pct < 80 ? \"yellow\" : \"red\";\n\n const hours = Math.floor(minutesRemaining / 60);\n const mins = Math.round(minutesRemaining % 60);\n const timeStr = hours > 0 ? `${hours}h ${mins}m` : `${mins}m`;\n\n return (\n <Box flexDirection=\"column\" paddingX={1}>\n <Text>\n <Text color={color}>{\">> \"}</Text>\n <Text bold>{formatCost(spent)}</Text>\n <Text dimColor> / ~{formatCost(windowBudget)} window</Text>\n <Text> | </Text>\n <Text color={color}>{formatCost(burnRate)}/min</Text>\n <Text> | </Text>\n <Text>~{timeStr} remaining</Text>\n <Text dimColor> [{model}]</Text>\n </Text>\n </Box>\n );\n}\n","import dayjs from \"dayjs\";\nimport isoWeek from \"dayjs/plugin/isoWeek.js\";\nimport { BILLING_WINDOW_HOURS } from \"./config.js\";\nimport type { ParsedMessage, ParsedSession } from \"../types/jsonl.js\";\nimport type {\n ModelPricing,\n PricingConfig,\n CostBreakdown,\n SessionCostSummary,\n CostVelocity,\n AggregationPeriod,\n AggregatedCost,\n} from \"../types/pricing.js\";\n\ndayjs.extend(isoWeek);\n\nexport const MODEL_PRICING: PricingConfig = {\n \"claude-sonnet-4-20250514\": {\n input: 3,\n output: 15,\n cacheRead: 0.3,\n cacheCreation: 3.75,\n },\n \"claude-opus-4-20250514\": {\n input: 15,\n output: 75,\n cacheRead: 1.5,\n cacheCreation: 18.75,\n },\n \"claude-haiku-4-20250514\": {\n input: 0.8,\n output: 4,\n cacheRead: 0.08,\n cacheCreation: 1.0,\n },\n};\n\n// Alias mappings for short model names\nconst MODEL_ALIASES: Record<string, string> = {\n sonnet: \"claude-sonnet-4-20250514\",\n opus: \"claude-opus-4-20250514\",\n haiku: \"claude-haiku-4-20250514\",\n};\n\nexport function resolveModelPricing(model: string): ModelPricing {\n const resolved = MODEL_ALIASES[model] ?? model;\n // Try exact match first, then prefix match\n if (MODEL_PRICING[resolved]) return MODEL_PRICING[resolved];\n const match = Object.keys(MODEL_PRICING).find((k) => resolved.startsWith(k) || k.startsWith(resolved));\n if (match) return MODEL_PRICING[match];\n // Default to sonnet pricing\n return MODEL_PRICING[\"claude-sonnet-4-20250514\"];\n}\n\nexport function calculateMessageCost(msg: ParsedMessage): CostBreakdown {\n // If authoritative cost is present, use it\n if (msg.totalCostUsd !== null && msg.totalCostUsd > 0) {\n return {\n inputCost: 0,\n outputCost: 0,\n cacheReadCost: 0,\n cacheCreationCost: 0,\n totalCost: msg.totalCostUsd,\n };\n }\n\n const pricing = resolveModelPricing(msg.model);\n const MILLION = 1_000_000;\n\n // Use multiply-then-divide to avoid floating point issues\n const inputCost = (msg.usage.input_tokens * pricing.input) / MILLION;\n const outputCost = (msg.usage.output_tokens * pricing.output) / MILLION;\n const cacheReadCost = (msg.usage.cache_read_input_tokens * pricing.cacheRead) / MILLION;\n const cacheCreationCost = (msg.usage.cache_creation_input_tokens * pricing.cacheCreation) / MILLION;\n\n return {\n inputCost,\n outputCost,\n cacheReadCost,\n cacheCreationCost,\n totalCost: inputCost + outputCost + cacheReadCost + cacheCreationCost,\n };\n}\n\nexport function calculateSessionCost(session: ParsedSession): SessionCostSummary {\n let totalCost = 0;\n const costBreakdown: CostBreakdown = {\n inputCost: 0,\n outputCost: 0,\n cacheReadCost: 0,\n cacheCreationCost: 0,\n totalCost: 0,\n };\n\n for (const msg of session.messages) {\n const msgCost = calculateMessageCost(msg);\n costBreakdown.inputCost += msgCost.inputCost;\n costBreakdown.outputCost += msgCost.outputCost;\n costBreakdown.cacheReadCost += msgCost.cacheReadCost;\n costBreakdown.cacheCreationCost += msgCost.cacheCreationCost;\n totalCost += msgCost.totalCost;\n }\n\n costBreakdown.totalCost = totalCost;\n\n return {\n sessionId: session.sessionId,\n totalCost,\n tokenBreakdown: {\n input: session.totalInputTokens,\n output: session.totalOutputTokens,\n cacheRead: session.totalCacheReadTokens,\n cacheCreation: session.totalCacheCreationTokens,\n },\n costBreakdown,\n model: session.messages[0]?.model ?? \"unknown\",\n messageCount: session.messageCount,\n startTime: session.startTime,\n endTime: session.endTime,\n };\n}\n\nexport function calculateCostVelocity(messages: ParsedMessage[]): CostVelocity {\n if (messages.length < 2) {\n return { dollarsPerMinute: 0, tokensPerMinute: 0, projectedWindowCost: 0, minutesRemaining: 0 };\n }\n\n // Use last 10 messages for velocity calculation\n const recent = messages.slice(-10);\n const firstTime = dayjs(recent[0].timestamp);\n const lastTime = dayjs(recent[recent.length - 1].timestamp);\n const durationMinutes = lastTime.diff(firstTime, \"minute\", true);\n\n if (durationMinutes <= 0) {\n return { dollarsPerMinute: 0, tokensPerMinute: 0, projectedWindowCost: 0, minutesRemaining: 0 };\n }\n\n let totalCost = 0;\n let totalTokens = 0;\n for (const msg of recent) {\n totalCost += calculateMessageCost(msg).totalCost;\n totalTokens += msg.usage.input_tokens + msg.usage.output_tokens;\n }\n\n const dollarsPerMinute = totalCost / durationMinutes;\n const tokensPerMinute = totalTokens / durationMinutes;\n const windowMinutes = BILLING_WINDOW_HOURS * 60;\n const projectedWindowCost = dollarsPerMinute * windowMinutes;\n\n // Time remaining in current billing window\n const windowStart = dayjs().subtract(BILLING_WINDOW_HOURS, \"hour\");\n const elapsed = dayjs().diff(windowStart, \"minute\", true);\n const minutesRemaining = Math.max(0, windowMinutes - elapsed);\n\n return { dollarsPerMinute, tokensPerMinute, projectedWindowCost, minutesRemaining };\n}\n\nexport function aggregateCosts(\n messages: ParsedMessage[],\n period: AggregationPeriod,\n): AggregatedCost[] {\n const groups = new Map<string, { messages: ParsedMessage[]; sessions: Set<string> }>();\n\n for (const msg of messages) {\n const key = getPeriodKey(msg.timestamp, period);\n const group = groups.get(key) ?? { messages: [], sessions: new Set() };\n group.messages.push(msg);\n group.sessions.add(msg.id.split(\"_\")[0] ?? msg.id);\n groups.set(key, group);\n }\n\n return Array.from(groups.entries()).map(([key, group]) => {\n let totalCost = 0;\n let totalInput = 0;\n let totalOutput = 0;\n\n for (const msg of group.messages) {\n totalCost += calculateMessageCost(msg).totalCost;\n totalInput += msg.usage.input_tokens;\n totalOutput += msg.usage.output_tokens;\n }\n\n return {\n period: key,\n periodLabel: formatPeriodLabel(key, period),\n totalCost,\n totalInputTokens: totalInput,\n totalOutputTokens: totalOutput,\n messageCount: group.messages.length,\n sessionCount: group.sessions.size,\n };\n });\n}\n\nfunction getPeriodKey(timestamp: string, period: AggregationPeriod): string {\n const d = dayjs(timestamp);\n switch (period) {\n case \"hour\":\n return d.format(\"YYYY-MM-DD-HH\");\n case \"day\":\n return d.format(\"YYYY-MM-DD\");\n case \"billing_window\":\n // 5-hour windows starting from midnight\n const hour = d.hour();\n const windowStart = Math.floor(hour / BILLING_WINDOW_HOURS) * BILLING_WINDOW_HOURS;\n return `${d.format(\"YYYY-MM-DD\")}-W${windowStart}`;\n case \"week\":\n return `${d.isoWeekYear()}-W${String(d.isoWeek()).padStart(2, \"0\")}`;\n case \"month\":\n return d.format(\"YYYY-MM\");\n case \"session\":\n default:\n return timestamp;\n }\n}\n\nfunction formatPeriodLabel(key: string, period: AggregationPeriod): string {\n switch (period) {\n case \"hour\": {\n // key is \"YYYY-MM-DD-HH\", convert to parseable format\n const parts = key.split(\"-\");\n const dateStr = `${parts[0]}-${parts[1]}-${parts[2]}T${parts[3]}:00:00`;\n return dayjs(dateStr).format(\"MMM D, h A\");\n }\n case \"day\":\n return dayjs(key).format(\"ddd, MMM D\");\n case \"week\":\n return `Week ${key.split(\"-W\")[1]}`;\n case \"month\":\n return dayjs(key).format(\"MMMM YYYY\");\n default:\n return key;\n }\n}\n\nexport function formatCost(cost: number): string {\n return `$${cost.toFixed(2)}`;\n}\n\nexport function formatTokens(tokens: number): string {\n if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}M`;\n if (tokens >= 1_000) return `${(tokens / 1_000).toFixed(1)}K`;\n return String(tokens);\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { ContextOverhead } from \"../../types/config.js\";\n\ninterface ContextBarProps {\n used: number;\n total: number;\n overhead: ContextOverhead;\n}\n\nexport function ContextBar({ used, total, overhead }: ContextBarProps) {\n const barWidth = 30;\n const usedPct = total > 0 ? (used / total) * 100 : 0;\n const clampedPct = Math.max(0, Math.min(usedPct, 100));\n const filledCount = Math.round((clampedPct / 100) * barWidth);\n const emptyCount = barWidth - filledCount;\n\n const color = usedPct < 50 ? \"green\" : usedPct < 80 ? \"yellow\" : \"red\";\n\n const filled = \"\\u2588\".repeat(filledCount);\n const empty = \"\\u2591\".repeat(emptyCount);\n\n const formatK = (n: number) => `${Math.round(n / 1000)}K`;\n\n return (\n <Box flexDirection=\"column\" paddingX={1}>\n <Text>\n <Text>[</Text>\n <Text color={color}>{filled}</Text>\n <Text dimColor>{empty}</Text>\n <Text>]</Text>\n <Text> {usedPct.toFixed(0)}%</Text>\n <Text> | {formatK(used)} / {formatK(total)} tokens</Text>\n </Text>\n <Text dimColor>\n {\" \"}system({formatK(overhead.systemPrompt)}) + tools({formatK(overhead.builtInTools)}) + mcp(\n {formatK(overhead.mcpTools)}) + claude.md({formatK(overhead.claudeMd)})\n </Text>\n </Box>\n );\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport {\n CONTEXT_WINDOW_SIZE,\n SYSTEM_PROMPT_TOKENS,\n BUILT_IN_TOOLS_TOKENS,\n AUTOCOMPACT_BUFFER_TOKENS,\n MCP_TOKENS_PER_TOOL,\n} from \"./config.js\";\nimport type { ContextOverhead, McpServerInfo } from \"../types/config.js\";\n\nconst SUPPORTED_EXTENSIONS = new Set([\".md\", \".ts\", \".js\", \".json\", \".yaml\", \".yml\", \".py\", \".txt\"]);\n\nfunction findGitRootClaudeMd(): string[] {\n try {\n const gitRoot = execSync(\"git rev-parse --show-toplevel\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n }).trim();\n if (gitRoot && gitRoot !== process.cwd()) {\n return [\n join(gitRoot, \"CLAUDE.md\"),\n join(gitRoot, \".claude\", \"CLAUDE.md\"),\n ];\n }\n } catch {\n // Not in a git repo\n }\n return [];\n}\n\n/**\n * Fast local heuristic: tokens ~= characters / 3.5\n */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 3.5);\n}\n\n/**\n * Count tokens in a file using the heuristic\n */\nexport function countFileTokens(filePath: string): number {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n return estimateTokens(content);\n } catch {\n return 0;\n }\n}\n\nexport interface ClaudeMdSection {\n title: string;\n content: string;\n tokens: number;\n lineStart: number;\n lineEnd: number;\n}\n\n/**\n * Parse CLAUDE.md into sections by ## headers\n */\nexport function parseClaudeMdSections(content: string): ClaudeMdSection[] {\n const lines = content.split(\"\\n\");\n const sections: ClaudeMdSection[] = [];\n let currentTitle = \"Preamble\";\n let currentContent: string[] = [];\n let currentLineStart = 1;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line.startsWith(\"## \")) {\n // Save previous section\n if (currentContent.length > 0 || currentTitle !== \"Preamble\") {\n const sectionContent = currentContent.join(\"\\n\");\n sections.push({\n title: currentTitle,\n content: sectionContent,\n tokens: estimateTokens(sectionContent),\n lineStart: currentLineStart,\n lineEnd: i,\n });\n }\n currentTitle = line.replace(/^##\\s*/, \"\");\n currentContent = [];\n currentLineStart = i + 1;\n } else {\n currentContent.push(line);\n }\n }\n\n // Save last section\n if (currentContent.length > 0) {\n const sectionContent = currentContent.join(\"\\n\");\n sections.push({\n title: currentTitle,\n content: sectionContent,\n tokens: estimateTokens(sectionContent),\n lineStart: currentLineStart,\n lineEnd: lines.length,\n });\n }\n\n return sections;\n}\n\n/**\n * Analyze CLAUDE.md token overhead\n */\nexport function analyzeClaudeMd(filePath?: string): { totalTokens: number; sections: ClaudeMdSection[]; heavySections: ClaudeMdSection[] } {\n const paths = filePath\n ? [filePath]\n : [\n join(process.cwd(), \"CLAUDE.md\"),\n join(process.cwd(), \".claude\", \"CLAUDE.md\"),\n ...findGitRootClaudeMd(),\n join(homedir(), \".claude\", \"CLAUDE.md\"),\n ];\n\n for (const p of paths) {\n if (existsSync(p)) {\n const content = readFileSync(p, \"utf-8\");\n const sections = parseClaudeMdSections(content);\n const totalTokens = sections.reduce((sum, s) => sum + s.tokens, 0);\n const heavySections = sections.filter((s) => s.tokens > 500);\n return { totalTokens, sections, heavySections };\n }\n }\n\n return { totalTokens: 0, sections: [], heavySections: [] };\n}\n\n/**\n * Parse MCP server configurations and estimate token cost\n */\nexport function analyzeMcpServers(): McpServerInfo[] {\n const servers: McpServerInfo[] = [];\n const paths = [\n join(process.cwd(), \".mcp.json\"),\n join(homedir(), \".claude.json\"),\n ];\n\n for (const configPath of paths) {\n if (!existsSync(configPath)) continue;\n try {\n const raw = JSON.parse(readFileSync(configPath, \"utf-8\"));\n const mcpServers = raw.mcpServers ?? raw.mcp_servers ?? {};\n for (const [name, config] of Object.entries(mcpServers)) {\n const cfg = config as Record<string, unknown>;\n // Estimate tools: if tools array is present, use its length; otherwise default to 5\n const tools = Array.isArray(cfg.tools) ? cfg.tools : [];\n const toolCount = tools.length || 5;\n const estimatedTokens = toolCount * MCP_TOKENS_PER_TOOL;\n servers.push({\n name,\n toolCount,\n estimatedTokens,\n isHeavy: toolCount > 10,\n });\n }\n } catch {\n continue;\n }\n }\n\n return servers;\n}\n\n/**\n * Estimate total context overhead (ghost tokens)\n */\nexport function estimateContextOverhead(claudeMdPath?: string): ContextOverhead {\n const claudeMd = analyzeClaudeMd(claudeMdPath);\n const mcpServers = analyzeMcpServers();\n const mcpToolTokens = mcpServers.reduce((sum, s) => sum + s.estimatedTokens, 0);\n\n const totalOverhead =\n SYSTEM_PROMPT_TOKENS +\n BUILT_IN_TOOLS_TOKENS +\n mcpToolTokens +\n claudeMd.totalTokens +\n AUTOCOMPACT_BUFFER_TOKENS;\n\n const effectiveWindow = CONTEXT_WINDOW_SIZE - totalOverhead;\n const percentUsable = (effectiveWindow / CONTEXT_WINDOW_SIZE) * 100;\n\n return {\n systemPrompt: SYSTEM_PROMPT_TOKENS,\n builtInTools: BUILT_IN_TOOLS_TOKENS,\n claudeMd: claudeMd.totalTokens,\n mcpTools: mcpToolTokens,\n autocompactBuffer: AUTOCOMPACT_BUFFER_TOKENS,\n totalOverhead,\n effectiveWindow,\n percentUsable,\n };\n}\n","import React from \"react\";\nimport { render } from \"ink\";\nimport { Command } from \"commander\";\nimport { glob } from \"glob\";\nimport chalk from \"chalk\";\nimport { estimateTaskCost } from \"../../core/estimator.js\";\nimport { EstimateCard } from \"../ui/EstimateCard.js\";\n\nexport function registerEstimateCommand(program: Command): void {\n program\n .command(\"estimate <task>\")\n .description(\"Pre-flight cost estimation\")\n .option(\"-m, --model <model>\", \"Model to estimate for\", \"sonnet\")\n .option(\"-f, --files <glob>\", \"Specific files that will be touched\")\n .option(\"--compare\", \"Show Sonnet vs Opus vs Haiku comparison\")\n .option(\"--json\", \"Output as JSON\")\n .action(async (task: string, opts) => {\n const files: string[] = [];\n if (opts.files) {\n const matched = await glob(opts.files, { absolute: true });\n files.push(...matched);\n }\n\n if (opts.compare) {\n const models = [\"sonnet\", \"opus\", \"haiku\"] as const;\n\n if (opts.json) {\n for (const model of models) {\n const estimate = await estimateTaskCost(task, { model, files, cwd: process.cwd() });\n console.log(JSON.stringify(estimate, null, 2));\n }\n return;\n }\n\n // Print comparison table\n const estimates = await Promise.all(\n models.map(async (model) => ({\n model,\n estimate: await estimateTaskCost(task, { model, files, cwd: process.cwd() }),\n })),\n );\n\n console.log(chalk.bold.cyan(`\\n kerf-cli estimate: '${task}'\\n`));\n console.log(\n ` ${\"Model\".padEnd(10)} ${\"Turns\".padEnd(14)} ${\"Low\".padEnd(12)} ${\"Expected\".padEnd(12)} ${\"High\".padEnd(12)}`,\n );\n console.log(\" \" + \"-\".repeat(58));\n for (const { model, estimate } of estimates) {\n const turns = `${estimate.estimatedTurns.low}-${estimate.estimatedTurns.high}`;\n console.log(\n ` ${model.padEnd(10)} ${turns.padEnd(14)} ${chalk.green(estimate.estimatedCost.low.padEnd(12))} ${chalk.yellow(estimate.estimatedCost.expected.padEnd(12))} ${chalk.red(estimate.estimatedCost.high.padEnd(12))}`,\n );\n }\n console.log();\n\n const cheapest = estimates[2]; // haiku\n const priciest = estimates[1]; // opus\n console.log(\n chalk.dim(` Cheapest: ${cheapest.model} at ${cheapest.estimate.estimatedCost.expected}`),\n );\n console.log(\n chalk.dim(` Priciest: ${priciest.model} at ${priciest.estimate.estimatedCost.expected}`),\n );\n console.log();\n return;\n }\n\n const estimate = await estimateTaskCost(task, {\n model: opts.model,\n files,\n cwd: process.cwd(),\n });\n\n if (opts.json) {\n console.log(JSON.stringify(estimate, null, 2));\n return;\n }\n\n const { waitUntilExit } = render(\n React.createElement(EstimateCard, { task, estimate }),\n );\n await waitUntilExit();\n });\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { glob } from \"glob\";\nimport { estimateTokens, countFileTokens, estimateContextOverhead } from \"./tokenCounter.js\";\nimport { resolveModelPricing, formatCost } from \"./costCalculator.js\";\nimport { BILLING_WINDOW_HOURS } from \"./config.js\";\nimport type { CostEstimate, EstimateOptions } from \"../types/config.js\";\n\ntype TaskComplexity = \"simple\" | \"medium\" | \"complex\";\n\ninterface ComplexityProfile {\n turns: { low: number; expected: number; high: number };\n outputTokensPerTurn: number;\n}\n\nconst COMPLEXITY_PROFILES: Record<TaskComplexity, ComplexityProfile> = {\n simple: { turns: { low: 2, expected: 3, high: 5 }, outputTokensPerTurn: 1000 },\n medium: { turns: { low: 5, expected: 10, high: 15 }, outputTokensPerTurn: 2000 },\n complex: { turns: { low: 15, expected: 25, high: 40 }, outputTokensPerTurn: 2500 },\n};\n\nconst SIMPLE_KEYWORDS = [\"typo\", \"rename\", \"fix typo\", \"update version\", \"change name\", \"remove unused\", \"delete\"];\nconst COMPLEX_KEYWORDS = [\"refactor\", \"rewrite\", \"new module\", \"implement\", \"build\", \"create\", \"migrate\", \"redesign\", \"overhaul\", \"architecture\"];\n\nfunction detectComplexity(taskDescription: string): TaskComplexity {\n const lower = taskDescription.toLowerCase();\n if (SIMPLE_KEYWORDS.some((k) => lower.includes(k))) return \"simple\";\n if (COMPLEX_KEYWORDS.some((k) => lower.includes(k))) return \"complex\";\n return \"medium\";\n}\n\nexport async function estimateTaskCost(\n taskDescription: string,\n options: Partial<EstimateOptions> = {},\n): Promise<CostEstimate> {\n const model = options.model ?? \"sonnet\";\n const cwd = options.cwd ?? process.cwd();\n const pricing = resolveModelPricing(model);\n const MILLION = 1_000_000;\n\n // Calculate context overhead\n const overhead = estimateContextOverhead();\n\n // Count file tokens\n let fileTokens = 0;\n let fileList = options.files ?? [];\n\n if (fileList.length === 0) {\n // Try to auto-detect from git status\n try {\n const { execSync } = await import(\"node:child_process\");\n const output = execSync(\"git diff --name-only HEAD 2>/dev/null || git ls-files -m 2>/dev/null\", {\n cwd,\n encoding: \"utf-8\",\n });\n fileList = output\n .split(\"\\n\")\n .filter(Boolean)\n .map((f) => `${cwd}/${f}`);\n } catch {\n // No git, no files\n }\n }\n\n for (const filePattern of fileList) {\n const matched = await glob(filePattern, { cwd, absolute: true });\n for (const f of matched) {\n fileTokens += countFileTokens(f);\n }\n }\n\n // Detect complexity and get profile\n const complexity = detectComplexity(taskDescription);\n const profile = COMPLEXITY_PROFILES[complexity];\n\n // Calculate per-turn costs\n const contextPerTurn = overhead.totalOverhead + fileTokens;\n const CACHE_HIT_RATE = 0.9;\n\n function estimateCostForTurns(turns: number): number {\n let totalCost = 0;\n for (let turn = 1; turn <= turns; turn++) {\n const conversationGrowth = (turn - 1) * profile.outputTokensPerTurn;\n const inputTokens = contextPerTurn + conversationGrowth;\n\n let effectiveInputCost: number;\n if (turn <= 2) {\n // First turns: no cache\n effectiveInputCost = (inputTokens * pricing.input) / MILLION;\n } else {\n // After turn 2: 90% cache hit\n const cachedTokens = inputTokens * CACHE_HIT_RATE;\n const uncachedTokens = inputTokens * (1 - CACHE_HIT_RATE);\n effectiveInputCost =\n (cachedTokens * pricing.cacheRead) / MILLION +\n (uncachedTokens * pricing.input) / MILLION;\n }\n\n const outputCost = (profile.outputTokensPerTurn * pricing.output) / MILLION;\n totalCost += effectiveInputCost + outputCost;\n }\n return totalCost;\n }\n\n const lowCost = estimateCostForTurns(profile.turns.low);\n const expectedCost = estimateCostForTurns(profile.turns.expected);\n const highCost = estimateCostForTurns(profile.turns.high);\n\n // Estimate total tokens for expected case\n const expectedInputTokens = contextPerTurn * profile.turns.expected;\n const expectedOutputTokens = profile.outputTokensPerTurn * profile.turns.expected;\n const expectedCachedTokens = expectedInputTokens * CACHE_HIT_RATE;\n\n // Window usage\n const windowMinutes = BILLING_WINDOW_HOURS * 60;\n const percentOfWindow = (expectedCost / (expectedCost * 3)) * 100; // rough estimate\n\n // Recommendations\n const recommendations: string[] = [];\n if (model !== \"sonnet\") {\n const sonnetPricing = resolveModelPricing(\"sonnet\");\n const sonnetCost = estimateCostForTurns(profile.turns.expected);\n // Recalculate with sonnet pricing isn't straightforward here,\n // so we do a ratio estimate\n const ratio = pricing.output / resolveModelPricing(\"sonnet\").output;\n if (ratio > 2) {\n recommendations.push(\n `Consider Sonnet to save ~${formatCost(expectedCost - expectedCost / ratio)} (${ratio.toFixed(0)}x cheaper)`,\n );\n }\n }\n\n if (model === \"sonnet\") {\n const opusPricing = resolveModelPricing(\"opus\");\n const ratio = opusPricing.output / pricing.output;\n recommendations.push(`Using Opus would cost ~${formatCost(expectedCost * ratio)} (${ratio.toFixed(0)}x more)`);\n }\n\n if (overhead.percentUsable < 60) {\n recommendations.push(`High ghost token overhead (${(100 - overhead.percentUsable).toFixed(0)}%). Run 'kerf-cli audit' to optimize.`);\n }\n\n if (fileTokens > 50000) {\n recommendations.push(`Large file context (${(fileTokens / 1000).toFixed(0)}K tokens). Consider narrowing scope.`);\n }\n\n return {\n model,\n estimatedTurns: profile.turns,\n estimatedTokens: {\n input: Math.round(expectedInputTokens),\n output: Math.round(expectedOutputTokens),\n cached: Math.round(expectedCachedTokens),\n },\n estimatedCost: {\n low: formatCost(lowCost),\n expected: formatCost(expectedCost),\n high: formatCost(highCost),\n },\n contextOverhead: overhead.totalOverhead,\n fileTokens,\n percentOfWindow: Math.round(percentOfWindow),\n recommendations,\n };\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { CostEstimate } from \"../../types/config.js\";\n\ninterface EstimateCardProps {\n task: string;\n estimate: CostEstimate;\n}\n\nexport function EstimateCard({ task, estimate }: EstimateCardProps) {\n const formatK = (n: number) => `${(n / 1000).toFixed(1)}K`;\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"cyan\" paddingX={2} paddingY={1}>\n <Text bold color=\"cyan\">\n kerf-cli estimate: '{task}'\n </Text>\n <Text> </Text>\n <Text>\n Model: <Text bold>{estimate.model}</Text>\n </Text>\n <Text>\n Estimated turns: {estimate.estimatedTurns.low}-{estimate.estimatedTurns.high} (expected:{\" \"}\n {estimate.estimatedTurns.expected})\n </Text>\n <Text>\n Files: {formatK(estimate.fileTokens)} tokens\n </Text>\n <Text>\n Context overhead: {formatK(estimate.contextOverhead)} tokens (ghost tokens)\n </Text>\n <Text> </Text>\n <Text bold>Estimated Cost:</Text>\n <Text>\n {\" \"}Low: <Text color=\"green\">{estimate.estimatedCost.low}</Text>\n </Text>\n <Text>\n {\" \"}Expected: <Text color=\"yellow\">{estimate.estimatedCost.expected}</Text>\n </Text>\n <Text>\n {\" \"}High: <Text color=\"red\">{estimate.estimatedCost.high}</Text>\n </Text>\n <Text> </Text>\n <Text>Window Usage: ~{estimate.percentOfWindow}% of 5-hour window</Text>\n {estimate.recommendations.map((rec, i) => (\n <Text key={i} color=\"cyan\">\n {\" -> \"}{rec}\n </Text>\n ))}\n </Box>\n );\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { BudgetManager } from \"../../core/budgetManager.js\";\nimport { formatCost } from \"../../core/costCalculator.js\";\n\nexport function registerBudgetCommand(program: Command): void {\n const budget = program.command(\"budget\").description(\"Per-project budget management\");\n\n budget\n .command(\"set <amount>\")\n .description(\"Set budget for current project\")\n .option(\"-p, --period <period>\", \"Budget period (daily|weekly|monthly)\", \"weekly\")\n .option(\"--project <path>\", \"Project path\")\n .action((amount: string, opts) => {\n const manager = new BudgetManager();\n const projectPath = opts.project || process.cwd();\n const amountNum = parseFloat(amount);\n\n if (isNaN(amountNum) || amountNum <= 0) {\n console.log(chalk.red(\"Budget amount must be a positive number.\"));\n process.exit(1);\n }\n\n manager.setBudget(projectPath, amountNum, opts.period);\n console.log(\n chalk.green(`Budget set: ${formatCost(amountNum)}/${opts.period} for ${projectPath}`),\n );\n manager.close();\n });\n\n budget\n .command(\"show\")\n .description(\"Show current project budget\")\n .option(\"--project <path>\", \"Project path\")\n .option(\"--json\", \"Output as JSON\")\n .action((opts) => {\n const manager = new BudgetManager();\n const projectPath = opts.project || process.cwd();\n const status = manager.checkBudget(projectPath);\n\n if (!status) {\n console.log(\"No budget set for this project. Use 'kerf-cli budget set <amount>' to set one.\");\n manager.close();\n return;\n }\n\n if (opts.json) {\n console.log(JSON.stringify(status, null, 2));\n manager.close();\n return;\n }\n\n const pct = status.percentUsed;\n const barWidth = 20;\n const filled = Math.round((Math.min(pct, 100) / 100) * barWidth);\n const empty = barWidth - filled;\n const color = pct < 50 ? \"green\" : pct < 80 ? \"yellow\" : \"red\";\n const barColor = color === \"green\" ? chalk.green : color === \"yellow\" ? chalk.yellow : chalk.red;\n\n console.log(chalk.bold.cyan(\"\\n kerf-cli budget\\n\"));\n console.log(` Period: ${status.period} (${status.periodStart.slice(0, 10)} to ${status.periodEnd.slice(0, 10)})`);\n console.log(` Budget: ${formatCost(status.budget)}`);\n console.log(` Spent: ${barColor(formatCost(status.spent))}`);\n console.log(` ${barColor(\"[\" + \"\\u2588\".repeat(filled) + \"\\u2591\".repeat(empty) + \"]\")} ${pct.toFixed(1)}%`);\n\n if (status.isOverBudget) {\n console.log(chalk.red.bold(`\\n OVER BUDGET by ${formatCost(status.spent - status.budget)}`));\n }\n console.log();\n\n manager.close();\n });\n\n budget\n .command(\"list\")\n .description(\"List all project budgets\")\n .action(() => {\n const manager = new BudgetManager();\n const projects = manager.listProjects();\n\n if (projects.length === 0) {\n console.log(\"No projects with budgets. Use 'kerf-cli budget set <amount>' to set one.\");\n manager.close();\n return;\n }\n\n console.log(chalk.bold.cyan(\"\\n kerf-cli budget list\\n\"));\n for (const p of projects) {\n const budgetStr = p.budget ? `${formatCost(p.budget)}/${p.period}` : \"no budget\";\n const spentStr = p.spent > 0 ? ` (spent: ${formatCost(p.spent)})` : \"\";\n console.log(` ${chalk.bold(p.name)} — ${budgetStr}${spentStr}`);\n console.log(chalk.dim(` ${p.path}`));\n }\n console.log();\n\n manager.close();\n });\n\n budget\n .command(\"remove\")\n .description(\"Remove budget for current project\")\n .option(\"--project <path>\", \"Project path\")\n .action((opts) => {\n const manager = new BudgetManager();\n const projectPath = opts.project || process.cwd();\n const removed = manager.removeBudget(projectPath);\n\n if (removed) {\n console.log(chalk.green(\"Budget removed.\"));\n } else {\n console.log(\"No budget found for this project.\");\n }\n\n manager.close();\n });\n}\n","import dayjs from \"dayjs\";\nimport isoWeek from \"dayjs/plugin/isoWeek.js\";\nimport { basename } from \"node:path\";\nimport { initDatabase } from \"../db/schema.js\";\nimport { runMigrations } from \"../db/migrations.js\";\nimport type { BudgetStatus } from \"../types/config.js\";\nimport type Database from \"better-sqlite3\";\n\ndayjs.extend(isoWeek);\n\ntype BudgetPeriod = \"daily\" | \"weekly\" | \"monthly\";\n\nexport class BudgetManager {\n private db: Database.Database;\n\n constructor(dbPath?: string) {\n this.db = initDatabase(dbPath);\n runMigrations(this.db);\n }\n\n private getOrCreateProject(projectPath: string): number {\n const name = basename(projectPath) || projectPath;\n const existing = this.db\n .prepare(\"SELECT id FROM projects WHERE path = ?\")\n .get(projectPath) as { id: number } | undefined;\n\n if (existing) return existing.id;\n\n const result = this.db\n .prepare(\"INSERT INTO projects (name, path) VALUES (?, ?)\")\n .run(name, projectPath);\n\n return Number(result.lastInsertRowid);\n }\n\n setBudget(projectPath: string, amount: number, period: BudgetPeriod): void {\n const projectId = this.getOrCreateProject(projectPath);\n this.db\n .prepare(\n `INSERT INTO budgets (project_id, amount_usd, period)\n VALUES (?, ?, ?)\n ON CONFLICT(project_id, period)\n DO UPDATE SET amount_usd = excluded.amount_usd`,\n )\n .run(projectId, amount, period);\n }\n\n getBudget(projectPath: string): { amount: number; period: BudgetPeriod } | null {\n const project = this.db\n .prepare(\"SELECT id FROM projects WHERE path = ?\")\n .get(projectPath) as { id: number } | undefined;\n\n if (!project) return null;\n\n const budget = this.db\n .prepare(\"SELECT amount_usd, period FROM budgets WHERE project_id = ? ORDER BY created_at DESC LIMIT 1\")\n .get(project.id) as { amount_usd: number; period: BudgetPeriod } | undefined;\n\n if (!budget) return null;\n return { amount: budget.amount_usd, period: budget.period };\n }\n\n recordUsage(\n projectPath: string,\n sessionId: string,\n tokensIn: number,\n tokensOut: number,\n costUsd: number,\n timestamp: string,\n ): void {\n const projectId = this.getOrCreateProject(projectPath);\n this.db\n .prepare(\n `INSERT OR IGNORE INTO usage_snapshots (project_id, session_id, tokens_in, tokens_out, cost_usd, timestamp)\n VALUES (?, ?, ?, ?, ?, ?)`,\n )\n .run(projectId, sessionId, tokensIn, tokensOut, costUsd, timestamp);\n }\n\n getUsage(projectPath: string, period: BudgetPeriod): number {\n const project = this.db\n .prepare(\"SELECT id FROM projects WHERE path = ?\")\n .get(projectPath) as { id: number } | undefined;\n\n if (!project) return 0;\n\n const start = getPeriodStart(period);\n const result = this.db\n .prepare(\n `SELECT COALESCE(SUM(cost_usd), 0) as total\n FROM usage_snapshots\n WHERE project_id = ? AND timestamp >= ?`,\n )\n .get(project.id, start.toISOString()) as { total: number };\n\n return result.total;\n }\n\n checkBudget(projectPath: string): BudgetStatus | null {\n const budgetConfig = this.getBudget(projectPath);\n if (!budgetConfig) return null;\n\n const spent = this.getUsage(projectPath, budgetConfig.period);\n const remaining = Math.max(0, budgetConfig.amount - spent);\n const percentUsed = budgetConfig.amount > 0 ? (spent / budgetConfig.amount) * 100 : 0;\n\n const periodStart = getPeriodStart(budgetConfig.period);\n const periodEnd = getPeriodEnd(budgetConfig.period);\n\n return {\n budget: budgetConfig.amount,\n spent,\n remaining,\n percentUsed,\n isOverBudget: spent > budgetConfig.amount,\n period: budgetConfig.period,\n periodStart: periodStart.toISOString(),\n periodEnd: periodEnd.toISOString(),\n };\n }\n\n listProjects(): Array<{ name: string; path: string; budget: number | null; period: string | null; spent: number }> {\n const rows = this.db\n .prepare(\n `SELECT p.name, p.path, b.amount_usd, b.period\n FROM projects p\n LEFT JOIN budgets b ON b.project_id = p.id\n ORDER BY p.name`,\n )\n .all() as Array<{ name: string; path: string; amount_usd: number | null; period: string | null }>;\n\n return rows.map((row) => ({\n name: row.name,\n path: row.path,\n budget: row.amount_usd,\n period: row.period,\n spent: row.period ? this.getUsage(row.path, row.period as BudgetPeriod) : 0,\n }));\n }\n\n removeBudget(projectPath: string): boolean {\n const project = this.db\n .prepare(\"SELECT id FROM projects WHERE path = ?\")\n .get(projectPath) as { id: number } | undefined;\n\n if (!project) return false;\n\n const result = this.db.prepare(\"DELETE FROM budgets WHERE project_id = ?\").run(project.id);\n return result.changes > 0;\n }\n\n close(): void {\n this.db.close();\n }\n}\n\nfunction getPeriodStart(period: BudgetPeriod): dayjs.Dayjs {\n switch (period) {\n case \"daily\":\n return dayjs().startOf(\"day\");\n case \"weekly\":\n return dayjs().startOf(\"isoWeek\" as dayjs.OpUnitType);\n case \"monthly\":\n return dayjs().startOf(\"month\");\n }\n}\n\nfunction getPeriodEnd(period: BudgetPeriod): dayjs.Dayjs {\n switch (period) {\n case \"daily\":\n return dayjs().endOf(\"day\");\n case \"weekly\":\n return dayjs().endOf(\"isoWeek\" as dayjs.OpUnitType);\n case \"monthly\":\n return dayjs().endOf(\"month\");\n }\n}\n","import Database from \"better-sqlite3\";\nimport { mkdirSync, existsSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { KERF_DB_PATH } from \"../core/config.js\";\n\nexport function initDatabase(dbPath?: string): Database.Database {\n const path = dbPath ?? KERF_DB_PATH;\n const dir = dirname(path);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n const db = new Database(path);\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"foreign_keys = ON\");\n\n createTables(db);\n return db;\n}\n\nfunction createTables(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS projects (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL,\n path TEXT NOT NULL UNIQUE,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS budgets (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n amount_usd REAL NOT NULL,\n period TEXT NOT NULL CHECK (period IN ('daily', 'weekly', 'monthly')),\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n UNIQUE(project_id, period)\n );\n\n CREATE TABLE IF NOT EXISTS usage_snapshots (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n session_id TEXT NOT NULL,\n tokens_in INTEGER NOT NULL DEFAULT 0,\n tokens_out INTEGER NOT NULL DEFAULT 0,\n cost_usd REAL NOT NULL DEFAULT 0,\n timestamp TEXT NOT NULL,\n UNIQUE(project_id, session_id, timestamp)\n );\n\n CREATE INDEX IF NOT EXISTS idx_usage_project_time\n ON usage_snapshots(project_id, timestamp);\n `);\n}\n","import type Database from \"better-sqlite3\";\n\ninterface Migration {\n version: number;\n description: string;\n up: (db: Database.Database) => void;\n}\n\nconst migrations: Migration[] = [\n {\n version: 1,\n description: \"Initial schema\",\n up(_db) {\n // Schema is created in schema.ts on init — this is a placeholder for future migrations\n },\n },\n];\n\nexport function runMigrations(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS schema_migrations (\n version INTEGER PRIMARY KEY,\n applied_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `);\n\n const applied = new Set(\n db\n .prepare(\"SELECT version FROM schema_migrations\")\n .all()\n .map((row: any) => row.version as number),\n );\n\n for (const migration of migrations) {\n if (!applied.has(migration.version)) {\n migration.up(db);\n db.prepare(\"INSERT INTO schema_migrations (version) VALUES (?)\").run(migration.version);\n }\n }\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { runFullAudit } from \"../../audit/recommendations.js\";\nimport { CONTEXT_WINDOW_SIZE } from \"../../core/config.js\";\n\nexport function registerAuditCommand(program: Command): void {\n program\n .command(\"audit\")\n .description(\"Ghost token & CLAUDE.md audit\")\n .option(\"--fix\", \"Auto-apply safe fixes\")\n .option(\"--claude-md-only\", \"Only audit CLAUDE.md\")\n .option(\"--mcp-only\", \"Only audit MCP servers\")\n .option(\"--json\", \"Output as JSON\")\n .action((opts) => {\n const result = runFullAudit();\n\n if (opts.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n const gradeColor =\n result.grade === \"A\" ? chalk.green :\n result.grade === \"B\" ? chalk.yellow :\n chalk.red;\n\n console.log(chalk.bold.cyan(\"\\n kerf-cli audit report\\n\"));\n console.log(\n ` Context Window Health: ${gradeColor.bold(result.grade)} (${result.contextOverhead.percentUsable.toFixed(0)}% usable)\\n`,\n );\n\n // Ghost token breakdown — show unless --claude-md-only\n if (!opts.claudeMdOnly) {\n console.log(chalk.bold(\" Ghost Token Breakdown:\"));\n const oh = result.contextOverhead;\n const fmt = (label: string, tokens: number) => {\n const pct = ((tokens / CONTEXT_WINDOW_SIZE) * 100).toFixed(1);\n return ` ${label.padEnd(22)} ${tokens.toLocaleString().padStart(6)} tokens (${pct}%)`;\n };\n console.log(fmt(\"System prompt:\", oh.systemPrompt));\n console.log(fmt(\"Built-in tools:\", oh.builtInTools));\n console.log(fmt(`MCP tools (${result.mcpServers.length} srv):`, oh.mcpTools));\n console.log(fmt(\"CLAUDE.md:\", oh.claudeMd));\n console.log(fmt(\"Autocompact buffer:\", oh.autocompactBuffer));\n console.log(\" \" + \"-\".repeat(40));\n console.log(fmt(\"Total overhead:\", oh.totalOverhead));\n console.log(\n ` ${\"Effective window:\".padEnd(22)} ${oh.effectiveWindow.toLocaleString().padStart(6)} tokens (${oh.percentUsable.toFixed(1)}%)\\n`,\n );\n }\n\n // CLAUDE.md analysis — show unless --mcp-only\n if (!opts.mcpOnly && result.claudeMdAnalysis) {\n const cma = result.claudeMdAnalysis;\n console.log(chalk.bold(\" CLAUDE.md Analysis:\"));\n console.log(\n ` Lines: ${cma.totalLines}${cma.isOverLineLimit ? chalk.yellow(\" (over 200 limit)\") : \"\"}`,\n );\n console.log(` Tokens: ${cma.totalTokens.toLocaleString()}`);\n console.log(\n ` Critical rules in dead zone: ${cma.criticalRulesInDeadZone > 0 ? chalk.red(String(cma.criticalRulesInDeadZone)) : \"0\"}`,\n );\n\n if (opts.claudeMdOnly) {\n // Show per-section breakdown when claude-md-only\n console.log();\n console.log(chalk.bold(\" Sections:\"));\n for (const section of cma.sections) {\n const zone = section.attentionZone === \"low-middle\" ? chalk.red(\" [dead zone]\") : chalk.green(\" [high attention]\");\n const critical = section.hasCriticalRules ? chalk.yellow(\" *critical rules*\") : \"\";\n console.log(\n ` ${section.title.padEnd(30)} ${String(section.tokens).padStart(5)} tokens L${section.lineStart}-${section.lineEnd}${zone}${critical}`,\n );\n }\n\n if (cma.suggestedReorder.length > 0) {\n console.log();\n console.log(chalk.bold(\" Suggested section order:\"));\n cma.suggestedReorder.forEach((title, i) => {\n console.log(` ${i + 1}. ${title}`);\n });\n }\n }\n console.log();\n } else if (!opts.mcpOnly && !result.claudeMdAnalysis) {\n console.log(chalk.yellow(\" No CLAUDE.md found in current directory or git root.\\n\"));\n }\n\n // MCP details — show when --mcp-only\n if (opts.mcpOnly && result.mcpServers.length > 0) {\n console.log(chalk.bold(\" MCP Servers:\"));\n for (const server of result.mcpServers) {\n const heavy = server.isHeavy ? chalk.red(\" [heavy]\") : \"\";\n console.log(\n ` ${server.name.padEnd(20)} ${String(server.toolCount).padStart(3)} tools ${server.estimatedTokens.toLocaleString().padStart(6)} tokens${heavy}`,\n );\n }\n console.log();\n } else if (opts.mcpOnly && result.mcpServers.length === 0) {\n console.log(chalk.dim(\" No MCP servers configured.\\n\"));\n }\n\n // Recommendations — always show\n if (result.recommendations.length > 0) {\n const filteredRecs = opts.claudeMdOnly\n ? result.recommendations.filter((r) => r.category === \"claude-md\")\n : opts.mcpOnly\n ? result.recommendations.filter((r) => r.category === \"mcp\")\n : result.recommendations;\n\n if (filteredRecs.length > 0) {\n console.log(chalk.bold(\" Recommendations:\"));\n filteredRecs.forEach((rec, i) => {\n const priorityColor =\n rec.priority === \"high\" ? chalk.red :\n rec.priority === \"medium\" ? chalk.yellow :\n chalk.dim;\n console.log(\n ` ${i + 1}. ${priorityColor(`[${rec.priority.toUpperCase()}]`)} ${rec.action}`,\n );\n console.log(chalk.dim(` Impact: ${rec.impact}`));\n });\n }\n }\n console.log();\n\n if (opts.fix) {\n console.log(chalk.yellow(\" --fix: Auto-fix is not yet implemented. Coming in v0.2.0.\\n\"));\n }\n });\n}\n","import { estimateContextOverhead, analyzeMcpServers } from \"../core/tokenCounter.js\";\nimport { CONTEXT_WINDOW_SIZE } from \"../core/config.js\";\nimport type { ContextOverhead, McpServerInfo } from \"../types/config.js\";\n\nexport type ContextGrade = \"A\" | \"B\" | \"C\" | \"D\";\n\nexport interface GhostTokenReport {\n grade: ContextGrade;\n overhead: ContextOverhead;\n mcpServers: McpServerInfo[];\n percentUsable: number;\n breakdown: Array<{ label: string; tokens: number; percent: number }>;\n}\n\nexport function calculateGrade(percentUsable: number): ContextGrade {\n if (percentUsable >= 70) return \"A\";\n if (percentUsable >= 50) return \"B\";\n if (percentUsable >= 30) return \"C\";\n return \"D\";\n}\n\nexport function analyzeGhostTokens(claudeMdPath?: string): GhostTokenReport {\n const overhead = estimateContextOverhead(claudeMdPath);\n const mcpServers = analyzeMcpServers();\n const grade = calculateGrade(overhead.percentUsable);\n\n const breakdown = [\n { label: \"System prompt\", tokens: overhead.systemPrompt, percent: (overhead.systemPrompt / CONTEXT_WINDOW_SIZE) * 100 },\n { label: \"Built-in tools\", tokens: overhead.builtInTools, percent: (overhead.builtInTools / CONTEXT_WINDOW_SIZE) * 100 },\n { label: `MCP tools (${mcpServers.length} srv)`, tokens: overhead.mcpTools, percent: (overhead.mcpTools / CONTEXT_WINDOW_SIZE) * 100 },\n { label: \"CLAUDE.md\", tokens: overhead.claudeMd, percent: (overhead.claudeMd / CONTEXT_WINDOW_SIZE) * 100 },\n { label: \"Autocompact buffer\", tokens: overhead.autocompactBuffer, percent: (overhead.autocompactBuffer / CONTEXT_WINDOW_SIZE) * 100 },\n ];\n\n return {\n grade,\n overhead,\n mcpServers,\n percentUsable: overhead.percentUsable,\n breakdown,\n };\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { estimateTokens, parseClaudeMdSections } from \"../core/tokenCounter.js\";\nimport type { ClaudeMdAnalysis, ClaudeMdSection } from \"../types/config.js\";\n\nconst CRITICAL_RULE_PATTERN = /\\b(NEVER|ALWAYS|MUST|IMPORTANT|CRITICAL)\\b/i;\nconst SKILL_CANDIDATES = /\\b(review|deploy|release|migration|template|boilerplate|scaffold)\\b/i;\nconst LINE_LIMIT = 200;\n\ntype AttentionZone = \"high-start\" | \"low-middle\" | \"high-end\";\n\nfunction getAttentionZone(position: number, total: number): AttentionZone {\n const pct = total > 0 ? position / total : 0;\n if (pct <= 0.3) return \"high-start\";\n if (pct >= 0.7) return \"high-end\";\n return \"low-middle\";\n}\n\nexport function lintClaudeMd(filePath?: string): ClaudeMdAnalysis | null {\n const paths = filePath\n ? [filePath]\n : [\n join(process.cwd(), \"CLAUDE.md\"),\n join(process.cwd(), \".claude\", \"CLAUDE.md\"),\n ];\n\n let resolvedPath: string | null = null;\n for (const p of paths) {\n if (existsSync(p)) {\n resolvedPath = p;\n break;\n }\n }\n\n if (!resolvedPath) return null;\n\n const content = readFileSync(resolvedPath, \"utf-8\");\n const lines = content.split(\"\\n\");\n const totalLines = lines.length;\n const rawSections = parseClaudeMdSections(content);\n const totalTokens = rawSections.reduce((sum, s) => sum + s.tokens, 0);\n\n let criticalRulesInDeadZone = 0;\n const sectionsToSkill: string[] = [];\n\n const sections: ClaudeMdSection[] = rawSections.map((s) => {\n const midpoint = (s.lineStart + s.lineEnd) / 2;\n const attentionZone = getAttentionZone(midpoint, totalLines);\n const hasCriticalRules = CRITICAL_RULE_PATTERN.test(s.content);\n\n if (hasCriticalRules && attentionZone === \"low-middle\") {\n criticalRulesInDeadZone++;\n }\n\n if (SKILL_CANDIDATES.test(s.title) || SKILL_CANDIDATES.test(s.content)) {\n sectionsToSkill.push(s.title);\n }\n\n return {\n title: s.title,\n content: s.content,\n tokens: s.tokens,\n lineStart: s.lineStart,\n lineEnd: s.lineEnd,\n hasCriticalRules,\n attentionZone,\n };\n });\n\n // Generate suggested reordering: critical rules first, then normal, then verbose\n const critical = sections.filter((s) => s.hasCriticalRules);\n const normal = sections.filter((s) => !s.hasCriticalRules && s.tokens <= 500);\n const heavy = sections.filter((s) => !s.hasCriticalRules && s.tokens > 500);\n const suggestedReorder = [...critical, ...normal, ...heavy].map((s) => s.title);\n\n return {\n totalLines,\n totalTokens,\n sections,\n criticalRulesInDeadZone,\n isOverLineLimit: totalLines > LINE_LIMIT,\n suggestedReorder,\n };\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { MCP_TOKENS_PER_TOOL } from \"../core/config.js\";\nimport type { McpServerInfo } from \"../types/config.js\";\n\nexport interface McpAnalysis {\n servers: McpServerInfo[];\n totalTools: number;\n totalTokens: number;\n heavyServers: McpServerInfo[];\n hasToolSearch: boolean;\n effectiveTokens: number;\n recommendations: string[];\n}\n\nconst CLI_ALTERNATIVES: Record<string, string> = {\n playwright: \"Consider using the built-in Bash tool with playwright CLI instead\",\n puppeteer: \"Consider using the built-in Bash tool with puppeteer scripts\",\n filesystem: \"Claude Code has built-in file tools (Read, Write, Edit, Glob, Grep)\",\n github: \"Consider using 'gh' CLI via Bash tool instead\",\n slack: \"Consider using 'slack' CLI or curl for API calls\",\n};\n\nexport function analyzeMcp(): McpAnalysis {\n const servers: McpServerInfo[] = [];\n const configPaths = [\n join(process.cwd(), \".mcp.json\"),\n join(homedir(), \".claude.json\"),\n ];\n\n for (const configPath of configPaths) {\n if (!existsSync(configPath)) continue;\n try {\n const raw = JSON.parse(readFileSync(configPath, \"utf-8\"));\n const mcpServers = raw.mcpServers ?? raw.mcp_servers ?? {};\n for (const [name, config] of Object.entries(mcpServers)) {\n const cfg = config as Record<string, unknown>;\n const tools = Array.isArray(cfg.tools) ? cfg.tools : [];\n const toolCount = tools.length || 5;\n const estimatedTokens = toolCount * MCP_TOKENS_PER_TOOL;\n servers.push({\n name,\n toolCount,\n estimatedTokens,\n isHeavy: toolCount > 10,\n });\n }\n } catch {\n continue;\n }\n }\n\n const totalTools = servers.reduce((sum, s) => sum + s.toolCount, 0);\n const totalTokens = servers.reduce((sum, s) => sum + s.estimatedTokens, 0);\n const heavyServers = servers.filter((s) => s.isHeavy);\n\n // Check if Tool Search is enabled (reduces overhead by ~85%)\n let hasToolSearch = false;\n const settingsPaths = [\n join(process.cwd(), \".claude\", \"settings.json\"),\n join(homedir(), \".claude\", \"settings.json\"),\n ];\n for (const sp of settingsPaths) {\n if (!existsSync(sp)) continue;\n try {\n const settings = JSON.parse(readFileSync(sp, \"utf-8\"));\n if (settings.enableToolSearch || settings.tool_search) {\n hasToolSearch = true;\n break;\n }\n } catch {\n continue;\n }\n }\n\n const effectiveTokens = hasToolSearch ? Math.round(totalTokens * 0.15) : totalTokens;\n\n const recommendations: string[] = [];\n for (const server of heavyServers) {\n recommendations.push(\n `'${server.name}' has ${server.toolCount} tools (${server.estimatedTokens.toLocaleString()} tokens). Consider enabling Tool Search to reduce overhead by ~85%.`,\n );\n }\n\n for (const server of servers) {\n const alt = CLI_ALTERNATIVES[server.name.toLowerCase()];\n if (alt) {\n recommendations.push(`${server.name}: ${alt}`);\n }\n }\n\n return {\n servers,\n totalTools,\n totalTokens,\n heavyServers,\n hasToolSearch,\n effectiveTokens,\n recommendations,\n };\n}\n","import { analyzeGhostTokens } from \"./ghostTokens.js\";\nimport { lintClaudeMd } from \"./claudeMdLinter.js\";\nimport { analyzeMcp } from \"./mcpAnalyzer.js\";\nimport type { AuditRecommendation, AuditResult } from \"../types/config.js\";\n\nexport function runFullAudit(claudeMdPath?: string): AuditResult {\n const ghostReport = analyzeGhostTokens(claudeMdPath);\n const claudeMdAnalysis = lintClaudeMd(claudeMdPath);\n const mcpAnalysis = analyzeMcp();\n\n const recommendations: AuditRecommendation[] = [];\n\n // CLAUDE.md recommendations\n if (claudeMdAnalysis) {\n if (claudeMdAnalysis.criticalRulesInDeadZone > 0) {\n recommendations.push({\n priority: \"high\",\n impact: \"improved rule adherence\",\n action: `Reorder CLAUDE.md — ${claudeMdAnalysis.criticalRulesInDeadZone} critical rule(s) in the low-attention dead zone (30-70% position). Move them to the top or bottom.`,\n category: \"claude-md\",\n });\n }\n\n if (claudeMdAnalysis.isOverLineLimit) {\n recommendations.push({\n priority: \"high\",\n impact: `${claudeMdAnalysis.totalLines - 200} lines over limit`,\n action: `CLAUDE.md is ${claudeMdAnalysis.totalLines} lines (limit: 200). Trim or move sections to skills.`,\n category: \"claude-md\",\n });\n }\n\n const heavySections = claudeMdAnalysis.sections.filter((s) => s.tokens > 500);\n for (const section of heavySections) {\n recommendations.push({\n priority: \"medium\",\n impact: `-${section.tokens} tokens/session`,\n action: `Move '${section.title}' section to a skill (${section.tokens} tokens — heavy section)`,\n category: \"claude-md\",\n });\n }\n }\n\n // MCP recommendations\n for (const server of mcpAnalysis.heavyServers) {\n recommendations.push({\n priority: \"medium\",\n impact: `-${server.estimatedTokens.toLocaleString()} tokens/session`,\n action: `MCP server '${server.name}' has ${server.toolCount} tools. Consider disabling if unused or enabling Tool Search.`,\n category: \"mcp\",\n });\n }\n\n if (!mcpAnalysis.hasToolSearch && mcpAnalysis.totalTools > 10) {\n recommendations.push({\n priority: \"high\",\n impact: `~${Math.round(mcpAnalysis.totalTokens * 0.85).toLocaleString()} tokens saved`,\n action: \"Enable Tool Search (deferred tool loading) to reduce MCP overhead by ~85%.\",\n category: \"mcp\",\n });\n }\n\n for (const rec of mcpAnalysis.recommendations) {\n if (rec.includes(\"CLI\")) {\n recommendations.push({\n priority: \"low\",\n impact: \"reduced token overhead\",\n action: rec,\n category: \"mcp\",\n });\n }\n }\n\n // Ghost token recommendations\n if (ghostReport.percentUsable < 50) {\n recommendations.push({\n priority: \"high\",\n impact: `only ${ghostReport.percentUsable.toFixed(0)}% usable`,\n action: `Context window health is poor (grade ${ghostReport.grade}). Total overhead: ${ghostReport.overhead.totalOverhead.toLocaleString()} tokens.`,\n category: \"ghost-tokens\",\n });\n }\n\n // Sort by priority\n const priorityOrder = { high: 0, medium: 1, low: 2 };\n recommendations.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);\n\n return {\n grade: ghostReport.grade,\n contextOverhead: ghostReport.overhead,\n claudeMdAnalysis,\n mcpServers: ghostReport.mcpServers,\n recommendations,\n };\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport dayjs from \"dayjs\";\nimport { getActiveSessions, parseSessionFile, findJsonlFiles } from \"../../core/parser.js\";\nimport {\n calculateMessageCost,\n aggregateCosts,\n formatCost,\n formatTokens,\n} from \"../../core/costCalculator.js\";\nimport type { ParsedMessage } from \"../../types/jsonl.js\";\n\nexport function registerReportCommand(program: Command): void {\n program\n .command(\"report\")\n .description(\"Historical cost reports\")\n .option(\"--period <period>\", \"Time period (today|week|month|all)\", \"today\")\n .option(\"-p, --project <path>\", \"Filter to specific project\")\n .option(\"--model\", \"Show per-model breakdown\")\n .option(\"--sessions\", \"Show per-session breakdown\")\n .option(\"--csv\", \"Export as CSV\")\n .option(\"--json\", \"Export as JSON\")\n .action(async (opts) => {\n const files = await findJsonlFiles(opts.project);\n\n if (files.length === 0) {\n console.log(\"No session data found. Start using Claude Code to generate data.\");\n return;\n }\n\n // Determine time filter\n const now = dayjs();\n let cutoff: dayjs.Dayjs;\n switch (opts.period) {\n case \"today\":\n cutoff = now.startOf(\"day\");\n break;\n case \"week\":\n cutoff = now.subtract(7, \"day\");\n break;\n case \"month\":\n cutoff = now.subtract(30, \"day\");\n break;\n case \"all\":\n cutoff = dayjs(\"2000-01-01\");\n break;\n default:\n cutoff = now.startOf(\"day\");\n }\n\n // Parse all sessions and collect messages\n const allMessages: ParsedMessage[] = [];\n const sessionSummaries: Array<{ id: string; model: string; cost: number; messages: number }> = [];\n\n for (const file of files) {\n try {\n const session = parseSessionFile(file);\n const filteredMessages = session.messages.filter((m) =>\n dayjs(m.timestamp).isAfter(cutoff),\n );\n if (filteredMessages.length === 0) continue;\n\n allMessages.push(...filteredMessages);\n\n const sessionCost = filteredMessages.reduce(\n (sum, m) => sum + calculateMessageCost(m).totalCost,\n 0,\n );\n sessionSummaries.push({\n id: session.sessionId,\n model: filteredMessages[0]?.model ?? \"unknown\",\n cost: sessionCost,\n messages: filteredMessages.length,\n });\n } catch {\n continue;\n }\n }\n\n if (allMessages.length === 0) {\n console.log(`No data found for period: ${opts.period}`);\n return;\n }\n\n // Calculate totals\n let totalCost = 0;\n let totalInput = 0;\n let totalOutput = 0;\n let totalCacheRead = 0;\n\n for (const msg of allMessages) {\n totalCost += calculateMessageCost(msg).totalCost;\n totalInput += msg.usage.input_tokens;\n totalOutput += msg.usage.output_tokens;\n totalCacheRead += msg.usage.cache_read_input_tokens;\n }\n\n const totalCacheable = totalInput + totalCacheRead;\n const cacheHitRate = totalCacheable > 0 ? (totalCacheRead / totalCacheable) * 100 : 0;\n\n if (opts.json) {\n console.log(\n JSON.stringify(\n {\n period: opts.period,\n totalCost,\n totalInput,\n totalOutput,\n cacheHitRate,\n sessions: sessionSummaries,\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n if (opts.csv) {\n console.log(\"session_id,model,cost_usd,messages\");\n for (const s of sessionSummaries) {\n console.log(`${s.id},${s.model},${s.cost.toFixed(4)},${s.messages}`);\n }\n return;\n }\n\n // Pretty print\n const periodLabel = opts.period === \"today\" ? now.format(\"ddd, MMM D, YYYY\") : opts.period;\n console.log(chalk.bold.cyan(`\\n kerf-cli report -- ${periodLabel}\\n`));\n console.log(` Total Cost: ${chalk.bold(formatCost(totalCost))}`);\n console.log(` Total Tokens: ${formatTokens(totalInput)} in / ${formatTokens(totalOutput)} out`);\n console.log(` Cache Hit Rate: ${cacheHitRate.toFixed(1)}%`);\n console.log(` Sessions: ${sessionSummaries.length}`);\n console.log();\n\n if (opts.model || opts.sessions) {\n // Model breakdown\n const byModel = new Map<string, { cost: number; sessions: number }>();\n for (const s of sessionSummaries) {\n const existing = byModel.get(s.model) ?? { cost: 0, sessions: 0 };\n existing.cost += s.cost;\n existing.sessions++;\n byModel.set(s.model, existing);\n }\n\n console.log(chalk.bold(\" Model Breakdown:\"));\n for (const [model, data] of byModel) {\n const pct = totalCost > 0 ? ((data.cost / totalCost) * 100).toFixed(1) : \"0\";\n const shortModel = model.replace(\"claude-\", \"\").replace(/-20\\d{6}$/, \"\");\n console.log(\n ` ${shortModel}: ${formatCost(data.cost)} (${pct}%) -- ${data.sessions} session(s)`,\n );\n }\n console.log();\n }\n\n if (opts.sessions) {\n console.log(chalk.bold(\" Session Breakdown:\"));\n for (const s of sessionSummaries.sort((a, b) => b.cost - a.cost)) {\n console.log(` ${s.id.slice(0, 12)} ${formatCost(s.cost)} ${s.messages} msgs [${s.model}]`);\n }\n console.log();\n }\n\n // Hourly breakdown\n const hourly = aggregateCosts(allMessages, \"hour\");\n if (hourly.length > 1) {\n console.log(chalk.bold(\" Hourly:\"));\n const maxCost = Math.max(...hourly.map((h) => h.totalCost));\n for (const h of hourly.slice(-8)) {\n const barLen = maxCost > 0 ? Math.round((h.totalCost / maxCost) * 12) : 0;\n const bar = \"\\u2588\".repeat(barLen) + \"\\u2591\".repeat(12 - barLen);\n console.log(` ${h.periodLabel.padEnd(14)} ${bar} ${formatCost(h.totalCost)}`);\n }\n console.log();\n }\n });\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { mkdirSync, existsSync, readFileSync, writeFileSync, copyFileSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { initDatabase } from \"../../db/schema.js\";\nimport { runMigrations } from \"../../db/migrations.js\";\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Set up kerf-cli for the current project\")\n .option(\"--global\", \"Install hooks globally\")\n .option(\"--hooks-only\", \"Only install hooks\")\n .option(\"--no-hooks\", \"Skip hook installation\")\n .option(\"--force\", \"Skip confirmation prompts\")\n .action(async (opts) => {\n console.log(chalk.bold.cyan(\"\\n Welcome to kerf-cli!\\n\"));\n console.log(\" Setting up cost intelligence for Claude Code...\\n\");\n\n // Create ~/.kerf/ directory\n const kerfDir = join(homedir(), \".kerf\");\n if (!existsSync(kerfDir)) {\n mkdirSync(kerfDir, { recursive: true });\n console.log(chalk.green(\" Created ~/.kerf/\"));\n }\n\n if (!opts.hooksOnly) {\n // Initialize database\n try {\n const db = initDatabase();\n runMigrations(db);\n db.close();\n console.log(chalk.green(\" Created ~/.kerf/kerf.db\"));\n } catch (err) {\n console.log(chalk.red(` Failed to create database: ${err}`));\n }\n }\n\n // Detect existing tools\n try {\n const { execSync } = await import(\"node:child_process\");\n try {\n execSync(\"which rtk\", { stdio: \"ignore\" });\n console.log(chalk.green(\" Detected RTK (command compression) -- compatible!\"));\n } catch { /* not installed */ }\n\n try {\n execSync(\"which ccusage\", { stdio: \"ignore\" });\n console.log(chalk.green(\" Detected ccusage -- will import historical data\"));\n } catch { /* not installed */ }\n } catch { /* ignore */ }\n\n // Install hooks\n if (opts.hooks !== false) {\n const settingsPath = opts.global\n ? join(homedir(), \".claude\", \"settings.json\")\n : join(process.cwd(), \".claude\", \"settings.json\");\n\n console.log(\"\\n Install hooks? These enable:\");\n console.log(\" - Real-time token tracking (Notification hook)\");\n console.log(\" - Budget enforcement (Stop hook)\");\n console.log(`\\n Hooks will be added to ${opts.global ? \"~/.claude\" : \".claude\"}/settings.json`);\n\n try {\n installHooks(settingsPath);\n console.log(chalk.green(\"\\n Hooks installed\"));\n } catch (err) {\n console.log(chalk.yellow(`\\n Skipped hook installation: ${err}`));\n }\n }\n\n console.log(chalk.bold(\"\\n Recommended settings for your setup:\"));\n console.log(chalk.dim(' Add to .claude/settings.json or ~/.claude/settings.json:'));\n console.log(chalk.dim(JSON.stringify({\n env: {\n MAX_THINKING_TOKENS: \"10000\",\n CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: \"50\",\n },\n }, null, 4).split(\"\\n\").map(l => \" \" + l).join(\"\\n\")));\n\n console.log(chalk.bold.cyan(\"\\n Run 'kerf-cli watch' to start the live dashboard!\\n\"));\n });\n}\n\nfunction installHooks(settingsPath: string): void {\n const dir = dirname(settingsPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n let settings: Record<string, unknown> = {};\n if (existsSync(settingsPath)) {\n // Backup existing settings\n const backupPath = settingsPath + \".bak\";\n copyFileSync(settingsPath, backupPath);\n settings = JSON.parse(readFileSync(settingsPath, \"utf-8\"));\n }\n\n const hooks = (settings.hooks ?? {}) as Record<string, unknown[]>;\n\n // Add Notification hook if not present\n if (!hooks.Notification) {\n hooks.Notification = [];\n }\n\n // Add Stop hook if not present\n if (!hooks.Stop) {\n hooks.Stop = [];\n }\n\n settings.hooks = hooks;\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2));\n}\n"],"mappings":"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","names":["React","join","join","Box","Text","dayjs","dayjs","dayjs","Box","Text","jsx","jsxs","readFileSync","join","homedir","join","readFileSync","homedir","jsx","jsxs","Box","Text","program","React","React","render","glob","execSync","Box","Text","jsx","jsxs","program","glob","estimate","render","React","chalk","dayjs","isoWeek","basename","existsSync","existsSync","dayjs","isoWeek","basename","program","chalk","chalk","readFileSync","existsSync","join","join","existsSync","readFileSync","readFileSync","existsSync","join","homedir","join","homedir","existsSync","readFileSync","program","chalk","chalk","dayjs","program","dayjs","chalk","chalk","mkdirSync","existsSync","readFileSync","join","dirname","homedir","program","chalk","join","homedir","existsSync","mkdirSync","execSync","dirname","readFileSync"]}
1
+ {"version":3,"sources":["../src/cli/index.ts","../src/cli/commands/watch.ts","../src/core/parser.ts","../src/core/config.ts","../src/cli/ui/Dashboard.tsx","../src/cli/ui/CostMeter.tsx","../src/core/costCalculator.ts","../src/cli/ui/ContextBar.tsx","../src/core/tokenCounter.ts","../src/cli/commands/estimate.ts","../src/core/estimator.ts","../src/cli/ui/EstimateCard.tsx","../src/cli/commands/budget.ts","../src/core/budgetManager.ts","../src/db/schema.ts","../src/db/migrations.ts","../src/cli/commands/audit.ts","../src/audit/ghostTokens.ts","../src/audit/claudeMdLinter.ts","../src/audit/mcpAnalyzer.ts","../src/audit/recommendations.ts","../src/cli/commands/report.ts","../src/core/cacheAnalyzer.ts","../src/cli/commands/init.ts","../src/hooks/installer.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport { registerWatchCommand } from \"./commands/watch.js\";\nimport { registerEstimateCommand } from \"./commands/estimate.js\";\nimport { registerBudgetCommand } from \"./commands/budget.js\";\nimport { registerAuditCommand } from \"./commands/audit.js\";\nimport { registerReportCommand } from \"./commands/report.js\";\nimport { registerInitCommand } from \"./commands/init.js\";\n\ndeclare const __KERF_VERSION__: string;\n\nconst program = new Command();\n\nprogram\n .name(\"kerf-cli\")\n .version(__KERF_VERSION__)\n .description(\"Cost intelligence for Claude Code. Know before you spend.\");\n\n// Register all subcommands\nregisterWatchCommand(program);\nregisterEstimateCommand(program);\nregisterBudgetCommand(program);\nregisterAuditCommand(program);\nregisterReportCommand(program);\nregisterInitCommand(program);\n\n// Default to watch if no command given\nprogram.action(async () => {\n await program.commands.find((c) => c.name() === \"watch\")?.parseAsync([], { from: \"user\" });\n});\n\nprogram.parse();\n","import React from \"react\";\nimport { render } from \"ink\";\nimport { Command } from \"commander\";\nimport { getActiveSessions } from \"../../core/parser.js\";\nimport { Dashboard } from \"../ui/Dashboard.js\";\n\nexport function registerWatchCommand(program: Command): void {\n program\n .command(\"watch\")\n .description(\"Real-time cost dashboard (default)\")\n .option(\"-s, --session <id>\", \"Watch a specific session\")\n .option(\"-p, --project <path>\", \"Watch sessions for a specific project\")\n .option(\"-i, --interval <ms>\", \"Polling interval in ms\", \"2000\")\n .option(\"--no-color\", \"Disable colors\")\n .action(async (opts) => {\n const interval = parseInt(opts.interval, 10);\n\n let sessionFilePath: string | undefined;\n\n if (opts.session) {\n const sessions = await getActiveSessions(opts.project);\n const found = sessions.find((s) => s.sessionId.startsWith(opts.session));\n sessionFilePath = found?.filePath;\n } else {\n const sessions = await getActiveSessions(opts.project);\n sessionFilePath = sessions[0]?.filePath;\n }\n\n if (!sessionFilePath) {\n console.log(\n \"No active Claude Code session found. Start Claude Code and run 'kerf-cli watch' again.\",\n );\n process.exit(0);\n }\n\n if (!process.stdin.isTTY) {\n console.log(\n \"kerf-cli watch requires an interactive terminal (TTY). Run it directly in a terminal tab, not piped.\",\n );\n process.exit(1);\n }\n\n const { waitUntilExit } = render(\n React.createElement(Dashboard, { sessionFilePath, interval }),\n );\n await waitUntilExit();\n });\n}\n","import { readFileSync, statSync, readdirSync, openSync, readSync, closeSync } from \"node:fs\";\nimport { readdir } from \"node:fs/promises\";\nimport { join, basename } from \"node:path\";\n\nimport dayjs from \"dayjs\";\nimport { watch } from \"chokidar\";\nimport { CLAUDE_PROJECTS_DIR, BILLING_WINDOW_HOURS } from \"./config.js\";\nimport type {\n RawJsonlMessage,\n ParsedMessage,\n SessionData,\n ParsedSession,\n MessageUsage,\n} from \"../types/jsonl.js\";\n\nconst DEFAULT_USAGE: MessageUsage = {\n input_tokens: 0,\n output_tokens: 0,\n cache_creation_input_tokens: 0,\n cache_read_input_tokens: 0,\n};\n\nfunction extractUsage(raw: RawJsonlMessage): Partial<MessageUsage> | null {\n return raw.message?.usage ?? raw.usage ?? raw.delta?.usage ?? null;\n}\n\nfunction extractMessageId(raw: RawJsonlMessage): string | null {\n return raw.message?.id ?? null;\n}\n\nfunction extractModel(raw: RawJsonlMessage): string | null {\n return raw.message?.model ?? null;\n}\n\nfunction extractTimestamp(raw: RawJsonlMessage): string {\n return raw.timestamp ?? dayjs().toISOString();\n}\n\nexport function parseJsonlLine(line: string): RawJsonlMessage | null {\n const trimmed = line.trim();\n if (!trimmed) return null;\n try {\n return JSON.parse(trimmed) as RawJsonlMessage;\n } catch {\n return null;\n }\n}\n\nexport function parseJsonlContent(content: string, sessionId: string): ParsedMessage[] {\n const lines = content.split(\"\\n\");\n const messageMap = new Map<string, ParsedMessage>();\n let anonymousCounter = 0;\n\n for (const line of lines) {\n const raw = parseJsonlLine(line);\n if (!raw) continue;\n\n const usage = extractUsage(raw);\n if (!usage) continue;\n\n const id = extractMessageId(raw) ?? `anon_${anonymousCounter++}`;\n const model = extractModel(raw) ?? \"unknown\";\n const timestamp = extractTimestamp(raw);\n\n const existing = messageMap.get(id);\n const parsedUsage: MessageUsage = {\n input_tokens: usage.input_tokens ?? existing?.usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? existing?.usage.output_tokens ?? 0,\n cache_creation_input_tokens:\n usage.cache_creation_input_tokens ?? existing?.usage.cache_creation_input_tokens ?? 0,\n cache_read_input_tokens:\n usage.cache_read_input_tokens ?? existing?.usage.cache_read_input_tokens ?? 0,\n };\n\n // Deduplicate by message id — take the LAST occurrence (handles streaming intermediates)\n messageMap.set(id, {\n id,\n sessionId,\n model: model !== \"unknown\" ? model : existing?.model ?? \"unknown\",\n timestamp,\n usage: parsedUsage,\n totalCostUsd: raw.total_cost_usd ?? existing?.totalCostUsd ?? null,\n });\n }\n\n return Array.from(messageMap.values());\n}\n\nexport function parseSessionFile(filePath: string): ParsedSession {\n const content = readFileSync(filePath, \"utf-8\");\n const sessionId = basename(filePath, \".jsonl\");\n const messages = parseJsonlContent(content, sessionId);\n\n const totals = messages.reduce(\n (acc, msg) => ({\n input: acc.input + msg.usage.input_tokens,\n output: acc.output + msg.usage.output_tokens,\n cacheRead: acc.cacheRead + msg.usage.cache_read_input_tokens,\n cacheCreation: acc.cacheCreation + msg.usage.cache_creation_input_tokens,\n cost: acc.cost + (msg.totalCostUsd ?? 0),\n }),\n { input: 0, output: 0, cacheRead: 0, cacheCreation: 0, cost: 0 },\n );\n\n const timestamps = messages.map((m) => m.timestamp).sort();\n\n return {\n sessionId,\n filePath,\n messages,\n totalInputTokens: totals.input,\n totalOutputTokens: totals.output,\n totalCacheReadTokens: totals.cacheRead,\n totalCacheCreationTokens: totals.cacheCreation,\n totalCostUsd: totals.cost,\n startTime: timestamps[0] ?? \"\",\n endTime: timestamps[timestamps.length - 1] ?? \"\",\n messageCount: messages.length,\n };\n}\n\nexport async function findJsonlFiles(baseDir?: string): Promise<string[]> {\n const dir = baseDir ?? CLAUDE_PROJECTS_DIR;\n const files: string[] = [];\n\n async function walk(currentDir: string): Promise<void> {\n let entries;\n try {\n entries = await readdir(currentDir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const fullPath = join(currentDir, entry.name);\n if (entry.isDirectory()) {\n await walk(fullPath);\n } else if (entry.name.endsWith(\".jsonl\")) {\n files.push(fullPath);\n }\n }\n }\n\n await walk(dir);\n return files;\n}\n\nexport function findJsonlFilesSync(baseDir?: string): string[] {\n const dir = baseDir ?? CLAUDE_PROJECTS_DIR;\n const files: string[] = [];\n\n function walkSync(currentDir: string): void {\n let entries;\n try {\n entries = readdirSync(currentDir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const fullPath = join(currentDir, entry.name);\n if (entry.isDirectory()) {\n walkSync(fullPath);\n } else if (entry.name.endsWith(\".jsonl\")) {\n files.push(fullPath);\n }\n }\n }\n\n walkSync(dir);\n return files;\n}\n\nexport async function getActiveSessions(baseDir?: string): Promise<SessionData[]> {\n const files = await findJsonlFiles(baseDir);\n const cutoff = dayjs().subtract(BILLING_WINDOW_HOURS, \"hour\");\n const activeSessions: SessionData[] = [];\n\n for (const filePath of files) {\n try {\n const stat = statSync(filePath);\n const lastModified = dayjs(stat.mtime);\n if (lastModified.isAfter(cutoff)) {\n const content = readFileSync(filePath, \"utf-8\");\n const sessionId = basename(filePath, \".jsonl\");\n const messages = parseJsonlContent(content, sessionId);\n\n if (messages.length === 0) continue;\n\n const timestamps = messages.map((m) => m.timestamp).sort();\n activeSessions.push({\n sessionId,\n filePath,\n messages,\n startTime: timestamps[0] ?? \"\",\n endTime: timestamps[timestamps.length - 1] ?? \"\",\n lastModified: stat.mtime,\n });\n }\n } catch {\n continue;\n }\n }\n\n return activeSessions.sort(\n (a, b) => b.lastModified.getTime() - a.lastModified.getTime(),\n );\n}\n\nexport interface StreamingParser {\n onMessage: (callback: (msg: ParsedMessage) => void) => void;\n stop: () => void;\n}\n\nexport function createStreamingParser(filePath: string): StreamingParser {\n const callbacks: Array<(msg: ParsedMessage) => void> = [];\n const sessionId = basename(filePath, \".jsonl\");\n let anonymousCounter = 0;\n let lastReadPosition = 0;\n\n // Set initial position to end of file\n try {\n const stat = statSync(filePath);\n lastReadPosition = stat.size;\n } catch {\n // File might not exist yet\n }\n\n const watcher = watch(filePath, { persistent: true });\n\n watcher.on(\"change\", () => {\n try {\n const stat = statSync(filePath);\n if (stat.size <= lastReadPosition) {\n lastReadPosition = stat.size;\n return;\n }\n\n // Read only new bytes since last position\n const fd = openSync(filePath, \"r\");\n const buffer = Buffer.alloc(stat.size - lastReadPosition);\n readSync(fd, buffer, 0, buffer.length, lastReadPosition);\n closeSync(fd);\n lastReadPosition = stat.size;\n\n const newContent = buffer.toString(\"utf-8\");\n const lines = newContent.split(\"\\n\");\n\n for (const line of lines) {\n const raw = parseJsonlLine(line);\n if (!raw) continue;\n const usage = extractUsage(raw);\n if (!usage) continue;\n\n const id = extractMessageId(raw) ?? `anon_${anonymousCounter++}`;\n const model = extractModel(raw) ?? \"unknown\";\n const timestamp = extractTimestamp(raw);\n\n const msg: ParsedMessage = {\n id,\n sessionId,\n model,\n timestamp,\n usage: {\n input_tokens: usage.input_tokens ?? 0,\n output_tokens: usage.output_tokens ?? 0,\n cache_creation_input_tokens: usage.cache_creation_input_tokens ?? 0,\n cache_read_input_tokens: usage.cache_read_input_tokens ?? 0,\n },\n totalCostUsd: raw.total_cost_usd ?? null,\n };\n\n for (const cb of callbacks) {\n cb(msg);\n }\n }\n } catch {\n // File may be in the middle of a write\n }\n });\n\n return {\n onMessage(callback) {\n callbacks.push(callback);\n },\n stop() {\n watcher.close();\n },\n };\n}\n","import { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport type { KerfConfig } from \"../types/config.js\";\n\nexport const DEFAULT_CONFIG: KerfConfig = {\n defaultModel: \"sonnet\",\n budgetWarningThreshold: 80,\n budgetBlockThreshold: 100,\n pollingInterval: 2000,\n dataDir: join(homedir(), \".kerf\"),\n enableHooks: true,\n};\n\nexport const CONTEXT_WINDOW_SIZE = 200_000;\nexport const SYSTEM_PROMPT_TOKENS = 14_328;\nexport const BUILT_IN_TOOLS_TOKENS = 15_000;\nexport const AUTOCOMPACT_BUFFER_TOKENS = 33_000;\nexport const MCP_TOKENS_PER_TOOL = 600;\nexport const BILLING_WINDOW_HOURS = 5;\n\nexport const CLAUDE_PROJECTS_DIR = join(homedir(), \".claude\", \"projects\");\nexport const CLAUDE_SETTINGS_GLOBAL = join(homedir(), \".claude\", \"settings.json\");\nexport const KERF_DB_PATH = join(homedir(), \".kerf\", \"kerf.db\");\nexport const KERF_SESSION_LOG = join(homedir(), \".kerf\", \"session-log.jsonl\");\n\nexport function getConfig(): KerfConfig {\n return { ...DEFAULT_CONFIG };\n}\n","import React, { useState, useEffect } from \"react\";\nimport { Box, Text, useInput, useApp } from \"ink\";\nimport { CostMeter } from \"./CostMeter.js\";\nimport { ContextBar } from \"./ContextBar.js\";\nimport { parseSessionFile } from \"../../core/parser.js\";\nimport {\n calculateMessageCost,\n calculateCostVelocity,\n formatCost,\n formatTokens,\n} from \"../../core/costCalculator.js\";\nimport { estimateContextOverhead } from \"../../core/tokenCounter.js\";\nimport { CONTEXT_WINDOW_SIZE, BILLING_WINDOW_HOURS } from \"../../core/config.js\";\nimport type { ParsedSession } from \"../../types/jsonl.js\";\nimport type { ContextOverhead } from \"../../types/config.js\";\n\ninterface DashboardProps {\n sessionFilePath: string;\n interval: number;\n}\n\nexport function Dashboard({ sessionFilePath, interval }: DashboardProps) {\n const { exit } = useApp();\n const [session, setSession] = useState<ParsedSession | null>(null);\n const [overhead, setOverhead] = useState<ContextOverhead>(estimateContextOverhead());\n const [showBudget, setShowBudget] = useState(false);\n\n useEffect(() => {\n function refresh() {\n try {\n const parsed = parseSessionFile(sessionFilePath);\n setSession(parsed);\n setOverhead(estimateContextOverhead());\n } catch {\n // File may be in the middle of a write\n }\n }\n\n refresh();\n const timer = setInterval(refresh, interval);\n return () => clearInterval(timer);\n }, [sessionFilePath, interval]);\n\n useInput(\n (input) => {\n if (input === \"q\") exit();\n if (input === \"b\") setShowBudget((prev) => !prev);\n },\n { isActive: process.stdin.isTTY ?? false },\n );\n\n if (!session || session.messages.length === 0) {\n return (\n <Box paddingX={1}>\n <Text dimColor>Waiting for session data...</Text>\n </Box>\n );\n }\n\n const totalCost = session.messages.reduce(\n (sum, msg) => sum + calculateMessageCost(msg).totalCost,\n 0,\n );\n const velocity = calculateCostVelocity(session.messages);\n const model = session.messages[session.messages.length - 1]?.model ?? \"unknown\";\n const windowBudget = velocity.projectedWindowCost || totalCost * 3;\n\n const totalInput = session.totalInputTokens + session.totalCacheReadTokens;\n const usedTokens = totalInput + session.totalOutputTokens;\n\n // Recent messages for the log\n const recentMessages = session.messages.slice(-8);\n\n return (\n <Box flexDirection=\"column\">\n <Box borderStyle=\"round\" borderColor=\"cyan\" paddingX={1}>\n <Text bold color=\"cyan\">\n kerf-cli watch\n </Text>\n <Text> | session: {session.sessionId.slice(0, 8)}...</Text>\n <Text> | {session.messageCount} messages</Text>\n <Text dimColor> (q=quit, b=budget)</Text>\n </Box>\n\n <CostMeter\n spent={totalCost}\n windowBudget={windowBudget}\n burnRate={velocity.dollarsPerMinute}\n minutesRemaining={velocity.minutesRemaining}\n model={model}\n />\n\n <ContextBar used={usedTokens} total={CONTEXT_WINDOW_SIZE} overhead={overhead} />\n\n <Box flexDirection=\"column\" paddingX={1} marginTop={1}>\n <Text bold>Recent Messages:</Text>\n {recentMessages.map((msg, i) => {\n const cost = calculateMessageCost(msg);\n return (\n <Text key={i}>\n <Text dimColor>{msg.timestamp.slice(11, 19)}</Text>\n <Text> {formatTokens(msg.usage.input_tokens + msg.usage.output_tokens)} tok</Text>\n <Text color=\"yellow\"> {formatCost(cost.totalCost)}</Text>\n </Text>\n );\n })}\n </Box>\n </Box>\n );\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport { formatCost } from \"../../core/costCalculator.js\";\n\ninterface CostMeterProps {\n spent: number;\n windowBudget: number;\n burnRate: number;\n minutesRemaining: number;\n model: string;\n}\n\nexport function CostMeter({ spent, windowBudget, burnRate, minutesRemaining, model }: CostMeterProps) {\n const pct = windowBudget > 0 ? (spent / windowBudget) * 100 : 0;\n const color = pct < 50 ? \"green\" : pct < 80 ? \"yellow\" : \"red\";\n\n const hours = Math.floor(minutesRemaining / 60);\n const mins = Math.round(minutesRemaining % 60);\n const timeStr = hours > 0 ? `${hours}h ${mins}m` : `${mins}m`;\n\n return (\n <Box flexDirection=\"column\" paddingX={1}>\n <Text>\n <Text color={color}>{\">> \"}</Text>\n <Text bold>{formatCost(spent)}</Text>\n <Text dimColor> / ~{formatCost(windowBudget)} window</Text>\n <Text> | </Text>\n <Text color={color}>{formatCost(burnRate)}/min</Text>\n <Text> | </Text>\n <Text>~{timeStr} remaining</Text>\n <Text dimColor> [{model}]</Text>\n </Text>\n </Box>\n );\n}\n","import dayjs from \"dayjs\";\nimport isoWeek from \"dayjs/plugin/isoWeek.js\";\nimport { BILLING_WINDOW_HOURS } from \"./config.js\";\nimport type { ParsedMessage, ParsedSession } from \"../types/jsonl.js\";\nimport type {\n ModelPricing,\n PricingConfig,\n CostBreakdown,\n SessionCostSummary,\n CostVelocity,\n AggregationPeriod,\n AggregatedCost,\n} from \"../types/pricing.js\";\n\ndayjs.extend(isoWeek);\n\nexport const MODEL_PRICING: PricingConfig = {\n \"claude-sonnet-4-20250514\": {\n input: 3,\n output: 15,\n cacheRead: 0.3,\n cacheCreation: 3.75,\n },\n \"claude-opus-4-20250514\": {\n input: 15,\n output: 75,\n cacheRead: 1.5,\n cacheCreation: 18.75,\n },\n \"claude-haiku-4-20250514\": {\n input: 0.8,\n output: 4,\n cacheRead: 0.08,\n cacheCreation: 1.0,\n },\n};\n\n// Alias mappings for short model names\nconst MODEL_ALIASES: Record<string, string> = {\n sonnet: \"claude-sonnet-4-20250514\",\n opus: \"claude-opus-4-20250514\",\n haiku: \"claude-haiku-4-20250514\",\n};\n\nexport function resolveModelPricing(model: string): ModelPricing {\n const resolved = MODEL_ALIASES[model] ?? model;\n // Try exact match first, then prefix match\n if (MODEL_PRICING[resolved]) return MODEL_PRICING[resolved];\n const match = Object.keys(MODEL_PRICING).find((k) => resolved.startsWith(k) || k.startsWith(resolved));\n if (match) return MODEL_PRICING[match];\n // Default to sonnet pricing\n return MODEL_PRICING[\"claude-sonnet-4-20250514\"];\n}\n\nexport function calculateMessageCost(msg: ParsedMessage): CostBreakdown {\n // If authoritative cost is present, use it\n if (msg.totalCostUsd !== null && msg.totalCostUsd > 0) {\n return {\n inputCost: 0,\n outputCost: 0,\n cacheReadCost: 0,\n cacheCreationCost: 0,\n totalCost: msg.totalCostUsd,\n };\n }\n\n const pricing = resolveModelPricing(msg.model);\n const MILLION = 1_000_000;\n\n // Use multiply-then-divide to avoid floating point issues\n const inputCost = (msg.usage.input_tokens * pricing.input) / MILLION;\n const outputCost = (msg.usage.output_tokens * pricing.output) / MILLION;\n const cacheReadCost = (msg.usage.cache_read_input_tokens * pricing.cacheRead) / MILLION;\n const cacheCreationCost = (msg.usage.cache_creation_input_tokens * pricing.cacheCreation) / MILLION;\n\n return {\n inputCost,\n outputCost,\n cacheReadCost,\n cacheCreationCost,\n totalCost: inputCost + outputCost + cacheReadCost + cacheCreationCost,\n };\n}\n\nexport function calculateSessionCost(session: ParsedSession): SessionCostSummary {\n let totalCost = 0;\n const costBreakdown: CostBreakdown = {\n inputCost: 0,\n outputCost: 0,\n cacheReadCost: 0,\n cacheCreationCost: 0,\n totalCost: 0,\n };\n\n for (const msg of session.messages) {\n const msgCost = calculateMessageCost(msg);\n costBreakdown.inputCost += msgCost.inputCost;\n costBreakdown.outputCost += msgCost.outputCost;\n costBreakdown.cacheReadCost += msgCost.cacheReadCost;\n costBreakdown.cacheCreationCost += msgCost.cacheCreationCost;\n totalCost += msgCost.totalCost;\n }\n\n costBreakdown.totalCost = totalCost;\n\n return {\n sessionId: session.sessionId,\n totalCost,\n tokenBreakdown: {\n input: session.totalInputTokens,\n output: session.totalOutputTokens,\n cacheRead: session.totalCacheReadTokens,\n cacheCreation: session.totalCacheCreationTokens,\n },\n costBreakdown,\n model: session.messages[0]?.model ?? \"unknown\",\n messageCount: session.messageCount,\n startTime: session.startTime,\n endTime: session.endTime,\n };\n}\n\nexport function calculateCostVelocity(messages: ParsedMessage[]): CostVelocity {\n if (messages.length < 2) {\n return { dollarsPerMinute: 0, tokensPerMinute: 0, projectedWindowCost: 0, minutesRemaining: 0 };\n }\n\n // Use last 10 messages for velocity calculation\n const recent = messages.slice(-10);\n const firstTime = dayjs(recent[0].timestamp);\n const lastTime = dayjs(recent[recent.length - 1].timestamp);\n const durationMinutes = lastTime.diff(firstTime, \"minute\", true);\n\n if (durationMinutes <= 0) {\n return { dollarsPerMinute: 0, tokensPerMinute: 0, projectedWindowCost: 0, minutesRemaining: 0 };\n }\n\n let totalCost = 0;\n let totalTokens = 0;\n for (const msg of recent) {\n totalCost += calculateMessageCost(msg).totalCost;\n totalTokens += msg.usage.input_tokens + msg.usage.output_tokens;\n }\n\n const dollarsPerMinute = totalCost / durationMinutes;\n const tokensPerMinute = totalTokens / durationMinutes;\n const windowMinutes = BILLING_WINDOW_HOURS * 60;\n const projectedWindowCost = dollarsPerMinute * windowMinutes;\n\n // Time remaining in current billing window\n const windowStart = dayjs().subtract(BILLING_WINDOW_HOURS, \"hour\");\n const elapsed = dayjs().diff(windowStart, \"minute\", true);\n const minutesRemaining = Math.max(0, windowMinutes - elapsed);\n\n return { dollarsPerMinute, tokensPerMinute, projectedWindowCost, minutesRemaining };\n}\n\nexport function aggregateCosts(\n messages: ParsedMessage[],\n period: AggregationPeriod,\n): AggregatedCost[] {\n const groups = new Map<string, { messages: ParsedMessage[]; sessions: Set<string> }>();\n\n for (const msg of messages) {\n const key = getPeriodKey(msg.timestamp, period);\n const group = groups.get(key) ?? { messages: [], sessions: new Set() };\n group.messages.push(msg);\n group.sessions.add(msg.sessionId);\n groups.set(key, group);\n }\n\n return Array.from(groups.entries()).map(([key, group]) => {\n let totalCost = 0;\n let totalInput = 0;\n let totalOutput = 0;\n\n for (const msg of group.messages) {\n totalCost += calculateMessageCost(msg).totalCost;\n totalInput += msg.usage.input_tokens;\n totalOutput += msg.usage.output_tokens;\n }\n\n return {\n period: key,\n periodLabel: formatPeriodLabel(key, period),\n totalCost,\n totalInputTokens: totalInput,\n totalOutputTokens: totalOutput,\n messageCount: group.messages.length,\n sessionCount: group.sessions.size,\n };\n });\n}\n\nfunction getPeriodKey(timestamp: string, period: AggregationPeriod): string {\n const d = dayjs(timestamp);\n switch (period) {\n case \"hour\":\n return d.format(\"YYYY-MM-DD-HH\");\n case \"day\":\n return d.format(\"YYYY-MM-DD\");\n case \"billing_window\":\n // 5-hour windows starting from midnight\n const hour = d.hour();\n const windowStart = Math.floor(hour / BILLING_WINDOW_HOURS) * BILLING_WINDOW_HOURS;\n return `${d.format(\"YYYY-MM-DD\")}-W${windowStart}`;\n case \"week\":\n return `${d.isoWeekYear()}-W${String(d.isoWeek()).padStart(2, \"0\")}`;\n case \"month\":\n return d.format(\"YYYY-MM\");\n case \"session\":\n default:\n return timestamp;\n }\n}\n\nfunction formatPeriodLabel(key: string, period: AggregationPeriod): string {\n switch (period) {\n case \"hour\": {\n // key is \"YYYY-MM-DD-HH\", convert to parseable format\n const parts = key.split(\"-\");\n const dateStr = `${parts[0]}-${parts[1]}-${parts[2]}T${parts[3]}:00:00`;\n return dayjs(dateStr).format(\"MMM D, h A\");\n }\n case \"day\":\n return dayjs(key).format(\"ddd, MMM D\");\n case \"week\":\n return `Week ${key.split(\"-W\")[1]}`;\n case \"month\":\n return dayjs(key).format(\"MMMM YYYY\");\n default:\n return key;\n }\n}\n\nexport function formatCost(cost: number): string {\n return `$${cost.toFixed(2)}`;\n}\n\nexport function formatTokens(tokens: number): string {\n if (tokens >= 1_000_000) return `${(tokens / 1_000_000).toFixed(1)}M`;\n if (tokens >= 1_000) return `${(tokens / 1_000).toFixed(1)}K`;\n return String(tokens);\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { ContextOverhead } from \"../../types/config.js\";\n\ninterface ContextBarProps {\n used: number;\n total: number;\n overhead: ContextOverhead;\n}\n\nexport function ContextBar({ used, total, overhead }: ContextBarProps) {\n const barWidth = 30;\n const usedPct = total > 0 ? (used / total) * 100 : 0;\n const clampedPct = Math.max(0, Math.min(usedPct, 100));\n const filledCount = Math.round((clampedPct / 100) * barWidth);\n const emptyCount = barWidth - filledCount;\n\n const color = usedPct < 50 ? \"green\" : usedPct < 80 ? \"yellow\" : \"red\";\n\n const filled = \"\\u2588\".repeat(filledCount);\n const empty = \"\\u2591\".repeat(emptyCount);\n\n const formatK = (n: number) => `${Math.round(n / 1000)}K`;\n\n return (\n <Box flexDirection=\"column\" paddingX={1}>\n <Text>\n <Text>[</Text>\n <Text color={color}>{filled}</Text>\n <Text dimColor>{empty}</Text>\n <Text>]</Text>\n <Text> {usedPct.toFixed(0)}%</Text>\n <Text> | {formatK(used)} / {formatK(total)} tokens</Text>\n </Text>\n <Text dimColor>\n {\" \"}system({formatK(overhead.systemPrompt)}) + tools({formatK(overhead.builtInTools)}) + mcp(\n {formatK(overhead.mcpTools)}) + claude.md({formatK(overhead.claudeMd)})\n </Text>\n </Box>\n );\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { execSync } from \"node:child_process\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport {\n CONTEXT_WINDOW_SIZE,\n SYSTEM_PROMPT_TOKENS,\n BUILT_IN_TOOLS_TOKENS,\n AUTOCOMPACT_BUFFER_TOKENS,\n MCP_TOKENS_PER_TOOL,\n} from \"./config.js\";\nimport type { ContextOverhead, McpServerInfo } from \"../types/config.js\";\n\nconst SUPPORTED_EXTENSIONS = new Set([\".md\", \".ts\", \".js\", \".json\", \".yaml\", \".yml\", \".py\", \".txt\"]);\n\nexport function findGitRootClaudeMd(): string[] {\n try {\n const gitRoot = execSync(\"git rev-parse --show-toplevel\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"ignore\"],\n }).trim();\n if (gitRoot && gitRoot !== process.cwd()) {\n return [\n join(gitRoot, \"CLAUDE.md\"),\n join(gitRoot, \".claude\", \"CLAUDE.md\"),\n ];\n }\n } catch {\n // Not in a git repo\n }\n return [];\n}\n\n/**\n * Fast local heuristic: tokens ~= characters / 3.5\n */\nexport function estimateTokens(text: string): number {\n return Math.ceil(text.length / 3.5);\n}\n\n/**\n * Count tokens in a file using the heuristic\n */\nexport function countFileTokens(filePath: string): number {\n try {\n const content = readFileSync(filePath, \"utf-8\");\n return estimateTokens(content);\n } catch {\n return 0;\n }\n}\n\nexport interface ClaudeMdSection {\n title: string;\n content: string;\n tokens: number;\n lineStart: number;\n lineEnd: number;\n}\n\n/**\n * Parse CLAUDE.md into sections by ## headers\n */\nexport function parseClaudeMdSections(content: string): ClaudeMdSection[] {\n const lines = content.split(\"\\n\");\n const sections: ClaudeMdSection[] = [];\n let currentTitle = \"Preamble\";\n let currentContent: string[] = [];\n let currentLineStart = 1;\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (line.startsWith(\"## \")) {\n // Save previous section\n if (currentContent.length > 0 || currentTitle !== \"Preamble\") {\n const sectionContent = currentContent.join(\"\\n\");\n sections.push({\n title: currentTitle,\n content: sectionContent,\n tokens: estimateTokens(sectionContent),\n lineStart: currentLineStart,\n lineEnd: i,\n });\n }\n currentTitle = line.replace(/^##\\s*/, \"\");\n currentContent = [];\n currentLineStart = i + 1;\n } else {\n currentContent.push(line);\n }\n }\n\n // Save last section\n if (currentContent.length > 0) {\n const sectionContent = currentContent.join(\"\\n\");\n sections.push({\n title: currentTitle,\n content: sectionContent,\n tokens: estimateTokens(sectionContent),\n lineStart: currentLineStart,\n lineEnd: lines.length,\n });\n }\n\n return sections;\n}\n\n/**\n * Analyze CLAUDE.md token overhead\n */\nexport function analyzeClaudeMd(filePath?: string): { totalTokens: number; sections: ClaudeMdSection[]; heavySections: ClaudeMdSection[] } {\n const paths = filePath\n ? [filePath]\n : [\n join(process.cwd(), \"CLAUDE.md\"),\n join(process.cwd(), \".claude\", \"CLAUDE.md\"),\n ...findGitRootClaudeMd(),\n join(homedir(), \".claude\", \"CLAUDE.md\"),\n ];\n\n for (const p of paths) {\n if (existsSync(p)) {\n const content = readFileSync(p, \"utf-8\");\n const sections = parseClaudeMdSections(content);\n const totalTokens = sections.reduce((sum, s) => sum + s.tokens, 0);\n const heavySections = sections.filter((s) => s.tokens > 500);\n return { totalTokens, sections, heavySections };\n }\n }\n\n return { totalTokens: 0, sections: [], heavySections: [] };\n}\n\n/**\n * Parse MCP server configurations and estimate token cost\n */\nexport function analyzeMcpServers(): McpServerInfo[] {\n const servers: McpServerInfo[] = [];\n const paths = [\n join(process.cwd(), \".mcp.json\"),\n join(homedir(), \".claude.json\"),\n ];\n\n for (const configPath of paths) {\n if (!existsSync(configPath)) continue;\n try {\n const raw = JSON.parse(readFileSync(configPath, \"utf-8\"));\n const mcpServers = raw.mcpServers ?? raw.mcp_servers ?? {};\n for (const [name, config] of Object.entries(mcpServers)) {\n const cfg = config as Record<string, unknown>;\n // Estimate tools: if tools array is present, use its length; otherwise default to 5\n const tools = Array.isArray(cfg.tools) ? cfg.tools : [];\n const toolCount = tools.length || 5;\n const estimatedTokens = toolCount * MCP_TOKENS_PER_TOOL;\n servers.push({\n name,\n toolCount,\n estimatedTokens,\n isHeavy: toolCount > 10,\n });\n }\n } catch {\n continue;\n }\n }\n\n return servers;\n}\n\n/**\n * Estimate total context overhead (ghost tokens)\n */\nexport function estimateContextOverhead(claudeMdPath?: string): ContextOverhead {\n const claudeMd = analyzeClaudeMd(claudeMdPath);\n const mcpServers = analyzeMcpServers();\n const mcpToolTokens = mcpServers.reduce((sum, s) => sum + s.estimatedTokens, 0);\n\n const totalOverhead =\n SYSTEM_PROMPT_TOKENS +\n BUILT_IN_TOOLS_TOKENS +\n mcpToolTokens +\n claudeMd.totalTokens +\n AUTOCOMPACT_BUFFER_TOKENS;\n\n const effectiveWindow = CONTEXT_WINDOW_SIZE - totalOverhead;\n const percentUsable = (effectiveWindow / CONTEXT_WINDOW_SIZE) * 100;\n\n return {\n systemPrompt: SYSTEM_PROMPT_TOKENS,\n builtInTools: BUILT_IN_TOOLS_TOKENS,\n claudeMd: claudeMd.totalTokens,\n mcpTools: mcpToolTokens,\n autocompactBuffer: AUTOCOMPACT_BUFFER_TOKENS,\n totalOverhead,\n effectiveWindow,\n percentUsable,\n };\n}\n","import React from \"react\";\nimport { render } from \"ink\";\nimport { Command } from \"commander\";\nimport { glob } from \"glob\";\nimport chalk from \"chalk\";\nimport { estimateTaskCost } from \"../../core/estimator.js\";\nimport { EstimateCard } from \"../ui/EstimateCard.js\";\n\nexport function registerEstimateCommand(program: Command): void {\n program\n .command(\"estimate <task>\")\n .description(\"Pre-flight cost estimation\")\n .option(\"-m, --model <model>\", \"Model to estimate for\", \"sonnet\")\n .option(\"-f, --files <glob>\", \"Specific files that will be touched\")\n .option(\"--compare\", \"Show Sonnet vs Opus vs Haiku comparison\")\n .option(\"--json\", \"Output as JSON\")\n .action(async (task: string, opts) => {\n const files: string[] = [];\n if (opts.files) {\n const matched = await glob(opts.files, { absolute: true });\n files.push(...matched);\n }\n\n if (opts.compare) {\n const models = [\"sonnet\", \"opus\", \"haiku\"] as const;\n\n if (opts.json) {\n for (const model of models) {\n const estimate = await estimateTaskCost(task, { model, files, cwd: process.cwd() });\n console.log(JSON.stringify(estimate, null, 2));\n }\n return;\n }\n\n // Print comparison table\n const estimates = await Promise.all(\n models.map(async (model) => ({\n model,\n estimate: await estimateTaskCost(task, { model, files, cwd: process.cwd() }),\n })),\n );\n\n console.log(chalk.bold.cyan(`\\n kerf-cli estimate: '${task}'\\n`));\n console.log(\n ` ${\"Model\".padEnd(10)} ${\"Turns\".padEnd(14)} ${\"Low\".padEnd(12)} ${\"Expected\".padEnd(12)} ${\"High\".padEnd(12)}`,\n );\n console.log(\" \" + \"-\".repeat(58));\n for (const { model, estimate } of estimates) {\n const turns = `${estimate.estimatedTurns.low}-${estimate.estimatedTurns.high}`;\n console.log(\n ` ${model.padEnd(10)} ${turns.padEnd(14)} ${chalk.green(estimate.estimatedCost.low.padEnd(12))} ${chalk.yellow(estimate.estimatedCost.expected.padEnd(12))} ${chalk.red(estimate.estimatedCost.high.padEnd(12))}`,\n );\n }\n console.log();\n\n const cheapest = estimates[2]; // haiku\n const priciest = estimates[1]; // opus\n console.log(\n chalk.dim(` Cheapest: ${cheapest.model} at ${cheapest.estimate.estimatedCost.expected}`),\n );\n console.log(\n chalk.dim(` Priciest: ${priciest.model} at ${priciest.estimate.estimatedCost.expected}`),\n );\n console.log();\n return;\n }\n\n const estimate = await estimateTaskCost(task, {\n model: opts.model,\n files,\n cwd: process.cwd(),\n });\n\n if (opts.json) {\n console.log(JSON.stringify(estimate, null, 2));\n return;\n }\n\n const { waitUntilExit } = render(\n React.createElement(EstimateCard, { task, estimate }),\n );\n await waitUntilExit();\n });\n}\n","import { glob } from \"glob\";\nimport { countFileTokens, estimateContextOverhead } from \"./tokenCounter.js\";\nimport { resolveModelPricing, formatCost } from \"./costCalculator.js\";\nimport type { CostEstimate, EstimateOptions } from \"../types/config.js\";\nimport type { ModelPricing } from \"../types/pricing.js\";\n\ntype TaskComplexity = \"simple\" | \"medium\" | \"complex\";\n\ninterface ComplexityProfile {\n turns: { low: number; expected: number; high: number };\n outputTokensPerTurn: number;\n}\n\nconst COMPLEXITY_PROFILES: Record<TaskComplexity, ComplexityProfile> = {\n simple: { turns: { low: 2, expected: 3, high: 5 }, outputTokensPerTurn: 1000 },\n medium: { turns: { low: 5, expected: 10, high: 15 }, outputTokensPerTurn: 2000 },\n complex: { turns: { low: 15, expected: 25, high: 40 }, outputTokensPerTurn: 2500 },\n};\n\nconst SIMPLE_KEYWORDS = [\"typo\", \"rename\", \"fix typo\", \"update version\", \"change name\", \"remove unused\", \"delete\"];\nconst COMPLEX_KEYWORDS = [\"refactor\", \"rewrite\", \"new module\", \"implement\", \"build\", \"create\", \"migrate\", \"redesign\", \"overhaul\", \"architecture\"];\n\n// Typical 5-hour window costs per model (for percentOfWindow calculation)\nconst TYPICAL_WINDOW_COSTS: Record<string, number> = {\n sonnet: 15,\n opus: 75,\n haiku: 4,\n};\n\nfunction detectComplexity(taskDescription: string): TaskComplexity {\n const lower = taskDescription.toLowerCase();\n if (SIMPLE_KEYWORDS.some((k) => lower.includes(k))) return \"simple\";\n if (COMPLEX_KEYWORDS.some((k) => lower.includes(k))) return \"complex\";\n return \"medium\";\n}\n\nconst MILLION = 1_000_000;\nconst CACHE_HIT_RATE = 0.9;\n\nfunction estimateCostForTurns(\n turns: number,\n modelPricing: ModelPricing,\n contextPerTurn: number,\n outputTokensPerTurn: number,\n): number {\n let totalCost = 0;\n for (let turn = 1; turn <= turns; turn++) {\n const conversationGrowth = (turn - 1) * outputTokensPerTurn;\n const inputTokens = contextPerTurn + conversationGrowth;\n\n let effectiveInputCost: number;\n if (turn <= 2) {\n effectiveInputCost = (inputTokens * modelPricing.input) / MILLION;\n } else {\n const cachedTokens = inputTokens * CACHE_HIT_RATE;\n const uncachedTokens = inputTokens * (1 - CACHE_HIT_RATE);\n effectiveInputCost =\n (cachedTokens * modelPricing.cacheRead) / MILLION +\n (uncachedTokens * modelPricing.input) / MILLION;\n }\n\n const outputCost = (outputTokensPerTurn * modelPricing.output) / MILLION;\n totalCost += effectiveInputCost + outputCost;\n }\n return totalCost;\n}\n\nexport async function estimateTaskCost(\n taskDescription: string,\n options: Partial<EstimateOptions> = {},\n): Promise<CostEstimate> {\n const model = options.model ?? \"sonnet\";\n const cwd = options.cwd ?? process.cwd();\n const pricing = resolveModelPricing(model);\n\n // Calculate context overhead\n const overhead = estimateContextOverhead();\n\n // Count file tokens\n let fileTokens = 0;\n let fileList = options.files ?? [];\n\n if (fileList.length === 0) {\n try {\n const { execSync } = await import(\"node:child_process\");\n const output = execSync(\"git diff --name-only HEAD 2>/dev/null || git ls-files -m 2>/dev/null\", {\n cwd,\n encoding: \"utf-8\",\n });\n fileList = output\n .split(\"\\n\")\n .filter(Boolean)\n .map((f) => `${cwd}/${f}`);\n } catch {\n // No git, no files\n }\n }\n\n for (const filePattern of fileList) {\n const matched = await glob(filePattern, { cwd, absolute: true });\n for (const f of matched) {\n fileTokens += countFileTokens(f);\n }\n }\n\n // Detect complexity and get profile\n const complexity = detectComplexity(taskDescription);\n const profile = COMPLEXITY_PROFILES[complexity];\n const contextPerTurn = overhead.totalOverhead + fileTokens;\n\n const lowCost = estimateCostForTurns(profile.turns.low, pricing, contextPerTurn, profile.outputTokensPerTurn);\n const expectedCost = estimateCostForTurns(profile.turns.expected, pricing, contextPerTurn, profile.outputTokensPerTurn);\n const highCost = estimateCostForTurns(profile.turns.high, pricing, contextPerTurn, profile.outputTokensPerTurn);\n\n // Estimate total tokens for expected case\n const expectedInputTokens = contextPerTurn * profile.turns.expected;\n const expectedOutputTokens = profile.outputTokensPerTurn * profile.turns.expected;\n const expectedCachedTokens = expectedInputTokens * CACHE_HIT_RATE;\n\n // Window usage — based on typical costs per model\n const typicalWindowCost = TYPICAL_WINDOW_COSTS[model] ?? TYPICAL_WINDOW_COSTS.sonnet;\n const percentOfWindow = Math.min(100, Math.round((expectedCost / typicalWindowCost) * 100));\n\n // Recommendations\n const recommendations: string[] = [];\n if (model !== \"sonnet\") {\n const sonnetPricing = resolveModelPricing(\"sonnet\");\n const sonnetExpected = estimateCostForTurns(profile.turns.expected, sonnetPricing, contextPerTurn, profile.outputTokensPerTurn);\n const savings = expectedCost - sonnetExpected;\n if (savings > 0.01) {\n recommendations.push(\n `Consider Sonnet to save ~${formatCost(savings)} (${(expectedCost / sonnetExpected).toFixed(1)}x cheaper)`,\n );\n }\n }\n\n if (model === \"sonnet\") {\n const opusPricing = resolveModelPricing(\"opus\");\n const opusExpected = estimateCostForTurns(profile.turns.expected, opusPricing, contextPerTurn, profile.outputTokensPerTurn);\n recommendations.push(`Using Opus would cost ~${formatCost(opusExpected)} (${(opusExpected / expectedCost).toFixed(1)}x more)`);\n }\n\n if (overhead.percentUsable < 60) {\n recommendations.push(`High ghost token overhead (${(100 - overhead.percentUsable).toFixed(0)}%). Run 'kerf-cli audit' to optimize.`);\n }\n\n if (fileTokens > 50000) {\n recommendations.push(`Large file context (${(fileTokens / 1000).toFixed(0)}K tokens). Consider narrowing scope.`);\n }\n\n return {\n model,\n estimatedTurns: profile.turns,\n estimatedTokens: {\n input: Math.round(expectedInputTokens),\n output: Math.round(expectedOutputTokens),\n cached: Math.round(expectedCachedTokens),\n },\n estimatedCost: {\n low: formatCost(lowCost),\n expected: formatCost(expectedCost),\n high: formatCost(highCost),\n },\n contextOverhead: overhead.totalOverhead,\n fileTokens,\n percentOfWindow,\n recommendations,\n };\n}\n","import React from \"react\";\nimport { Box, Text } from \"ink\";\nimport type { CostEstimate } from \"../../types/config.js\";\n\ninterface EstimateCardProps {\n task: string;\n estimate: CostEstimate;\n}\n\nexport function EstimateCard({ task, estimate }: EstimateCardProps) {\n const formatK = (n: number) => `${(n / 1000).toFixed(1)}K`;\n\n return (\n <Box flexDirection=\"column\" borderStyle=\"round\" borderColor=\"cyan\" paddingX={2} paddingY={1}>\n <Text bold color=\"cyan\">\n kerf-cli estimate: '{task}'\n </Text>\n <Text> </Text>\n <Text>\n Model: <Text bold>{estimate.model}</Text>\n </Text>\n <Text>\n Estimated turns: {estimate.estimatedTurns.low}-{estimate.estimatedTurns.high} (expected:{\" \"}\n {estimate.estimatedTurns.expected})\n </Text>\n <Text>\n Files: {formatK(estimate.fileTokens)} tokens\n </Text>\n <Text>\n Context overhead: {formatK(estimate.contextOverhead)} tokens (ghost tokens)\n </Text>\n <Text> </Text>\n <Text bold>Estimated Cost:</Text>\n <Text>\n {\" \"}Low: <Text color=\"green\">{estimate.estimatedCost.low}</Text>\n </Text>\n <Text>\n {\" \"}Expected: <Text color=\"yellow\">{estimate.estimatedCost.expected}</Text>\n </Text>\n <Text>\n {\" \"}High: <Text color=\"red\">{estimate.estimatedCost.high}</Text>\n </Text>\n <Text> </Text>\n <Text>Window Usage: ~{estimate.percentOfWindow}% of 5-hour window</Text>\n {estimate.recommendations.map((rec, i) => (\n <Text key={i} color=\"cyan\">\n {\" -> \"}{rec}\n </Text>\n ))}\n </Box>\n );\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { BudgetManager } from \"../../core/budgetManager.js\";\nimport { formatCost } from \"../../core/costCalculator.js\";\n\nexport function registerBudgetCommand(program: Command): void {\n const budget = program.command(\"budget\").description(\"Per-project budget management\");\n\n budget\n .command(\"set <amount>\")\n .description(\"Set budget for current project\")\n .option(\"-p, --period <period>\", \"Budget period (daily|weekly|monthly)\", \"weekly\")\n .option(\"--project <path>\", \"Project path\")\n .action((amount: string, opts) => {\n const manager = new BudgetManager();\n const projectPath = opts.project || process.cwd();\n const amountNum = parseFloat(amount);\n\n if (isNaN(amountNum) || amountNum <= 0) {\n console.log(chalk.red(\"Budget amount must be a positive number.\"));\n process.exit(1);\n }\n\n manager.setBudget(projectPath, amountNum, opts.period);\n console.log(\n chalk.green(`Budget set: ${formatCost(amountNum)}/${opts.period} for ${projectPath}`),\n );\n manager.close();\n });\n\n budget\n .command(\"show\")\n .description(\"Show current project budget\")\n .option(\"--project <path>\", \"Project path\")\n .option(\"--json\", \"Output as JSON\")\n .action((opts) => {\n const manager = new BudgetManager();\n const projectPath = opts.project || process.cwd();\n const status = manager.checkBudget(projectPath);\n\n if (!status) {\n console.log(\"No budget set for this project. Use 'kerf-cli budget set <amount>' to set one.\");\n manager.close();\n return;\n }\n\n if (opts.json) {\n console.log(JSON.stringify(status, null, 2));\n manager.close();\n return;\n }\n\n const pct = status.percentUsed;\n const barWidth = 20;\n const filled = Math.round((Math.min(pct, 100) / 100) * barWidth);\n const empty = barWidth - filled;\n const color = pct < 50 ? \"green\" : pct < 80 ? \"yellow\" : \"red\";\n const barColor = color === \"green\" ? chalk.green : color === \"yellow\" ? chalk.yellow : chalk.red;\n\n console.log(chalk.bold.cyan(\"\\n kerf-cli budget\\n\"));\n console.log(` Period: ${status.period} (${status.periodStart.slice(0, 10)} to ${status.periodEnd.slice(0, 10)})`);\n console.log(` Budget: ${formatCost(status.budget)}`);\n console.log(` Spent: ${barColor(formatCost(status.spent))}`);\n console.log(` ${barColor(\"[\" + \"\\u2588\".repeat(filled) + \"\\u2591\".repeat(empty) + \"]\")} ${pct.toFixed(1)}%`);\n\n if (status.isOverBudget) {\n console.log(chalk.red.bold(`\\n OVER BUDGET by ${formatCost(status.spent - status.budget)}`));\n }\n console.log();\n\n manager.close();\n });\n\n budget\n .command(\"list\")\n .description(\"List all project budgets\")\n .action(() => {\n const manager = new BudgetManager();\n const projects = manager.listProjects();\n\n if (projects.length === 0) {\n console.log(\"No projects with budgets. Use 'kerf-cli budget set <amount>' to set one.\");\n manager.close();\n return;\n }\n\n console.log(chalk.bold.cyan(\"\\n kerf-cli budget list\\n\"));\n for (const p of projects) {\n const budgetStr = p.budget ? `${formatCost(p.budget)}/${p.period}` : \"no budget\";\n const spentStr = p.spent > 0 ? ` (spent: ${formatCost(p.spent)})` : \"\";\n console.log(` ${chalk.bold(p.name)} — ${budgetStr}${spentStr}`);\n console.log(chalk.dim(` ${p.path}`));\n }\n console.log();\n\n manager.close();\n });\n\n budget\n .command(\"remove\")\n .description(\"Remove budget for current project\")\n .option(\"--project <path>\", \"Project path\")\n .action((opts) => {\n const manager = new BudgetManager();\n const projectPath = opts.project || process.cwd();\n const removed = manager.removeBudget(projectPath);\n\n if (removed) {\n console.log(chalk.green(\"Budget removed.\"));\n } else {\n console.log(\"No budget found for this project.\");\n }\n\n manager.close();\n });\n}\n","import dayjs from \"dayjs\";\nimport isoWeek from \"dayjs/plugin/isoWeek.js\";\nimport { basename } from \"node:path\";\nimport { initDatabase } from \"../db/schema.js\";\nimport { runMigrations } from \"../db/migrations.js\";\nimport { findJsonlFilesSync, parseSessionFile } from \"./parser.js\";\nimport { calculateMessageCost } from \"./costCalculator.js\";\nimport type { BudgetStatus } from \"../types/config.js\";\nimport type Database from \"better-sqlite3\";\n\ndayjs.extend(isoWeek);\n\ntype BudgetPeriod = \"daily\" | \"weekly\" | \"monthly\";\n\nexport class BudgetManager {\n private db: Database.Database;\n\n constructor(dbPath?: string) {\n this.db = initDatabase(dbPath);\n runMigrations(this.db);\n }\n\n private getOrCreateProject(projectPath: string): number {\n const name = basename(projectPath) || projectPath;\n const existing = this.db\n .prepare(\"SELECT id FROM projects WHERE path = ?\")\n .get(projectPath) as { id: number } | undefined;\n\n if (existing) return existing.id;\n\n const result = this.db\n .prepare(\"INSERT INTO projects (name, path) VALUES (?, ?)\")\n .run(name, projectPath);\n\n return Number(result.lastInsertRowid);\n }\n\n setBudget(projectPath: string, amount: number, period: BudgetPeriod): void {\n const projectId = this.getOrCreateProject(projectPath);\n this.db\n .prepare(\n `INSERT INTO budgets (project_id, amount_usd, period)\n VALUES (?, ?, ?)\n ON CONFLICT(project_id, period)\n DO UPDATE SET amount_usd = excluded.amount_usd`,\n )\n .run(projectId, amount, period);\n }\n\n getBudget(projectPath: string): { amount: number; period: BudgetPeriod } | null {\n const project = this.db\n .prepare(\"SELECT id FROM projects WHERE path = ?\")\n .get(projectPath) as { id: number } | undefined;\n\n if (!project) return null;\n\n const budget = this.db\n .prepare(\"SELECT amount_usd, period FROM budgets WHERE project_id = ? ORDER BY created_at DESC LIMIT 1\")\n .get(project.id) as { amount_usd: number; period: BudgetPeriod } | undefined;\n\n if (!budget) return null;\n return { amount: budget.amount_usd, period: budget.period };\n }\n\n recordUsage(\n projectPath: string,\n sessionId: string,\n tokensIn: number,\n tokensOut: number,\n costUsd: number,\n timestamp: string,\n ): void {\n const projectId = this.getOrCreateProject(projectPath);\n this.db\n .prepare(\n `INSERT OR IGNORE INTO usage_snapshots (project_id, session_id, tokens_in, tokens_out, cost_usd, timestamp)\n VALUES (?, ?, ?, ?, ?, ?)`,\n )\n .run(projectId, sessionId, tokensIn, tokensOut, costUsd, timestamp);\n }\n\n syncFromJsonl(projectPath: string): number {\n const projectName = basename(projectPath);\n const allFiles = findJsonlFilesSync();\n\n // Filter to files matching this project\n const encodedPath = projectPath.replace(/\\//g, \"-\");\n const filesToProcess = allFiles.filter(\n (f) => f.includes(projectName) || f.includes(encodeURIComponent(projectPath)) || f.includes(encodedPath),\n );\n if (filesToProcess.length === 0) return 0;\n\n let synced = 0;\n for (const file of filesToProcess) {\n try {\n const session = parseSessionFile(file);\n for (const msg of session.messages) {\n const cost = calculateMessageCost(msg);\n try {\n this.recordUsage(\n projectPath,\n session.sessionId,\n msg.usage.input_tokens,\n msg.usage.output_tokens,\n cost.totalCost,\n msg.timestamp,\n );\n synced++;\n } catch {\n // UNIQUE constraint — already synced\n }\n }\n } catch {\n continue;\n }\n }\n return synced;\n }\n\n getUsage(projectPath: string, period: BudgetPeriod): number {\n const project = this.db\n .prepare(\"SELECT id FROM projects WHERE path = ?\")\n .get(projectPath) as { id: number } | undefined;\n\n if (!project) return 0;\n\n const start = getPeriodStart(period);\n const result = this.db\n .prepare(\n `SELECT COALESCE(SUM(cost_usd), 0) as total\n FROM usage_snapshots\n WHERE project_id = ? AND timestamp >= ?`,\n )\n .get(project.id, start.toISOString()) as { total: number };\n\n return result.total;\n }\n\n checkBudget(projectPath: string): BudgetStatus | null {\n const budgetConfig = this.getBudget(projectPath);\n if (!budgetConfig) return null;\n\n // Sync latest JSONL data before checking\n this.syncFromJsonl(projectPath);\n\n const spent = this.getUsage(projectPath, budgetConfig.period);\n const remaining = Math.max(0, budgetConfig.amount - spent);\n const percentUsed = budgetConfig.amount > 0 ? (spent / budgetConfig.amount) * 100 : 0;\n\n const periodStart = getPeriodStart(budgetConfig.period);\n const periodEnd = getPeriodEnd(budgetConfig.period);\n\n return {\n budget: budgetConfig.amount,\n spent,\n remaining,\n percentUsed,\n isOverBudget: spent > budgetConfig.amount,\n period: budgetConfig.period,\n periodStart: periodStart.toISOString(),\n periodEnd: periodEnd.toISOString(),\n };\n }\n\n listProjects(): Array<{ name: string; path: string; budget: number | null; period: string | null; spent: number }> {\n const rows = this.db\n .prepare(\n `SELECT p.name, p.path, b.amount_usd, b.period\n FROM projects p\n LEFT JOIN budgets b ON b.project_id = p.id\n ORDER BY p.name`,\n )\n .all() as Array<{ name: string; path: string; amount_usd: number | null; period: string | null }>;\n\n return rows.map((row) => ({\n name: row.name,\n path: row.path,\n budget: row.amount_usd,\n period: row.period,\n spent: row.period ? this.getUsage(row.path, row.period as BudgetPeriod) : 0,\n }));\n }\n\n removeBudget(projectPath: string): boolean {\n const project = this.db\n .prepare(\"SELECT id FROM projects WHERE path = ?\")\n .get(projectPath) as { id: number } | undefined;\n\n if (!project) return false;\n\n const result = this.db.prepare(\"DELETE FROM budgets WHERE project_id = ?\").run(project.id);\n return result.changes > 0;\n }\n\n close(): void {\n this.db.close();\n }\n}\n\nfunction getPeriodStart(period: BudgetPeriod): dayjs.Dayjs {\n switch (period) {\n case \"daily\":\n return dayjs().startOf(\"day\");\n case \"weekly\":\n return dayjs().startOf(\"isoWeek\" as dayjs.OpUnitType);\n case \"monthly\":\n return dayjs().startOf(\"month\");\n }\n}\n\nfunction getPeriodEnd(period: BudgetPeriod): dayjs.Dayjs {\n switch (period) {\n case \"daily\":\n return dayjs().endOf(\"day\");\n case \"weekly\":\n return dayjs().endOf(\"isoWeek\" as dayjs.OpUnitType);\n case \"monthly\":\n return dayjs().endOf(\"month\");\n }\n}\n","import Database from \"better-sqlite3\";\nimport { mkdirSync, existsSync } from \"node:fs\";\nimport { dirname } from \"node:path\";\nimport { KERF_DB_PATH } from \"../core/config.js\";\n\nexport function initDatabase(dbPath?: string): Database.Database {\n const path = dbPath ?? KERF_DB_PATH;\n const dir = dirname(path);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n const db = new Database(path);\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"foreign_keys = ON\");\n\n createTables(db);\n return db;\n}\n\nfunction createTables(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS projects (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL,\n path TEXT NOT NULL UNIQUE,\n created_at TEXT NOT NULL DEFAULT (datetime('now'))\n );\n\n CREATE TABLE IF NOT EXISTS budgets (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n amount_usd REAL NOT NULL,\n period TEXT NOT NULL CHECK (period IN ('daily', 'weekly', 'monthly')),\n created_at TEXT NOT NULL DEFAULT (datetime('now')),\n UNIQUE(project_id, period)\n );\n\n CREATE TABLE IF NOT EXISTS usage_snapshots (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL REFERENCES projects(id) ON DELETE CASCADE,\n session_id TEXT NOT NULL,\n tokens_in INTEGER NOT NULL DEFAULT 0,\n tokens_out INTEGER NOT NULL DEFAULT 0,\n cost_usd REAL NOT NULL DEFAULT 0,\n timestamp TEXT NOT NULL,\n UNIQUE(project_id, session_id, timestamp)\n );\n\n CREATE INDEX IF NOT EXISTS idx_usage_project_time\n ON usage_snapshots(project_id, timestamp);\n `);\n}\n","import type Database from \"better-sqlite3\";\n\ninterface Migration {\n version: number;\n description: string;\n up: (db: Database.Database) => void;\n}\n\nconst migrations: Migration[] = [\n {\n version: 1,\n description: \"Initial schema\",\n up(_db) {\n // Schema is created in schema.ts on init — this is a placeholder for future migrations\n },\n },\n];\n\nexport function runMigrations(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS schema_migrations (\n version INTEGER PRIMARY KEY,\n applied_at TEXT NOT NULL DEFAULT (datetime('now'))\n )\n `);\n\n const applied = new Set(\n db\n .prepare(\"SELECT version FROM schema_migrations\")\n .all()\n .map((row: any) => row.version as number),\n );\n\n for (const migration of migrations) {\n if (!applied.has(migration.version)) {\n migration.up(db);\n db.prepare(\"INSERT INTO schema_migrations (version) VALUES (?)\").run(migration.version);\n }\n }\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { runFullAudit } from \"../../audit/recommendations.js\";\nimport { CONTEXT_WINDOW_SIZE } from \"../../core/config.js\";\n\nexport function registerAuditCommand(program: Command): void {\n program\n .command(\"audit\")\n .description(\"Ghost token & CLAUDE.md audit\")\n .option(\"--fix\", \"Auto-apply safe fixes\")\n .option(\"--claude-md-only\", \"Only audit CLAUDE.md\")\n .option(\"--mcp-only\", \"Only audit MCP servers\")\n .option(\"--json\", \"Output as JSON\")\n .action((opts) => {\n const result = runFullAudit();\n\n if (opts.json) {\n console.log(JSON.stringify(result, null, 2));\n return;\n }\n\n const gradeColor =\n result.grade === \"A\" ? chalk.green :\n result.grade === \"B\" ? chalk.yellow :\n chalk.red;\n\n console.log(chalk.bold.cyan(\"\\n kerf-cli audit report\\n\"));\n console.log(\n ` Context Window Health: ${gradeColor.bold(result.grade)} (${result.contextOverhead.percentUsable.toFixed(0)}% usable)\\n`,\n );\n\n // Ghost token breakdown — show unless --claude-md-only\n if (!opts.claudeMdOnly) {\n console.log(chalk.bold(\" Ghost Token Breakdown:\"));\n const oh = result.contextOverhead;\n const fmt = (label: string, tokens: number) => {\n const pct = ((tokens / CONTEXT_WINDOW_SIZE) * 100).toFixed(1);\n return ` ${label.padEnd(22)} ${tokens.toLocaleString().padStart(6)} tokens (${pct}%)`;\n };\n console.log(fmt(\"System prompt:\", oh.systemPrompt));\n console.log(fmt(\"Built-in tools:\", oh.builtInTools));\n console.log(fmt(`MCP tools (${result.mcpServers.length} srv):`, oh.mcpTools));\n console.log(fmt(\"CLAUDE.md:\", oh.claudeMd));\n console.log(fmt(\"Autocompact buffer:\", oh.autocompactBuffer));\n console.log(\" \" + \"-\".repeat(40));\n console.log(fmt(\"Total overhead:\", oh.totalOverhead));\n console.log(\n ` ${\"Effective window:\".padEnd(22)} ${oh.effectiveWindow.toLocaleString().padStart(6)} tokens (${oh.percentUsable.toFixed(1)}%)\\n`,\n );\n }\n\n // CLAUDE.md analysis — show unless --mcp-only\n if (!opts.mcpOnly && result.claudeMdAnalysis) {\n const cma = result.claudeMdAnalysis;\n console.log(chalk.bold(\" CLAUDE.md Analysis:\"));\n console.log(\n ` Lines: ${cma.totalLines}${cma.isOverLineLimit ? chalk.yellow(\" (over 200 limit)\") : \"\"}`,\n );\n console.log(` Tokens: ${cma.totalTokens.toLocaleString()}`);\n console.log(\n ` Critical rules in dead zone: ${cma.criticalRulesInDeadZone > 0 ? chalk.red(String(cma.criticalRulesInDeadZone)) : \"0\"}`,\n );\n\n if (opts.claudeMdOnly) {\n // Show per-section breakdown when claude-md-only\n console.log();\n console.log(chalk.bold(\" Sections:\"));\n for (const section of cma.sections) {\n const zone = section.attentionZone === \"low-middle\" ? chalk.red(\" [dead zone]\") : chalk.green(\" [high attention]\");\n const critical = section.hasCriticalRules ? chalk.yellow(\" *critical rules*\") : \"\";\n console.log(\n ` ${section.title.padEnd(30)} ${String(section.tokens).padStart(5)} tokens L${section.lineStart}-${section.lineEnd}${zone}${critical}`,\n );\n }\n\n if (cma.suggestedReorder.length > 0) {\n console.log();\n console.log(chalk.bold(\" Suggested section order:\"));\n cma.suggestedReorder.forEach((title, i) => {\n console.log(` ${i + 1}. ${title}`);\n });\n }\n }\n console.log();\n } else if (!opts.mcpOnly && !result.claudeMdAnalysis) {\n console.log(chalk.yellow(\" No CLAUDE.md found in current directory or git root.\\n\"));\n }\n\n // MCP details — show when --mcp-only\n if (opts.mcpOnly && result.mcpServers.length > 0) {\n console.log(chalk.bold(\" MCP Servers:\"));\n for (const server of result.mcpServers) {\n const heavy = server.isHeavy ? chalk.red(\" [heavy]\") : \"\";\n console.log(\n ` ${server.name.padEnd(20)} ${String(server.toolCount).padStart(3)} tools ${server.estimatedTokens.toLocaleString().padStart(6)} tokens${heavy}`,\n );\n }\n console.log();\n } else if (opts.mcpOnly && result.mcpServers.length === 0) {\n console.log(chalk.dim(\" No MCP servers configured.\\n\"));\n }\n\n // Recommendations — always show\n if (result.recommendations.length > 0) {\n const filteredRecs = opts.claudeMdOnly\n ? result.recommendations.filter((r) => r.category === \"claude-md\")\n : opts.mcpOnly\n ? result.recommendations.filter((r) => r.category === \"mcp\")\n : result.recommendations;\n\n if (filteredRecs.length > 0) {\n console.log(chalk.bold(\" Recommendations:\"));\n filteredRecs.forEach((rec, i) => {\n const priorityColor =\n rec.priority === \"high\" ? chalk.red :\n rec.priority === \"medium\" ? chalk.yellow :\n chalk.dim;\n console.log(\n ` ${i + 1}. ${priorityColor(`[${rec.priority.toUpperCase()}]`)} ${rec.action}`,\n );\n console.log(chalk.dim(` Impact: ${rec.impact}`));\n });\n }\n }\n console.log();\n\n if (opts.fix) {\n console.log(chalk.yellow(\" --fix: Auto-fix is not yet implemented. Coming in v0.2.0.\\n\"));\n }\n });\n}\n","import { estimateContextOverhead, analyzeMcpServers } from \"../core/tokenCounter.js\";\nimport { CONTEXT_WINDOW_SIZE } from \"../core/config.js\";\nimport type { ContextOverhead, McpServerInfo } from \"../types/config.js\";\n\nexport type ContextGrade = \"A\" | \"B\" | \"C\" | \"D\";\n\nexport interface GhostTokenReport {\n grade: ContextGrade;\n overhead: ContextOverhead;\n mcpServers: McpServerInfo[];\n percentUsable: number;\n breakdown: Array<{ label: string; tokens: number; percent: number }>;\n}\n\nexport function calculateGrade(percentUsable: number): ContextGrade {\n if (percentUsable >= 70) return \"A\";\n if (percentUsable >= 50) return \"B\";\n if (percentUsable >= 30) return \"C\";\n return \"D\";\n}\n\nexport function analyzeGhostTokens(claudeMdPath?: string): GhostTokenReport {\n const overhead = estimateContextOverhead(claudeMdPath);\n const mcpServers = analyzeMcpServers();\n const grade = calculateGrade(overhead.percentUsable);\n\n const breakdown = [\n { label: \"System prompt\", tokens: overhead.systemPrompt, percent: (overhead.systemPrompt / CONTEXT_WINDOW_SIZE) * 100 },\n { label: \"Built-in tools\", tokens: overhead.builtInTools, percent: (overhead.builtInTools / CONTEXT_WINDOW_SIZE) * 100 },\n { label: `MCP tools (${mcpServers.length} srv)`, tokens: overhead.mcpTools, percent: (overhead.mcpTools / CONTEXT_WINDOW_SIZE) * 100 },\n { label: \"CLAUDE.md\", tokens: overhead.claudeMd, percent: (overhead.claudeMd / CONTEXT_WINDOW_SIZE) * 100 },\n { label: \"Autocompact buffer\", tokens: overhead.autocompactBuffer, percent: (overhead.autocompactBuffer / CONTEXT_WINDOW_SIZE) * 100 },\n ];\n\n return {\n grade,\n overhead,\n mcpServers,\n percentUsable: overhead.percentUsable,\n breakdown,\n };\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { parseClaudeMdSections, findGitRootClaudeMd } from \"../core/tokenCounter.js\";\nimport type { ClaudeMdAnalysis, ClaudeMdSection } from \"../types/config.js\";\n\nconst CRITICAL_RULE_PATTERN = /\\b(NEVER|ALWAYS|MUST|IMPORTANT|CRITICAL)\\b/i;\nconst SKILL_CANDIDATES = /\\b(review|deploy|release|migration|template|boilerplate|scaffold)\\b/i;\nconst LINE_LIMIT = 200;\n\ntype AttentionZone = \"high-start\" | \"low-middle\" | \"high-end\";\n\nfunction getAttentionZone(position: number, total: number): AttentionZone {\n const pct = total > 0 ? position / total : 0;\n if (pct <= 0.3) return \"high-start\";\n if (pct >= 0.7) return \"high-end\";\n return \"low-middle\";\n}\n\nexport function lintClaudeMd(filePath?: string): ClaudeMdAnalysis | null {\n const paths = filePath\n ? [filePath]\n : [\n join(process.cwd(), \"CLAUDE.md\"),\n join(process.cwd(), \".claude\", \"CLAUDE.md\"),\n ...findGitRootClaudeMd(),\n join(homedir(), \".claude\", \"CLAUDE.md\"),\n ];\n\n let resolvedPath: string | null = null;\n for (const p of paths) {\n if (existsSync(p)) {\n resolvedPath = p;\n break;\n }\n }\n\n if (!resolvedPath) return null;\n\n const content = readFileSync(resolvedPath, \"utf-8\");\n const lines = content.split(\"\\n\");\n const totalLines = lines.length;\n const rawSections = parseClaudeMdSections(content);\n const totalTokens = rawSections.reduce((sum, s) => sum + s.tokens, 0);\n\n let criticalRulesInDeadZone = 0;\n const sectionsToSkill: string[] = [];\n\n const sections: ClaudeMdSection[] = rawSections.map((s) => {\n const midpoint = (s.lineStart + s.lineEnd) / 2;\n const attentionZone = getAttentionZone(midpoint, totalLines);\n const hasCriticalRules = CRITICAL_RULE_PATTERN.test(s.content);\n\n if (hasCriticalRules && attentionZone === \"low-middle\") {\n criticalRulesInDeadZone++;\n }\n\n if (SKILL_CANDIDATES.test(s.title) || SKILL_CANDIDATES.test(s.content)) {\n sectionsToSkill.push(s.title);\n }\n\n return {\n title: s.title,\n content: s.content,\n tokens: s.tokens,\n lineStart: s.lineStart,\n lineEnd: s.lineEnd,\n hasCriticalRules,\n attentionZone,\n };\n });\n\n // Generate suggested reordering: critical rules first, then normal, then verbose\n const critical = sections.filter((s) => s.hasCriticalRules);\n const normal = sections.filter((s) => !s.hasCriticalRules && s.tokens <= 500);\n const heavy = sections.filter((s) => !s.hasCriticalRules && s.tokens > 500);\n const suggestedReorder = [...critical, ...normal, ...heavy].map((s) => s.title);\n\n return {\n totalLines,\n totalTokens,\n sections,\n criticalRulesInDeadZone,\n isOverLineLimit: totalLines > LINE_LIMIT,\n suggestedReorder,\n };\n}\n","import { readFileSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { analyzeMcpServers } from \"../core/tokenCounter.js\";\nimport type { McpServerInfo } from \"../types/config.js\";\n\nexport interface McpAnalysis {\n servers: McpServerInfo[];\n totalTools: number;\n totalTokens: number;\n heavyServers: McpServerInfo[];\n hasToolSearch: boolean;\n effectiveTokens: number;\n recommendations: string[];\n}\n\nconst CLI_ALTERNATIVES: Record<string, string> = {\n playwright: \"Consider using the built-in Bash tool with playwright CLI instead\",\n puppeteer: \"Consider using the built-in Bash tool with puppeteer scripts\",\n filesystem: \"Claude Code has built-in file tools (Read, Write, Edit, Glob, Grep)\",\n github: \"Consider using 'gh' CLI via Bash tool instead\",\n slack: \"Consider using 'slack' CLI or curl for API calls\",\n};\n\nexport function analyzeMcp(): McpAnalysis {\n const servers = analyzeMcpServers();\n\n const totalTools = servers.reduce((sum, s) => sum + s.toolCount, 0);\n const totalTokens = servers.reduce((sum, s) => sum + s.estimatedTokens, 0);\n const heavyServers = servers.filter((s) => s.isHeavy);\n\n // Check if Tool Search is enabled (reduces overhead by ~85%)\n let hasToolSearch = false;\n const settingsPaths = [\n join(process.cwd(), \".claude\", \"settings.json\"),\n join(homedir(), \".claude\", \"settings.json\"),\n ];\n for (const sp of settingsPaths) {\n if (!existsSync(sp)) continue;\n try {\n const settings = JSON.parse(readFileSync(sp, \"utf-8\"));\n if (settings.enableToolSearch || settings.tool_search) {\n hasToolSearch = true;\n break;\n }\n } catch {\n continue;\n }\n }\n\n const effectiveTokens = hasToolSearch ? Math.round(totalTokens * 0.15) : totalTokens;\n\n const recommendations: string[] = [];\n for (const server of heavyServers) {\n recommendations.push(\n `'${server.name}' has ${server.toolCount} tools (${server.estimatedTokens.toLocaleString()} tokens). Consider enabling Tool Search to reduce overhead by ~85%.`,\n );\n }\n\n for (const server of servers) {\n const alt = CLI_ALTERNATIVES[server.name.toLowerCase()];\n if (alt) {\n recommendations.push(`${server.name}: ${alt}`);\n }\n }\n\n return {\n servers,\n totalTools,\n totalTokens,\n heavyServers,\n hasToolSearch,\n effectiveTokens,\n recommendations,\n };\n}\n","import { analyzeGhostTokens } from \"./ghostTokens.js\";\nimport { lintClaudeMd } from \"./claudeMdLinter.js\";\nimport { analyzeMcp } from \"./mcpAnalyzer.js\";\nimport type { AuditRecommendation, AuditResult } from \"../types/config.js\";\n\nexport function runFullAudit(claudeMdPath?: string): AuditResult {\n const ghostReport = analyzeGhostTokens(claudeMdPath);\n const claudeMdAnalysis = lintClaudeMd(claudeMdPath);\n const mcpAnalysis = analyzeMcp();\n\n const recommendations: AuditRecommendation[] = [];\n\n // CLAUDE.md recommendations\n if (claudeMdAnalysis) {\n if (claudeMdAnalysis.criticalRulesInDeadZone > 0) {\n recommendations.push({\n priority: \"high\",\n impact: \"improved rule adherence\",\n action: `Reorder CLAUDE.md — ${claudeMdAnalysis.criticalRulesInDeadZone} critical rule(s) in the low-attention dead zone (30-70% position). Move them to the top or bottom.`,\n category: \"claude-md\",\n });\n }\n\n if (claudeMdAnalysis.isOverLineLimit) {\n recommendations.push({\n priority: \"high\",\n impact: `${claudeMdAnalysis.totalLines - 200} lines over limit`,\n action: `CLAUDE.md is ${claudeMdAnalysis.totalLines} lines (limit: 200). Trim or move sections to skills.`,\n category: \"claude-md\",\n });\n }\n\n const heavySections = claudeMdAnalysis.sections.filter((s) => s.tokens > 500);\n for (const section of heavySections) {\n recommendations.push({\n priority: \"medium\",\n impact: `-${section.tokens} tokens/session`,\n action: `Move '${section.title}' section to a skill (${section.tokens} tokens — heavy section)`,\n category: \"claude-md\",\n });\n }\n }\n\n // MCP recommendations\n for (const server of mcpAnalysis.heavyServers) {\n recommendations.push({\n priority: \"medium\",\n impact: `-${server.estimatedTokens.toLocaleString()} tokens/session`,\n action: `MCP server '${server.name}' has ${server.toolCount} tools. Consider disabling if unused or enabling Tool Search.`,\n category: \"mcp\",\n });\n }\n\n if (!mcpAnalysis.hasToolSearch && mcpAnalysis.totalTools > 10) {\n recommendations.push({\n priority: \"high\",\n impact: `~${Math.round(mcpAnalysis.totalTokens * 0.85).toLocaleString()} tokens saved`,\n action: \"Enable Tool Search (deferred tool loading) to reduce MCP overhead by ~85%.\",\n category: \"mcp\",\n });\n }\n\n for (const rec of mcpAnalysis.recommendations) {\n if (rec.includes(\"CLI\")) {\n recommendations.push({\n priority: \"low\",\n impact: \"reduced token overhead\",\n action: rec,\n category: \"mcp\",\n });\n }\n }\n\n // Ghost token recommendations\n if (ghostReport.percentUsable < 50) {\n recommendations.push({\n priority: \"high\",\n impact: `only ${ghostReport.percentUsable.toFixed(0)}% usable`,\n action: `Context window health is poor (grade ${ghostReport.grade}). Total overhead: ${ghostReport.overhead.totalOverhead.toLocaleString()} tokens.`,\n category: \"ghost-tokens\",\n });\n }\n\n // Sort by priority\n const priorityOrder = { high: 0, medium: 1, low: 2 };\n recommendations.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);\n\n return {\n grade: ghostReport.grade,\n contextOverhead: ghostReport.overhead,\n claudeMdAnalysis,\n mcpServers: ghostReport.mcpServers,\n recommendations,\n };\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport dayjs from \"dayjs\";\nimport { parseSessionFile, findJsonlFiles } from \"../../core/parser.js\";\nimport {\n calculateMessageCost,\n aggregateCosts,\n formatCost,\n formatTokens,\n} from \"../../core/costCalculator.js\";\nimport { analyzeCacheUsage } from \"../../core/cacheAnalyzer.js\";\nimport type { ParsedMessage } from \"../../types/jsonl.js\";\n\nexport function registerReportCommand(program: Command): void {\n program\n .command(\"report\")\n .description(\"Historical cost reports\")\n .option(\"--period <period>\", \"Time period (today|week|month|all)\", \"today\")\n .option(\"-p, --project <path>\", \"Filter to specific project\")\n .option(\"--model\", \"Show per-model breakdown\")\n .option(\"--sessions\", \"Show per-session breakdown\")\n .option(\"--csv\", \"Export as CSV\")\n .option(\"--json\", \"Export as JSON\")\n .action(async (opts) => {\n const files = await findJsonlFiles(opts.project);\n\n if (files.length === 0) {\n console.log(\"No session data found. Start using Claude Code to generate data.\");\n return;\n }\n\n // Determine time filter\n const now = dayjs();\n let cutoff: dayjs.Dayjs;\n switch (opts.period) {\n case \"today\":\n cutoff = now.startOf(\"day\");\n break;\n case \"week\":\n cutoff = now.subtract(7, \"day\");\n break;\n case \"month\":\n cutoff = now.subtract(30, \"day\");\n break;\n case \"all\":\n cutoff = dayjs(\"2000-01-01\");\n break;\n default:\n cutoff = now.startOf(\"day\");\n }\n\n // Parse all sessions and collect messages\n const allMessages: ParsedMessage[] = [];\n const sessionSummaries: Array<{ id: string; model: string; cost: number; messages: number }> = [];\n\n for (const file of files) {\n try {\n const session = parseSessionFile(file);\n const filteredMessages = session.messages.filter((m) =>\n dayjs(m.timestamp).isAfter(cutoff),\n );\n if (filteredMessages.length === 0) continue;\n\n allMessages.push(...filteredMessages);\n\n const sessionCost = filteredMessages.reduce(\n (sum, m) => sum + calculateMessageCost(m).totalCost,\n 0,\n );\n sessionSummaries.push({\n id: session.sessionId,\n model: filteredMessages[0]?.model ?? \"unknown\",\n cost: sessionCost,\n messages: filteredMessages.length,\n });\n } catch {\n continue;\n }\n }\n\n if (allMessages.length === 0) {\n console.log(`No data found for period: ${opts.period}`);\n return;\n }\n\n // Calculate totals\n let totalCost = 0;\n let totalInput = 0;\n let totalOutput = 0;\n\n for (const msg of allMessages) {\n totalCost += calculateMessageCost(msg).totalCost;\n totalInput += msg.usage.input_tokens;\n totalOutput += msg.usage.output_tokens;\n }\n\n const cacheAnalysis = analyzeCacheUsage(allMessages);\n const cacheHitRate = cacheAnalysis.cacheHitRate;\n\n if (opts.json) {\n console.log(\n JSON.stringify(\n {\n period: opts.period,\n totalCost,\n totalInput,\n totalOutput,\n cacheHitRate,\n sessions: sessionSummaries,\n },\n null,\n 2,\n ),\n );\n return;\n }\n\n if (opts.csv) {\n console.log(\"session_id,model,cost_usd,messages\");\n for (const s of sessionSummaries) {\n console.log(`${s.id},${s.model},${s.cost.toFixed(4)},${s.messages}`);\n }\n return;\n }\n\n // Pretty print\n const periodLabel = opts.period === \"today\" ? now.format(\"ddd, MMM D, YYYY\") : opts.period;\n console.log(chalk.bold.cyan(`\\n kerf-cli report -- ${periodLabel}\\n`));\n console.log(` Total Cost: ${chalk.bold(formatCost(totalCost))}`);\n console.log(` Total Tokens: ${formatTokens(totalInput)} in / ${formatTokens(totalOutput)} out`);\n console.log(` Cache Hit Rate: ${cacheHitRate.toFixed(1)}%`);\n console.log(` Sessions: ${sessionSummaries.length}`);\n console.log();\n\n if (opts.model || opts.sessions) {\n // Model breakdown\n const byModel = new Map<string, { cost: number; sessions: number }>();\n for (const s of sessionSummaries) {\n const existing = byModel.get(s.model) ?? { cost: 0, sessions: 0 };\n existing.cost += s.cost;\n existing.sessions++;\n byModel.set(s.model, existing);\n }\n\n console.log(chalk.bold(\" Model Breakdown:\"));\n for (const [model, data] of byModel) {\n const pct = totalCost > 0 ? ((data.cost / totalCost) * 100).toFixed(1) : \"0\";\n const shortModel = model.replace(\"claude-\", \"\").replace(/-20\\d{6}$/, \"\");\n console.log(\n ` ${shortModel}: ${formatCost(data.cost)} (${pct}%) -- ${data.sessions} session(s)`,\n );\n }\n console.log();\n }\n\n if (opts.sessions) {\n console.log(chalk.bold(\" Session Breakdown:\"));\n for (const s of sessionSummaries.sort((a, b) => b.cost - a.cost)) {\n console.log(` ${s.id.slice(0, 12)} ${formatCost(s.cost)} ${s.messages} msgs [${s.model}]`);\n }\n console.log();\n }\n\n // Hourly breakdown\n const hourly = aggregateCosts(allMessages, \"hour\");\n if (hourly.length > 1) {\n console.log(chalk.bold(\" Hourly:\"));\n const maxCost = Math.max(...hourly.map((h) => h.totalCost));\n for (const h of hourly.slice(-8)) {\n const barLen = maxCost > 0 ? Math.round((h.totalCost / maxCost) * 12) : 0;\n const bar = \"\\u2588\".repeat(barLen) + \"\\u2591\".repeat(12 - barLen);\n console.log(` ${h.periodLabel.padEnd(14)} ${bar} ${formatCost(h.totalCost)}`);\n }\n console.log();\n }\n });\n}\n","import type { ParsedMessage } from \"../types/jsonl.js\";\n\nexport interface CacheAnalysis {\n totalCacheReads: number;\n totalCacheCreations: number;\n totalInputTokens: number;\n cacheHitRate: number;\n estimatedSavings: number;\n perMessageBreakdown: Array<{\n id: string;\n cacheRead: number;\n cacheCreation: number;\n input: number;\n hitRate: number;\n }>;\n}\n\n/**\n * Analyze prompt cache hit/miss patterns\n */\nexport function analyzeCacheUsage(messages: ParsedMessage[]): CacheAnalysis {\n let totalCacheReads = 0;\n let totalCacheCreations = 0;\n let totalInputTokens = 0;\n\n const perMessage = messages.map((msg) => {\n const cacheRead = msg.usage.cache_read_input_tokens;\n const cacheCreation = msg.usage.cache_creation_input_tokens;\n const input = msg.usage.input_tokens;\n\n totalCacheReads += cacheRead;\n totalCacheCreations += cacheCreation;\n totalInputTokens += input;\n\n const totalCacheable = cacheRead + cacheCreation + input;\n const hitRate = totalCacheable > 0 ? (cacheRead / totalCacheable) * 100 : 0;\n\n return {\n id: msg.id,\n cacheRead,\n cacheCreation,\n input,\n hitRate,\n };\n });\n\n const totalCacheable = totalCacheReads + totalCacheCreations + totalInputTokens;\n const cacheHitRate = totalCacheable > 0 ? (totalCacheReads / totalCacheable) * 100 : 0;\n\n // Estimated savings: cache reads cost ~10x less than full input\n const savingsMultiplier = 0.9; // 90% savings on cached tokens\n const estimatedSavings = totalCacheReads * savingsMultiplier;\n\n return {\n totalCacheReads,\n totalCacheCreations,\n totalInputTokens,\n cacheHitRate,\n estimatedSavings,\n perMessageBreakdown: perMessage,\n };\n}\n","import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport { mkdirSync, existsSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\nimport { initDatabase } from \"../../db/schema.js\";\nimport { runMigrations } from \"../../db/migrations.js\";\nimport { installHooks } from \"../../hooks/installer.js\";\n\nexport function registerInitCommand(program: Command): void {\n program\n .command(\"init\")\n .description(\"Set up kerf-cli for the current project\")\n .option(\"--global\", \"Install hooks globally\")\n .option(\"--hooks-only\", \"Only install hooks\")\n .option(\"--no-hooks\", \"Skip hook installation\")\n .option(\"--force\", \"Skip confirmation prompts\")\n .action(async (opts) => {\n console.log(chalk.bold.cyan(\"\\n Welcome to kerf-cli!\\n\"));\n console.log(\" Setting up cost intelligence for Claude Code...\\n\");\n\n // Create ~/.kerf/ directory\n const kerfDir = join(homedir(), \".kerf\");\n if (!existsSync(kerfDir)) {\n mkdirSync(kerfDir, { recursive: true });\n console.log(chalk.green(\" Created ~/.kerf/\"));\n }\n\n if (!opts.hooksOnly) {\n try {\n const db = initDatabase();\n runMigrations(db);\n db.close();\n console.log(chalk.green(\" Created ~/.kerf/kerf.db\"));\n } catch (err) {\n console.log(chalk.red(` Failed to create database: ${err}`));\n }\n }\n\n // Detect existing tools\n try {\n const { execSync } = await import(\"node:child_process\");\n try {\n execSync(\"which rtk\", { stdio: \"ignore\" });\n console.log(chalk.green(\" Detected RTK (command compression) -- compatible!\"));\n } catch { /* not installed */ }\n try {\n execSync(\"which ccusage\", { stdio: \"ignore\" });\n console.log(chalk.green(\" Detected ccusage -- will import historical data\"));\n } catch { /* not installed */ }\n } catch { /* ignore */ }\n\n // Install hooks\n if (opts.hooks !== false) {\n console.log(\"\\n Install hooks? These enable:\");\n console.log(\" - Real-time token tracking (Notification hook)\");\n console.log(\" - Budget enforcement (Stop hook)\");\n console.log(`\\n Hooks will be added to ${opts.global ? \"~/.claude\" : \".claude\"}/settings.json`);\n\n try {\n const result = installHooks({ global: opts.global, force: opts.force });\n for (const hook of result.installed) {\n console.log(chalk.green(` Installed ${hook} hook`));\n }\n for (const hook of result.skipped) {\n console.log(chalk.dim(` Skipped ${hook}`));\n }\n } catch (err) {\n console.log(chalk.yellow(`\\n Skipped hook installation: ${err}`));\n }\n }\n\n console.log(chalk.bold(\"\\n Recommended settings for your setup:\"));\n console.log(chalk.dim(' Add to .claude/settings.json or ~/.claude/settings.json:'));\n console.log(chalk.dim(JSON.stringify({\n env: {\n MAX_THINKING_TOKENS: \"10000\",\n CLAUDE_AUTOCOMPACT_PCT_OVERRIDE: \"50\",\n },\n }, null, 4).split(\"\\n\").map(l => \" \" + l).join(\"\\n\")));\n\n console.log(chalk.bold.cyan(\"\\n Run 'kerf-cli watch' to start the live dashboard!\\n\"));\n });\n}\n","import { existsSync, readFileSync, writeFileSync, copyFileSync, mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport { homedir } from \"node:os\";\n\n// Embedded hook templates (avoids runtime file path issues after tsup bundling)\nconst NOTIFICATION_HOOK = `#!/bin/bash\n# kerf-cli notification hook\nKERF_LOG=\"\\${HOME}/.kerf/session-log.jsonl\"\nmkdir -p \"\\$(dirname \"\\$KERF_LOG\")\"\nINPUT=\\$(cat)\nTIMESTAMP=\\$(date -u +\"%Y-%m-%dT%H:%M:%SZ\")\nSESSION_ID=\\$(echo \"\\$INPUT\" | grep -o '\"session_id\"[[:space:]]*:[[:space:]]*\"[^\"]*\"' | head -1 | sed 's/.*: *\"//;s/\"//')\necho \"{\\\\\"timestamp\\\\\":\\\\\"\\$TIMESTAMP\\\\\",\\\\\"session_id\\\\\":\\\\\"\\$SESSION_ID\\\\\",\\\\\"event\\\\\":\\\\\"notification\\\\\",\\\\\"raw\\\\\":\\$INPUT}\" >> \"\\$KERF_LOG\"\n`;\n\nconst STOP_HOOK = `#!/bin/bash\n# kerf-cli stop hook — budget enforcement\nKERF_BIN=\\$(which kerf-cli 2>/dev/null || echo \"npx kerf-cli@latest\")\nBUDGET_CHECK=\\$(\\$KERF_BIN budget show --json 2>/dev/null)\nif [ \\$? -ne 0 ] || [ -z \"\\$BUDGET_CHECK\" ]; then\n exit 0\nfi\nPERCENT_USED=\\$(echo \"\\$BUDGET_CHECK\" | grep -o '\"percentUsed\"[[:space:]]*:[[:space:]]*[0-9.]*' | head -1 | sed 's/.*: *//')\nIS_OVER=\\$(echo \"\\$BUDGET_CHECK\" | grep -o '\"isOverBudget\"[[:space:]]*:[[:space:]]*\\\\(true\\\\|false\\\\)' | head -1 | sed 's/.*: *//')\nif [ \"\\$IS_OVER\" = \"true\" ]; then\n echo '{\"reason\":\"Budget exceeded. Run kerf-cli budget show for details.\"}'\n exit 0\nfi\nif [ -n \"\\$PERCENT_USED\" ]; then\n THRESHOLD=80\n OVER=\\$(echo \"\\$PERCENT_USED > \\$THRESHOLD\" | bc -l 2>/dev/null || echo \"0\")\n if [ \"\\$OVER\" = \"1\" ]; then\n echo \"{\\\\\"reason\\\\\":\\\\\"Budget warning: \\$PERCENT_USED% used. Run kerf-cli budget show for details.\\\\\"}\"\n fi\nfi\nexit 0\n`;\n\ninterface HookConfig {\n matcher: string;\n hooks: Array<{ type: string; command: string }>;\n}\n\ninterface SettingsWithHooks {\n hooks?: Record<string, HookConfig[]>;\n [key: string]: unknown;\n}\n\nexport function installHooks(options: { global?: boolean; force?: boolean } = {}): {\n installed: string[];\n skipped: string[];\n settingsPath: string;\n} {\n const settingsPath = options.global\n ? join(homedir(), \".claude\", \"settings.json\")\n : join(process.cwd(), \".claude\", \"settings.json\");\n\n const dir = dirname(settingsPath);\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n let settings: SettingsWithHooks = {};\n if (existsSync(settingsPath)) {\n const backupPath = settingsPath + \".kerf-backup\";\n copyFileSync(settingsPath, backupPath);\n settings = JSON.parse(readFileSync(settingsPath, \"utf-8\"));\n }\n\n if (!settings.hooks) {\n settings.hooks = {};\n }\n\n const installed: string[] = [];\n const skipped: string[] = [];\n\n // Write hook scripts to ~/.kerf/hooks/\n const hooksDir = join(homedir(), \".kerf\", \"hooks\");\n if (!existsSync(hooksDir)) {\n mkdirSync(hooksDir, { recursive: true });\n }\n\n const notificationPath = join(hooksDir, \"notification.sh\");\n const stopPath = join(hooksDir, \"stop.sh\");\n\n writeFileSync(notificationPath, NOTIFICATION_HOOK, { mode: 0o755 });\n writeFileSync(stopPath, STOP_HOOK, { mode: 0o755 });\n\n // Notification hook\n if (!hasKerfHook(settings.hooks, \"Notification\")) {\n addHook(settings.hooks, \"Notification\", notificationPath);\n installed.push(\"Notification\");\n } else {\n skipped.push(\"Notification (already installed)\");\n }\n\n // Stop hook\n if (!hasKerfHook(settings.hooks, \"Stop\")) {\n addHook(settings.hooks, \"Stop\", stopPath);\n installed.push(\"Stop\");\n } else {\n skipped.push(\"Stop (already installed)\");\n }\n\n writeFileSync(settingsPath, JSON.stringify(settings, null, 2));\n return { installed, skipped, settingsPath };\n}\n\nfunction hasKerfHook(hooks: Record<string, HookConfig[]>, event: string): boolean {\n const eventHooks = hooks[event] ?? [];\n return eventHooks.some((h) => h.hooks.some((hh) => hh.command.includes(\"kerf\")));\n}\n\nfunction addHook(hooks: Record<string, HookConfig[]>, event: string, scriptPath: string): void {\n if (!hooks[event]) {\n hooks[event] = [];\n }\n hooks[event].push({\n matcher: \"\",\n hooks: [{ type: \"command\", command: `bash ${scriptPath}` }],\n });\n}\n"],"mappings":"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","names":["React","join","join","Box","Text","dayjs","dayjs","MILLION","dayjs","Box","Text","jsx","jsxs","readFileSync","join","homedir","join","readFileSync","homedir","jsx","jsxs","Box","Text","program","React","React","render","glob","execSync","Box","Text","jsx","jsxs","program","glob","estimate","render","React","chalk","dayjs","isoWeek","basename","existsSync","existsSync","dayjs","isoWeek","basename","program","chalk","chalk","readFileSync","existsSync","join","homedir","join","homedir","existsSync","readFileSync","readFileSync","existsSync","join","homedir","join","homedir","existsSync","readFileSync","program","chalk","chalk","dayjs","totalCacheable","program","dayjs","chalk","chalk","mkdirSync","existsSync","join","homedir","existsSync","readFileSync","mkdirSync","join","dirname","homedir","program","chalk","join","homedir","existsSync","mkdirSync","execSync"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kerf-cli",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "description": "Cost intelligence for Claude Code. Know before you spend.",
6
6
  "bin": {