@ekkos/cli 1.0.19 → 1.0.21
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.
|
@@ -697,6 +697,13 @@ async function launchDashboard(initialSessionName, jsonlPath, refreshMs) {
|
|
|
697
697
|
footerBox.left = H_PAD;
|
|
698
698
|
footerBox.width = contentWidth;
|
|
699
699
|
footerBox.height = layout.footer.height;
|
|
700
|
+
// Force blessed-contrib to re-render the chart canvas at the new dimensions
|
|
701
|
+
if (lastChartSeries) {
|
|
702
|
+
try {
|
|
703
|
+
tokenChart.setData(lastChartSeries);
|
|
704
|
+
}
|
|
705
|
+
catch { }
|
|
706
|
+
}
|
|
700
707
|
}
|
|
701
708
|
// Track geometry so we can re-anchor widgets even if tmux resize events are flaky
|
|
702
709
|
let lastLayoutW = screen.width || 0;
|
|
@@ -766,6 +773,7 @@ async function launchDashboard(initialSessionName, jsonlPath, refreshMs) {
|
|
|
766
773
|
// ── Update function ──
|
|
767
774
|
let lastFileSize = 0;
|
|
768
775
|
let lastData = null;
|
|
776
|
+
let lastChartSeries = null;
|
|
769
777
|
let lastScrollPerc = 0; // Preserve scroll position across updates
|
|
770
778
|
const debugLog = path.join(os.homedir(), '.ekkos', 'dashboard.log');
|
|
771
779
|
function dlog(msg) {
|
|
@@ -848,11 +856,12 @@ async function launchDashboard(initialSessionName, jsonlPath, refreshMs) {
|
|
|
848
856
|
const recent = data.turns.slice(-30);
|
|
849
857
|
if (recent.length >= 2) {
|
|
850
858
|
const x = recent.map(t => String(t.turn));
|
|
851
|
-
|
|
859
|
+
lastChartSeries = [
|
|
852
860
|
{ title: 'Rd', x, y: recent.map(t => Math.round(t.cacheRead / 1000)), style: { line: 'green' } },
|
|
853
861
|
{ title: 'Wr', x, y: recent.map(t => Math.round(t.cacheCreate / 1000)), style: { line: 'yellow' } },
|
|
854
862
|
{ title: 'Out', x, y: recent.map(t => Math.round(t.output / 1000)), style: { line: 'cyan' } },
|
|
855
|
-
]
|
|
863
|
+
];
|
|
864
|
+
tokenChart.setData(lastChartSeries);
|
|
856
865
|
}
|
|
857
866
|
}
|
|
858
867
|
catch (err) {
|
|
@@ -999,12 +1008,20 @@ async function launchDashboard(initialSessionName, jsonlPath, refreshMs) {
|
|
|
999
1008
|
*/
|
|
1000
1009
|
async function fetchAnthropicUsage() {
|
|
1001
1010
|
try {
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1011
|
+
let token = null;
|
|
1012
|
+
if (process.platform === 'darwin') {
|
|
1013
|
+
const { execSync } = require('child_process');
|
|
1014
|
+
const credsJson = execSync('security find-generic-password -s "Claude Code-credentials" -w', { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
1015
|
+
token = JSON.parse(credsJson)?.claudeAiOauth?.accessToken ?? null;
|
|
1016
|
+
}
|
|
1017
|
+
else if (process.platform === 'win32') {
|
|
1018
|
+
// Windows: Claude Code stores credentials in ~/.claude/.credentials.json
|
|
1019
|
+
const credsPath = path.join(os.homedir(), '.claude', '.credentials.json');
|
|
1020
|
+
if (fs.existsSync(credsPath)) {
|
|
1021
|
+
const creds = JSON.parse(fs.readFileSync(credsPath, 'utf-8'));
|
|
1022
|
+
token = creds?.claudeAiOauth?.accessToken ?? null;
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1008
1025
|
if (!token)
|
|
1009
1026
|
return null;
|
|
1010
1027
|
const resp = await fetch('https://api.anthropic.com/api/oauth/usage', {
|
|
@@ -1070,10 +1087,19 @@ async function launchDashboard(initialSessionName, jsonlPath, refreshMs) {
|
|
|
1070
1087
|
screen.on('resize', () => {
|
|
1071
1088
|
try {
|
|
1072
1089
|
ensureLayoutSynced();
|
|
1073
|
-
if (lastData)
|
|
1090
|
+
if (lastData) {
|
|
1074
1091
|
updateDashboard();
|
|
1075
|
-
|
|
1092
|
+
}
|
|
1093
|
+
else {
|
|
1094
|
+
// Even without data, re-apply chart series so the canvas redraws at new size
|
|
1095
|
+
if (lastChartSeries) {
|
|
1096
|
+
try {
|
|
1097
|
+
tokenChart.setData(lastChartSeries);
|
|
1098
|
+
}
|
|
1099
|
+
catch { }
|
|
1100
|
+
}
|
|
1076
1101
|
screen.render();
|
|
1102
|
+
}
|
|
1077
1103
|
}
|
|
1078
1104
|
catch (err) {
|
|
1079
1105
|
dlog(`Resize: ${err.message}`);
|
|
@@ -582,12 +582,19 @@ async function launchSwarmDashboard(launchTs, refreshMs) {
|
|
|
582
582
|
// ── Usage window (Anthropic OAuth) ──
|
|
583
583
|
async function fetchAnthropicUsage() {
|
|
584
584
|
try {
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
585
|
+
let token = null;
|
|
586
|
+
if (process.platform === 'darwin') {
|
|
587
|
+
const { execSync } = require('child_process');
|
|
588
|
+
const credsJson = execSync('security find-generic-password -s "Claude Code-credentials" -w', { encoding: 'utf-8', timeout: 5000 }).trim();
|
|
589
|
+
token = JSON.parse(credsJson)?.claudeAiOauth?.accessToken ?? null;
|
|
590
|
+
}
|
|
591
|
+
else if (process.platform === 'win32') {
|
|
592
|
+
const credsPath = path.join(os.homedir(), '.claude', '.credentials.json');
|
|
593
|
+
if (require('fs').existsSync(credsPath)) {
|
|
594
|
+
const creds = JSON.parse(require('fs').readFileSync(credsPath, 'utf-8'));
|
|
595
|
+
token = creds?.claudeAiOauth?.accessToken ?? null;
|
|
596
|
+
}
|
|
597
|
+
}
|
|
591
598
|
if (!token)
|
|
592
599
|
return null;
|
|
593
600
|
const resp = await fetch('https://api.anthropic.com/api/oauth/usage', {
|