sigrank 1.0.40 → 1.0.41
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/adapters/index.mjs +97 -1
- package/adapters/tokenpull.mjs +15 -11
- package/lib/constants.mjs +20 -17
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/presentation/cli.mjs +24 -18
- package/tools/_helpers.mjs +1 -1
package/adapters/index.mjs
CHANGED
|
@@ -42,13 +42,16 @@
|
|
|
42
42
|
*/
|
|
43
43
|
|
|
44
44
|
import { readdir, readFile } from "node:fs/promises";
|
|
45
|
+
import { existsSync } from "node:fs";
|
|
45
46
|
import { join, dirname } from "node:path";
|
|
46
47
|
import { homedir } from "node:os";
|
|
47
48
|
import { execFile as execFileCb } from "node:child_process";
|
|
48
49
|
import { promisify } from "node:util";
|
|
50
|
+
import { fileURLToPath } from "node:url";
|
|
49
51
|
import { cachedOmpScan, ompCacheEnabled } from "../omp-cache.mjs";
|
|
50
52
|
|
|
51
53
|
const execFileP = promisify(execFileCb);
|
|
54
|
+
const PACKAGE_ROOT = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
52
55
|
const DAY_MS = 86_400_000; // shared with tokenpull.mjs but kept local to avoid circular import
|
|
53
56
|
|
|
54
57
|
// ── File-system helpers ───────────────────────────────────────────────────────
|
|
@@ -1075,6 +1078,96 @@ export const proxyAdapter = {
|
|
|
1075
1078
|
},
|
|
1076
1079
|
};
|
|
1077
1080
|
|
|
1081
|
+
|
|
1082
|
+
// ── ccusage-backed adapters ──────────────────────────────────────────────────
|
|
1083
|
+
// ccusage maintains source-specific readers for these platforms and normalizes
|
|
1084
|
+
// its daily JSON output into the same four token buckets SigRank requires.
|
|
1085
|
+
// Keep these as thin adapters instead of duplicating upstream parsers here.
|
|
1086
|
+
// The bundled dependency is preferred; PATH is a fallback for development.
|
|
1087
|
+
async function execCcusage(args) {
|
|
1088
|
+
const localEntrypoint = join(
|
|
1089
|
+
PACKAGE_ROOT,
|
|
1090
|
+
"node_modules",
|
|
1091
|
+
"ccusage",
|
|
1092
|
+
"src",
|
|
1093
|
+
"cli.js",
|
|
1094
|
+
);
|
|
1095
|
+
const options = {
|
|
1096
|
+
timeout: 30_000,
|
|
1097
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
1098
|
+
};
|
|
1099
|
+
if (existsSync(localEntrypoint)) {
|
|
1100
|
+
return execFileP(process.execPath, [localEntrypoint, ...args], options);
|
|
1101
|
+
}
|
|
1102
|
+
return execFileP("ccusage", args, options);
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
function makeCcusageAdapter(platform) {
|
|
1106
|
+
return {
|
|
1107
|
+
platform,
|
|
1108
|
+
defaultRoot: () => homedir(),
|
|
1109
|
+
async *messages() {
|
|
1110
|
+
let data;
|
|
1111
|
+
try {
|
|
1112
|
+
const { stdout } = await execCcusage([
|
|
1113
|
+
platform,
|
|
1114
|
+
"daily",
|
|
1115
|
+
"--json",
|
|
1116
|
+
"--no-cost",
|
|
1117
|
+
]);
|
|
1118
|
+
data = JSON.parse(stdout || "{}");
|
|
1119
|
+
} catch {
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
const rows = Array.isArray(data?.daily)
|
|
1124
|
+
? data.daily
|
|
1125
|
+
: Array.isArray(data?.data)
|
|
1126
|
+
? data.data
|
|
1127
|
+
: Array.isArray(data)
|
|
1128
|
+
? data
|
|
1129
|
+
: [];
|
|
1130
|
+
|
|
1131
|
+
for (const row of rows) {
|
|
1132
|
+
if (!row || typeof row !== "object") continue;
|
|
1133
|
+
const date = row.date || row.day;
|
|
1134
|
+
if (!date) continue;
|
|
1135
|
+
const input = Number(row.inputTokens ?? row.input_tokens ?? 0);
|
|
1136
|
+
const output = Number(row.outputTokens ?? row.output_tokens ?? 0);
|
|
1137
|
+
const cacheCreate = Number(
|
|
1138
|
+
row.cacheCreationTokens ?? row.cache_create_tokens ?? 0,
|
|
1139
|
+
);
|
|
1140
|
+
const cacheRead = Number(
|
|
1141
|
+
row.cacheReadTokens ?? row.cache_read_tokens ?? 0,
|
|
1142
|
+
);
|
|
1143
|
+
if (
|
|
1144
|
+
![input, output, cacheCreate, cacheRead].every(
|
|
1145
|
+
(n) => Number.isFinite(n) && n >= 0,
|
|
1146
|
+
)
|
|
1147
|
+
) {
|
|
1148
|
+
continue;
|
|
1149
|
+
}
|
|
1150
|
+
if (input + output + cacheCreate + cacheRead === 0) continue;
|
|
1151
|
+
|
|
1152
|
+
yield {
|
|
1153
|
+
id: `${platform}:${date}`,
|
|
1154
|
+
sid: null,
|
|
1155
|
+
ts: `${date}T12:00:00.000Z`,
|
|
1156
|
+
input,
|
|
1157
|
+
output,
|
|
1158
|
+
cacheCreate,
|
|
1159
|
+
cacheRead,
|
|
1160
|
+
file: `ccusage:${platform}`,
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
},
|
|
1164
|
+
};
|
|
1165
|
+
}
|
|
1166
|
+
|
|
1167
|
+
export const antigravityAdapter = makeCcusageAdapter("antigravity");
|
|
1168
|
+
export const grokAdapter = makeCcusageAdapter("grok");
|
|
1169
|
+
export const zcodeAdapter = makeCcusageAdapter("zcode");
|
|
1170
|
+
|
|
1078
1171
|
// ── Registry ──────────────────────────────────────────────────────────────────
|
|
1079
1172
|
/** All non-Claude, non-Codex adapters keyed by platform ID. */
|
|
1080
1173
|
export const ADAPTERS = {
|
|
@@ -1095,6 +1188,9 @@ export const ADAPTERS = {
|
|
|
1095
1188
|
other: otherAdapter,
|
|
1096
1189
|
omp: ompAdapter,
|
|
1097
1190
|
proxy: proxyAdapter,
|
|
1191
|
+
antigravity: antigravityAdapter,
|
|
1192
|
+
grok: grokAdapter,
|
|
1193
|
+
zcode: zcodeAdapter,
|
|
1098
1194
|
};
|
|
1099
1195
|
|
|
1100
|
-
export const ALL_PLATFORMS = Object.keys(ADAPTERS).concat(["claude", "codex"
|
|
1196
|
+
export const ALL_PLATFORMS = Object.keys(ADAPTERS).concat(["claude", "codex"]);
|
package/adapters/tokenpull.mjs
CHANGED
|
@@ -18,19 +18,20 @@
|
|
|
18
18
|
import { readdir, readFile } from "node:fs/promises";
|
|
19
19
|
import { existsSync } from "node:fs";
|
|
20
20
|
import { execFile } from "node:child_process";
|
|
21
|
-
import { join, dirname } from "node:path";
|
|
21
|
+
import { join, dirname, delimiter } from "node:path";
|
|
22
22
|
import { homedir } from "node:os";
|
|
23
23
|
import { fileURLToPath } from "node:url";
|
|
24
24
|
import { ADAPTERS, walkFiles } from "./index.mjs";
|
|
25
|
+
import { TOKSCALE_CLIENT_MAP } from "../lib/constants.mjs";
|
|
25
26
|
|
|
26
27
|
const DAY_MS = 86_400_000;
|
|
27
28
|
|
|
28
29
|
// Resolve the package root for finding bundled binaries (ccusage, tokscale, etc.)
|
|
29
|
-
const _pkgRoot = join(dirname(fileURLToPath(import.meta.url)));
|
|
30
|
+
const _pkgRoot = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
30
31
|
const _localBin = join(_pkgRoot, "node_modules", ".bin");
|
|
31
32
|
// Prepend local node_modules/.bin to PATH so bundled deps are found even when
|
|
32
33
|
// not globally installed (e.g., npx sigrank, local dev).
|
|
33
|
-
const _envPath = `${_localBin}${process.env.PATH ?
|
|
34
|
+
const _envPath = `${_localBin}${process.env.PATH ? delimiter + process.env.PATH : ""}`;
|
|
34
35
|
|
|
35
36
|
// ASYNC FIX (2026-06-27): execFile wrapped in a Promise — replaces execSync in the
|
|
36
37
|
// fresh verifier readers. execSync blocks the entire Node event loop (no key handling,
|
|
@@ -522,14 +523,17 @@ async function _freshTokscale(platform = "claude") {
|
|
|
522
523
|
: Array.isArray(data)
|
|
523
524
|
? data
|
|
524
525
|
: [];
|
|
525
|
-
const rows = entries.filter(
|
|
526
|
-
(e)
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
e.
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
526
|
+
const rows = entries.filter((e) => {
|
|
527
|
+
if (!e || e.model === "<synthetic>" || e.model === "unknown") return false;
|
|
528
|
+
const mapped = Object.prototype.hasOwnProperty.call(
|
|
529
|
+
TOKSCALE_CLIENT_MAP,
|
|
530
|
+
e.client,
|
|
531
|
+
)
|
|
532
|
+
? TOKSCALE_CLIENT_MAP[e.client]
|
|
533
|
+
: e.client;
|
|
534
|
+
if (mapped !== platform) return false;
|
|
535
|
+
return (Number(e.input) || 0) > 0 || (Number(e.output) || 0) > 0;
|
|
536
|
+
});
|
|
533
537
|
if (!rows.length) return null;
|
|
534
538
|
const acc = rows.reduce(
|
|
535
539
|
(a, e) => ({
|
package/lib/constants.mjs
CHANGED
|
@@ -68,8 +68,9 @@ export const TOKSCALE_CLIENT_MAP = {
|
|
|
68
68
|
roocode: "other",
|
|
69
69
|
mux: "other",
|
|
70
70
|
crush: "other",
|
|
71
|
-
antigravity: "
|
|
72
|
-
"antigravity-cli": "
|
|
71
|
+
antigravity: "antigravity",
|
|
72
|
+
"antigravity-cli": "antigravity",
|
|
73
|
+
"antigravity-extension": "antigravity",
|
|
73
74
|
zed: "other",
|
|
74
75
|
kiro: "other",
|
|
75
76
|
trae: "other",
|
|
@@ -77,12 +78,12 @@ export const TOKSCALE_CLIENT_MAP = {
|
|
|
77
78
|
cline: "other",
|
|
78
79
|
"9router": "other",
|
|
79
80
|
gjc: "other",
|
|
80
|
-
grok: "
|
|
81
|
+
grok: "grok",
|
|
81
82
|
jcode: "other",
|
|
82
83
|
commandcode: "other",
|
|
83
84
|
micode: "other",
|
|
84
85
|
junie: "other",
|
|
85
|
-
zcode: "
|
|
86
|
+
zcode: "zcode",
|
|
86
87
|
opencodereview: "other",
|
|
87
88
|
codebuddy: "other",
|
|
88
89
|
workbuddy: "other",
|
|
@@ -92,25 +93,27 @@ export const TOKSCALE_CLIENT_MAP = {
|
|
|
92
93
|
reasonix: "other",
|
|
93
94
|
"prime-agent": "other",
|
|
94
95
|
freebuff: "other",
|
|
96
|
+
cherrystudio: "other",
|
|
97
|
+
dsh: "other",
|
|
98
|
+
mcode: "other",
|
|
99
|
+
fx: "other",
|
|
100
|
+
lmstudio: "other",
|
|
101
|
+
unsloth: "other",
|
|
102
|
+
hindsight: "other",
|
|
103
|
+
"micode-desktop": "other",
|
|
104
|
+
muse: "other",
|
|
95
105
|
synthetic: null,
|
|
96
106
|
};
|
|
97
107
|
|
|
98
108
|
/**
|
|
99
|
-
* Platforms whose local data
|
|
100
|
-
* never lists them as an active client. pullActivePlatforms() auto-detect must
|
|
101
|
-
* probe these directly or their cascade row can never appear, even with GBs of
|
|
102
|
-
* native local telemetry (that was exactly the omp bug: tokscale reports
|
|
103
|
-
* claude/codex/copilot/gemini/grok/kimi/kiro/opencode/pi and nothing else, so
|
|
104
|
-
* a tokscale-detected machine silently dropped oh-my-pi entirely).
|
|
109
|
+
* Platforms whose local data the pinned tokscale release cannot discover.
|
|
105
110
|
*
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* (TOKSCALE_CLIENT_MAP already maps the `omp` / `oh-my-pi` client names for
|
|
111
|
-
* when that happens).
|
|
111
|
+
* Tokscale 4.17.0 includes oh-my-pi (`omp`) directly, so there are currently
|
|
112
|
+
* no blind platforms that need forced probing. Keep the hook because future
|
|
113
|
+
* platform-specific discovery gaps can still be added here without changing
|
|
114
|
+
* pullActivePlatforms().
|
|
112
115
|
*/
|
|
113
|
-
export const TOKSCALE_BLIND_PLATFORMS = [
|
|
116
|
+
export const TOKSCALE_BLIND_PLATFORMS = [];
|
|
114
117
|
|
|
115
118
|
/**
|
|
116
119
|
* The "actually on the board" predicate. A submission is ranked only when the
|
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": "1.0.
|
|
5
|
+
"version": "1.0.40",
|
|
6
6
|
"description": "Ranks AI coding operators by token cascade efficiency (Yield = cache_read \u00d7 output / input\u00b2). 25 tools including SigRank Standard record, 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": "1.0.
|
|
3
|
+
"version": "1.0.41",
|
|
4
4
|
"author": "SunrisesIllNeverSee (https://github.com/SunrisesIllNeverSee)",
|
|
5
5
|
"description": "Upsilon measurement engine distributed through the sigrank CLI/MCP compatibility package, with SigRank public leaderboard tools.",
|
|
6
6
|
"mcpName": "io.github.SunrisesIllNeverSee/sigrank-mcp",
|
package/presentation/cli.mjs
CHANGED
|
@@ -29,7 +29,7 @@ import { cascade, classify, CLASS_TIERS, UNCLASSED, tierOf } from "../cascade.mj
|
|
|
29
29
|
import { ALL_PLATFORMS } from "../adapters.mjs";
|
|
30
30
|
import { ensureIdentity, keystorePath } from "../keystore.mjs";
|
|
31
31
|
import { submitSignedWindow } from "../submit.mjs";
|
|
32
|
-
import { LEADERBOARD_METRIC } from "../lib/constants.mjs";
|
|
32
|
+
import { LEADERBOARD_METRIC, TOKSCALE_CLIENT_MAP } from "../lib/constants.mjs";
|
|
33
33
|
import { execFile } from "child_process";
|
|
34
34
|
import { existsSync, readFileSync } from "fs";
|
|
35
35
|
import os from "os";
|
|
@@ -37,9 +37,9 @@ import path from "path";
|
|
|
37
37
|
import { fileURLToPath } from "url";
|
|
38
38
|
|
|
39
39
|
// Resolve local node_modules/.bin for bundled deps (ccusage, tokscale)
|
|
40
|
-
const _pkgRoot = path.dirname(fileURLToPath(import.meta.url));
|
|
40
|
+
const _pkgRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
41
41
|
const _localBin = path.join(_pkgRoot, "node_modules", ".bin");
|
|
42
|
-
const _envPath = `${_localBin}${process.env.PATH ?
|
|
42
|
+
const _envPath = `${_localBin}${process.env.PATH ? path.delimiter + process.env.PATH : ""}`;
|
|
43
43
|
|
|
44
44
|
// ASYNC FIX (2026-06-27): execFile wrapped in a Promise — replaces execSync for
|
|
45
45
|
// defense-in-depth (shell injection prevention). execFile passes args as an
|
|
@@ -429,14 +429,17 @@ async function tokscalePillars(platform = "claude") {
|
|
|
429
429
|
: Array.isArray(data)
|
|
430
430
|
? data
|
|
431
431
|
: [];
|
|
432
|
-
const rows = entries.filter(
|
|
433
|
-
(e)
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
e.
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
432
|
+
const rows = entries.filter((e) => {
|
|
433
|
+
if (!e || e.model === "<synthetic>" || e.model === "unknown") return false;
|
|
434
|
+
const mapped = Object.prototype.hasOwnProperty.call(
|
|
435
|
+
TOKSCALE_CLIENT_MAP,
|
|
436
|
+
e.client,
|
|
437
|
+
)
|
|
438
|
+
? TOKSCALE_CLIENT_MAP[e.client]
|
|
439
|
+
: e.client;
|
|
440
|
+
if (mapped !== platform) return false;
|
|
441
|
+
return (Number(e.input) || 0) > 0 || (Number(e.output) || 0) > 0;
|
|
442
|
+
});
|
|
440
443
|
if (rows.length) {
|
|
441
444
|
const p = rows.reduce(
|
|
442
445
|
(acc, e) => ({
|
|
@@ -458,13 +461,16 @@ async function tokscalePillars(platform = "claude") {
|
|
|
458
461
|
try {
|
|
459
462
|
const data = JSON.parse(readFileSync(reportPath, "utf8"));
|
|
460
463
|
const entries = data.entries ?? [];
|
|
461
|
-
const rows = entries.filter(
|
|
462
|
-
(e)
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
e.
|
|
466
|
-
|
|
467
|
-
|
|
464
|
+
const rows = entries.filter((e) => {
|
|
465
|
+
if (!e || e.model === "<synthetic>" || e.model === "unknown") return false;
|
|
466
|
+
const mapped = Object.prototype.hasOwnProperty.call(
|
|
467
|
+
TOKSCALE_CLIENT_MAP,
|
|
468
|
+
e.client,
|
|
469
|
+
)
|
|
470
|
+
? TOKSCALE_CLIENT_MAP[e.client]
|
|
471
|
+
: e.client;
|
|
472
|
+
return mapped === platform && (e.input > 0 || e.output > 0);
|
|
473
|
+
});
|
|
468
474
|
if (rows.length === 0) return null;
|
|
469
475
|
const p = rows.reduce(
|
|
470
476
|
(acc, e) => ({
|
package/tools/_helpers.mjs
CHANGED
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
// Resolve local node_modules/.bin for bundled deps (ccusage, tokscale)
|
|
22
22
|
const _pkgRoot = path.dirname(fileURLToPath(import.meta.url));
|
|
23
23
|
const _localBin = path.join(_pkgRoot, "..", "node_modules", ".bin");
|
|
24
|
-
const _envPath = `${_localBin}${process.env.PATH ?
|
|
24
|
+
const _envPath = `${_localBin}${process.env.PATH ? path.delimiter + process.env.PATH : ""}`;
|
|
25
25
|
|
|
26
26
|
export const DEFAULT_API_BASE =
|
|
27
27
|
process.env.SIGRANK_API_BASE || "https://signalaf.com";
|