opencode-token-tracker 1.5.2 → 1.5.3

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.
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { BUILTIN_PRICING, DEFAULT_CONFIG, findModelConfigPricing, formatCost, formatTokens, getStartOfDay, getStartOfWeek, getStartOfMonth, validateConfig } from "../lib/shared.js";
3
- import { readFileSync, existsSync, writeFileSync } from "fs";
3
+ import { readFileSync, existsSync, writeFileSync, openSync, readSync, closeSync, statSync } from "fs";
4
4
  import { join } from "path";
5
5
  import { homedir } from "os";
6
6
  const CONFIG_DIR = join(homedir(), ".config", "opencode");
@@ -22,25 +22,62 @@ function loadEntries(since) {
22
22
  if (!existsSync(LOG_FILE)) {
23
23
  return [];
24
24
  }
25
- const content = readFileSync(LOG_FILE, "utf-8");
26
- const lines = content.trim().split("\n").filter(Boolean);
27
25
  const entries = [];
28
- for (const line of lines) {
29
- try {
30
- const entry = JSON.parse(line);
31
- if (entry.type !== "tokens")
32
- continue;
33
- if (since && entry._ts < since)
34
- continue;
35
- if (!entry.input && !entry.output)
26
+ const fd = openSync(LOG_FILE, "r");
27
+ const stat = statSync(LOG_FILE);
28
+ const fileSize = stat.size;
29
+ const CHUNK_SIZE = 64 * 1024; // 64KB chunks
30
+ const buffer = Buffer.alloc(CHUNK_SIZE);
31
+ let filePos = fileSize;
32
+ let leftover = "";
33
+ let shouldStop = false;
34
+ while (filePos > 0 && !shouldStop) {
35
+ const readLength = Math.min(CHUNK_SIZE, filePos);
36
+ filePos -= readLength;
37
+ readSync(fd, buffer, 0, readLength, filePos);
38
+ const chunkStr = buffer.toString("utf8", 0, readLength) + leftover;
39
+ const lines = chunkStr.split("\n");
40
+ // The leftmost line could be cut off, save it for the next chunk read to the left
41
+ leftover = lines[0];
42
+ // Iterate lines in reverse order (from end to start)
43
+ for (let i = lines.length - 1; i >= 1; i--) {
44
+ const line = lines[i].trim();
45
+ if (!line)
36
46
  continue;
37
- entries.push(entry);
47
+ try {
48
+ const entry = JSON.parse(line);
49
+ if (entry.type !== "tokens")
50
+ continue;
51
+ // Early break pruning: once we hit a record older than the threshold,
52
+ // we can safely stop reading earlier history thanks to monotonic time progression in JSONL.
53
+ if (since && entry._ts < since) {
54
+ shouldStop = true;
55
+ break;
56
+ }
57
+ if (!entry.input && !entry.output)
58
+ continue;
59
+ entries.push(entry);
60
+ }
61
+ catch {
62
+ // Skip malformed lines
63
+ }
64
+ }
65
+ }
66
+ // Include the very first line at the top
67
+ if (!shouldStop && leftover.trim()) {
68
+ try {
69
+ const entry = JSON.parse(leftover.trim());
70
+ if (entry.type === "tokens" && (!since || entry._ts >= since) && (entry.input || entry.output)) {
71
+ entries.push(entry);
72
+ }
38
73
  }
39
74
  catch {
40
- // Skip malformed lines
75
+ // Ignore
41
76
  }
42
77
  }
43
- return entries;
78
+ closeSync(fd);
79
+ // Re-establish original chronological order
80
+ return entries.reverse();
44
81
  }
45
82
  function loadConfig() {
46
83
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-token-tracker",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "description": "Real-time token usage and cost tracking plugin for OpenCode with Toast notifications and CLI stats",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",