aboutsummaryrefslogtreecommitdiff
path: root/modules/core/terminal.js
diff options
context:
space:
mode:
authorAgando <roduccomm@gmail.com>2026-06-24 06:01:05 +0200
committerAgando <roduccomm@gmail.com>2026-06-24 06:01:05 +0200
commitb08aa5b479395441462effed59ff1ee02d9d8c7f (patch)
tree91ff8aeb294b38cc07a63b31b224164aa971cac6 /modules/core/terminal.js
parent168a7bc6d50023215f75fa8a0d95362473cfe033 (diff)
auto: 2026-06-24_06:01 changes
Diffstat (limited to 'modules/core/terminal.js')
-rw-r--r--modules/core/terminal.js55
1 files changed, 55 insertions, 0 deletions
diff --git a/modules/core/terminal.js b/modules/core/terminal.js
index 2b41fd3..3abb074 100644
--- a/modules/core/terminal.js
+++ b/modules/core/terminal.js
@@ -1603,6 +1603,61 @@
}
return;
}
+ if (cmd === 'usage') {
+ const om = this.ollamaManager;
+ if (!om) { this.print('Ollama manager not available', 'error'); return; }
+ const filters = {};
+ for (let i = 0; i < args.length; i++) {
+ if (args[i] === '--json') { filters._json = true; }
+ else if (args[i] === '--reset') {
+ om._usageLog = [];
+ om._usageBuffer = [];
+ om._saveUsageLog();
+ this.print('Usage log cleared.', 'success');
+ return;
+ }
+ else if (args[i] === '--model' && args[i+1]) { filters.model = args[++i]; }
+ else if (args[i] === '--provider' && args[i+1]) { filters.provider = args[++i]; }
+ else if (args[i] === '--since' && args[i+1]) { filters.since_hours = parseFloat(args[++i]); }
+ }
+ const stats = om.getUsageStats(filters);
+ if (filters._json) {
+ this.print(JSON.stringify(stats, null, 2), '');
+ return;
+ }
+ if (stats.total === 0) {
+ this.print('No usage data recorded yet.', 'info');
+ return;
+ }
+ const fmt = (n) => n.toLocaleString();
+ const timeStr = stats.timeSpan < 60 ? stats.timeSpan + 's' :
+ stats.timeSpan < 3600 ? Math.round(stats.timeSpan / 60) + 'm' :
+ Math.round(stats.timeSpan / 3600) + 'h ' + Math.round((stats.timeSpan % 3600) / 60) + 'm';
+ this.print('╔══════════════════════════════════════════════════════╗', 'info');
+ this.print('║ LLM Usage Stats ║', 'info');
+ this.print('╠══════════════════════════════════════════════════════╣', 'info');
+ this.print(`║ Total requests: ${fmt(stats.total).padStart(30)} ║`, 'info');
+ this.print(`║ Total tokens: ${fmt(stats.totalPrompt + stats.totalCompletion).padStart(30)} ║`, 'info');
+ this.print(`║ Input: ${fmt(stats.totalPrompt).padStart(37)} ║`, 'info');
+ this.print(`║ Output: ${fmt(stats.totalCompletion).padStart(37)} ║`, 'info');
+ this.print(`║ Avg latency: ${(stats.avgLatency / 1000).toFixed(1) + 's'.padStart(30)} ║`, 'info');
+ this.print(`║ Time span: ${timeStr.padStart(30)} ║`, 'info');
+ this.print('╠══════════════════════════════════════════════════════╣', 'info');
+ this.print('║ Per model: ║', 'info');
+ for (const [model, data] of Object.entries(stats.byModel).sort((a, b) => b[1].requests - a[1].requests)) {
+ const label = (model.length > 30 ? model.slice(0, 27) + '...' : model).padEnd(30);
+ this.print(`║ ${label} ${fmt(data.requests).padStart(4)} req ${fmt(data.tokens).padStart(8)} tok ║`, '');
+ }
+ this.print('╠══════════════════════════════════════════════════════╣', 'info');
+ this.print('║ Per provider: ║', 'info');
+ for (const [prov, data] of Object.entries(stats.byProvider).sort((a, b) => b[1].requests - a[1].requests)) {
+ const label = (prov.length > 30 ? prov.slice(0, 27) + '...' : prov).padEnd(30);
+ this.print(`║ ${label} ${fmt(data.requests).padStart(4)} req ${fmt(data.tokens).padStart(8)} tok ║`, '');
+ }
+ this.print('╚══════════════════════════════════════════════════════╝', 'info');
+ this.print('Flags: --json, --model=<name>, --provider=<name>, --since=<hours>, --reset', 'text-muted');
+ return;
+ }
if (cmd === 'history') {
const entries = this.history;
if (!entries.length) { this.print('No command history.', 'info'); return; }