opencode-token-tracker 1.6.1 → 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.
- package/dist/bin/opencode-tokens.js +60 -35
- package/package.json +1 -1
|
@@ -945,10 +945,16 @@ function cmdTrend(flags) {
|
|
|
945
945
|
console.log(`\n ${spark}\n`);
|
|
946
946
|
return;
|
|
947
947
|
}
|
|
948
|
-
// Build chart
|
|
948
|
+
// Build chart — pixel-based rendering
|
|
949
949
|
const cols = values.map((v) => ({ value: v, y: Math.round((v / maxVal) * (H - 1)) }));
|
|
950
950
|
const chartWidth = Math.max(width - 12, 20);
|
|
951
|
-
|
|
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
|
+
}
|
|
952
958
|
const yLabelStep = Math.max(1, Math.floor(H / 5));
|
|
953
959
|
const lines = [];
|
|
954
960
|
for (let row = H - 1; row >= 0; row--) {
|
|
@@ -959,56 +965,75 @@ function cmdTrend(flags) {
|
|
|
959
965
|
: "";
|
|
960
966
|
line += padLeft(label, 9);
|
|
961
967
|
line += row === 0 ? " ┼" : " ┤";
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
line += "╭";
|
|
970
|
-
else if (prevY > col.y && nextY >= col.y)
|
|
971
|
-
line += "╰";
|
|
972
|
-
else if (prevY < col.y || nextY < col.y)
|
|
973
|
-
line += "╭";
|
|
974
|
-
else if (prevY > col.y || nextY > col.y)
|
|
975
|
-
line += "╰";
|
|
976
|
-
else
|
|
977
|
-
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: "─" });
|
|
978
975
|
}
|
|
979
976
|
else {
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
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 });
|
|
984
993
|
}
|
|
985
994
|
}
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
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++;
|
|
994
1016
|
}
|
|
1017
|
+
line += c;
|
|
1018
|
+
prevX = x + 1;
|
|
995
1019
|
}
|
|
996
1020
|
lines.push(line);
|
|
997
1021
|
}
|
|
998
1022
|
// Bottom axis
|
|
999
1023
|
let axis = " ".repeat(9) + " └";
|
|
1000
|
-
axis += "─".repeat(
|
|
1024
|
+
axis += "─".repeat(chartWidth);
|
|
1001
1025
|
lines.push(axis);
|
|
1002
1026
|
// X axis labels
|
|
1003
1027
|
const labelStep = Math.max(1, Math.ceil(sorted.length / 6));
|
|
1004
1028
|
let xLabels = " ".repeat(11);
|
|
1005
|
-
for (let i = 0; i <
|
|
1006
|
-
if (i % labelStep === 0 || i ===
|
|
1029
|
+
for (let i = 0; i < px.length; i++) {
|
|
1030
|
+
if (i % labelStep === 0 || i === px.length - 1) {
|
|
1007
1031
|
const d = new Date(sorted[i][0]);
|
|
1008
1032
|
const ds = `${d.getMonth() + 1}/${d.getDate()}`;
|
|
1033
|
+
const pos = px[i] + 0;
|
|
1034
|
+
while (xLabels.length - 11 < pos)
|
|
1035
|
+
xLabels += " ";
|
|
1009
1036
|
xLabels += ds;
|
|
1010
|
-
if (i < cols.length - 1)
|
|
1011
|
-
xLabels += " ".repeat(Math.max(1, xStep - ds.length + 1));
|
|
1012
1037
|
}
|
|
1013
1038
|
}
|
|
1014
1039
|
lines.push(xLabels);
|
package/package.json
CHANGED