sigrank 0.0.177 → 0.0.179
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 +100 -0
- package/MCP_SERVER_DESCRIPTION.md +141 -0
- package/README.md +23 -3
- package/adapters/index.mjs +865 -0
- package/adapters/tokenpull.mjs +576 -0
- package/adapters.mjs +1 -750
- package/analytics/cascade.mjs +274 -0
- package/cascade.mjs +1 -274
- package/cli.mjs +1 -1850
- package/connect.mjs +1 -13
- package/identity/connect.mjs +13 -0
- package/identity/keystore.mjs +242 -0
- package/identity/sign.mjs +106 -0
- package/index.mjs +30 -148
- package/keystore.mjs +1 -242
- package/narrate.mjs +1 -77
- package/package.json +31 -15
- package/preflight.mjs +1 -191
- package/presentation/cli.mjs +1874 -0
- package/presentation/narrate.mjs +77 -0
- package/presentation/tui.mjs +2668 -0
- package/prompts/check-my-efficiency.md +1 -0
- package/prompts/compare-with-leader.md +1 -0
- package/prompts/simulate-improvement.md +1 -0
- package/resources/class-tiers.md +23 -0
- package/resources/data-policy.md +27 -0
- package/resources/install-guide.md +59 -0
- package/resources/privacy-model.md +30 -0
- package/resources/scoring-formula.md +28 -0
- package/review.mjs +263 -0
- package/sign.mjs +1 -106
- package/submit/index.mjs +309 -0
- package/submit/preflight.mjs +191 -0
- package/submit.mjs +1 -303
- package/tokenpull.mjs +1 -584
- package/tools/_framing.mjs +139 -0
- package/tools/_helpers.mjs +258 -0
- package/tools/_report.mjs +262 -0
- package/tools/_schemas.mjs +394 -0
- package/tools/_verifiers.mjs +148 -0
- package/tools/compare-operators.mjs +79 -0
- package/tools/compare-self.mjs +122 -0
- package/tools/describe-power-user.mjs +68 -0
- package/tools/diagnose-cascade.mjs +192 -0
- package/tools/enroll.mjs +121 -0
- package/tools/get-best-operator.mjs +58 -0
- package/tools/get-leaderboard.mjs +26 -0
- package/tools/get-operator.mjs +33 -0
- package/tools/index.mjs +257 -0
- package/tools/optimize-efficiency.mjs +160 -0
- package/tools/rank-paste.mjs +51 -0
- package/tools/rank-windows.mjs +120 -0
- package/tools/self-improve.mjs +423 -0
- package/tools/simulate-change.mjs +207 -0
- package/tools/submit-paste.mjs +118 -0
- package/tools/submit-verified.mjs +153 -0
- package/tools/suggest-improvements.mjs +168 -0
- package/tools/tokenpull-compare.mjs +123 -0
- package/tools/tokenpull-submit.mjs +234 -0
- package/tools/tokenpull.mjs +113 -0
- package/tools/tokscale-breakdown.mjs +159 -0
- package/tools/tokscale-competitive-intel.mjs +45 -0
- package/tools/tokscale-cost-analysis.mjs +31 -0
- package/tools/tokscale-developer-profile.mjs +36 -0
- package/tools/tokscale-device-profile.mjs +35 -0
- package/tools/tokscale-market-share.mjs +38 -0
- package/tools/tokscale-mcp-usage.mjs +33 -0
- package/tools/tokscale-model-trends.mjs +32 -0
- package/tools/watch-tokenpull.mjs +134 -0
- package/tools.mjs +1 -3385
- package/tui.mjs +4 -2650
- package/banner.svg +0 -7
package/tools/index.mjs
ADDED
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tools/index.mjs — the SigRank MCP tool table + dispatcher, transport-free so it can be
|
|
3
|
+
* unit-tested without spawning the stdio server.
|
|
4
|
+
*
|
|
5
|
+
* Imports individual tool modules from ./ and re-exports the TOOLS array + callTool
|
|
6
|
+
* dispatcher. Backward-compatible root import via ../tools.mjs (shim).
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { ALL_PLATFORMS } from "../adapters/index.mjs";
|
|
10
|
+
import { execFileAsync } from "./_helpers.mjs";
|
|
11
|
+
import { buildFetch, DEFAULT_API_BASE, DEFAULT_FETCH_TIMEOUT } from "./_helpers.mjs";
|
|
12
|
+
|
|
13
|
+
import { TOOL_DEF as rankPasteTool, handleRankPaste } from "./rank-paste.mjs";
|
|
14
|
+
import { TOOL_DEF as getLeaderboardTool, handleGetLeaderboard } from "./get-leaderboard.mjs";
|
|
15
|
+
import { TOOL_DEF as getOperatorTool, handleGetOperator } from "./get-operator.mjs";
|
|
16
|
+
import { TOOL_DEF as submitPasteTool, handleSubmitPaste } from "./submit-paste.mjs";
|
|
17
|
+
import { TOOL_DEF as tokenpullTool, handleTokenpull } from "./tokenpull.mjs";
|
|
18
|
+
import { TOOL_DEF as tokenpullSubmitTool, handleTokenpullSubmit } from "./tokenpull-submit.mjs";
|
|
19
|
+
import { TOOL_DEF as rankWindowsTool, handleRankWindows } from "./rank-windows.mjs";
|
|
20
|
+
import { TOOL_DEF as watchTokenpullTool, handleWatchTokenpull } from "./watch-tokenpull.mjs";
|
|
21
|
+
import { TOOL_DEF as tokenpullCompareTool, handleTokenpullCompare } from "./tokenpull-compare.mjs";
|
|
22
|
+
import { TOOL_DEF as enrollTool, handleEnroll } from "./enroll.mjs";
|
|
23
|
+
import { TOOL_DEF as submitVerifiedTool, handleSubmitVerified } from "./submit-verified.mjs";
|
|
24
|
+
import { TOOL_DEF as simulateChangeTool, handleSimulateChange } from "./simulate-change.mjs";
|
|
25
|
+
import { TOOL_DEF as diagnoseCascadeTool, handleDiagnoseCascade } from "./diagnose-cascade.mjs";
|
|
26
|
+
import { TOOL_DEF as suggestImprovementsTool, handleSuggestImprovements } from "./suggest-improvements.mjs";
|
|
27
|
+
import { TOOL_DEF as selfImproveTool, handleSelfImprove } from "./self-improve.mjs";
|
|
28
|
+
import { TOOL_DEF as getBestOperatorTool, handleGetBestOperator } from "./get-best-operator.mjs";
|
|
29
|
+
import { TOOL_DEF as compareSelfTool, handleCompareSelf } from "./compare-self.mjs";
|
|
30
|
+
import { TOOL_DEF as compareOperatorsTool, handleCompareOperators } from "./compare-operators.mjs";
|
|
31
|
+
import { TOOL_DEF as describePowerUserTool, handleDescribePowerUser } from "./describe-power-user.mjs";
|
|
32
|
+
import { TOOL_DEF as optimizeEfficiencyTool, handleOptimizeEfficiency } from "./optimize-efficiency.mjs";
|
|
33
|
+
import { TOOL_DEF as tokscaleBreakdownTool, handleTokscaleBreakdown } from "./tokscale-breakdown.mjs";
|
|
34
|
+
import { TOOL_DEF as tokscaleMarketShareTool, handleTokscaleMarketShare } from "./tokscale-market-share.mjs";
|
|
35
|
+
import { TOOL_DEF as tokscaleDeveloperProfileTool, handleTokscaleDeveloperProfile } from "./tokscale-developer-profile.mjs";
|
|
36
|
+
import { TOOL_DEF as tokscaleModelTrendsTool, handleTokscaleModelTrends } from "./tokscale-model-trends.mjs";
|
|
37
|
+
import { TOOL_DEF as tokscaleCostAnalysisTool, handleTokscaleCostAnalysis } from "./tokscale-cost-analysis.mjs";
|
|
38
|
+
import { TOOL_DEF as tokscaleDeviceProfileTool, handleTokscaleDeviceProfile } from "./tokscale-device-profile.mjs";
|
|
39
|
+
import { TOOL_DEF as tokscaleMcpUsageTool, handleTokscaleMcpUsage } from "./tokscale-mcp-usage.mjs";
|
|
40
|
+
import { TOOL_DEF as tokscaleCompetitiveIntelTool, handleTokscaleCompetitiveIntel } from "./tokscale-competitive-intel.mjs";
|
|
41
|
+
|
|
42
|
+
export { DEFAULT_API_BASE, DEFAULT_FETCH_TIMEOUT };
|
|
43
|
+
|
|
44
|
+
export const TOOLS = [
|
|
45
|
+
rankPasteTool,
|
|
46
|
+
getLeaderboardTool,
|
|
47
|
+
getOperatorTool,
|
|
48
|
+
submitPasteTool,
|
|
49
|
+
tokenpullTool,
|
|
50
|
+
tokenpullSubmitTool,
|
|
51
|
+
rankWindowsTool,
|
|
52
|
+
watchTokenpullTool,
|
|
53
|
+
tokenpullCompareTool,
|
|
54
|
+
enrollTool,
|
|
55
|
+
submitVerifiedTool,
|
|
56
|
+
simulateChangeTool,
|
|
57
|
+
diagnoseCascadeTool,
|
|
58
|
+
suggestImprovementsTool,
|
|
59
|
+
selfImproveTool,
|
|
60
|
+
getBestOperatorTool,
|
|
61
|
+
compareSelfTool,
|
|
62
|
+
compareOperatorsTool,
|
|
63
|
+
describePowerUserTool,
|
|
64
|
+
optimizeEfficiencyTool,
|
|
65
|
+
tokscaleBreakdownTool,
|
|
66
|
+
tokscaleMarketShareTool,
|
|
67
|
+
tokscaleDeveloperProfileTool,
|
|
68
|
+
tokscaleModelTrendsTool,
|
|
69
|
+
tokscaleCostAnalysisTool,
|
|
70
|
+
tokscaleDeviceProfileTool,
|
|
71
|
+
tokscaleMcpUsageTool,
|
|
72
|
+
tokscaleCompetitiveIntelTool,
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
const TOKSCALE_CLIENT_MAP = {
|
|
76
|
+
claude: "claude",
|
|
77
|
+
codex: "codex",
|
|
78
|
+
"devin-cli": "devin",
|
|
79
|
+
"devin-desktop": "devin",
|
|
80
|
+
gemini: "gemini",
|
|
81
|
+
amp: "amp",
|
|
82
|
+
kimi: "kimi",
|
|
83
|
+
qwen: "qwen",
|
|
84
|
+
goose: "goose",
|
|
85
|
+
kilo: "kilo",
|
|
86
|
+
kilocode: "kilo",
|
|
87
|
+
hermes: "hermes",
|
|
88
|
+
droid: "droid",
|
|
89
|
+
codebuff: "codebuff",
|
|
90
|
+
copilot: "copilot",
|
|
91
|
+
opencode: "opencode",
|
|
92
|
+
openclaw: "openclaw",
|
|
93
|
+
pi: "pi",
|
|
94
|
+
cursor: "other",
|
|
95
|
+
roocode: "other",
|
|
96
|
+
mux: "other",
|
|
97
|
+
crush: "other",
|
|
98
|
+
antigravity: "other",
|
|
99
|
+
"antigravity-cli": "other",
|
|
100
|
+
zed: "other",
|
|
101
|
+
kiro: "other",
|
|
102
|
+
trae: "other",
|
|
103
|
+
warp: "other",
|
|
104
|
+
cline: "other",
|
|
105
|
+
gjc: "other",
|
|
106
|
+
grok: "other",
|
|
107
|
+
jcode: "other",
|
|
108
|
+
commandcode: "other",
|
|
109
|
+
micode: "other",
|
|
110
|
+
junie: "other",
|
|
111
|
+
zcode: "other",
|
|
112
|
+
opencodereview: "other",
|
|
113
|
+
codebuddy: "other",
|
|
114
|
+
workbuddy: "other",
|
|
115
|
+
synthetic: null,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** Run `tokscale models --json` and return the list of our platform names. */
|
|
119
|
+
async function _tokscaleDetectClients() {
|
|
120
|
+
const raw = await execFileAsync("tokscale", ["models", "--json"], 60000);
|
|
121
|
+
const data = JSON.parse(raw);
|
|
122
|
+
const entries = Array.isArray(data?.entries)
|
|
123
|
+
? data.entries
|
|
124
|
+
: Array.isArray(data)
|
|
125
|
+
? data
|
|
126
|
+
: [];
|
|
127
|
+
if (!entries.length) return [];
|
|
128
|
+
const clients = new Set();
|
|
129
|
+
for (const e of entries) {
|
|
130
|
+
if (!e || !e.client) continue;
|
|
131
|
+
if (e.model === "<synthetic>" || e.model === "unknown") continue;
|
|
132
|
+
const input = Number(e.input) || 0;
|
|
133
|
+
const output = Number(e.output) || 0;
|
|
134
|
+
if (input + output === 0) continue;
|
|
135
|
+
const platform = TOKSCALE_CLIENT_MAP[e.client];
|
|
136
|
+
if (platform === null) continue; // synthetic → skip
|
|
137
|
+
clients.add(platform || "other");
|
|
138
|
+
}
|
|
139
|
+
return [...clients];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/** Pull a specific set of platforms in parallel, filter to active ones. */
|
|
143
|
+
async function _pullExplicit(platforms, opts = {}) {
|
|
144
|
+
const settled = await Promise.allSettled(
|
|
145
|
+
platforms.map((p) => callTool("tokenpull", { platform: p }, opts)),
|
|
146
|
+
);
|
|
147
|
+
const active = settled
|
|
148
|
+
.filter((r) => r.status === "fulfilled" && r.value)
|
|
149
|
+
.map((r) => r.value)
|
|
150
|
+
.filter((d) =>
|
|
151
|
+
(d.windows || []).some(
|
|
152
|
+
(w) => (w.pillars?.input ?? 0) + (w.pillars?.output ?? 0) > 0,
|
|
153
|
+
),
|
|
154
|
+
);
|
|
155
|
+
const rank = (p) =>
|
|
156
|
+
p === "claude" ? -2 : p === "codex" ? -1 : ALL_PLATFORMS.indexOf(p);
|
|
157
|
+
active.sort((a, b) => rank(a.platform) - rank(b.platform));
|
|
158
|
+
return active;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ── Shared active-platform loader ───────────────────────────────────────────
|
|
162
|
+
// THE single data path for "show my cascade across platforms" — used by `me`,
|
|
163
|
+
// `watch`, and the TUI Dashboard so they can't drift apart again. Pulls each
|
|
164
|
+
// target platform via the tokenpull tool (enriched: pillars + cascade + card),
|
|
165
|
+
// keeps only platforms with real local data, and sorts claude → codex → rest.
|
|
166
|
+
// Pass `platforms` to scope it (e.g. ['claude'] for a fast first paint).
|
|
167
|
+
export async function pullActivePlatforms({ platforms } = {}, opts = {}) {
|
|
168
|
+
// If the caller specified explicit platforms, use those.
|
|
169
|
+
if (platforms && platforms.length) {
|
|
170
|
+
return _pullExplicit(platforms, opts);
|
|
171
|
+
}
|
|
172
|
+
// Auto-detect: run tokscale once to discover all active clients, then pull
|
|
173
|
+
// only those. This is much faster than trying all 17 adapters (most fail
|
|
174
|
+
// silently on a machine that doesn't have that tool installed).
|
|
175
|
+
//
|
|
176
|
+
// Flow: tokscale surfaces ALL clients → map to our platform names →
|
|
177
|
+
// ccusage is primary for Claude (more accurate) → other platforms use
|
|
178
|
+
// their adapters. Anything in tokscale NOT in ccusage gets included.
|
|
179
|
+
const detected = await _tokscaleDetectClients().catch(() => null);
|
|
180
|
+
if (detected && detected.length > 0) {
|
|
181
|
+
return _pullExplicit(detected, opts);
|
|
182
|
+
}
|
|
183
|
+
// Fallback: tokscale not installed or failed → try all adapters (old behavior)
|
|
184
|
+
return _pullExplicit(ALL_PLATFORMS, opts);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
export async function callTool(name, args, opts = {}) {
|
|
188
|
+
const { apiBase, doFetch, fetchJson } = buildFetch(opts);
|
|
189
|
+
const ctx = {
|
|
190
|
+
apiBase,
|
|
191
|
+
doFetch,
|
|
192
|
+
fetchJson,
|
|
193
|
+
opts,
|
|
194
|
+
callTool: (n, a) => callTool(n, a, opts),
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
switch (name) {
|
|
198
|
+
case "rank_paste":
|
|
199
|
+
return handleRankPaste(args);
|
|
200
|
+
case "get_leaderboard":
|
|
201
|
+
return handleGetLeaderboard(args, ctx);
|
|
202
|
+
case "get_operator":
|
|
203
|
+
return handleGetOperator(args, ctx);
|
|
204
|
+
case "submit_paste":
|
|
205
|
+
return handleSubmitPaste(args, ctx);
|
|
206
|
+
case "tokenpull":
|
|
207
|
+
return handleTokenpull(args, ctx);
|
|
208
|
+
case "tokenpull_submit":
|
|
209
|
+
return handleTokenpullSubmit(args, ctx);
|
|
210
|
+
case "rank_windows":
|
|
211
|
+
return handleRankWindows(args);
|
|
212
|
+
case "watch_tokenpull":
|
|
213
|
+
return handleWatchTokenpull(args, ctx);
|
|
214
|
+
case "tokenpull_compare":
|
|
215
|
+
return handleTokenpullCompare(args, ctx);
|
|
216
|
+
case "enroll":
|
|
217
|
+
return handleEnroll(args, ctx);
|
|
218
|
+
case "submit_verified":
|
|
219
|
+
return handleSubmitVerified(args, ctx);
|
|
220
|
+
case "simulate_change":
|
|
221
|
+
return handleSimulateChange(args);
|
|
222
|
+
case "diagnose_cascade":
|
|
223
|
+
return handleDiagnoseCascade(args);
|
|
224
|
+
case "suggest_improvements":
|
|
225
|
+
return handleSuggestImprovements(args);
|
|
226
|
+
case "self_improve":
|
|
227
|
+
return handleSelfImprove(args, ctx);
|
|
228
|
+
case "get_best_operator":
|
|
229
|
+
return handleGetBestOperator(args, ctx);
|
|
230
|
+
case "compare_self":
|
|
231
|
+
return handleCompareSelf(args, ctx);
|
|
232
|
+
case "compare_operators":
|
|
233
|
+
return handleCompareOperators(args, ctx);
|
|
234
|
+
case "describe_power_user":
|
|
235
|
+
return handleDescribePowerUser();
|
|
236
|
+
case "optimize_efficiency":
|
|
237
|
+
return handleOptimizeEfficiency(args, ctx);
|
|
238
|
+
case "tokscale_breakdown":
|
|
239
|
+
return handleTokscaleBreakdown(args);
|
|
240
|
+
case "tokscale_market_share":
|
|
241
|
+
return handleTokscaleMarketShare();
|
|
242
|
+
case "tokscale_developer_profile":
|
|
243
|
+
return handleTokscaleDeveloperProfile();
|
|
244
|
+
case "tokscale_model_trends":
|
|
245
|
+
return handleTokscaleModelTrends();
|
|
246
|
+
case "tokscale_cost_analysis":
|
|
247
|
+
return handleTokscaleCostAnalysis();
|
|
248
|
+
case "tokscale_device_profile":
|
|
249
|
+
return handleTokscaleDeviceProfile();
|
|
250
|
+
case "tokscale_mcp_usage":
|
|
251
|
+
return handleTokscaleMcpUsage();
|
|
252
|
+
case "tokscale_competitive_intel":
|
|
253
|
+
return handleTokscaleCompetitiveIntel(args);
|
|
254
|
+
default:
|
|
255
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tools/optimize-efficiency.mjs — optimize_efficiency tool.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { cascade, parsePillars } from "../analytics/cascade.mjs";
|
|
6
|
+
import { ANNOTATIONS } from "./_schemas.mjs";
|
|
7
|
+
import { MAX_INPUT, withParseWarnings } from "./_helpers.mjs";
|
|
8
|
+
import {
|
|
9
|
+
_improvementSuggestion,
|
|
10
|
+
_competitiveLayer,
|
|
11
|
+
_competitiveSummary,
|
|
12
|
+
} from "./_framing.mjs";
|
|
13
|
+
|
|
14
|
+
export const TOOL_DEF = {
|
|
15
|
+
name: "optimize_efficiency",
|
|
16
|
+
description:
|
|
17
|
+
"Returns actionable suggestions for improving your token cascade efficiency, tied to your current metrics. Accepts either a codename (fetches from board) or raw token pillars (computes locally). Returns: your current metrics, ranked efficiency suggestions tied to cascade shape (increase cache reuse, reduce input, increase output), and references to power-user practices. Use this when users ask 'how can I use AI more efficiently?' or 'reduce token burn' or 'optimize token usage' or 'stop tokenmaxxing'. Intent: OPTIMIZE_EFFICIENCY (Informational + Transactional).",
|
|
18
|
+
annotations: { title: "Optimize efficiency", ...ANNOTATIONS.readOnlyHint, ...ANNOTATIONS.idempotentHint },
|
|
19
|
+
inputSchema: {
|
|
20
|
+
type: "object",
|
|
21
|
+
properties: {
|
|
22
|
+
codename: {
|
|
23
|
+
type: "string",
|
|
24
|
+
description:
|
|
25
|
+
"Your codename on the SigRank leaderboard. If provided, fetches your live profile from the board.",
|
|
26
|
+
},
|
|
27
|
+
text: {
|
|
28
|
+
type: "string",
|
|
29
|
+
description:
|
|
30
|
+
'Alternative: raw token pillars to score locally (ccusage JSON or "input output cacheCreate cacheRead"). Use this if you are not on the board yet.',
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
description:
|
|
34
|
+
"Provide either `codename` (to fetch from the board) or `text` (to score locally). At least one is required.",
|
|
35
|
+
},
|
|
36
|
+
outputSchema: {
|
|
37
|
+
type: "object",
|
|
38
|
+
properties: {
|
|
39
|
+
your_metrics: {
|
|
40
|
+
type: "object",
|
|
41
|
+
description: "Your current cascade metrics",
|
|
42
|
+
properties: {
|
|
43
|
+
yield_: { type: "number" },
|
|
44
|
+
leverage: { type: "number" },
|
|
45
|
+
velocity: { type: "number" },
|
|
46
|
+
class: { type: "string", enum: ["Burner", "Builder", "10xer"] },
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
suggestions: {
|
|
50
|
+
type: "array",
|
|
51
|
+
description: "Ranked efficiency suggestions",
|
|
52
|
+
items: {
|
|
53
|
+
type: "object",
|
|
54
|
+
properties: {
|
|
55
|
+
action: { type: "string", description: "What to change" },
|
|
56
|
+
why: { type: "string", description: "Why this helps your yield" },
|
|
57
|
+
power_user_practice: { type: "string", description: "The power-user practice this maps to" },
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
summary: { type: "string", description: "One-line summary of your efficiency status" },
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export async function handleOptimizeEfficiency(args, ctx) {
|
|
67
|
+
const codename = String(args?.codename || "").trim();
|
|
68
|
+
const text = String(args?.text || "").trim();
|
|
69
|
+
|
|
70
|
+
if (!codename && !text)
|
|
71
|
+
throw new Error(
|
|
72
|
+
"optimize_efficiency requires either `codename` (to fetch from the board) or `text` (raw token pillars to score locally).",
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
let metrics;
|
|
76
|
+
if (codename) {
|
|
77
|
+
metrics = await ctx.fetchJson(
|
|
78
|
+
`/api/v1/operators/${encodeURIComponent(codename)}`,
|
|
79
|
+
);
|
|
80
|
+
} else {
|
|
81
|
+
if (text.length > MAX_INPUT) {
|
|
82
|
+
return { error: "input_too_large", detail: `text exceeds ${MAX_INPUT} chars.` };
|
|
83
|
+
}
|
|
84
|
+
const pillars = parsePillars(text);
|
|
85
|
+
const c = withParseWarnings(pillars, cascade(pillars));
|
|
86
|
+
metrics = {
|
|
87
|
+
codename: "you (local)",
|
|
88
|
+
yield_: c.yield,
|
|
89
|
+
leverage: c.leverage,
|
|
90
|
+
velocity: c.velocity,
|
|
91
|
+
class: c.class,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const klass = metrics.class || "Burner";
|
|
96
|
+
const l = metrics.leverage || 0;
|
|
97
|
+
const v = metrics.velocity || 0;
|
|
98
|
+
const y = metrics.yield_ || 0;
|
|
99
|
+
|
|
100
|
+
// Build ranked suggestions based on current cascade shape
|
|
101
|
+
const suggestions = [];
|
|
102
|
+
|
|
103
|
+
if (l < 5) {
|
|
104
|
+
suggestions.push({
|
|
105
|
+
action: "Increase cache reuse — reuse prompts, templates, and workflows instead of starting from scratch",
|
|
106
|
+
why: "Your leverage is " + l.toFixed(1) + "×, meaning most of your context is fresh input. Each reused cached token multiplies your yield because input² is in the denominator.",
|
|
107
|
+
power_user_practice: "Power users build template libraries and workflow patterns they invoke repeatedly, letting cached context accumulate.",
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
if (v < 1) {
|
|
111
|
+
suggestions.push({
|
|
112
|
+
action: "Increase output per session — produce more, don't just read",
|
|
113
|
+
why: "Your velocity is " + v.toFixed(2) + ", meaning you're consuming more input than producing output. Yield rewards output production.",
|
|
114
|
+
power_user_practice: "Power users maximize output per session — they ask AI to generate, transform, and produce, not just explain.",
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (l >= 5 && v >= 1 && klass !== "10xer") {
|
|
118
|
+
suggestions.push({
|
|
119
|
+
action: "Extend session length to compound cached context further",
|
|
120
|
+
why: "Your leverage (" + l.toFixed(1) + "×) and velocity (" + v.toFixed(2) + ") are solid. Longer sessions with consistent context will push your yield higher.",
|
|
121
|
+
power_user_practice: "Power users maintain long, context-rich sessions where the cache grows and compounds.",
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
if (suggestions.length === 0) {
|
|
125
|
+
suggestions.push({
|
|
126
|
+
action: "Maintain your cascade architecture — you're at the top tier",
|
|
127
|
+
why: "Your yield (" + y.toLocaleString() + "), leverage (" + l.toFixed(1) + "×), and velocity (" + v.toFixed(2) + ") are all strong. Keep doing what you're doing.",
|
|
128
|
+
power_user_practice: "Power users don't rest on their metrics — they experiment with new workflow patterns and measure the impact.",
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const summary = `Your Υ Yield is ${y.toLocaleString()} (${klass}). ${_improvementSuggestion(klass, metrics)}`;
|
|
133
|
+
|
|
134
|
+
// Competitive layer per SHARED_DESIGN_DECISIONS.md §3/§4/§5
|
|
135
|
+
const board = await ctx.fetchJson("/api/v1/leaderboard?metric=yield_");
|
|
136
|
+
const competitive = _competitiveLayer(metrics, board);
|
|
137
|
+
const competitiveSummary = _competitiveSummary(metrics, board);
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
your_metrics: {
|
|
141
|
+
yield_: y,
|
|
142
|
+
leverage: l,
|
|
143
|
+
velocity: v,
|
|
144
|
+
class: klass,
|
|
145
|
+
},
|
|
146
|
+
competitive: {
|
|
147
|
+
rank: competitive.rank,
|
|
148
|
+
total_operators: competitive.total_operators,
|
|
149
|
+
percentile: competitive.percentile,
|
|
150
|
+
class_tier: competitive.class_tier,
|
|
151
|
+
delta_from_average: competitive.delta_from_average,
|
|
152
|
+
delta_from_top: competitive.delta_from_top,
|
|
153
|
+
},
|
|
154
|
+
competitive_summary: competitiveSummary,
|
|
155
|
+
shareable_url: competitive.shareable_url,
|
|
156
|
+
suggestions,
|
|
157
|
+
summary,
|
|
158
|
+
cta: "Improve my score",
|
|
159
|
+
};
|
|
160
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tools/rank-paste.mjs — rank_paste tool.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { cascade, parsePillars } from "../analytics/cascade.mjs";
|
|
6
|
+
import { narrate } from "../presentation/narrate.mjs";
|
|
7
|
+
import { CASCADE_OUTPUT, ANNOTATIONS } from "./_schemas.mjs";
|
|
8
|
+
import { MAX_INPUT, withParseWarnings } from "./_helpers.mjs";
|
|
9
|
+
|
|
10
|
+
export const TOOL_DEF = {
|
|
11
|
+
name: "rank_paste",
|
|
12
|
+
description:
|
|
13
|
+
'Computes the SigRank yield cascade from a paste of token counts. Parses the input, runs the full cascade math locally (no network calls), and returns: Υ Yield (the headline efficiency metric, Υ = Cache Reads × Output / Input²), SNR (signal-to-noise ratio), Leverage ratio (Cr/I = cache reads divided by input), Velocity (O/I = output divided by input), 10xDEV score, operator class tier (Burner / Builder / 10xer), and a deterministic prose "card" summarizing the result in plain English. Accepts two input formats: (1) JSON object {"input":N,"output":N,"cacheCreate":N,"cacheRead":N} or (2) four whitespace-separated numbers in order: input output cacheCreate cacheRead. Returns an error if the input is malformed or has negative values. Use this for a quick one-off ranking without submitting to the board. Do NOT use this to submit your score — use submit_paste instead, which both ranks and publishes. Do NOT use this if you want to rank all four time windows at once — use rank_windows for that. After calling this, use submit_paste to publish the result if you want to appear on the leaderboard.',
|
|
14
|
+
annotations: {
|
|
15
|
+
title: "Rank a paste",
|
|
16
|
+
...ANNOTATIONS.readOnlyHint,
|
|
17
|
+
...ANNOTATIONS.destructiveHint,
|
|
18
|
+
...ANNOTATIONS.idempotentHint,
|
|
19
|
+
...ANNOTATIONS.openWorldHint,
|
|
20
|
+
},
|
|
21
|
+
inputSchema: {
|
|
22
|
+
type: "object",
|
|
23
|
+
properties: {
|
|
24
|
+
text: {
|
|
25
|
+
type: "string",
|
|
26
|
+
description:
|
|
27
|
+
'Token counts to rank. Two formats accepted: (1) JSON object {"input":N,"output":N,"cacheCreate":N,"cacheRead":N} where all values are non-negative integers, or (2) four whitespace-separated numbers in order: input output cacheCreate cacheRead. Get these from `ccusage` output, the Claude Max usage dashboard, tokscale, or any token reader. Example valid input: {"input":1000000,"output":500000,"cacheCreate":50000,"cacheRead":800000}',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
required: ["text"],
|
|
31
|
+
description:
|
|
32
|
+
"Requires the token counts as a string. No other parameters are accepted.",
|
|
33
|
+
},
|
|
34
|
+
outputSchema: CASCADE_OUTPUT,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export async function handleRankPaste(args) {
|
|
38
|
+
if (!args?.text)
|
|
39
|
+
throw new Error("rank_paste requires a non-empty `text` argument.");
|
|
40
|
+
// E2: reject oversized pastes before parsing (parity with submit_paste / rank_windows).
|
|
41
|
+
if (typeof args.text === "string" && args.text.length > MAX_INPUT) {
|
|
42
|
+
return {
|
|
43
|
+
status: "error",
|
|
44
|
+
reason: "input_too_large",
|
|
45
|
+
detail: `text exceeds ${MAX_INPUT} chars (${args.text.length}). Paste only the token-count table, not full output.`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const pillars = parsePillars(args.text);
|
|
49
|
+
const c = withParseWarnings(pillars, cascade(pillars));
|
|
50
|
+
return { ...c, card: narrate(c) };
|
|
51
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* tools/rank-windows.mjs — rank_windows tool.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { cascade, parsePillars } from "../analytics/cascade.mjs";
|
|
6
|
+
import { narrate } from "../presentation/narrate.mjs";
|
|
7
|
+
import { CASCADE_OUTPUT, ANNOTATIONS } from "./_schemas.mjs";
|
|
8
|
+
import { MAX_INPUT, withParseWarnings } from "./_helpers.mjs";
|
|
9
|
+
|
|
10
|
+
export const TOOL_DEF = {
|
|
11
|
+
name: "rank_windows",
|
|
12
|
+
description:
|
|
13
|
+
"Rank all four time windows (7d/30d/90d/all-time) in one call from a dashboard paste — paste the full table from ccusage, tokscale, or the Claude Max usage dashboard and get the cascade (Υ, SNR, Leverage, Velocity, 10xDEV, class, card) for each window. Each window is parsed and scored independently. Named keys required (input/output/cacheCreate/cacheRead); positional order is NOT safe here (dashboards list cache_read before cache_create — see WINDOWED_PROFILES gotcha). Omit windows you don't have — partial input is allowed (1–4 windows). Does NOT submit to the board; use tokenpull_submit for zero-paste publishing.",
|
|
14
|
+
annotations: {
|
|
15
|
+
title: "Rank all time windows",
|
|
16
|
+
...ANNOTATIONS.readOnlyHint,
|
|
17
|
+
...ANNOTATIONS.idempotentHint,
|
|
18
|
+
...ANNOTATIONS.openWorldHint,
|
|
19
|
+
},
|
|
20
|
+
inputSchema: {
|
|
21
|
+
type: "object",
|
|
22
|
+
properties: {
|
|
23
|
+
"7d": {
|
|
24
|
+
type: "string",
|
|
25
|
+
description:
|
|
26
|
+
"ccusage/tokscale paste or JSON for the 7-day window (optional)",
|
|
27
|
+
},
|
|
28
|
+
"30d": {
|
|
29
|
+
type: "string",
|
|
30
|
+
description:
|
|
31
|
+
"ccusage/tokscale paste or JSON for the 30-day window (optional)",
|
|
32
|
+
},
|
|
33
|
+
"90d": {
|
|
34
|
+
type: "string",
|
|
35
|
+
description:
|
|
36
|
+
"ccusage/tokscale paste or JSON for the 90-day window (optional)",
|
|
37
|
+
},
|
|
38
|
+
all: {
|
|
39
|
+
type: "string",
|
|
40
|
+
description:
|
|
41
|
+
"ccusage/tokscale paste or JSON for the all-time window (optional)",
|
|
42
|
+
},
|
|
43
|
+
source_tool: {
|
|
44
|
+
type: "string",
|
|
45
|
+
enum: [
|
|
46
|
+
"ccusage",
|
|
47
|
+
"tokscale",
|
|
48
|
+
"claude_max",
|
|
49
|
+
"token_dashboard",
|
|
50
|
+
"other",
|
|
51
|
+
],
|
|
52
|
+
description:
|
|
53
|
+
"which token reader produced the paste (for cross-tool variance tracking)",
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
// at least one window paste is required (runtime check backs this up)
|
|
57
|
+
anyOf: [
|
|
58
|
+
{ required: ["7d"] },
|
|
59
|
+
{ required: ["30d"] },
|
|
60
|
+
{ required: ["90d"] },
|
|
61
|
+
{ required: ["all"] },
|
|
62
|
+
],
|
|
63
|
+
},
|
|
64
|
+
outputSchema: {
|
|
65
|
+
type: "object",
|
|
66
|
+
properties: {
|
|
67
|
+
windows: {
|
|
68
|
+
type: "array",
|
|
69
|
+
description: "Cascade results per window",
|
|
70
|
+
items: {
|
|
71
|
+
type: "object",
|
|
72
|
+
properties: {
|
|
73
|
+
window: { type: "string", enum: ["7d", "30d", "90d", "all"] },
|
|
74
|
+
...CASCADE_OUTPUT.properties,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export async function handleRankWindows(args) {
|
|
83
|
+
// Score up to 4 named window pastes independently. Named-key parsing only —
|
|
84
|
+
// positional is unsafe here because dashboards list cache_read before cache_create
|
|
85
|
+
// (the WINDOWED_PROFILES swap gotcha). Each window goes through parsePillars →
|
|
86
|
+
// cascade → narrate individually; results are collected into a windows[] array
|
|
87
|
+
// in the same shape as tokenpull output for easy follow-up with tokenpull_submit.
|
|
88
|
+
const WINDOW_KEYS = ["7d", "30d", "90d", "all"];
|
|
89
|
+
const sourceTool = args?.source_tool || null;
|
|
90
|
+
// E2: reject any oversized window paste up front (token tables are tiny).
|
|
91
|
+
for (const wk of WINDOW_KEYS) {
|
|
92
|
+
const v = args?.[wk];
|
|
93
|
+
if (typeof v === "string" && v.length > MAX_INPUT) {
|
|
94
|
+
return {
|
|
95
|
+
status: "error",
|
|
96
|
+
reason: "input_too_large",
|
|
97
|
+
detail: `window '${wk}' exceeds ${MAX_INPUT} chars (${v.length}). Paste only the token-count table.`,
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const windows = [];
|
|
102
|
+
for (const wk of WINDOW_KEYS) {
|
|
103
|
+
const text = args?.[wk];
|
|
104
|
+
if (!text || typeof text !== "string" || !text.trim()) continue;
|
|
105
|
+
const pillars = parsePillars(text);
|
|
106
|
+
const c = withParseWarnings(pillars, cascade(pillars));
|
|
107
|
+
const card = narrate(c, `${wk} window`);
|
|
108
|
+
windows.push({ window: wk, pillars, cascade: c, card });
|
|
109
|
+
}
|
|
110
|
+
if (windows.length === 0) {
|
|
111
|
+
throw new Error(
|
|
112
|
+
"rank_windows requires at least one window paste (7d, 30d, 90d, or all).",
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
windows,
|
|
117
|
+
source_tool: sourceTool,
|
|
118
|
+
note: "Local preview only — use tokenpull_submit to publish to the board.",
|
|
119
|
+
};
|
|
120
|
+
}
|