sigrank 1.0.43 → 1.0.45
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/CHANGELOG.md +30 -0
- package/MCP_SERVER_DESCRIPTION.md +22 -21
- package/README.md +4 -5
- package/adapters/tokenpull.mjs +9 -2
- package/index.mjs +16 -4
- package/lib/constants.mjs +12 -0
- package/manifest.json +1 -1
- package/package.json +3 -3
- package/presentation/cli.mjs +10 -2
- package/presentation/tui.mjs +1 -1
- package/tokscale_analytics.mjs +12 -8
- package/tools/_verifiers.mjs +6 -1
- package/tools/index.mjs +6 -1
- package/tools/tokscale-breakdown.mjs +9 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.0.44](https://github.com/SunrisesIllNeverSee/sigrank-mcp/releases/tag/v1.0.44) (2026-10-05)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
|
|
7
|
+
* MCP: explicit opt-in support for protocol revision 2026-07-28 via `serveStdio` — a `server/discover` probe with the modern `_meta` envelope pins the connection to the modern era; `initialize` openings keep the 2025-era protocol unchanged (dual-era serving, `legacy: 'serve'`)
|
|
8
|
+
* Docs: `docs/PROTOCOL-COMPATIBILITY.md` — served eras, negotiation rules, host/client matrix
|
|
9
|
+
|
|
10
|
+
### Tests
|
|
11
|
+
|
|
12
|
+
* stdio characterization suite 15 → 24: 9 modern-era tests (discover negotiation, era parity, envelope-claim requirement, `-32022` late-initialize, probe→initialize fallback, modern stdout purity + EOF)
|
|
13
|
+
|
|
14
|
+
## [1.0.43](https://github.com/SunrisesIllNeverSee/sigrank-mcp/releases/tag/v1.0.43) (2026-10-05)
|
|
15
|
+
|
|
16
|
+
### Breaking Changes
|
|
17
|
+
|
|
18
|
+
* Node.js >= 20 required (was >= 18)
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* MCP: migrated `@modelcontextprotocol/sdk` v1 → official v2 packages (`@modelcontextprotocol/server` 2.3.0); zero v1 imports remain
|
|
23
|
+
* `sigrank standard --json`: `sigrank/0.1-draft` now correctly labeled `legacy_alias` under TTEOP authority (`tteop-spec@0.1.5-draft`)
|
|
24
|
+
|
|
25
|
+
### Fixes
|
|
26
|
+
|
|
27
|
+
* Release workflow: explicit releases only — no auto-publish after CI; real npm OIDC trusted publishing (dead NPM_TOKEN path removed); `--dry-run` + collision pre-gates; `--provenance`
|
|
28
|
+
|
|
29
|
+
### Tests
|
|
30
|
+
|
|
31
|
+
* 15-test SDK-agnostic stdio behavior freeze locked identical across v1 → v2 (tools/prompts/resources, error classes, stdout purity, routing, EOF) on Node 20/22/26
|
|
32
|
+
|
|
3
33
|
## [1.0.37](https://github.com/SunrisesIllNeverSee/sigrank-mcp/releases/tag/v1.0.37) (2026-09-08)
|
|
4
34
|
|
|
5
35
|
### Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SigRank MCP Server
|
|
2
2
|
|
|
3
|
-
> Operator leaderboard measuring users, not models —
|
|
3
|
+
> Operator leaderboard measuring users, not models — 25 tools, TUI, signed submit, privacy-first.
|
|
4
4
|
|
|
5
5
|
SigRank is the first leaderboard that ranks **AI operators** — the humans — by token cascade efficiency, not the models. The yield metric (Υ = cache_read × output / input²) turns raw token telemetry into a competitive ranking on [signalaf.com](https://signalaf.com).
|
|
6
6
|
|
|
@@ -64,7 +64,7 @@ npx sigrank diagnose # Diagnose cascade inefficiencies
|
|
|
64
64
|
npx sigrank improve # Get improvement suggestions
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
-
## The
|
|
67
|
+
## The 25 MCP Tools
|
|
68
68
|
|
|
69
69
|
### Read-only — pure math (no auth, no filesystem)
|
|
70
70
|
|
|
@@ -81,39 +81,40 @@ npx sigrank improve # Get improvement suggestions
|
|
|
81
81
|
|
|
82
82
|
| # | Tool | What it does |
|
|
83
83
|
|---|------|-------------|
|
|
84
|
-
| 7 | `
|
|
85
|
-
| 8 | `
|
|
86
|
-
| 9 | `
|
|
84
|
+
| 7 | `get_sigrank_standard_record` | Build the portable `sigrank/0.1-draft` compatibility record (legacy alias under TTEOP authority) from token telemetry. Computes the canonical cascade locally — no network. |
|
|
85
|
+
| 8 | `get_leaderboard` | Fetch the live public leaderboard from signalaf.com. Returns all ranked operators sorted by yield, with codename, Υ, leverage, velocity, class, and rank position. |
|
|
86
|
+
| 9 | `get_operator` | Get any operator's full profile by codename. Returns detailed metrics + per-window breakdowns (7d/30d/90d/all-time) with the four token pillars per window. |
|
|
87
|
+
| 10 | `discover_peers` | Find mentors, peers, and complementary operators for your operator on the leaderboard. |
|
|
87
88
|
|
|
88
89
|
### Read-only — local filesystem (no auth, no network)
|
|
89
90
|
|
|
90
91
|
| # | Tool | What it does |
|
|
91
92
|
|---|------|-------------|
|
|
92
|
-
|
|
|
93
|
-
|
|
|
94
|
-
|
|
|
93
|
+
| 11 | `tokenpull` | Pull your LOCAL token usage from session logs and rank it across all four windows — zero paste. Reads token counts, not message content. Numbers stay on your machine. 17 platform adapters. |
|
|
94
|
+
| 12 | `tokenpull_compare` | Pull token usage from ALL four local sources in parallel (JSONL canon, ccusage CLI, token-dashboard SQLite, tokscale) and compare side-by-side with delta % vs baseline. |
|
|
95
|
+
| 13 | `watch_tokenpull` | One poll per call — pulls local token logs and returns current cascade for the watched window. Re-call at your desired cadence to monitor. With `submit:true`, signs + publishes (rate-limited to once per 5 min). |
|
|
95
96
|
|
|
96
97
|
### Write — submit to board (needs enrolled identity)
|
|
97
98
|
|
|
98
99
|
| # | Tool | What it does |
|
|
99
100
|
|---|------|-------------|
|
|
100
|
-
|
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
|
101
|
+
| 14 | `submit_paste` | Ranks a paste of token counts AND publishes to the live board in one call. Computes local preview, then submits to server for authoritative scoring. Returns both local + server results. |
|
|
102
|
+
| 15 | `tokenpull_submit` | Pull your LOCAL token usage AND publish to the board in one call — the zero-paste flow. Reads pillars per window, computes cascade, submits each window server-side. Token-only, no prompt content. |
|
|
103
|
+
| 16 | `submit_verified` | Publish your LOCAL token runs as a VERIFIED operator — the enrolled, signed path. Reads pillars, builds Schema 1.0 snapshot, ed25519-signs with your device key, POSTs to board. Requires `enroll` first. |
|
|
104
|
+
| 17 | `enroll` | Bind THIS device to your SigRank operator. Paste the key from signalaf.com → Settings → "New key". Generates + stores a local ed25519 keypair. Only the PUBLIC key is ever sent. |
|
|
104
105
|
|
|
105
106
|
### Tokscale analytics — local tokscale data (no auth, no network)
|
|
106
107
|
|
|
107
108
|
| # | Tool | What it does |
|
|
108
109
|
|---|------|-------------|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
113
|
-
|
|
|
114
|
-
|
|
|
115
|
-
|
|
|
116
|
-
|
|
|
110
|
+
| 18 | `tokscale_breakdown` | Per-model token breakdown across platforms (models under threshold → "other"). |
|
|
111
|
+
| 19 | `tokscale_market_share` | AI tool market share: each tool's % of tokens/cost/messages, ranked. From local tokscale data. |
|
|
112
|
+
| 20 | `tokscale_developer_profile` | Per-developer usage profile across all detected tools: model mix, pillars, sessions, workspaces. Paths redacted. |
|
|
113
|
+
| 21 | `tokscale_model_trends` | Model adoption over time: per-model first/last seen, active days, month-by-month adoption curve. |
|
|
114
|
+
| 22 | `tokscale_cost_analysis` | Cost per developer per model: cost_per_million_tokens, cost_per_message, share_cost, client rollup. |
|
|
115
|
+
| 23 | `tokscale_device_profile` | Device fingerprinting: installed tools, session counts, active days, day-of-week distribution, concurrency. Paths redacted. |
|
|
116
|
+
| 24 | `tokscale_mcp_usage` | MCP server usage: detected servers, detection window, active days. |
|
|
117
|
+
| 25 | `tokscale_competitive_intel` | Competitive intelligence for any AI tool: rank, model mix, cost efficiency, share vs all competitors. |
|
|
117
118
|
|
|
118
119
|
### Moved to bestuser-router-mcp (5 intent tools)
|
|
119
120
|
|
|
@@ -160,7 +161,7 @@ The intent-based tools (in bestuser-router-mcp) are designed to map natural-lang
|
|
|
160
161
|
| Transport | stdio |
|
|
161
162
|
| Platform | Cross-platform (Node.js) |
|
|
162
163
|
| Language | JavaScript |
|
|
163
|
-
| Tools |
|
|
164
|
+
| Tools | 25 |
|
|
164
165
|
| Auth | None for reads; Supabase anon key for submits |
|
|
165
166
|
| Category | Developer Tools |
|
|
166
167
|
|
package/README.md
CHANGED
|
@@ -303,6 +303,8 @@ Or if installed globally:
|
|
|
303
303
|
| `tokenpull_submit(codename, window?)` | `{codename?, window?}` | `tokenpull` → publish to board. Omit codename for preview |
|
|
304
304
|
| `tokenpull_compare(platform?)` | `{platform?}` | All four sources side-by-side: tokenpull + ccusage + token-dash + tokscale. Returns pillars, cascade metrics, and delta % vs tokenpull per window |
|
|
305
305
|
| `rank_windows` | `{platform?, window?}` | Multi-window cascade from local logs |
|
|
306
|
+
| `get_sigrank_standard_record` | `{input, output, cache_write?, cache_read?}` | Builds the portable `sigrank/0.1-draft` compatibility record (legacy alias under TTEOP authority) — canonical cascade, computed locally |
|
|
307
|
+
| `discover_peers` | `{codename?}` | Find mentors, peers, and complementary operators on the leaderboard |
|
|
306
308
|
| `watch_tokenpull` | `{platform?, interval_s?}` | One cascade snapshot per call (interval_s advisory) |
|
|
307
309
|
| `submit_verified` | `{window?, platform?, dry_run?}` | THE ranked path: builds + ed25519-signs Schema 1.0 snapshots and POSTs them. `platform:'multi'` sums all active platforms. `dry_run:true` returns the exact payload unsent |
|
|
308
310
|
| `enroll` | `{code, device_label?}` | Bind this device with a connect code from signalaf.com → Settings |
|
|
@@ -310,11 +312,6 @@ Or if installed globally:
|
|
|
310
312
|
| `simulate_change` | `{text?, changes}` | Prescriptive "what if" — test proposed pillar changes and see the exact Υ delta + class change before committing |
|
|
311
313
|
| `suggest_improvements` | `{text?}` | Generates ranked, simulated improvement suggestions — tests strategies and returns them sorted by Υ yield impact |
|
|
312
314
|
| `self_improve` | `{text?}` | One-click optimize: diagnoses, suggests, and simulates the best change in a single call |
|
|
313
|
-
| `get_best_operator(n?)` | `{n?}` | Top N operators with behavioral framing in power-user language. Intent: "who is the best AI user?" |
|
|
314
|
-
| `compare_self(codename? \| text?)` | `{codename?}` or `{text?}` | Your metrics vs board averages + power-user assessment + percentile + suggestion. Intent: "how do I measure up?" |
|
|
315
|
-
| `compare_operators(a, b)` | `{codename_a, codename_b}` | Side-by-side comparison with behavioral verdict. Intent: "compare operator X vs Y" |
|
|
316
|
-
| `describe_power_user()` | `{}` | Static explanation of AI power user archetype + metrics explained. Intent: "what is an AI power user?" |
|
|
317
|
-
| `optimize_efficiency(codename? \| text?)` | `{codename?}` or `{text?}` | Ranked efficiency suggestions tied to your cascade shape. Intent: "how can I use AI more efficiently?" |
|
|
318
315
|
| `tokscale_breakdown(threshold?)` | `{threshold?}` | Per-model token breakdown across platforms (models under threshold → "other") |
|
|
319
316
|
| `tokscale_market_share()` | `{}` | AI tool market share: each tool's % of tokens/cost/messages, ranked. From local tokscale data |
|
|
320
317
|
| `tokscale_developer_profile()` | `{}` | Per-developer usage profile across all detected tools: model mix, pillars, sessions, workspaces. Paths redacted |
|
|
@@ -324,6 +321,8 @@ Or if installed globally:
|
|
|
324
321
|
| `tokscale_mcp_usage()` | `{}` | MCP server usage: detected servers, detection window, active days |
|
|
325
322
|
| `tokscale_competitive_intel(target)` | `{target}` | Competitive intelligence for any AI tool: rank, model mix, cost efficiency, share vs all competitors |
|
|
326
323
|
|
|
324
|
+
Intent tools (`get_best_operator`, `compare_self`, `compare_operators`, `describe_power_user`, `optimize_efficiency`) moved to [bestuser-router-mcp](https://github.com/SunrisesIllNeverSee/bestuser-router-mcp) — `npx bestuser-router-mcp`.
|
|
325
|
+
|
|
327
326
|
---
|
|
328
327
|
|
|
329
328
|
## Cascade math
|
package/adapters/tokenpull.mjs
CHANGED
|
@@ -22,7 +22,10 @@ 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 {
|
|
25
|
+
import {
|
|
26
|
+
TOKSCALE_CLIENT_MAP,
|
|
27
|
+
TOKSCALE_SCAN_TIMEOUT_MS,
|
|
28
|
+
} from "../lib/constants.mjs";
|
|
26
29
|
|
|
27
30
|
const DAY_MS = 86_400_000;
|
|
28
31
|
|
|
@@ -516,7 +519,11 @@ async function _freshTokendash(platform = "claude") {
|
|
|
516
519
|
// Now uses execFile (async) so the TUI stays responsive.
|
|
517
520
|
async function _freshTokscale(platform = "claude") {
|
|
518
521
|
try {
|
|
519
|
-
const raw = await execFileAsync(
|
|
522
|
+
const raw = await execFileAsync(
|
|
523
|
+
"tokscale",
|
|
524
|
+
["models", "--json"],
|
|
525
|
+
TOKSCALE_SCAN_TIMEOUT_MS,
|
|
526
|
+
);
|
|
520
527
|
const data = JSON.parse(raw);
|
|
521
528
|
const entries = Array.isArray(data?.entries)
|
|
522
529
|
? data.entries
|
package/index.mjs
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* Token-only — no transcript content.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import {
|
|
25
|
+
import { serveStdio } from "@modelcontextprotocol/server/stdio";
|
|
26
26
|
import { Server, ProtocolError, ProtocolErrorCode } from "@modelcontextprotocol/server";
|
|
27
27
|
import { TOOLS, callTool } from "./tools.mjs";
|
|
28
28
|
import { runCli } from "./cli.mjs";
|
|
@@ -64,8 +64,12 @@ function installMcpCrashHandlers() {
|
|
|
64
64
|
});
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
// One factory builds a server instance per connection. serveStdio owns the
|
|
68
|
+
// era decision: a `server/discover` probe with the modern envelope pins the
|
|
69
|
+
// connection to protocol revision 2026-07-28; an `initialize` opening serves
|
|
70
|
+
// the 2025-era protocol unchanged (legacy: 'serve' — retained deliberately;
|
|
71
|
+
// see docs/PROTOCOL-COMPATIBILITY.md). The same handlers back both eras.
|
|
72
|
+
function buildServer() {
|
|
69
73
|
const server = new Server(
|
|
70
74
|
{ name: "sigrank", version: serverVersion() },
|
|
71
75
|
{ capabilities: { tools: { listChanged: false }, prompts: { listChanged: false }, resources: { listChanged: false } } },
|
|
@@ -251,7 +255,15 @@ async function startMcpServer() {
|
|
|
251
255
|
};
|
|
252
256
|
});
|
|
253
257
|
|
|
254
|
-
|
|
258
|
+
return server;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function startMcpServer() {
|
|
262
|
+
installMcpCrashHandlers();
|
|
263
|
+
serveStdio(() => buildServer(), {
|
|
264
|
+
onerror: (e) =>
|
|
265
|
+
process.stderr.write(`[sigrank-mcp] stdio transport: ${e.message}\n`),
|
|
266
|
+
});
|
|
255
267
|
}
|
|
256
268
|
|
|
257
269
|
// Route:
|
package/lib/constants.mjs
CHANGED
|
@@ -115,6 +115,18 @@ export const TOKSCALE_CLIENT_MAP = {
|
|
|
115
115
|
*/
|
|
116
116
|
export const TOKSCALE_BLIND_PLATFORMS = [];
|
|
117
117
|
|
|
118
|
+
/**
|
|
119
|
+
* Timeout for `tokscale` CLI invocations (models/clients/graph/report scans).
|
|
120
|
+
* The scan walks every session log on the machine; on heavy machines it runs
|
|
121
|
+
* ~55–60s and GROWS with log volume, so the old hardcoded 60s ceiling flaked —
|
|
122
|
+
* the subprocess was killed mid-scan and the caller silently got null
|
|
123
|
+
* (TUI Compare showed "no data from tokscale"). 180s gives 3x headroom and
|
|
124
|
+
* stays under tokscale's own nativeTimeoutMs default (300s).
|
|
125
|
+
* Override via SIGRANK_TOKSCALE_TIMEOUT_MS.
|
|
126
|
+
*/
|
|
127
|
+
export const TOKSCALE_SCAN_TIMEOUT_MS =
|
|
128
|
+
Number(process.env.SIGRANK_TOKSCALE_TIMEOUT_MS) || 180_000;
|
|
129
|
+
|
|
118
130
|
/**
|
|
119
131
|
* The "actually on the board" predicate. A submission is ranked only when the
|
|
120
132
|
* server returns HTTP ok AND verification_tier === "verified" AND persisted
|
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.45",
|
|
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.45",
|
|
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",
|
|
@@ -81,10 +81,10 @@
|
|
|
81
81
|
"on-device"
|
|
82
82
|
],
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"token-cascade": "
|
|
84
|
+
"token-cascade": "0.2.1",
|
|
85
85
|
"ccusage": "^20.0.19",
|
|
86
86
|
"tokscale": "^4.7.0",
|
|
87
|
-
"@modelcontextprotocol/server": "
|
|
87
|
+
"@modelcontextprotocol/server": "2.3.0"
|
|
88
88
|
},
|
|
89
89
|
"devDependencies": {
|
|
90
90
|
"@resvg/resvg-js": "^2.6.2",
|
package/presentation/cli.mjs
CHANGED
|
@@ -29,7 +29,11 @@ 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 {
|
|
32
|
+
import {
|
|
33
|
+
LEADERBOARD_METRIC,
|
|
34
|
+
TOKSCALE_CLIENT_MAP,
|
|
35
|
+
TOKSCALE_SCAN_TIMEOUT_MS,
|
|
36
|
+
} from "../lib/constants.mjs";
|
|
33
37
|
import { execFile } from "child_process";
|
|
34
38
|
import { existsSync, readFileSync } from "fs";
|
|
35
39
|
import os from "os";
|
|
@@ -422,7 +426,11 @@ async function ccusagePillars(platform = "claude") {
|
|
|
422
426
|
async function tokscalePillars(platform = "claude") {
|
|
423
427
|
// Try the bundled tokscale CLI first (fresh data), fall back to saved report file.
|
|
424
428
|
try {
|
|
425
|
-
const raw = await execFileAsync(
|
|
429
|
+
const raw = await execFileAsync(
|
|
430
|
+
"tokscale",
|
|
431
|
+
["models", "--json"],
|
|
432
|
+
TOKSCALE_SCAN_TIMEOUT_MS,
|
|
433
|
+
);
|
|
426
434
|
const data = JSON.parse(raw);
|
|
427
435
|
const entries = Array.isArray(data?.entries)
|
|
428
436
|
? data.entries
|
package/presentation/tui.mjs
CHANGED
|
@@ -1444,7 +1444,7 @@ function renderCompare(data) {
|
|
|
1444
1444
|
const missing = [];
|
|
1445
1445
|
if (!cc) missing.push("ccusage (npm i -g ccusage)");
|
|
1446
1446
|
if (!td) missing.push("token-dashboard (~/.claude/token-dashboard.db)");
|
|
1447
|
-
if (!ts) missing.push("tokscale (
|
|
1447
|
+
if (!ts) missing.push("tokscale (not installed, or scan timed out)");
|
|
1448
1448
|
if (missing.length)
|
|
1449
1449
|
for (const ln of wrapDim(`no data from: ${missing.join(" · ")}`)) emit(ln);
|
|
1450
1450
|
emit();
|
package/tokscale_analytics.mjs
CHANGED
|
@@ -33,7 +33,10 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
33
33
|
import os from "node:os";
|
|
34
34
|
import path from "node:path";
|
|
35
35
|
import { fileURLToPath } from "node:url";
|
|
36
|
-
import {
|
|
36
|
+
import {
|
|
37
|
+
TOKSCALE_CLIENT_MAP,
|
|
38
|
+
TOKSCALE_SCAN_TIMEOUT_MS,
|
|
39
|
+
} from "./lib/constants.mjs";
|
|
37
40
|
|
|
38
41
|
// Resolve local node_modules/.bin for the bundled tokscale binary.
|
|
39
42
|
const _pkgRoot = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -61,13 +64,14 @@ function execFileAsync(cmd, args, timeoutMs) {
|
|
|
61
64
|
});
|
|
62
65
|
}
|
|
63
66
|
|
|
64
|
-
// tokscale subcommand timeouts. `models`
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
const
|
|
68
|
-
const
|
|
69
|
-
const
|
|
70
|
-
const
|
|
67
|
+
// tokscale subcommand timeouts. `models`/`clients`/`graph`/`report` all walk the
|
|
68
|
+
// session logs — on a heavy machine the scan runs ~55-60s and grows with log
|
|
69
|
+
// volume, so they share TOKSCALE_SCAN_TIMEOUT_MS (was a flat 60s that flaked).
|
|
70
|
+
const T_MODELS = TOKSCALE_SCAN_TIMEOUT_MS;
|
|
71
|
+
const T_MONTHLY = TOKSCALE_SCAN_TIMEOUT_MS;
|
|
72
|
+
const T_CLIENTS = TOKSCALE_SCAN_TIMEOUT_MS;
|
|
73
|
+
const T_GRAPH = TOKSCALE_SCAN_TIMEOUT_MS;
|
|
74
|
+
const T_REPORT = TOKSCALE_SCAN_TIMEOUT_MS;
|
|
71
75
|
|
|
72
76
|
const HOME = os.homedir();
|
|
73
77
|
|
package/tools/_verifiers.mjs
CHANGED
|
@@ -10,6 +10,7 @@ import { existsSync, readFileSync } from "node:fs";
|
|
|
10
10
|
import os from "node:os";
|
|
11
11
|
import path from "node:path";
|
|
12
12
|
import { execFileAsync } from "./_helpers.mjs";
|
|
13
|
+
import { TOKSCALE_SCAN_TIMEOUT_MS } from "../lib/constants.mjs";
|
|
13
14
|
|
|
14
15
|
async function _ccusagePillars(platform = "claude") {
|
|
15
16
|
try {
|
|
@@ -87,7 +88,11 @@ async function _tokenDashPillars() {
|
|
|
87
88
|
async function _tokscalePillars(platform = "claude") {
|
|
88
89
|
// Try the bundled tokscale CLI first (fresh data), fall back to saved report file.
|
|
89
90
|
try {
|
|
90
|
-
const raw = await execFileAsync(
|
|
91
|
+
const raw = await execFileAsync(
|
|
92
|
+
"tokscale",
|
|
93
|
+
["models", "--json"],
|
|
94
|
+
TOKSCALE_SCAN_TIMEOUT_MS,
|
|
95
|
+
);
|
|
91
96
|
const data = JSON.parse(raw);
|
|
92
97
|
const entries = Array.isArray(data?.entries)
|
|
93
98
|
? data.entries
|
package/tools/index.mjs
CHANGED
|
@@ -12,6 +12,7 @@ import { buildFetch, DEFAULT_API_BASE, DEFAULT_FETCH_TIMEOUT } from "./_helpers.
|
|
|
12
12
|
import {
|
|
13
13
|
TOKSCALE_CLIENT_MAP,
|
|
14
14
|
TOKSCALE_BLIND_PLATFORMS,
|
|
15
|
+
TOKSCALE_SCAN_TIMEOUT_MS,
|
|
15
16
|
} from "../lib/constants.mjs";
|
|
16
17
|
|
|
17
18
|
import { TOOL_DEF as rankPasteTool, handleRankPaste } from "./rank-paste.mjs";
|
|
@@ -83,7 +84,11 @@ export const TOOLS = [
|
|
|
83
84
|
|
|
84
85
|
/** Run `tokscale models --json` and return the list of our platform names. */
|
|
85
86
|
async function _tokscaleDetectClients() {
|
|
86
|
-
const raw = await execFileAsync(
|
|
87
|
+
const raw = await execFileAsync(
|
|
88
|
+
"tokscale",
|
|
89
|
+
["models", "--json"],
|
|
90
|
+
TOKSCALE_SCAN_TIMEOUT_MS,
|
|
91
|
+
);
|
|
87
92
|
const data = JSON.parse(raw);
|
|
88
93
|
const entries = Array.isArray(data?.entries)
|
|
89
94
|
? data.entries
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
|
|
5
5
|
import { execFileAsync } from "./_helpers.mjs";
|
|
6
6
|
import { ANNOTATIONS } from "./_schemas.mjs";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
TOKSCALE_CLIENT_MAP,
|
|
9
|
+
TOKSCALE_SCAN_TIMEOUT_MS,
|
|
10
|
+
} from "../lib/constants.mjs";
|
|
8
11
|
|
|
9
12
|
export const TOOL_DEF = {
|
|
10
13
|
name: "tokscale_breakdown",
|
|
@@ -47,7 +50,11 @@ export const TOOL_DEF = {
|
|
|
47
50
|
* Returns: { platform: [{ model, input, output, cacheRead, cacheCreate, pct }] }
|
|
48
51
|
*/
|
|
49
52
|
export async function tokscaleModelBreakdown(threshold = 0.01) {
|
|
50
|
-
const raw = await execFileAsync(
|
|
53
|
+
const raw = await execFileAsync(
|
|
54
|
+
"tokscale",
|
|
55
|
+
["models", "--json"],
|
|
56
|
+
TOKSCALE_SCAN_TIMEOUT_MS,
|
|
57
|
+
);
|
|
51
58
|
const data = JSON.parse(raw);
|
|
52
59
|
const entries = Array.isArray(data?.entries)
|
|
53
60
|
? data.entries
|