opencode-token-tracker 1.6.0 → 1.6.2

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.
@@ -534,13 +534,12 @@ function cmdConfig(positional) {
534
534
  console.log("\n Usage: opencode-tokens config get <key>\n");
535
535
  return;
536
536
  }
537
- const value = resolveConfigKey(config, key);
538
- if (value === undefined) {
537
+ if (!SETTABLE_KEYS[key]) {
539
538
  console.log(`\n Unknown key: ${key}\n Available: ${Object.keys(SETTABLE_KEYS).join(", ")}\n`);
539
+ return;
540
540
  }
541
- else {
542
- console.log(`\n ${key} = ${JSON.stringify(value)}\n`);
543
- }
541
+ const value = resolveConfigKey(config, key);
542
+ console.log(`\n ${key} = ${JSON.stringify(value)} (default: ${JSON.stringify(SETTABLE_KEYS[key].default)})\n`);
544
543
  return;
545
544
  }
546
545
  if (action === "set") {
@@ -946,10 +945,16 @@ function cmdTrend(flags) {
946
945
  console.log(`\n ${spark}\n`);
947
946
  return;
948
947
  }
949
- // Build chart
948
+ // Build chart — pixel-based rendering
950
949
  const cols = values.map((v) => ({ value: v, y: Math.round((v / maxVal) * (H - 1)) }));
951
950
  const chartWidth = Math.max(width - 12, 20);
952
- const xStep = Math.max(2, Math.floor(chartWidth / sorted.length));
951
+ // Map data points to pixel x-positions (evenly spaced across chartWidth)
952
+ const px = [];
953
+ const py = [];
954
+ for (let i = 0; i < cols.length; i++) {
955
+ px.push(cols.length === 1 ? Math.floor(chartWidth / 2) : Math.round((i / (cols.length - 1)) * (chartWidth - 1)));
956
+ py.push(cols[i].y);
957
+ }
953
958
  const yLabelStep = Math.max(1, Math.floor(H / 5));
954
959
  const lines = [];
955
960
  for (let row = H - 1; row >= 0; row--) {
@@ -960,56 +965,75 @@ function cmdTrend(flags) {
960
965
  : "";
961
966
  line += padLeft(label, 9);
962
967
  line += row === 0 ? " ┼" : " ┤";
963
- for (let ci = 0; ci < cols.length; ci++) {
964
- const col = cols[ci];
965
- const nextY = ci < cols.length - 1 ? cols[ci + 1].y : col.y;
966
- if (col.y === row) {
967
- if (ci > 0) {
968
- const prevY = cols[ci - 1].y;
969
- if (prevY < col.y && nextY <= col.y)
970
- line += "╭";
971
- else if (prevY > col.y && nextY >= col.y)
972
- line += "╰";
973
- else if (prevY < col.y || nextY < col.y)
974
- line += "╭";
975
- else if (prevY > col.y || nextY > col.y)
976
- line += "╰";
977
- else
978
- line += "─";
968
+ // Build a sparse array of characters at specific x-positions for this row
969
+ const chars = [];
970
+ // Data points that land on this row
971
+ for (let i = 0; i < px.length; i++) {
972
+ if (py[i] === row) {
973
+ if (cols.length === 1) {
974
+ chars.push({ x: px[i], c: "─" });
979
975
  }
980
976
  else {
981
- line += nextY > col.y ? "╭" : nextY < col.y ? "╰" : "─";
982
- }
983
- if (xStep > 1 && ci < cols.length - 1 && nextY === row) {
984
- line += "─".repeat(xStep - 1);
977
+ const prevSlope = i > 0 ? py[i] - py[i - 1] : 0;
978
+ const nextSlope = i < px.length - 1 ? py[i + 1] - py[i] : 0;
979
+ let c = "─";
980
+ if (i === 0)
981
+ c = nextSlope > 0 ? "╭" : nextSlope < 0 ? "╰" : "─";
982
+ else if (i === px.length - 1)
983
+ c = prevSlope > 0 ? "╮" : prevSlope < 0 ? "╯" : "─";
984
+ else if (prevSlope > 0 && nextSlope > 0)
985
+ c = "╭";
986
+ else if (prevSlope < 0 && nextSlope < 0)
987
+ c = "╰";
988
+ else if (prevSlope > 0 && nextSlope < 0)
989
+ c = "╮";
990
+ else if (prevSlope < 0 && nextSlope > 0)
991
+ c = "╯";
992
+ chars.push({ x: px[i], c });
985
993
  }
986
994
  }
987
- else if (ci > 0 && ci < cols.length) {
988
- const prevY = cols[ci - 1].y;
989
- if ((prevY < row && col.y > row) || (prevY > row && col.y < row)) {
990
- line += prevY < col.y ? "╱" : "╲";
991
- }
992
- else {
993
- line += " ".repeat(xStep > 1 && nextY !== row ? 1 : Math.min(xStep, 1));
994
- }
995
+ }
996
+ // Line segments crossing this row (exact x of intersection)
997
+ for (let i = 1; i < px.length; i++) {
998
+ const y0 = py[i - 1], y1 = py[i];
999
+ // Skip if segment doesn't cross this row
1000
+ if ((y0 <= row && y1 <= row) || (y0 >= row && y1 >= row))
1001
+ continue;
1002
+ if (y0 === y1)
1003
+ continue;
1004
+ const t = (row - y0) / (y1 - y0);
1005
+ const cx = Math.round(px[i - 1] + t * (px[i] - px[i - 1]));
1006
+ const slope = y1 - y0;
1007
+ chars.push({ x: cx, c: slope > 0 ? "╱" : "╲" });
1008
+ }
1009
+ // Render the row: sort chars by x and fill gaps with spaces
1010
+ chars.sort((a, b) => a.x - b.x);
1011
+ let prevX = 0;
1012
+ for (const { x, c } of chars) {
1013
+ while (prevX < x) {
1014
+ line += " ";
1015
+ prevX++;
995
1016
  }
1017
+ line += c;
1018
+ prevX = x + 1;
996
1019
  }
997
1020
  lines.push(line);
998
1021
  }
999
1022
  // Bottom axis
1000
1023
  let axis = " ".repeat(9) + " └";
1001
- axis += "─".repeat(xStep * cols.length);
1024
+ axis += "─".repeat(chartWidth);
1002
1025
  lines.push(axis);
1003
1026
  // X axis labels
1004
1027
  const labelStep = Math.max(1, Math.ceil(sorted.length / 6));
1005
1028
  let xLabels = " ".repeat(11);
1006
- for (let i = 0; i < cols.length; i++) {
1007
- if (i % labelStep === 0 || i === cols.length - 1) {
1029
+ for (let i = 0; i < px.length; i++) {
1030
+ if (i % labelStep === 0 || i === px.length - 1) {
1008
1031
  const d = new Date(sorted[i][0]);
1009
1032
  const ds = `${d.getMonth() + 1}/${d.getDate()}`;
1033
+ const pos = px[i] + 0;
1034
+ while (xLabels.length - 11 < pos)
1035
+ xLabels += " ";
1010
1036
  xLabels += ds;
1011
- if (i < cols.length - 1)
1012
- xLabels += " ".repeat(Math.max(1, xStep - ds.length + 1));
1013
1037
  }
1014
1038
  }
1015
1039
  lines.push(xLabels);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-token-tracker",
3
- "version": "1.6.0",
3
+ "version": "1.6.2",
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",