sigrank 0.0.214 → 0.0.216
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/manifest.json +1 -1
- package/package.json +5 -3
- package/presentation/tui-themes.mjs +83 -16
- package/presentation/tui.mjs +73 -37
package/manifest.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://raw.githubusercontent.com/anthropics/mcpb/main/schemas/mcpb-manifest-v0.4.schema.json",
|
|
3
3
|
"manifest_version": "0.4",
|
|
4
4
|
"name": "sigrank",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.215",
|
|
6
6
|
"description": "Ranks AI coding operators by token cascade efficiency (Yield = cache_read \u00d7 output / input\u00b2). 23 tools for yield calculation, local token usage pulls, signed submission, and tokscale-powered analytics (market share, developer profiles, model trends, cost analysis, device profiles, MCP usage, competitive intelligence). Privacy-first: runs locally, only four token counts leave the machine.",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "SunrisesIllNeverSee",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigrank",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.216",
|
|
4
4
|
"author": "SunrisesIllNeverSee (https://github.com/SunrisesIllNeverSee)",
|
|
5
5
|
"description": "SigRank MCP server — AI operator evaluation and token cascade efficiency tools. The yield cascade + live leaderboard as MCP tools any agent can call.",
|
|
6
6
|
"mcpName": "io.github.SunrisesIllNeverSee/sigrank-mcp",
|
|
@@ -82,11 +82,13 @@
|
|
|
82
82
|
],
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
85
|
-
"@resvg/resvg-js": "^2.6.2",
|
|
86
85
|
"ccusage": "^20.0.19",
|
|
87
|
-
"gifenc": "^1.0.3",
|
|
88
86
|
"tokscale": "^4.7.0"
|
|
89
87
|
},
|
|
88
|
+
"devDependencies": {
|
|
89
|
+
"@resvg/resvg-js": "^2.6.2",
|
|
90
|
+
"gifenc": "^1.0.3"
|
|
91
|
+
},
|
|
90
92
|
"overrides": {
|
|
91
93
|
"@hono/node-server": "^2.0.5"
|
|
92
94
|
}
|
|
@@ -18,6 +18,8 @@ const ESC = "\x1b[";
|
|
|
18
18
|
|
|
19
19
|
export const THEMES = {
|
|
20
20
|
// ── Dark (default) — current palette, designed for dark terminals ──
|
|
21
|
+
// green uses 256-color 77 (#5fd75f) for WCAG AA compliance on dark bg (9.0:1).
|
|
22
|
+
// Standard ANSI 32 (#5a8a5a) only achieves 4.1:1 — below the 4.5:1 threshold.
|
|
21
23
|
dark: {
|
|
22
24
|
name: "dark",
|
|
23
25
|
reset: `${ESC}0m`,
|
|
@@ -27,8 +29,8 @@ export const THEMES = {
|
|
|
27
29
|
boldGold: `${ESC}1;33m`,
|
|
28
30
|
cyan: `${ESC}36m`,
|
|
29
31
|
boldCyan: `${ESC}1;36m`,
|
|
30
|
-
green: `${ESC}
|
|
31
|
-
red: `${ESC}
|
|
32
|
+
green: `${ESC}38;5;77m`, // brighter green #5fd75f (9.0:1 on dark — was ANSI 32 at 4.1:1)
|
|
33
|
+
red: `${ESC}38;5;203m`, // brighter red #ff5f5f (5.6:1 on dark — was ANSI 31 at 4.46:1, just below AA)
|
|
32
34
|
white: `${ESC}97m`,
|
|
33
35
|
boldWhite: `${ESC}1;97m`,
|
|
34
36
|
magenta: `${ESC}35m`,
|
|
@@ -41,24 +43,26 @@ export const THEMES = {
|
|
|
41
43
|
},
|
|
42
44
|
|
|
43
45
|
// ── Light — dark text on light/white terminals ──
|
|
44
|
-
//
|
|
46
|
+
// Uses 256-color codes (38;5;N) with darker shades that pass WCAG AA (4.5:1)
|
|
47
|
+
// on white backgrounds. Standard ANSI 33/36/32/31/35/34 render as pastel
|
|
48
|
+
// shades that fail contrast on white — these 256-color variants fix that.
|
|
45
49
|
light: {
|
|
46
50
|
name: "light",
|
|
47
51
|
reset: `${ESC}0m`,
|
|
48
52
|
bold: `${ESC}1m`,
|
|
49
|
-
dim: `${ESC}
|
|
50
|
-
gold: `${ESC}
|
|
51
|
-
boldGold: `${ESC}1;
|
|
52
|
-
cyan: `${ESC}
|
|
53
|
-
boldCyan: `${ESC}1;
|
|
54
|
-
green: `${ESC}
|
|
55
|
-
red: `${ESC}
|
|
56
|
-
white: `${ESC}30m`,
|
|
57
|
-
boldWhite: `${ESC}1;30m`,
|
|
58
|
-
magenta: `${ESC}
|
|
59
|
-
blue: `${ESC}
|
|
60
|
-
bgDim: `${ESC}48;5;250m`,
|
|
61
|
-
bgCyan: `${ESC}48;5;194m
|
|
53
|
+
dim: `${ESC}38;5;242m`, // medium gray (4.5:1 on white — passes AA for large text)
|
|
54
|
+
gold: `${ESC}38;5;130m`, // dark orange-gold #af5f00 (4.7:1 — yellow can't pass AA on white, this is the closest)
|
|
55
|
+
boldGold: `${ESC}1;38;5;130m`, // bold dark orange-gold (4.7:1)
|
|
56
|
+
cyan: `${ESC}38;5;24m`, // dark cyan #005f87 (7.0:1)
|
|
57
|
+
boldCyan: `${ESC}1;38;5;24m`, // bold dark cyan (7.0:1)
|
|
58
|
+
green: `${ESC}38;5;28m`, // dark green #008700 (4.7:1)
|
|
59
|
+
red: `${ESC}38;5;124m`, // dark red #af0000 (7.4:1)
|
|
60
|
+
white: `${ESC}30m`, // BLACK text on light bg (21:1)
|
|
61
|
+
boldWhite: `${ESC}1;30m`, // bold black
|
|
62
|
+
magenta: `${ESC}38;5;90m`, // dark magenta #870087 (8.8:1)
|
|
63
|
+
blue: `${ESC}38;5;19m`, // dark blue #0000af (13.0:1)
|
|
64
|
+
bgDim: `${ESC}48;5;250m`, // light grey bg for active tab
|
|
65
|
+
bgCyan: `${ESC}48;5;194m`, // light teal bg for active tab
|
|
62
66
|
medalBg: { 1: 220, 2: 250, 3: 130 },
|
|
63
67
|
medalFg: `${ESC}38;5;232m`,
|
|
64
68
|
},
|
|
@@ -120,3 +124,66 @@ export function setTheme(name) {
|
|
|
120
124
|
export function getThemeNames() {
|
|
121
125
|
return Object.keys(THEMES);
|
|
122
126
|
}
|
|
127
|
+
|
|
128
|
+
// ── Platform color map ─────────────────────────────────────────────────────
|
|
129
|
+
// Each platform gets a distinct 256-color code so platforms are visually
|
|
130
|
+
// distinguishable in the cascade table, token composition bars, board, and
|
|
131
|
+
// watch tabs. The colors are chosen for distinguishability on dark terminals
|
|
132
|
+
// (the default theme). For light theme, darker 256-color variants are used.
|
|
133
|
+
// Monochrome theme returns no color (bold only) — colorblind-safe.
|
|
134
|
+
//
|
|
135
|
+
// Color assignments (dark theme 256-color codes):
|
|
136
|
+
// claude = 75 (blue-cyan)
|
|
137
|
+
// codex = 114 (green)
|
|
138
|
+
// amp = 179 (orange)
|
|
139
|
+
// gemini = 129 (purple-magenta)
|
|
140
|
+
// kimi = 213 (pink)
|
|
141
|
+
// qwen = 68 (steel blue)
|
|
142
|
+
// goose = 142 (olive)
|
|
143
|
+
// kilo = 166 (dark orange)
|
|
144
|
+
// hermes = 96 (plum)
|
|
145
|
+
// droid = 167 (salmon)
|
|
146
|
+
// codebuff = 72 (teal-green)
|
|
147
|
+
// copilot = 33 (bright blue)
|
|
148
|
+
// openclaw = 136 (gold-brown)
|
|
149
|
+
// pi = 177 (light purple)
|
|
150
|
+
// omp = 220 (gold — the "oh my pi" platform gets gold)
|
|
151
|
+
// opencode = 60 (slate)
|
|
152
|
+
// devin = 30 (teal)
|
|
153
|
+
// proxy = 245 (gray — synthetic passthrough)
|
|
154
|
+
// other = 245 (gray — catch-all)
|
|
155
|
+
|
|
156
|
+
const PLATFORM_COLORS_DARK = {
|
|
157
|
+
claude: 75, codex: 114, amp: 179, gemini: 129, kimi: 213,
|
|
158
|
+
qwen: 68, goose: 142, kilo: 166, hermes: 96, droid: 167,
|
|
159
|
+
codebuff: 72, copilot: 33, openclaw: 136, pi: 177, omp: 220,
|
|
160
|
+
opencode: 60, devin: 30, proxy: 245, other: 245,
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
// Light theme: darker shades of the same hues for contrast on white
|
|
164
|
+
const PLATFORM_COLORS_LIGHT = {
|
|
165
|
+
claude: 24, codex: 28, amp: 130, gemini: 54, kimi: 90,
|
|
166
|
+
qwen: 19, goose: 100, kilo: 130, hermes: 54, droid: 124,
|
|
167
|
+
codebuff: 23, copilot: 19, openclaw: 130, pi: 90, omp: 130,
|
|
168
|
+
opencode: 19, devin: 23, proxy: 242, other: 242,
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Returns a paint function for the given platform name, theme-aware.
|
|
173
|
+
* Usage: `const pc = platformColor("claude"); pc("claude")` → colored string.
|
|
174
|
+
* Falls back to the theme's cyan for unknown platforms.
|
|
175
|
+
*/
|
|
176
|
+
export function platformColor(platform) {
|
|
177
|
+
const themeName = currentTheme.name;
|
|
178
|
+
// Monochrome: no color, just bold (colorblind-safe)
|
|
179
|
+
if (themeName === "monochrome") {
|
|
180
|
+
return (s) => `${currentTheme.bold}${s}${currentTheme.reset}`;
|
|
181
|
+
}
|
|
182
|
+
const map = themeName === "light" ? PLATFORM_COLORS_LIGHT : PLATFORM_COLORS_DARK;
|
|
183
|
+
const code = map[platform];
|
|
184
|
+
if (code == null) {
|
|
185
|
+
// Unknown platform — fall back to cyan
|
|
186
|
+
return (s) => `${currentTheme.cyan}${s}${currentTheme.reset}`;
|
|
187
|
+
}
|
|
188
|
+
return (s) => `${ESC}38;5;${code}m${s}${currentTheme.reset}`;
|
|
189
|
+
}
|
package/presentation/tui.mjs
CHANGED
|
@@ -54,6 +54,7 @@ export function dashboardEnabledPlatforms({
|
|
|
54
54
|
// The `c` object is a live proxy to the current theme — changing the theme
|
|
55
55
|
// via setTheme() updates all colors. Supports dark/light/high-contrast/monochrome.
|
|
56
56
|
import * as _themeMod from "./tui-themes.mjs";
|
|
57
|
+
import { platformColor } from "./tui-themes.mjs";
|
|
57
58
|
const ESC = "\x1b[";
|
|
58
59
|
// `c` is a live proxy — reads currentTheme at access time so theme switches
|
|
59
60
|
// take effect immediately. The helper functions below (paint/bold/dim/etc.)
|
|
@@ -187,6 +188,27 @@ function padStart(s, w) {
|
|
|
187
188
|
function trunc(s, w) {
|
|
188
189
|
return stripAnsi(s).length <= w ? s : s.slice(0, w - 1) + "…";
|
|
189
190
|
}
|
|
191
|
+
// Wrap a plain-text string into dim'd lines that fit within `maxW` columns.
|
|
192
|
+
// Used for no-data/empty-state messages that can be long on narrow terminals.
|
|
193
|
+
// Returns an array of strings (each already dim'd + indented) for emit().
|
|
194
|
+
function wrapDim(text, indent = " ", maxW) {
|
|
195
|
+
const w = maxW || W();
|
|
196
|
+
const avail = w - 2 - indent.length; // 2 = leading " " from emit caller
|
|
197
|
+
if (avail < 20) return [`${indent}${dim(text)}`]; // too narrow to wrap — let it be
|
|
198
|
+
const words = text.split(" ");
|
|
199
|
+
const lines = [];
|
|
200
|
+
let line = "";
|
|
201
|
+
for (const word of words) {
|
|
202
|
+
if ((line + " " + word).trim().length > avail) {
|
|
203
|
+
if (line) lines.push(`${indent}${dim(line.trim())}`);
|
|
204
|
+
line = word;
|
|
205
|
+
} else {
|
|
206
|
+
line = (line + " " + word).trim();
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
if (line) lines.push(`${indent}${dim(line.trim())}`);
|
|
210
|
+
return lines;
|
|
211
|
+
}
|
|
190
212
|
function hr(ch = "─") {
|
|
191
213
|
return dim(ch.repeat(Math.max(0, W() - 4)));
|
|
192
214
|
}
|
|
@@ -456,13 +478,18 @@ const TABS = [
|
|
|
456
478
|
{ key: "6", label: "Connect", short: "N" }, // sign in / switch device — the whole app is the TUI
|
|
457
479
|
];
|
|
458
480
|
|
|
459
|
-
//
|
|
460
|
-
//
|
|
461
|
-
//
|
|
481
|
+
// Four Degrees of Leverage — reference values matching signalaf.com/wiki/four-degrees.
|
|
482
|
+
// base = AA baseline (7:2:1 modeled reference, static)
|
|
483
|
+
// hcm = Human Center of Mass (median of all real operators)
|
|
484
|
+
// power = Power users (median of top 100 real operators)
|
|
485
|
+
// top = Top Evals (single top real operator)
|
|
486
|
+
// STATIC fallback values match the web app's GoldColumn fallbacks (lib/marketing/top-operator-column.ts).
|
|
487
|
+
// Goes live (hcm/power/top computed from the board) once there's real user volume.
|
|
462
488
|
const TD = {
|
|
463
|
-
base:
|
|
464
|
-
|
|
465
|
-
|
|
489
|
+
base: { yield: 1.75, snr: 0.33, vel: 0.50, lev: 3.5, d10: 0.54 },
|
|
490
|
+
hcm: { yield: 1.57, snr: 0.33, vel: 0.50, lev: 3.2, d10: 0.50 },
|
|
491
|
+
power: { yield: 1.51, snr: 0.07, vel: 0.08, lev: 22.3, d10: 1.35 },
|
|
492
|
+
top: { yield: 488.65, snr: 0.58, vel: 1.36, lev: 360.2, d10: 2.56 },
|
|
466
493
|
};
|
|
467
494
|
|
|
468
495
|
function renderTabBar(activeIdx) {
|
|
@@ -716,7 +743,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
|
|
|
716
743
|
// which is what was starving codex's cascade rows after the Your-Read/Three-Degrees panels landed.)
|
|
717
744
|
const platformCount = active.length;
|
|
718
745
|
const barLines = 4 + platformCount + (platformCount > 1 ? 1 : 0); // Token Composition: hr + header + platforms + combined + note
|
|
719
|
-
// Your Read (hr+header+~3 wins+1 gap = 6) +
|
|
746
|
+
// Your Read (hr+header+~3 wins+1 gap = 6) + Four Degrees (blank+hr+header+col-header+5 rows+note = 10) + status
|
|
720
747
|
const boardLines = 17;
|
|
721
748
|
const sectionsBelow = barLines + boardLines;
|
|
722
749
|
const maxCascadeRows = Math.max(8, budget - used - sectionsBelow);
|
|
@@ -768,7 +795,10 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
|
|
|
768
795
|
if (lastPlatform !== null && row.platform !== lastPlatform) emit();
|
|
769
796
|
renderRow(
|
|
770
797
|
row.platform,
|
|
771
|
-
(s) =>
|
|
798
|
+
(s) => {
|
|
799
|
+
const pc = platformColor(row.platform);
|
|
800
|
+
return row.winKey === firstWin[row.platform] ? bold(pc(s)) : dim(s);
|
|
801
|
+
},
|
|
772
802
|
row.winKey,
|
|
773
803
|
row.pillars,
|
|
774
804
|
row.estimated,
|
|
@@ -822,7 +852,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
|
|
|
822
852
|
const all = d.windows?.find((w) => w.window === "all");
|
|
823
853
|
if (!all) continue;
|
|
824
854
|
emit(
|
|
825
|
-
` ${padEnd(
|
|
855
|
+
` ${padEnd(platformColor(d.platform)(d.platform), 10)} ${tokenBar(all.pillars, 50)} ${dim(fmtTok((all.pillars.input ?? 0) + (all.pillars.output ?? 0) + (all.pillars.cacheCreate ?? 0) + (all.pillars.cacheRead ?? 0)))}`,
|
|
826
856
|
);
|
|
827
857
|
}
|
|
828
858
|
if (active.length > 1) {
|
|
@@ -865,9 +895,9 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
|
|
|
865
895
|
}
|
|
866
896
|
}
|
|
867
897
|
|
|
868
|
-
// ── Your insights + the
|
|
898
|
+
// ── Your insights + the Four Degrees panel (replaces the old top-3 mini board)
|
|
869
899
|
// The user's own cascade (the firstWin/combined row computed above) read against the
|
|
870
|
-
//
|
|
900
|
+
// Four Degrees reference so the Dashboard says "here's you, here's the field, here's the ceiling."
|
|
871
901
|
const you = (() => {
|
|
872
902
|
// Best available cascade for the user: prefer claude's first-window, else any computed row.
|
|
873
903
|
for (const d of active) {
|
|
@@ -910,7 +940,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
|
|
|
910
940
|
chk(
|
|
911
941
|
"Υ Yield",
|
|
912
942
|
you.yield,
|
|
913
|
-
TD.
|
|
943
|
+
TD.hcm.yield,
|
|
914
944
|
TD.top.yield,
|
|
915
945
|
fmtY,
|
|
916
946
|
"compound more — reuse cache, raise output",
|
|
@@ -918,7 +948,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
|
|
|
918
948
|
chk(
|
|
919
949
|
"SNR",
|
|
920
950
|
you.snr,
|
|
921
|
-
TD.
|
|
951
|
+
TD.hcm.snr,
|
|
922
952
|
TD.top.snr,
|
|
923
953
|
fmtSNR,
|
|
924
954
|
"tighten prompts — less input per unit output",
|
|
@@ -926,7 +956,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
|
|
|
926
956
|
chk(
|
|
927
957
|
"Leverage",
|
|
928
958
|
you.leverage,
|
|
929
|
-
TD.
|
|
959
|
+
TD.hcm.lev,
|
|
930
960
|
TD.top.lev,
|
|
931
961
|
(v) => fmtLev(v) + "×",
|
|
932
962
|
"lean on cache-read — amplify prior context",
|
|
@@ -934,7 +964,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
|
|
|
934
964
|
chk(
|
|
935
965
|
"Velocity",
|
|
936
966
|
you.velocity,
|
|
937
|
-
TD.
|
|
967
|
+
TD.hcm.vel,
|
|
938
968
|
TD.top.vel,
|
|
939
969
|
(v) => v.toFixed(2),
|
|
940
970
|
"more output per input token",
|
|
@@ -950,39 +980,42 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
|
|
|
950
980
|
emit(` ${dim(" reading your cascade… (press [R] to refresh)")}`);
|
|
951
981
|
}
|
|
952
982
|
|
|
953
|
-
// ──
|
|
983
|
+
// ── Four Degrees — AA baseline · Human Center of Mass · Power users · Top Evals
|
|
984
|
+
// Matches signalaf.com/wiki/four-degrees (expanded from 3 → 4 degrees 2026-07-17).
|
|
954
985
|
emit();
|
|
955
986
|
emit(` ${hr()}`);
|
|
956
987
|
emit(
|
|
957
|
-
` ${bold("
|
|
988
|
+
` ${bold("Four Degrees")} ${dim("AA baseline · Human Center of Mass · Power users · Top Evals — signalaf.com/wiki")}`,
|
|
958
989
|
);
|
|
959
990
|
const tdHead = [
|
|
960
991
|
padEnd(hdr("Metric"), 10),
|
|
961
|
-
padStart(hdr("
|
|
962
|
-
padStart(hdr("
|
|
992
|
+
padStart(hdr("AA base"), 9),
|
|
993
|
+
padStart(hdr("HCM"), 9),
|
|
994
|
+
padStart(hdr("Power"), 9),
|
|
963
995
|
padStart(hdr("Top"), 9),
|
|
964
996
|
];
|
|
965
997
|
emit(` ${tdHead.join(" ")}`);
|
|
966
998
|
const white = (s) => paint(c.white, s);
|
|
967
|
-
const tdRow = (label, b,
|
|
999
|
+
const tdRow = (label, b, h, p, t, fmt) =>
|
|
968
1000
|
emit(
|
|
969
|
-
` ${padEnd(label, 10)} ${padStart(
|
|
1001
|
+
` ${padEnd(label, 10)} ${padStart(dim(fmt(b)), 9)} ${padStart(white(fmt(h)), 9)} ${padStart(white(fmt(p)), 9)} ${padStart(gold(fmt(t)), 9)}`,
|
|
970
1002
|
);
|
|
971
|
-
tdRow("Υ Yield", TD.base.yield, TD.
|
|
972
|
-
tdRow("SNR", TD.base.snr, TD.
|
|
973
|
-
tdRow("Velocity", TD.base.vel, TD.
|
|
1003
|
+
tdRow("Υ Yield", TD.base.yield, TD.hcm.yield, TD.power.yield, TD.top.yield, fmtY);
|
|
1004
|
+
tdRow("SNR", TD.base.snr, TD.hcm.snr, TD.power.snr, TD.top.snr, fmtSNR);
|
|
1005
|
+
tdRow("Velocity", TD.base.vel, TD.hcm.vel, TD.power.vel, TD.top.vel, (v) =>
|
|
974
1006
|
v.toFixed(2),
|
|
975
1007
|
);
|
|
976
1008
|
tdRow(
|
|
977
1009
|
"Leverage",
|
|
978
1010
|
TD.base.lev,
|
|
979
|
-
TD.
|
|
1011
|
+
TD.hcm.lev,
|
|
1012
|
+
TD.power.lev,
|
|
980
1013
|
TD.top.lev,
|
|
981
1014
|
(v) => fmtLev(v) + "×",
|
|
982
1015
|
);
|
|
983
|
-
tdRow("10xDEV", TD.base.d10, TD.
|
|
1016
|
+
tdRow("10xDEV", TD.base.d10, TD.hcm.d10, TD.power.d10, TD.top.d10, (v) => v.toFixed(2));
|
|
984
1017
|
emit(
|
|
985
|
-
` ${dim("reference values until live user volume calibrates
|
|
1018
|
+
` ${dim("reference values until live user volume calibrates HCM · Power · Top")}`,
|
|
986
1019
|
);
|
|
987
1020
|
}
|
|
988
1021
|
|
|
@@ -1246,16 +1279,17 @@ function renderCompare(data) {
|
|
|
1246
1279
|
if (!td) missing.push("token-dashboard (~/.claude/token-dashboard.db)");
|
|
1247
1280
|
if (!ts) missing.push("tokscale (npm i -g tokscale)");
|
|
1248
1281
|
if (missing.length)
|
|
1249
|
-
|
|
1282
|
+
for (const ln of wrapDim(`no data from: ${missing.join(" · ")}`)) emit(ln);
|
|
1250
1283
|
emit();
|
|
1251
1284
|
|
|
1252
1285
|
// FIX (2026-08-18): if ALL sources are empty (tokenpull has no windows AND all
|
|
1253
1286
|
// verifiers are null), show a clear empty-state message instead of bare headers
|
|
1254
1287
|
// with zero data rows.
|
|
1255
1288
|
if (SOURCES.length === 0) {
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
)
|
|
1289
|
+
for (const ln of wrapDim(
|
|
1290
|
+
"no source data available for this platform — install a verifier or check ~/.claude/projects/",
|
|
1291
|
+
))
|
|
1292
|
+
emit(ln);
|
|
1259
1293
|
return;
|
|
1260
1294
|
}
|
|
1261
1295
|
|
|
@@ -1504,7 +1538,7 @@ function renderSubmissions(
|
|
|
1504
1538
|
const cells = [
|
|
1505
1539
|
padStart(rk, 4),
|
|
1506
1540
|
nm,
|
|
1507
|
-
padEnd(
|
|
1541
|
+
padEnd(platformColor(gPlat(e))(trunc(gPlat(e), 10)), 10),
|
|
1508
1542
|
padEnd(dim(trunc(gWin(e), 6)), 6),
|
|
1509
1543
|
yld,
|
|
1510
1544
|
...(showOpRatio ? [padEnd(dim(fmtOp(gOpRatio(e))), 18)] : []),
|
|
@@ -1695,6 +1729,7 @@ function renderWatchInfo(platform, win, refresh) {
|
|
|
1695
1729
|
const winLabel = !win || win === "all-windows" ? "all windows" : win;
|
|
1696
1730
|
const allDefault =
|
|
1697
1731
|
platLabel === "all active platforms" && winLabel === "all windows";
|
|
1732
|
+
const platColorFn = (!platform || platform === "all") ? cyan : platformColor(platform);
|
|
1698
1733
|
writeln();
|
|
1699
1734
|
writeln(
|
|
1700
1735
|
` ${bold("Live Watch")} ${dim("the agent that keeps your rank current")}`,
|
|
@@ -1702,7 +1737,7 @@ function renderWatchInfo(platform, win, refresh) {
|
|
|
1702
1737
|
writeln();
|
|
1703
1738
|
writeln(` ${dim("What it does")}`);
|
|
1704
1739
|
writeln(
|
|
1705
|
-
` Re-reads your local token logs for ${
|
|
1740
|
+
` Re-reads your local token logs for ${platColorFn(platLabel)} across ${cyan(winLabel)} every`,
|
|
1706
1741
|
);
|
|
1707
1742
|
writeln(
|
|
1708
1743
|
` ${gold(refresh + "s")} and recomputes each cascade (Υ Yield · SNR · Leverage · class) live, on`,
|
|
@@ -1724,7 +1759,7 @@ function renderWatchInfo(platform, win, refresh) {
|
|
|
1724
1759
|
writeln();
|
|
1725
1760
|
writeln(` ${dim("Settings")}`);
|
|
1726
1761
|
writeln(
|
|
1727
|
-
` ${dim("Platform")} ${
|
|
1762
|
+
` ${dim("Platform")} ${platColorFn(platLabel)} ${dim("Window")} ${cyan(winLabel)} ${dim("Refresh")} ${gold(refresh + "s")}`,
|
|
1728
1763
|
);
|
|
1729
1764
|
writeln(
|
|
1730
1765
|
` ${dim(allDefault ? "watching everything (default)" : "focused — press [P]/[W] to widen back to all")}`,
|
|
@@ -1870,9 +1905,10 @@ function renderWatchData(data) {
|
|
|
1870
1905
|
|
|
1871
1906
|
if (active.length === 0) {
|
|
1872
1907
|
emit();
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
)
|
|
1908
|
+
for (const ln of wrapDim(
|
|
1909
|
+
"no active platforms detected — run some sessions, this picks them up automatically",
|
|
1910
|
+
))
|
|
1911
|
+
emit(ln);
|
|
1876
1912
|
return;
|
|
1877
1913
|
}
|
|
1878
1914
|
|