sigrank 0.0.215 → 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 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.214",
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.215",
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",
@@ -124,3 +124,66 @@ export function setTheme(name) {
124
124
  export function getThemeNames() {
125
125
  return Object.keys(THEMES);
126
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
+ }
@@ -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.)
@@ -477,13 +478,18 @@ const TABS = [
477
478
  { key: "6", label: "Connect", short: "N" }, // sign in / switch device — the whole app is the TUI
478
479
  ];
479
480
 
480
- // Three Degrees of Leverage — reference values pulled from signalaf.com/wiki (2026-06-25).
481
- // base = AI avg (modeled 7:2:1 baseline) · field = SigRank avg (wild field median) · top = best operator.
482
- // STATIC for now; goes live (field/top computed from the board) once there's real user volume.
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.
483
488
  const TD = {
484
- base: { yield: 1.57, snr: 0.33, vel: 0.5, lev: 3.2, d10: 0.5 },
485
- field: { yield: 1.51, snr: 0.07, vel: 0.08, lev: 22.3, d10: 1.35 },
486
- top: { yield: 745.4, snr: 0.63, vel: 1.7, lev: 438.6, d10: 2.64 },
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 },
487
493
  };
488
494
 
489
495
  function renderTabBar(activeIdx) {
@@ -737,7 +743,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
737
743
  // which is what was starving codex's cascade rows after the Your-Read/Three-Degrees panels landed.)
738
744
  const platformCount = active.length;
739
745
  const barLines = 4 + platformCount + (platformCount > 1 ? 1 : 0); // Token Composition: hr + header + platforms + combined + note
740
- // Your Read (hr+header+~3 wins+1 gap = 6) + Three Degrees (blank+hr+header+col-header+5 rows+note = 10) + status
746
+ // Your Read (hr+header+~3 wins+1 gap = 6) + Four Degrees (blank+hr+header+col-header+5 rows+note = 10) + status
741
747
  const boardLines = 17;
742
748
  const sectionsBelow = barLines + boardLines;
743
749
  const maxCascadeRows = Math.max(8, budget - used - sectionsBelow);
@@ -789,7 +795,10 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
789
795
  if (lastPlatform !== null && row.platform !== lastPlatform) emit();
790
796
  renderRow(
791
797
  row.platform,
792
- (s) => (row.winKey === firstWin[row.platform] ? cyan(s) : dim(s)),
798
+ (s) => {
799
+ const pc = platformColor(row.platform);
800
+ return row.winKey === firstWin[row.platform] ? bold(pc(s)) : dim(s);
801
+ },
793
802
  row.winKey,
794
803
  row.pillars,
795
804
  row.estimated,
@@ -843,7 +852,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
843
852
  const all = d.windows?.find((w) => w.window === "all");
844
853
  if (!all) continue;
845
854
  emit(
846
- ` ${padEnd(cyan(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)))}`,
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)))}`,
847
856
  );
848
857
  }
849
858
  if (active.length > 1) {
@@ -886,9 +895,9 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
886
895
  }
887
896
  }
888
897
 
889
- // ── Your insights + the Three Degrees panel (replaces the old top-3 mini board)
898
+ // ── Your insights + the Four Degrees panel (replaces the old top-3 mini board)
890
899
  // The user's own cascade (the firstWin/combined row computed above) read against the
891
- // Three Degrees reference so the Dashboard says "here's you, here's the field, here's the ceiling."
900
+ // Four Degrees reference so the Dashboard says "here's you, here's the field, here's the ceiling."
892
901
  const you = (() => {
893
902
  // Best available cascade for the user: prefer claude's first-window, else any computed row.
894
903
  for (const d of active) {
@@ -931,7 +940,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
931
940
  chk(
932
941
  "Υ Yield",
933
942
  you.yield,
934
- TD.field.yield,
943
+ TD.hcm.yield,
935
944
  TD.top.yield,
936
945
  fmtY,
937
946
  "compound more — reuse cache, raise output",
@@ -939,7 +948,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
939
948
  chk(
940
949
  "SNR",
941
950
  you.snr,
942
- TD.field.snr,
951
+ TD.hcm.snr,
943
952
  TD.top.snr,
944
953
  fmtSNR,
945
954
  "tighten prompts — less input per unit output",
@@ -947,7 +956,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
947
956
  chk(
948
957
  "Leverage",
949
958
  you.leverage,
950
- TD.field.lev,
959
+ TD.hcm.lev,
951
960
  TD.top.lev,
952
961
  (v) => fmtLev(v) + "×",
953
962
  "lean on cache-read — amplify prior context",
@@ -955,7 +964,7 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
955
964
  chk(
956
965
  "Velocity",
957
966
  you.velocity,
958
- TD.field.vel,
967
+ TD.hcm.vel,
959
968
  TD.top.vel,
960
969
  (v) => v.toFixed(2),
961
970
  "more output per input token",
@@ -971,39 +980,42 @@ function renderDashboard(data, status = "", scrollOffset = 0) {
971
980
  emit(` ${dim(" reading your cascade… (press [R] to refresh)")}`);
972
981
  }
973
982
 
974
- // ── Three Degrees — AI avg · SigRank avg · Top (live values from signalaf.com)
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).
975
985
  emit();
976
986
  emit(` ${hr()}`);
977
987
  emit(
978
- ` ${bold("Three Degrees")} ${dim("AI avg · SigRank avg · top — signalaf.com/wiki")}`,
988
+ ` ${bold("Four Degrees")} ${dim("AA baseline · Human Center of Mass · Power users · Top Evals — signalaf.com/wiki")}`,
979
989
  );
980
990
  const tdHead = [
981
991
  padEnd(hdr("Metric"), 10),
982
- padStart(hdr("AI avg"), 9),
983
- padStart(hdr("SigRank avg"), 12),
992
+ padStart(hdr("AA base"), 9),
993
+ padStart(hdr("HCM"), 9),
994
+ padStart(hdr("Power"), 9),
984
995
  padStart(hdr("Top"), 9),
985
996
  ];
986
997
  emit(` ${tdHead.join(" ")}`);
987
998
  const white = (s) => paint(c.white, s);
988
- const tdRow = (label, b, f, t, fmt) =>
999
+ const tdRow = (label, b, h, p, t, fmt) =>
989
1000
  emit(
990
- ` ${padEnd(label, 10)} ${padStart(white(fmt(b)), 9)} ${padStart(fmt(f), 12)} ${padStart(gold(fmt(t)), 9)}`,
1001
+ ` ${padEnd(label, 10)} ${padStart(dim(fmt(b)), 9)} ${padStart(white(fmt(h)), 9)} ${padStart(white(fmt(p)), 9)} ${padStart(gold(fmt(t)), 9)}`,
991
1002
  );
992
- tdRow("Υ Yield", TD.base.yield, TD.field.yield, TD.top.yield, fmtY);
993
- tdRow("SNR", TD.base.snr, TD.field.snr, TD.top.snr, fmtSNR);
994
- tdRow("Velocity", TD.base.vel, TD.field.vel, TD.top.vel, (v) =>
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) =>
995
1006
  v.toFixed(2),
996
1007
  );
997
1008
  tdRow(
998
1009
  "Leverage",
999
1010
  TD.base.lev,
1000
- TD.field.lev,
1011
+ TD.hcm.lev,
1012
+ TD.power.lev,
1001
1013
  TD.top.lev,
1002
1014
  (v) => fmtLev(v) + "×",
1003
1015
  );
1004
- tdRow("10xDEV", TD.base.d10, TD.field.d10, TD.top.d10, (v) => v.toFixed(2));
1016
+ tdRow("10xDEV", TD.base.d10, TD.hcm.d10, TD.power.d10, TD.top.d10, (v) => v.toFixed(2));
1005
1017
  emit(
1006
- ` ${dim("reference values until live user volume calibrates SigRank avg")}`,
1018
+ ` ${dim("reference values until live user volume calibrates HCM · Power · Top")}`,
1007
1019
  );
1008
1020
  }
1009
1021
 
@@ -1526,7 +1538,7 @@ function renderSubmissions(
1526
1538
  const cells = [
1527
1539
  padStart(rk, 4),
1528
1540
  nm,
1529
- padEnd(cyan(trunc(gPlat(e), 10)), 10),
1541
+ padEnd(platformColor(gPlat(e))(trunc(gPlat(e), 10)), 10),
1530
1542
  padEnd(dim(trunc(gWin(e), 6)), 6),
1531
1543
  yld,
1532
1544
  ...(showOpRatio ? [padEnd(dim(fmtOp(gOpRatio(e))), 18)] : []),
@@ -1717,6 +1729,7 @@ function renderWatchInfo(platform, win, refresh) {
1717
1729
  const winLabel = !win || win === "all-windows" ? "all windows" : win;
1718
1730
  const allDefault =
1719
1731
  platLabel === "all active platforms" && winLabel === "all windows";
1732
+ const platColorFn = (!platform || platform === "all") ? cyan : platformColor(platform);
1720
1733
  writeln();
1721
1734
  writeln(
1722
1735
  ` ${bold("Live Watch")} ${dim("the agent that keeps your rank current")}`,
@@ -1724,7 +1737,7 @@ function renderWatchInfo(platform, win, refresh) {
1724
1737
  writeln();
1725
1738
  writeln(` ${dim("What it does")}`);
1726
1739
  writeln(
1727
- ` Re-reads your local token logs for ${cyan(platLabel)} across ${cyan(winLabel)} every`,
1740
+ ` Re-reads your local token logs for ${platColorFn(platLabel)} across ${cyan(winLabel)} every`,
1728
1741
  );
1729
1742
  writeln(
1730
1743
  ` ${gold(refresh + "s")} and recomputes each cascade (Υ Yield · SNR · Leverage · class) live, on`,
@@ -1746,7 +1759,7 @@ function renderWatchInfo(platform, win, refresh) {
1746
1759
  writeln();
1747
1760
  writeln(` ${dim("Settings")}`);
1748
1761
  writeln(
1749
- ` ${dim("Platform")} ${cyan(platLabel)} ${dim("Window")} ${cyan(winLabel)} ${dim("Refresh")} ${gold(refresh + "s")}`,
1762
+ ` ${dim("Platform")} ${platColorFn(platLabel)} ${dim("Window")} ${cyan(winLabel)} ${dim("Refresh")} ${gold(refresh + "s")}`,
1750
1763
  );
1751
1764
  writeln(
1752
1765
  ` ${dim(allDefault ? "watching everything (default)" : "focused — press [P]/[W] to widen back to all")}`,