sigrank 0.0.214 → 0.0.215

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.213",
5
+ "version": "0.0.214",
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.214",
3
+ "version": "0.0.215",
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}32m`,
31
- red: `${ESC}31m`,
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
- // Colors adjusted for contrast against white/light backgrounds.
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}2m`,
50
- gold: `${ESC}33m`, // yellow is readable on white
51
- boldGold: `${ESC}1;33m`,
52
- cyan: `${ESC}36m`, // cyan is readable on white
53
- boldCyan: `${ESC}1;36m`,
54
- green: `${ESC}32m`, // standard green (darker shade would be better but ANSI 32 is the option)
55
- red: `${ESC}31m`, // standard red
56
- white: `${ESC}30m`, // BLACK text on light bg (was bright white)
57
- boldWhite: `${ESC}1;30m`, // bold black
58
- magenta: `${ESC}35m`,
59
- blue: `${ESC}34m`, // blue is readable on white
60
- bgDim: `${ESC}48;5;250m`, // light grey bg for active tab
61
- bgCyan: `${ESC}48;5;194m`,// light teal bg for active tab
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
  },
@@ -187,6 +187,27 @@ function padStart(s, w) {
187
187
  function trunc(s, w) {
188
188
  return stripAnsi(s).length <= w ? s : s.slice(0, w - 1) + "…";
189
189
  }
190
+ // Wrap a plain-text string into dim'd lines that fit within `maxW` columns.
191
+ // Used for no-data/empty-state messages that can be long on narrow terminals.
192
+ // Returns an array of strings (each already dim'd + indented) for emit().
193
+ function wrapDim(text, indent = " ", maxW) {
194
+ const w = maxW || W();
195
+ const avail = w - 2 - indent.length; // 2 = leading " " from emit caller
196
+ if (avail < 20) return [`${indent}${dim(text)}`]; // too narrow to wrap — let it be
197
+ const words = text.split(" ");
198
+ const lines = [];
199
+ let line = "";
200
+ for (const word of words) {
201
+ if ((line + " " + word).trim().length > avail) {
202
+ if (line) lines.push(`${indent}${dim(line.trim())}`);
203
+ line = word;
204
+ } else {
205
+ line = (line + " " + word).trim();
206
+ }
207
+ }
208
+ if (line) lines.push(`${indent}${dim(line.trim())}`);
209
+ return lines;
210
+ }
190
211
  function hr(ch = "─") {
191
212
  return dim(ch.repeat(Math.max(0, W() - 4)));
192
213
  }
@@ -1246,16 +1267,17 @@ function renderCompare(data) {
1246
1267
  if (!td) missing.push("token-dashboard (~/.claude/token-dashboard.db)");
1247
1268
  if (!ts) missing.push("tokscale (npm i -g tokscale)");
1248
1269
  if (missing.length)
1249
- emit(` ${dim(` no data from: ${missing.join(" · ")}`)}`);
1270
+ for (const ln of wrapDim(`no data from: ${missing.join(" · ")}`)) emit(ln);
1250
1271
  emit();
1251
1272
 
1252
1273
  // FIX (2026-08-18): if ALL sources are empty (tokenpull has no windows AND all
1253
1274
  // verifiers are null), show a clear empty-state message instead of bare headers
1254
1275
  // with zero data rows.
1255
1276
  if (SOURCES.length === 0) {
1256
- emit(
1257
- ` ${dim(" no source data available for this platform — install a verifier or check ~/.claude/projects/")}`,
1258
- );
1277
+ for (const ln of wrapDim(
1278
+ "no source data available for this platform — install a verifier or check ~/.claude/projects/",
1279
+ ))
1280
+ emit(ln);
1259
1281
  return;
1260
1282
  }
1261
1283
 
@@ -1870,9 +1892,10 @@ function renderWatchData(data) {
1870
1892
 
1871
1893
  if (active.length === 0) {
1872
1894
  emit();
1873
- emit(
1874
- ` ${dim(" no active platforms detected — run some sessions, this picks them up automatically")}`,
1875
- );
1895
+ for (const ln of wrapDim(
1896
+ "no active platforms detected — run some sessions, this picks them up automatically",
1897
+ ))
1898
+ emit(ln);
1876
1899
  return;
1877
1900
  }
1878
1901