"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var tracker_exports = {};
__export(tracker_exports, {
  TokenTracker: () => TokenTracker
});
module.exports = __toCommonJS(tracker_exports);
var fs = __toESM(require("fs"));
var path = __toESM(require("path"));
var crypto = __toESM(require("crypto"));
const TRACKER_DIR = ".kirograph";
const TRACKER_FILE = "token-savings.jsonl";
const MAX_RECORDS = 5e3;
class TokenTracker {
  constructor(projectRoot) {
    const dir = path.join(projectRoot, TRACKER_DIR);
    fs.mkdirSync(dir, { recursive: true });
    this.filePath = path.join(dir, TRACKER_FILE);
    this.sessionId = this.getOrCreateSessionId(dir);
  }
  getOrCreateSessionId(dir) {
    const sessionFile = path.join(dir, ".session-id");
    try {
      const existing = fs.readFileSync(sessionFile, "utf8").trim();
      if (existing) return existing;
    } catch {
    }
    const id = crypto.randomBytes(8).toString("hex");
    try {
      fs.writeFileSync(sessionFile, id, "utf8");
    } catch {
    }
    return id;
  }
  /**
   * Record a compression result.
   */
  record(command, originalTokens, compressedTokens, strategy, source = "exec") {
    const record = {
      timestamp: Date.now(),
      command: command.slice(0, 200),
      // Truncate long commands
      originalTokens,
      compressedTokens,
      strategy,
      sessionId: this.sessionId,
      source
    };
    try {
      fs.appendFileSync(this.filePath, JSON.stringify(record) + "\n", "utf8");
      this.maybeRotate();
    } catch {
    }
  }
  /**
   * Record a graph tool saving.
   * @param toolName - The MCP tool that was called
   * @param outputTokens - Actual tokens returned by the tool
   * @param naiveCost - Estimated tokens the agent would have used without the tool
   */
  recordGraphSaving(toolName, outputTokens, naiveCost) {
    this.record(toolName, naiveCost, outputTokens, `graph:${toolName}`, "graph");
  }
  /**
   * Record a memory tool saving.
   * @param toolName - The MCP tool that was called
   * @param outputTokens - Actual tokens returned by the tool
   * @param naiveCost - Estimated tokens the agent would have used without memory
   */
  recordMemorySaving(toolName, outputTokens, naiveCost) {
    this.record(toolName, naiveCost, outputTokens, `memory:${toolName}`, "memory");
  }
  /**
   * Record a docs tool saving.
   * @param toolName - The MCP tool that was called
   * @param outputTokens - Actual tokens returned by the tool
   * @param naiveCost - Estimated tokens the agent would have used without docs indexing
   */
  recordDocsSaving(toolName, outputTokens, naiveCost) {
    this.record(toolName, naiveCost, outputTokens, `docs:${toolName}`, "docs");
  }
  /**
   * Get aggregated statistics for a time period.
   */
  getStats(period) {
    const records = this.loadRecords(period);
    if (records.length === 0) {
      return {
        totalCommands: 0,
        totalOriginal: 0,
        totalCompressed: 0,
        totalSaved: 0,
        savingsPercent: 0,
        byFamily: {},
        recentCommands: [],
        bySource: { exec: { count: 0, saved: 0 }, graph: { count: 0, saved: 0 }, memory: { count: 0, saved: 0 }, docs: { count: 0, saved: 0 } }
      };
    }
    let totalOriginal = 0;
    let totalCompressed = 0;
    const byFamily = /* @__PURE__ */ new Map();
    const bySource = { exec: { count: 0, saved: 0 }, graph: { count: 0, saved: 0 }, memory: { count: 0, saved: 0 }, docs: { count: 0, saved: 0 } };
    for (const r of records) {
      totalOriginal += r.originalTokens;
      totalCompressed += r.compressedTokens;
      const family = this.extractFamily(r.strategy);
      const existing = byFamily.get(family) || { count: 0, totalOriginal: 0, totalCompressed: 0 };
      existing.count++;
      existing.totalOriginal += r.originalTokens;
      existing.totalCompressed += r.compressedTokens;
      byFamily.set(family, existing);
      const source = r.source || "exec";
      if (bySource[source]) {
        bySource[source].count++;
        bySource[source].saved += r.originalTokens - r.compressedTokens;
      } else {
        bySource.exec.count++;
        bySource.exec.saved += r.originalTokens - r.compressedTokens;
      }
    }
    const totalSaved = totalOriginal - totalCompressed;
    const savingsPercent = totalOriginal > 0 ? Math.round(totalSaved / totalOriginal * 100) : 0;
    const byFamilyObj = {};
    const sortedFamilies = [...byFamily.entries()].sort((a, b) => b[1].count - a[1].count);
    for (const [family, data] of sortedFamilies) {
      const familySaved = data.totalOriginal - data.totalCompressed;
      const familyPercent = data.totalOriginal > 0 ? Math.round(familySaved / data.totalOriginal * 100) : 0;
      byFamilyObj[family] = { count: data.count, savings: familyPercent };
    }
    const recentCommands = records.slice(-10).reverse().map((r) => ({
      command: r.command,
      savings: r.originalTokens > 0 ? Math.round((r.originalTokens - r.compressedTokens) / r.originalTokens * 100) : 0,
      timestamp: r.timestamp,
      source: r.source
    }));
    return {
      totalCommands: records.length,
      totalOriginal,
      totalCompressed,
      totalSaved,
      savingsPercent,
      byFamily: byFamilyObj,
      recentCommands,
      bySource
    };
  }
  /**
   * Get raw history for CLI display.
   */
  getHistory(limit = 20) {
    const records = this.loadRecords("all");
    return records.slice(-limit).reverse();
  }
  /**
   * Get daily breakdown for graph display.
   */
  getDailyBreakdown(days = 30) {
    const records = this.loadRecords("all");
    const now = Date.now();
    const cutoff = now - days * 24 * 60 * 60 * 1e3;
    const byDay = /* @__PURE__ */ new Map();
    for (const r of records) {
      if (r.timestamp < cutoff) continue;
      const date = new Date(r.timestamp).toISOString().slice(0, 10);
      const existing = byDay.get(date) || { commands: 0, saved: 0 };
      existing.commands++;
      existing.saved += r.originalTokens - r.compressedTokens;
      byDay.set(date, existing);
    }
    return [...byDay.entries()].sort((a, b) => a[0].localeCompare(b[0])).map(([date, data]) => ({ date, ...data }));
  }
  // ── Private ─────────────────────────────────────────────────────────────────
  loadRecords(period) {
    if (!fs.existsSync(this.filePath)) return [];
    let lines;
    try {
      lines = fs.readFileSync(this.filePath, "utf8").split("\n").filter((l) => l.trim());
    } catch {
      return [];
    }
    const records = [];
    for (const line of lines) {
      try {
        records.push(JSON.parse(line));
      } catch {
      }
    }
    const now = Date.now();
    switch (period) {
      case "session":
        return records.filter((r) => r.sessionId === this.sessionId);
      case "today": {
        const startOfDay = /* @__PURE__ */ new Date();
        startOfDay.setHours(0, 0, 0, 0);
        return records.filter((r) => r.timestamp >= startOfDay.getTime());
      }
      case "week":
        return records.filter((r) => r.timestamp >= now - 7 * 24 * 60 * 60 * 1e3);
      case "all":
        return records;
    }
  }
  extractFamily(strategy) {
    const colon = strategy.indexOf(":");
    return colon > 0 ? strategy.slice(0, colon) : strategy;
  }
  maybeRotate() {
    try {
      const stat = fs.statSync(this.filePath);
      if (stat.size > 500 * 1024) {
        const lines = fs.readFileSync(this.filePath, "utf8").split("\n").filter((l) => l.trim());
        if (lines.length > MAX_RECORDS) {
          const keep = lines.slice(-Math.floor(MAX_RECORDS / 2));
          fs.writeFileSync(this.filePath, keep.join("\n") + "\n", "utf8");
        }
      }
    } catch {
    }
  }
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  TokenTracker
});
//# sourceMappingURL=tracker.js.map
