sigrank-mcp 0.6.4 → 0.6.5
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/cli.mjs +243 -21
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -3,23 +3,28 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Commands (no external deps — pure Node.js ANSI escape codes):
|
|
5
5
|
*
|
|
6
|
-
* npx sigrank-mcp board
|
|
7
|
-
* npx sigrank-mcp board --window 7d
|
|
8
|
-
* npx sigrank-mcp board --once
|
|
9
|
-
* npx sigrank-mcp me
|
|
10
|
-
* npx sigrank-mcp me --platform amp
|
|
11
|
-
* npx sigrank-mcp
|
|
12
|
-
* npx sigrank-mcp watch
|
|
6
|
+
* npx sigrank-mcp board live leaderboard, refreshes every 30s
|
|
7
|
+
* npx sigrank-mcp board --window 7d board for a specific window
|
|
8
|
+
* npx sigrank-mcp board --once print once and exit (no live refresh)
|
|
9
|
+
* npx sigrank-mcp me your cascade across all 4 windows
|
|
10
|
+
* npx sigrank-mcp me --platform amp use a different platform adapter
|
|
11
|
+
* npx sigrank-mcp me --compare raw pillar comparison: ccusage vs tokenpull vs token-dashboard
|
|
12
|
+
* npx sigrank-mcp watch RT tune meter — local cascade, refreshes
|
|
13
|
+
* npx sigrank-mcp watch --window 7d watch a specific window
|
|
13
14
|
*
|
|
14
15
|
* Color palette mirrors the SigRank web dark theme:
|
|
15
16
|
* gold = class TRANSMITTER headline + rank #1
|
|
16
17
|
* cyan = active metrics / your row highlight
|
|
17
18
|
* dim = secondary data, separators
|
|
18
|
-
* red = negative movement
|
|
19
|
+
* red = negative movement / delta
|
|
19
20
|
* green = positive movement
|
|
20
21
|
*/
|
|
21
22
|
|
|
22
23
|
import { callTool, DEFAULT_API_BASE } from './tools.mjs'
|
|
24
|
+
import { execSync } from 'child_process'
|
|
25
|
+
import { existsSync } from 'fs'
|
|
26
|
+
import os from 'os'
|
|
27
|
+
import path from 'path'
|
|
23
28
|
|
|
24
29
|
// ── ANSI helpers (no chalk dep) ────────────────────────────────────────────
|
|
25
30
|
const ESC = '\x1b['
|
|
@@ -283,10 +288,10 @@ async function runBoard({ window = '30d', once = false, refresh = 30 } = {}) {
|
|
|
283
288
|
|
|
284
289
|
// ── ME command ───────────────────────────────────────────────────────────────
|
|
285
290
|
|
|
286
|
-
async function runMe({ platform = 'claude' } = {}) {
|
|
291
|
+
async function runMe({ platform = 'claude', compare = false } = {}) {
|
|
292
|
+
if (compare) return runCompare({ platform })
|
|
293
|
+
|
|
287
294
|
write(HIDE_CURSOR)
|
|
288
|
-
writeln()
|
|
289
|
-
writeln(` ${gold('⊙ SigRank')} ${bold('Your Cascade')} ${dim(`platform: ${platform}`)}`)
|
|
290
295
|
writeln(` ${dim('reading local token logs…')}`)
|
|
291
296
|
|
|
292
297
|
let pulled
|
|
@@ -294,6 +299,7 @@ async function runMe({ platform = 'claude' } = {}) {
|
|
|
294
299
|
pulled = await callTool('tokenpull', { platform })
|
|
295
300
|
} catch (e) {
|
|
296
301
|
write(SHOW_CURSOR)
|
|
302
|
+
write(CURSOR_UP(1) + ERASE_LINE)
|
|
297
303
|
writeln(red(` ✗ ${e.message}`))
|
|
298
304
|
process.exit(1)
|
|
299
305
|
}
|
|
@@ -302,6 +308,7 @@ async function runMe({ platform = 'claude' } = {}) {
|
|
|
302
308
|
write(CURSOR_UP(1) + ERASE_LINE)
|
|
303
309
|
|
|
304
310
|
const w = termWidth()
|
|
311
|
+
writeln()
|
|
305
312
|
writeln(` ${gold('⊙ SigRank')} ${bold('Your Cascade')} ${dim(`platform: ${pulled.platform ?? platform}`)}`)
|
|
306
313
|
if (pulled.estimated) writeln(` ${dim('⚠ estimated values (cache data unavailable for this platform)')}`)
|
|
307
314
|
writeln(` ${dim('─'.repeat(w - 4))}`)
|
|
@@ -380,6 +387,220 @@ async function runMe({ platform = 'claude' } = {}) {
|
|
|
380
387
|
write(SHOW_CURSOR)
|
|
381
388
|
}
|
|
382
389
|
|
|
390
|
+
// ── COMPARE command ───────────────────────────────────────────────────────────
|
|
391
|
+
// Side-by-side: ccusage (JSON) vs tokenpull vs token-dashboard (SQLite)
|
|
392
|
+
|
|
393
|
+
function ccusagePillars(platform = 'claude') {
|
|
394
|
+
// ccusage <platform> daily --json → sum by window
|
|
395
|
+
try {
|
|
396
|
+
const cmd = platform === 'claude' ? 'ccusage claude daily --json' : `ccusage ${platform} daily --json`
|
|
397
|
+
const raw = execSync(cmd, { timeout: 15000, stdio: ['ignore', 'pipe', 'ignore'] }).toString()
|
|
398
|
+
const data = JSON.parse(raw)
|
|
399
|
+
const rows = data.daily ?? data // ccusage may return {daily:[...]} or [...]
|
|
400
|
+
|
|
401
|
+
const now = Date.now()
|
|
402
|
+
const cutoff = { '7d': 7, '30d': 30, '90d': 90 }
|
|
403
|
+
const result = {}
|
|
404
|
+
|
|
405
|
+
for (const [win, days] of Object.entries(cutoff)) {
|
|
406
|
+
const since = new Date(now - days * 86400000)
|
|
407
|
+
let input = 0, output = 0, cacheCreate = 0, cacheRead = 0
|
|
408
|
+
for (const row of rows) {
|
|
409
|
+
const d = new Date(row.date ?? row.day ?? row.week ?? '1970-01-01')
|
|
410
|
+
if (d >= since) {
|
|
411
|
+
input += row.inputTokens ?? row.input_tokens ?? 0
|
|
412
|
+
output += row.outputTokens ?? row.output_tokens ?? 0
|
|
413
|
+
cacheCreate += row.cacheCreationTokens ?? row.cache_create_tokens ?? 0
|
|
414
|
+
cacheRead += row.cacheReadTokens ?? row.cache_read_tokens ?? 0
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
result[win] = { input, output, cacheCreate, cacheRead }
|
|
418
|
+
}
|
|
419
|
+
// all-time = sum everything
|
|
420
|
+
let input = 0, output = 0, cacheCreate = 0, cacheRead = 0
|
|
421
|
+
for (const row of rows) {
|
|
422
|
+
input += row.inputTokens ?? row.input_tokens ?? 0
|
|
423
|
+
output += row.outputTokens ?? row.output_tokens ?? 0
|
|
424
|
+
cacheCreate += row.cacheCreationTokens ?? row.cache_create_tokens ?? 0
|
|
425
|
+
cacheRead += row.cacheReadTokens ?? row.cache_read_tokens ?? 0
|
|
426
|
+
}
|
|
427
|
+
result['all'] = { input, output, cacheCreate, cacheRead }
|
|
428
|
+
return result
|
|
429
|
+
} catch {
|
|
430
|
+
return null
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function tokenDashPillars() {
|
|
435
|
+
// query token-dashboard SQLite directly
|
|
436
|
+
const dbPath = path.join(os.homedir(), '.claude', 'token-dashboard.db')
|
|
437
|
+
if (!existsSync(dbPath)) return null
|
|
438
|
+
try {
|
|
439
|
+
const claudeFilter = `(model LIKE '%claude%' OR model LIKE '%fable%' OR model LIKE '%sonnet%' OR model LIKE '%opus%' OR model LIKE '%haiku%')`
|
|
440
|
+
const now = new Date()
|
|
441
|
+
const result = {}
|
|
442
|
+
for (const [win, days] of [['7d', 7], ['30d', 30], ['90d', 90]]) {
|
|
443
|
+
const since = new Date(now - days * 86400000).toISOString()
|
|
444
|
+
const cmd = `python3 -c "
|
|
445
|
+
import sqlite3, json
|
|
446
|
+
db = sqlite3.connect('${dbPath}')
|
|
447
|
+
r = db.execute('''SELECT SUM(input_tokens),SUM(output_tokens),SUM(cache_create_5m_tokens+cache_create_1h_tokens),SUM(cache_read_tokens) FROM messages WHERE timestamp>=? AND ${claudeFilter}''',(('${since}',))).fetchone()
|
|
448
|
+
print(json.dumps({'input':r[0] or 0,'output':r[1] or 0,'cacheCreate':r[2] or 0,'cacheRead':r[3] or 0}))
|
|
449
|
+
"`
|
|
450
|
+
const raw = execSync(cmd, { timeout: 10000, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim()
|
|
451
|
+
result[win] = JSON.parse(raw)
|
|
452
|
+
}
|
|
453
|
+
// all-time
|
|
454
|
+
const cmd = `python3 -c "
|
|
455
|
+
import sqlite3, json
|
|
456
|
+
db = sqlite3.connect('${dbPath}')
|
|
457
|
+
r = db.execute('SELECT SUM(input_tokens),SUM(output_tokens),SUM(cache_create_5m_tokens+cache_create_1h_tokens),SUM(cache_read_tokens) FROM messages WHERE ${claudeFilter}').fetchone()
|
|
458
|
+
print(json.dumps({'input':r[0] or 0,'output':r[1] or 0,'cacheCreate':r[2] or 0,'cacheRead':r[3] or 0}))
|
|
459
|
+
"`
|
|
460
|
+
const raw = execSync(cmd, { timeout: 10000, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim()
|
|
461
|
+
result['all'] = JSON.parse(raw)
|
|
462
|
+
return result
|
|
463
|
+
} catch {
|
|
464
|
+
return null
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function fmtDelta(a, b) {
|
|
469
|
+
if (a == null || b == null) return dim(' —')
|
|
470
|
+
const d = b - a
|
|
471
|
+
if (d === 0) return dim(' =')
|
|
472
|
+
const pct = a !== 0 ? `${d > 0 ? '+' : ''}${((d / a) * 100).toFixed(1)}%` : ''
|
|
473
|
+
const abs = `${d > 0 ? '+' : ''}${fmtTokens(Math.abs(d))}`
|
|
474
|
+
const label = `${abs} ${pct}`
|
|
475
|
+
return d > 0 ? green(label) : red(label)
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
async function runCompare({ platform = 'claude' } = {}) {
|
|
479
|
+
write(HIDE_CURSOR)
|
|
480
|
+
writeln(` ${dim('reading ccusage…')}`)
|
|
481
|
+
const ccPillars = ccusagePillars(platform)
|
|
482
|
+
write(CURSOR_UP(1) + ERASE_LINE)
|
|
483
|
+
|
|
484
|
+
writeln(` ${dim('reading tokenpull…')}`)
|
|
485
|
+
let tpData
|
|
486
|
+
try { tpData = await callTool('tokenpull', { platform }) } catch { tpData = null }
|
|
487
|
+
write(CURSOR_UP(1) + ERASE_LINE)
|
|
488
|
+
|
|
489
|
+
writeln(` ${dim('reading token-dashboard…')}`)
|
|
490
|
+
const tdPillars = tokenDashPillars()
|
|
491
|
+
write(CURSOR_UP(1) + ERASE_LINE)
|
|
492
|
+
|
|
493
|
+
const w = termWidth()
|
|
494
|
+
const WINS = ['7d', '30d', '90d', 'all']
|
|
495
|
+
const WIN_LABEL = { '7d': '7d', '30d': '30d', '90d': '90d', 'all': 'all-time' }
|
|
496
|
+
|
|
497
|
+
// build tokenpull pillar lookup
|
|
498
|
+
const tpPillars = {}
|
|
499
|
+
for (const win of (tpData?.windows ?? [])) {
|
|
500
|
+
tpPillars[win.window] = win.pillars
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
writeln()
|
|
504
|
+
writeln(` ${gold('⊙ SigRank')} ${bold('Source Comparison')} ${dim(`platform: ${platform} · claude tokens only`)}`)
|
|
505
|
+
writeln(` ${dim('─'.repeat(w - 4))}`)
|
|
506
|
+
|
|
507
|
+
const PILLARS = [
|
|
508
|
+
{ key: 'input', label: 'Input' },
|
|
509
|
+
{ key: 'output', label: 'Output' },
|
|
510
|
+
{ key: 'cacheCreate', label: 'Cache Create' },
|
|
511
|
+
{ key: 'cacheRead', label: 'Cache Read' },
|
|
512
|
+
]
|
|
513
|
+
|
|
514
|
+
for (const { key, label } of PILLARS) {
|
|
515
|
+
writeln()
|
|
516
|
+
writeln(` ${bold(label)}`)
|
|
517
|
+
|
|
518
|
+
// header row
|
|
519
|
+
const hcols = [
|
|
520
|
+
padEnd(dim('Source'), 16),
|
|
521
|
+
...WINS.map(win => padStart(dim(WIN_LABEL[win]), 14))
|
|
522
|
+
]
|
|
523
|
+
writeln(` ${hcols.join(' ')}`)
|
|
524
|
+
writeln(` ${dim('·'.repeat(Math.min(w - 4, 16 + WINS.length * 16)))}`)
|
|
525
|
+
|
|
526
|
+
// ccusage row
|
|
527
|
+
if (ccPillars) {
|
|
528
|
+
const cols = [padEnd(cyan('ccusage'), 16), ...WINS.map(win => padStart(fmtTokens(ccPillars[win]?.[key] ?? 0), 14))]
|
|
529
|
+
writeln(` ${cols.join(' ')}`)
|
|
530
|
+
} else {
|
|
531
|
+
writeln(` ${padEnd(dim('ccusage'), 16)} ${dim('not found')}`)
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// tokenpull row
|
|
535
|
+
if (tpData) {
|
|
536
|
+
const cols = [padEnd(cyan('tokenpull'), 16), ...WINS.map(win => padStart(fmtTokens(tpPillars[win]?.[key] ?? 0), 14))]
|
|
537
|
+
writeln(` ${cols.join(' ')}`)
|
|
538
|
+
} else {
|
|
539
|
+
writeln(` ${padEnd(dim('tokenpull'), 16)} ${dim('not found')}`)
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// token-dashboard row
|
|
543
|
+
if (tdPillars) {
|
|
544
|
+
const cols = [padEnd(cyan('token-dash'), 16), ...WINS.map(win => padStart(fmtTokens(tdPillars[win]?.[key] ?? 0), 14))]
|
|
545
|
+
writeln(` ${cols.join(' ')}`)
|
|
546
|
+
} else {
|
|
547
|
+
writeln(` ${padEnd(dim('token-dash'), 16)} ${dim('not found — run: python3 ~/token-dashboard/cli.py scan')}`)
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
// delta row: tokenpull vs token-dash (the two most comparable)
|
|
551
|
+
if (tpData && tdPillars) {
|
|
552
|
+
const cols = [
|
|
553
|
+
padEnd(dim('Δ tp→td'), 16),
|
|
554
|
+
...WINS.map(win => {
|
|
555
|
+
const a = tpPillars[win]?.[key] ?? 0
|
|
556
|
+
const b = tdPillars[win]?.[key] ?? 0
|
|
557
|
+
return padStart(fmtDelta(a, b), 14)
|
|
558
|
+
})
|
|
559
|
+
]
|
|
560
|
+
writeln(` ${cols.join(' ')}`)
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
// SigRank cascade section
|
|
565
|
+
writeln()
|
|
566
|
+
writeln(` ${dim('─'.repeat(w - 4))}`)
|
|
567
|
+
writeln(` ${bold('SigRank Cascade')} ${dim('(tokenpull → cascade math)')}`)
|
|
568
|
+
writeln()
|
|
569
|
+
|
|
570
|
+
const CASCADE_ROWS = [
|
|
571
|
+
{ key: 'yield', label: 'Υ Yield', fmt: v => fmtYield(v) },
|
|
572
|
+
{ key: 'snr', label: 'SNR', fmt: v => fmtSNR(v) },
|
|
573
|
+
{ key: 'leverage', label: 'Leverage', fmt: v => `${fmtLev(v)}×` },
|
|
574
|
+
{ key: 'velocity', label: 'Velocity', fmt: v => v.toFixed(2) },
|
|
575
|
+
{ key: 'dev10x', label: '10xDEV', fmt: v => v.toFixed(2) },
|
|
576
|
+
{ key: 'class', label: 'Class', fmt: v => colorClass(v) },
|
|
577
|
+
]
|
|
578
|
+
|
|
579
|
+
const hcols = [padEnd(dim('Metric'), 12), ...WINS.map(win => padStart(dim(WIN_LABEL[win]), 12))]
|
|
580
|
+
writeln(` ${hcols.join(' ')}`)
|
|
581
|
+
writeln(` ${dim('·'.repeat(Math.min(w - 4, 12 + WINS.length * 14)))}`)
|
|
582
|
+
|
|
583
|
+
for (const { key, label, fmt } of CASCADE_ROWS) {
|
|
584
|
+
const cols = [
|
|
585
|
+
padEnd(dim(label), 12),
|
|
586
|
+
...WINS.map(win => {
|
|
587
|
+
const cas = tpPillars[win] ? (tpData?.windows?.find(w => w.window === win)?.cascade) : null
|
|
588
|
+
const v = cas?.[key]
|
|
589
|
+
return padStart(v != null ? fmt(v) : dim('—'), 12)
|
|
590
|
+
})
|
|
591
|
+
]
|
|
592
|
+
writeln(` ${cols.join(' ')}`)
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// estimated rank hint
|
|
596
|
+
writeln()
|
|
597
|
+
writeln(` ${dim('─'.repeat(w - 4))}`)
|
|
598
|
+
writeln(` ${dim('note: token-dash has longer history (SQLite); tokenpull reads live JSONL only')}`)
|
|
599
|
+
writeln(` ${dim('note: ccusage = primary pillar source (all agents); tokenpull = claude-only cascade input')}`)
|
|
600
|
+
writeln()
|
|
601
|
+
write(SHOW_CURSOR)
|
|
602
|
+
}
|
|
603
|
+
|
|
383
604
|
// ── WATCH command ─────────────────────────────────────────────────────────────
|
|
384
605
|
|
|
385
606
|
async function runWatch({ platform = 'claude', window: win = '7d', refresh = 30 } = {}) {
|
|
@@ -446,16 +667,17 @@ async function runWatch({ platform = 'claude', window: win = '7d', refresh = 30
|
|
|
446
667
|
|
|
447
668
|
function showHelp() {
|
|
448
669
|
writeln()
|
|
449
|
-
writeln(` ${gold('⊙ SigRank')} ${bold('CLI')} ${dim('v0.6.
|
|
670
|
+
writeln(` ${gold('⊙ SigRank')} ${bold('CLI')} ${dim('v0.6.5')}`)
|
|
450
671
|
writeln()
|
|
451
672
|
writeln(` ${bold('Commands')}`)
|
|
452
|
-
writeln(` ${cyan('board')}
|
|
453
|
-
writeln(` ${cyan('board --window 7d')}
|
|
454
|
-
writeln(` ${cyan('board --once')}
|
|
455
|
-
writeln(` ${cyan('me')}
|
|
456
|
-
writeln(` ${cyan('me --platform amp')}
|
|
457
|
-
writeln(` ${cyan('
|
|
458
|
-
writeln(` ${cyan('watch
|
|
673
|
+
writeln(` ${cyan('board')} live leaderboard (refreshes every 30s)`)
|
|
674
|
+
writeln(` ${cyan('board --window 7d')} board for a specific window (7d, 30d, 90d, all_time)`)
|
|
675
|
+
writeln(` ${cyan('board --once')} print once and exit`)
|
|
676
|
+
writeln(` ${cyan('me')} your cascade across all 4 time windows`)
|
|
677
|
+
writeln(` ${cyan('me --platform amp')} use a different platform adapter`)
|
|
678
|
+
writeln(` ${cyan('me --compare')} raw pillar comparison: ccusage vs tokenpull vs token-dashboard`)
|
|
679
|
+
writeln(` ${cyan('watch')} live tune meter — re-reads local logs every 30s`)
|
|
680
|
+
writeln(` ${cyan('watch --window 7d')} watch a specific window`)
|
|
459
681
|
writeln()
|
|
460
682
|
writeln(` ${bold('Options')}`)
|
|
461
683
|
writeln(` ${dim('--window')} 7d · 30d · 90d · all_time (default: 30d for board, 7d for watch)`)
|
|
@@ -498,7 +720,7 @@ export async function runCli(argv) {
|
|
|
498
720
|
refresh: Number(flags.refresh) || 30,
|
|
499
721
|
})
|
|
500
722
|
} else if (cmd === 'me') {
|
|
501
|
-
await runMe({ platform: flags.platform ?? 'claude' })
|
|
723
|
+
await runMe({ platform: flags.platform ?? 'claude', compare: flags.compare === true || flags.compare === 'true' })
|
|
502
724
|
} else if (cmd === 'watch') {
|
|
503
725
|
await runWatch({
|
|
504
726
|
platform: flags.platform ?? 'claude',
|
|
@@ -508,7 +730,7 @@ export async function runCli(argv) {
|
|
|
508
730
|
} else if (cmd === '--help' || cmd === '-h' || cmd === 'help') {
|
|
509
731
|
showHelp()
|
|
510
732
|
} else if (cmd === '--version' || cmd === '-v') {
|
|
511
|
-
writeln('0.6.
|
|
733
|
+
writeln('0.6.5')
|
|
512
734
|
} else {
|
|
513
735
|
// unknown command: show help
|
|
514
736
|
showHelp()
|