sigrank-mcp 0.6.4 → 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 +325 -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, readFileSync } 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,302 @@ 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 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
|
+
|
|
479
|
+
function tokenDashPillars() {
|
|
480
|
+
// query token-dashboard SQLite directly
|
|
481
|
+
const dbPath = path.join(os.homedir(), '.claude', 'token-dashboard.db')
|
|
482
|
+
if (!existsSync(dbPath)) return null
|
|
483
|
+
try {
|
|
484
|
+
const claudeFilter = `(model LIKE '%claude%' OR model LIKE '%fable%' OR model LIKE '%sonnet%' OR model LIKE '%opus%' OR model LIKE '%haiku%')`
|
|
485
|
+
const now = new Date()
|
|
486
|
+
const result = {}
|
|
487
|
+
for (const [win, days] of [['7d', 7], ['30d', 30], ['90d', 90]]) {
|
|
488
|
+
const since = new Date(now - days * 86400000).toISOString()
|
|
489
|
+
const cmd = `python3 -c "
|
|
490
|
+
import sqlite3, json
|
|
491
|
+
db = sqlite3.connect('${dbPath}')
|
|
492
|
+
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()
|
|
493
|
+
print(json.dumps({'input':r[0] or 0,'output':r[1] or 0,'cacheCreate':r[2] or 0,'cacheRead':r[3] or 0}))
|
|
494
|
+
"`
|
|
495
|
+
const raw = execSync(cmd, { timeout: 10000, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim()
|
|
496
|
+
result[win] = JSON.parse(raw)
|
|
497
|
+
}
|
|
498
|
+
// all-time
|
|
499
|
+
const cmd = `python3 -c "
|
|
500
|
+
import sqlite3, json
|
|
501
|
+
db = sqlite3.connect('${dbPath}')
|
|
502
|
+
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()
|
|
503
|
+
print(json.dumps({'input':r[0] or 0,'output':r[1] or 0,'cacheCreate':r[2] or 0,'cacheRead':r[3] or 0}))
|
|
504
|
+
"`
|
|
505
|
+
const raw = execSync(cmd, { timeout: 10000, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim()
|
|
506
|
+
result['all'] = JSON.parse(raw)
|
|
507
|
+
return result
|
|
508
|
+
} catch {
|
|
509
|
+
return null
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
function fmtDelta(a, b) {
|
|
514
|
+
if (a == null || b == null) return dim(' —')
|
|
515
|
+
const d = b - a
|
|
516
|
+
if (d === 0) return dim(' =')
|
|
517
|
+
const pct = a !== 0 ? `${d > 0 ? '+' : ''}${((d / a) * 100).toFixed(1)}%` : ''
|
|
518
|
+
const abs = `${d > 0 ? '+' : ''}${fmtTokens(Math.abs(d))}`
|
|
519
|
+
const label = `${abs} ${pct}`
|
|
520
|
+
return d > 0 ? green(label) : red(label)
|
|
521
|
+
}
|
|
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
|
+
|
|
549
|
+
async function runCompare({ platform = 'claude' } = {}) {
|
|
550
|
+
write(HIDE_CURSOR)
|
|
551
|
+
|
|
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
|
+
])
|
|
561
|
+
write(CURSOR_UP(1) + ERASE_LINE)
|
|
562
|
+
|
|
563
|
+
const w = termWidth()
|
|
564
|
+
const WINS = ['7d', '30d', '90d', 'all']
|
|
565
|
+
const WIN_LABEL = { '7d': '7d', '30d': '30d', '90d': '90d', 'all': 'all-time' }
|
|
566
|
+
|
|
567
|
+
// build tokenpull pillar lookup
|
|
568
|
+
const tpPillars = {}
|
|
569
|
+
for (const win of (tpData?.windows ?? [])) {
|
|
570
|
+
tpPillars[win.window] = win.pillars
|
|
571
|
+
}
|
|
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
|
+
|
|
582
|
+
writeln()
|
|
583
|
+
writeln(` ${gold('⊙ SigRank')} ${bold('5-Source Comparison')} ${dim(`platform: ${platform} · claude only`)}`)
|
|
584
|
+
writeln(` ${dim('─'.repeat(w - 4))}`)
|
|
585
|
+
|
|
586
|
+
// ── PILLARS TABLE ──────────────────────────────────────────────────────────
|
|
587
|
+
const PILLARS = [
|
|
588
|
+
{ key: 'input', label: 'Input' },
|
|
589
|
+
{ key: 'output', label: 'Output' },
|
|
590
|
+
{ key: 'cacheCreate', label: 'Cache Write' },
|
|
591
|
+
{ key: 'cacheRead', label: 'Cache Read' },
|
|
592
|
+
]
|
|
593
|
+
|
|
594
|
+
for (const { key, label } of PILLARS) {
|
|
595
|
+
writeln()
|
|
596
|
+
writeln(` ${bold(label)}`)
|
|
597
|
+
const hcols = [padEnd(dim('Source'), 14), ...WINS.map(win => padStart(dim(WIN_LABEL[win]), 13))]
|
|
598
|
+
writeln(` ${hcols.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(' ')}`)
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// ── SIGNATURE TABLE ────────────────────────────────────────────────────────
|
|
613
|
+
writeln()
|
|
614
|
+
writeln(` ${dim('─'.repeat(w - 4))}`)
|
|
615
|
+
writeln(` ${bold('Cascade Signature')} ${dim('per source · all windows where data available')}`)
|
|
616
|
+
writeln()
|
|
617
|
+
|
|
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 },
|
|
626
|
+
]
|
|
627
|
+
|
|
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)
|
|
668
|
+
})
|
|
669
|
+
writeln(` ${padEnd(srcLabel, 14)} ${padEnd(winLabel, 8)} ${sigCols.join(' ')}`)
|
|
670
|
+
first = false
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// ── NOTES ─────────────────────────────────────────────────────────────────
|
|
675
|
+
writeln()
|
|
676
|
+
writeln(` ${dim('─'.repeat(w - 4))}`)
|
|
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')}`)
|
|
682
|
+
writeln()
|
|
683
|
+
write(SHOW_CURSOR)
|
|
684
|
+
}
|
|
685
|
+
|
|
383
686
|
// ── WATCH command ─────────────────────────────────────────────────────────────
|
|
384
687
|
|
|
385
688
|
async function runWatch({ platform = 'claude', window: win = '7d', refresh = 30 } = {}) {
|
|
@@ -446,16 +749,17 @@ async function runWatch({ platform = 'claude', window: win = '7d', refresh = 30
|
|
|
446
749
|
|
|
447
750
|
function showHelp() {
|
|
448
751
|
writeln()
|
|
449
|
-
writeln(` ${gold('⊙ SigRank')} ${bold('CLI')} ${dim('v0.6.
|
|
752
|
+
writeln(` ${gold('⊙ SigRank')} ${bold('CLI')} ${dim('v0.6.5')}`)
|
|
450
753
|
writeln()
|
|
451
754
|
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
|
|
755
|
+
writeln(` ${cyan('board')} live leaderboard (refreshes every 30s)`)
|
|
756
|
+
writeln(` ${cyan('board --window 7d')} board for a specific window (7d, 30d, 90d, all_time)`)
|
|
757
|
+
writeln(` ${cyan('board --once')} print once and exit`)
|
|
758
|
+
writeln(` ${cyan('me')} your cascade across all 4 time windows`)
|
|
759
|
+
writeln(` ${cyan('me --platform amp')} use a different platform adapter`)
|
|
760
|
+
writeln(` ${cyan('me --compare')} raw pillar comparison: ccusage vs tokenpull vs token-dashboard`)
|
|
761
|
+
writeln(` ${cyan('watch')} live tune meter — re-reads local logs every 30s`)
|
|
762
|
+
writeln(` ${cyan('watch --window 7d')} watch a specific window`)
|
|
459
763
|
writeln()
|
|
460
764
|
writeln(` ${bold('Options')}`)
|
|
461
765
|
writeln(` ${dim('--window')} 7d · 30d · 90d · all_time (default: 30d for board, 7d for watch)`)
|
|
@@ -498,7 +802,7 @@ export async function runCli(argv) {
|
|
|
498
802
|
refresh: Number(flags.refresh) || 30,
|
|
499
803
|
})
|
|
500
804
|
} else if (cmd === 'me') {
|
|
501
|
-
await runMe({ platform: flags.platform ?? 'claude' })
|
|
805
|
+
await runMe({ platform: flags.platform ?? 'claude', compare: flags.compare === true || flags.compare === 'true' })
|
|
502
806
|
} else if (cmd === 'watch') {
|
|
503
807
|
await runWatch({
|
|
504
808
|
platform: flags.platform ?? 'claude',
|
|
@@ -508,7 +812,7 @@ export async function runCli(argv) {
|
|
|
508
812
|
} else if (cmd === '--help' || cmd === '-h' || cmd === 'help') {
|
|
509
813
|
showHelp()
|
|
510
814
|
} else if (cmd === '--version' || cmd === '-v') {
|
|
511
|
-
writeln('0.6.
|
|
815
|
+
writeln('0.6.5')
|
|
512
816
|
} else {
|
|
513
817
|
// unknown command: show help
|
|
514
818
|
showHelp()
|