sigrank-mcp 0.6.5 → 0.6.6
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 +163 -81
- package/package.json +1 -1
package/cli.mjs
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import { callTool, DEFAULT_API_BASE } from './tools.mjs'
|
|
24
24
|
import { execSync } from 'child_process'
|
|
25
|
-
import { existsSync } from 'fs'
|
|
25
|
+
import { existsSync, readFileSync } from 'fs'
|
|
26
26
|
import os from 'os'
|
|
27
27
|
import path from 'path'
|
|
28
28
|
|
|
@@ -431,6 +431,51 @@ function ccusagePillars(platform = 'claude') {
|
|
|
431
431
|
}
|
|
432
432
|
}
|
|
433
433
|
|
|
434
|
+
function tokscalePillars() {
|
|
435
|
+
// Read tokscale_report.json — claude client only, all-time only (no timestamps in export)
|
|
436
|
+
const reportPath = path.join(os.homedir(), 'tokscale_report.json')
|
|
437
|
+
if (!existsSync(reportPath)) return null
|
|
438
|
+
try {
|
|
439
|
+
const data = JSON.parse(readFileSync(reportPath, 'utf8'))
|
|
440
|
+
const entries = data.entries ?? []
|
|
441
|
+
const claude = entries.filter(e =>
|
|
442
|
+
e.client === 'claude' &&
|
|
443
|
+
e.model !== '<synthetic>' && e.model !== 'unknown' &&
|
|
444
|
+
e.provider !== 'unknown'
|
|
445
|
+
)
|
|
446
|
+
const p = claude.reduce((acc, e) => ({
|
|
447
|
+
input: acc.input + (e.input ?? 0),
|
|
448
|
+
output: acc.output + (e.output ?? 0),
|
|
449
|
+
cacheCreate: acc.cacheCreate + (e.cacheWrite ?? 0),
|
|
450
|
+
cacheRead: acc.cacheRead + (e.cacheRead ?? 0),
|
|
451
|
+
}), { input: 0, output: 0, cacheCreate: 0, cacheRead: 0 })
|
|
452
|
+
// tokscale export has no timestamps → only all-time available
|
|
453
|
+
return { all: p }
|
|
454
|
+
} catch { return null }
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
function appPillars() {
|
|
458
|
+
// App numbers from screenshots — all-time, per model (no cache fields)
|
|
459
|
+
// Hard-coded from 2026-06-23 screenshot capture (update when re-screenshotted)
|
|
460
|
+
return {
|
|
461
|
+
all: {
|
|
462
|
+
input: 6_378_000, // sum of all models: 5.6M + 102.1K + 92.9K + 130.3K + 418.9K + 33.5K
|
|
463
|
+
output: 38_682_400, // sum: 19.6M + 6.5M + 5.4M + 6.6M + 292.4K + 290.4K
|
|
464
|
+
cacheCreate: null, // not shown in App UI
|
|
465
|
+
cacheRead: null, // not shown in App UI
|
|
466
|
+
},
|
|
467
|
+
_note: 'App UI — all-time, per-model sum from screenshots 2026-06-23. No cache fields. Update when re-screenshotted.',
|
|
468
|
+
_perModel: [
|
|
469
|
+
{ model: 'claude-opus-4-8', input: 5_600_000, output: 19_600_000 },
|
|
470
|
+
{ model: 'claude-sonnet-4-5',input: 102_100, output: 6_500_000 },
|
|
471
|
+
{ model: 'claude-sonnet-4-6',input: 92_900, output: 5_400_000 },
|
|
472
|
+
{ model: 'claude-opus-4-7', input: 130_300, output: 6_600_000 },
|
|
473
|
+
{ model: 'claude-fable-5', input: 418_900, output: 292_400 },
|
|
474
|
+
{ model: 'claude-haiku-4-5', input: 33_500, output: 290_400 },
|
|
475
|
+
],
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
434
479
|
function tokenDashPillars() {
|
|
435
480
|
// query token-dashboard SQLite directly
|
|
436
481
|
const dbPath = path.join(os.homedir(), '.claude', 'token-dashboard.db')
|
|
@@ -475,19 +520,44 @@ function fmtDelta(a, b) {
|
|
|
475
520
|
return d > 0 ? green(label) : red(label)
|
|
476
521
|
}
|
|
477
522
|
|
|
523
|
+
// Compute cascade metrics from raw pillars (mirrors bridge.ts computeCascadeMetrics)
|
|
524
|
+
function cascadeFromPillars(p) {
|
|
525
|
+
if (!p) return null
|
|
526
|
+
const i = p.input ?? 0
|
|
527
|
+
const o = p.output ?? 0
|
|
528
|
+
const cw = p.cacheCreate ?? 0
|
|
529
|
+
const cr = p.cacheRead ?? 0
|
|
530
|
+
if (i === 0 && o === 0) return null
|
|
531
|
+
const safeI = Math.max(i, 1)
|
|
532
|
+
const total = i + o + cw + cr
|
|
533
|
+
const velocity = o / safeI
|
|
534
|
+
const leverage = cr / safeI
|
|
535
|
+
const yield_ = leverage * velocity
|
|
536
|
+
const snr = (i + o) > 0 ? o / (i + o) : 0
|
|
537
|
+
// dev10x = log10(T × C × R) — only when all four pillars present
|
|
538
|
+
let dev10x = null
|
|
539
|
+
if (cw > 0 && o > 0 && i > 0 && cr > 0) {
|
|
540
|
+
const T = o / i, C = cw / o, R = cr / cw
|
|
541
|
+
dev10x = Math.log10(T * C * R)
|
|
542
|
+
}
|
|
543
|
+
// efficiency = ((cr+cw+o)/i) / 4.0
|
|
544
|
+
const efficiency = ((cr + cw + o) / safeI) / 4.0
|
|
545
|
+
const cls = yield_ > 500 ? 'TRANSMITTER' : yield_ > 400 ? 'ARCH+' : yield_ > 300 ? 'ARCH' : yield_ > 150 ? 'POWER' : 'BASE'
|
|
546
|
+
return { yield: yield_, velocity, leverage, snr, dev10x, efficiency, class: cls, total }
|
|
547
|
+
}
|
|
548
|
+
|
|
478
549
|
async function runCompare({ platform = 'claude' } = {}) {
|
|
479
550
|
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
551
|
|
|
489
|
-
|
|
490
|
-
|
|
552
|
+
// Pull all five sources in parallel
|
|
553
|
+
writeln(` ${dim('reading all 5 sources…')}`)
|
|
554
|
+
const [ccPillars, tpData, tdPillars, tsPillars, apPillars] = await Promise.all([
|
|
555
|
+
Promise.resolve(ccusagePillars(platform)),
|
|
556
|
+
callTool('tokenpull', { platform }).catch(() => null),
|
|
557
|
+
Promise.resolve(tokenDashPillars()),
|
|
558
|
+
Promise.resolve(tokscalePillars()),
|
|
559
|
+
Promise.resolve(appPillars()),
|
|
560
|
+
])
|
|
491
561
|
write(CURSOR_UP(1) + ERASE_LINE)
|
|
492
562
|
|
|
493
563
|
const w = termWidth()
|
|
@@ -500,103 +570,115 @@ async function runCompare({ platform = 'claude' } = {}) {
|
|
|
500
570
|
tpPillars[win.window] = win.pillars
|
|
501
571
|
}
|
|
502
572
|
|
|
573
|
+
// sources: name, color, pillars-by-window, note
|
|
574
|
+
const SOURCES = [
|
|
575
|
+
{ name: 'tokenpull', color: cyan, pillars: tpPillars, note: 'JSONL deduped by msg id · canon source' },
|
|
576
|
+
{ name: 'ccusage', color: (s) => paint(c.green, s), pillars: ccPillars ?? {}, note: 'ccusage claude subcommand · monthly only' },
|
|
577
|
+
{ name: 'token-dash', color: (s) => paint(c.magenta,s), pillars: tdPillars ?? {}, note: 'SQLite — double-counts sessions · use with caution' },
|
|
578
|
+
{ name: 'tokscale', color: (s) => paint(c.blue, s), pillars: tsPillars ?? {}, note: 'all-time only · partial export (~5% of opus-4-8)' },
|
|
579
|
+
{ name: 'App', color: gold, pillars: apPillars ?? {}, note: 'screenshots 2026-06-23 · no cache fields · update manually' },
|
|
580
|
+
]
|
|
581
|
+
|
|
503
582
|
writeln()
|
|
504
|
-
writeln(` ${gold('⊙ SigRank')} ${bold('Source Comparison')} ${dim(`platform: ${platform} · claude
|
|
583
|
+
writeln(` ${gold('⊙ SigRank')} ${bold('5-Source Comparison')} ${dim(`platform: ${platform} · claude only`)}`)
|
|
505
584
|
writeln(` ${dim('─'.repeat(w - 4))}`)
|
|
506
585
|
|
|
586
|
+
// ── PILLARS TABLE ──────────────────────────────────────────────────────────
|
|
507
587
|
const PILLARS = [
|
|
508
588
|
{ key: 'input', label: 'Input' },
|
|
509
589
|
{ key: 'output', label: 'Output' },
|
|
510
|
-
{ key: 'cacheCreate', label: 'Cache
|
|
590
|
+
{ key: 'cacheCreate', label: 'Cache Write' },
|
|
511
591
|
{ key: 'cacheRead', label: 'Cache Read' },
|
|
512
592
|
]
|
|
513
593
|
|
|
514
594
|
for (const { key, label } of PILLARS) {
|
|
515
595
|
writeln()
|
|
516
596
|
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
|
-
]
|
|
597
|
+
const hcols = [padEnd(dim('Source'), 14), ...WINS.map(win => padStart(dim(WIN_LABEL[win]), 13))]
|
|
523
598
|
writeln(` ${hcols.join(' ')}`)
|
|
524
|
-
writeln(` ${dim('·'.repeat(Math.min(w - 4,
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
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(' ')}`)
|
|
599
|
+
writeln(` ${dim('·'.repeat(Math.min(w - 4, 14 + WINS.length * 15)))}`)
|
|
600
|
+
|
|
601
|
+
for (const src of SOURCES) {
|
|
602
|
+
const vals = WINS.map(win => {
|
|
603
|
+
const p = src.pillars[win]
|
|
604
|
+
const v = p?.[key]
|
|
605
|
+
if (v == null) return padStart(dim('—'), 13)
|
|
606
|
+
return padStart(fmtTokens(v), 13)
|
|
607
|
+
})
|
|
608
|
+
writeln(` ${padEnd(src.color(src.name), 14)} ${vals.join(' ')}`)
|
|
561
609
|
}
|
|
562
610
|
}
|
|
563
611
|
|
|
564
|
-
//
|
|
612
|
+
// ── SIGNATURE TABLE ────────────────────────────────────────────────────────
|
|
565
613
|
writeln()
|
|
566
614
|
writeln(` ${dim('─'.repeat(w - 4))}`)
|
|
567
|
-
writeln(` ${bold('
|
|
615
|
+
writeln(` ${bold('Cascade Signature')} ${dim('per source · all windows where data available')}`)
|
|
568
616
|
writeln()
|
|
569
617
|
|
|
570
|
-
const
|
|
571
|
-
{ key: 'yield',
|
|
572
|
-
{ key: '
|
|
573
|
-
{ key: 'leverage',
|
|
574
|
-
{ key: '
|
|
575
|
-
{ key: 'dev10x',
|
|
576
|
-
{ key: '
|
|
618
|
+
const SIG_METRICS = [
|
|
619
|
+
{ key: 'yield', label: 'Υ Yield', fmt: v => fmtYield(v), w: 9 },
|
|
620
|
+
{ key: 'velocity', label: 'Vel', fmt: v => v.toFixed(2), w: 6 },
|
|
621
|
+
{ key: 'leverage', label: 'Lev', fmt: v => `${fmtLev(v)}×`, w: 7 },
|
|
622
|
+
{ key: 'snr', label: 'SNR', fmt: v => fmtSNR(v), w: 6 },
|
|
623
|
+
{ key: 'dev10x', label: '10x', fmt: v => v.toFixed(2), w: 5 },
|
|
624
|
+
{ key: 'efficiency', label: 'Eff', fmt: v => v.toFixed(1), w: 6 },
|
|
625
|
+
{ key: 'class', label: 'Class', fmt: v => colorClass(v), w: 12 },
|
|
577
626
|
]
|
|
578
627
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
628
|
+
// header
|
|
629
|
+
const sigHdr = [
|
|
630
|
+
padEnd(dim('Source'), 14),
|
|
631
|
+
padEnd(dim('Window'), 8),
|
|
632
|
+
...SIG_METRICS.map(m => padStart(dim(m.label), m.w)),
|
|
633
|
+
]
|
|
634
|
+
writeln(` ${sigHdr.join(' ')}`)
|
|
635
|
+
writeln(` ${dim('·'.repeat(Math.min(w - 4, 80)))}`)
|
|
636
|
+
|
|
637
|
+
for (const src of SOURCES) {
|
|
638
|
+
const availWins = WINS.filter(win => src.pillars[win] != null)
|
|
639
|
+
if (availWins.length === 0) {
|
|
640
|
+
writeln(` ${padEnd(src.color(src.name), 14)} ${dim('no data')}`)
|
|
641
|
+
continue
|
|
642
|
+
}
|
|
643
|
+
let first = true
|
|
644
|
+
for (const win of availWins) {
|
|
645
|
+
const p = src.pillars[win]
|
|
646
|
+
// For tokenpull, use the pre-computed cascade from the tool if available
|
|
647
|
+
let cas
|
|
648
|
+
if (src.name === 'tokenpull') {
|
|
649
|
+
const tpWin = tpData?.windows?.find(ww => ww.window === win)
|
|
650
|
+
cas = tpWin?.cascade ? {
|
|
651
|
+
yield: tpWin.cascade.yield,
|
|
652
|
+
velocity: tpWin.cascade.velocity,
|
|
653
|
+
leverage: tpWin.cascade.leverage,
|
|
654
|
+
snr: tpWin.cascade.snr,
|
|
655
|
+
dev10x: tpWin.cascade.dev10x,
|
|
656
|
+
efficiency: null,
|
|
657
|
+
class: tpWin.cascade.class,
|
|
658
|
+
} : cascadeFromPillars(p)
|
|
659
|
+
} else {
|
|
660
|
+
cas = cascadeFromPillars(p)
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
const srcLabel = first ? src.color(src.name) : ' '.repeat(stripAnsi(src.name).length)
|
|
664
|
+
const winLabel = win === 'all' ? bold('all-time') : win
|
|
665
|
+
const sigCols = SIG_METRICS.map(m => {
|
|
666
|
+
const v = cas?.[m.key]
|
|
667
|
+
return padStart(v != null ? m.fmt(v) : dim('—'), m.w)
|
|
590
668
|
})
|
|
591
|
-
|
|
592
|
-
|
|
669
|
+
writeln(` ${padEnd(srcLabel, 14)} ${padEnd(winLabel, 8)} ${sigCols.join(' ')}`)
|
|
670
|
+
first = false
|
|
671
|
+
}
|
|
593
672
|
}
|
|
594
673
|
|
|
595
|
-
//
|
|
674
|
+
// ── NOTES ─────────────────────────────────────────────────────────────────
|
|
596
675
|
writeln()
|
|
597
676
|
writeln(` ${dim('─'.repeat(w - 4))}`)
|
|
598
|
-
|
|
599
|
-
|
|
677
|
+
for (const src of SOURCES) {
|
|
678
|
+
writeln(` ${src.color(src.name.padEnd(12))} ${dim(src.note)}`)
|
|
679
|
+
}
|
|
680
|
+
writeln(` ${dim('Eff = ((cacheRead+cacheWrite+output)/input)/4.0 vs AA baseline')}`)
|
|
681
|
+
writeln(` ${dim('App has no cache fields → Υ/Lev/Eff/10x unavailable from App source')}`)
|
|
600
682
|
writeln()
|
|
601
683
|
write(SHOW_CURSOR)
|
|
602
684
|
}
|