tokengolf 0.3.0 â 0.4.0
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/.husky/pre-commit +4 -0
- package/.prettierignore +2 -0
- package/.prettierrc +6 -0
- package/.vscode/settings.json +15 -0
- package/CHANGELOG.md +254 -0
- package/CLAUDE.md +136 -10
- package/README.md +89 -47
- package/assets/demo-hud.png +0 -0
- package/assets/scorecard.png +0 -0
- package/dist/cli.js +790 -103
- package/docs/assets/demo-hud.png +0 -0
- package/docs/assets/scorecard.png +0 -0
- package/docs/assets/tokengolf-bg-min.jpg +0 -0
- package/docs/index.html +1080 -0
- package/eslint.config.js +39 -0
- package/hooks/post-tool-use-failure.js +27 -0
- package/hooks/post-tool-use.js +11 -7
- package/hooks/pre-compact.js +9 -3
- package/hooks/session-end.js +168 -42
- package/hooks/session-start.js +31 -11
- package/hooks/session-stop.js +6 -2
- package/hooks/statusline.sh +16 -7
- package/hooks/stop.js +27 -0
- package/hooks/subagent-start.js +27 -0
- package/hooks/user-prompt-submit.js +8 -6
- package/package.json +16 -3
- package/src/cli.js +23 -6
- package/src/components/ActiveRun.js +76 -24
- package/src/components/ScoreCard.js +132 -37
- package/src/components/StartRun.js +156 -53
- package/src/components/StatsView.js +89 -37
- package/src/lib/__tests__/score.test.js +596 -0
- package/src/lib/cost.js +84 -21
- package/src/lib/demo.js +186 -0
- package/src/lib/install.js +92 -62
- package/src/lib/score.js +433 -136
- package/src/lib/store.js +11 -11
- package/.claude/settings.local.json +0 -36
package/src/lib/score.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
export const BUDGET_TIERS = [
|
|
2
|
-
{ label:
|
|
3
|
-
{ label:
|
|
4
|
-
{ label:
|
|
5
|
-
{ label:
|
|
6
|
-
{ label:
|
|
2
|
+
{ label: 'Diamond', emoji: 'ð', max: 0.1, color: 'cyan' },
|
|
3
|
+
{ label: 'Gold', emoji: 'ðĨ', max: 0.3, color: 'yellow' },
|
|
4
|
+
{ label: 'Silver', emoji: 'ðĨ', max: 1.0, color: 'white' },
|
|
5
|
+
{ label: 'Bronze', emoji: 'ðĨ', max: 3.0, color: 'yellow' },
|
|
6
|
+
{ label: 'Reckless', emoji: 'ðļ', max: Infinity, color: 'red' },
|
|
7
7
|
];
|
|
8
8
|
|
|
9
9
|
export const EFFORT_LEVELS = {
|
|
10
|
-
low: { label:
|
|
11
|
-
medium: { label:
|
|
12
|
-
high: { label:
|
|
13
|
-
max: { label:
|
|
10
|
+
low: { label: 'Low', emoji: 'ðŠķ', color: 'green' },
|
|
11
|
+
medium: { label: 'Medium', emoji: 'âïļ', color: 'white' },
|
|
12
|
+
high: { label: 'High', emoji: 'ðĨ', color: 'yellow' },
|
|
13
|
+
max: { label: 'Max', emoji: 'ðĨ', color: 'magenta', opusOnly: true },
|
|
14
14
|
};
|
|
15
15
|
|
|
16
16
|
export function getEffortLevel(effort) {
|
|
@@ -20,69 +20,76 @@ export function getEffortLevel(effort) {
|
|
|
20
20
|
export const MODEL_BUDGET_TIERS = {
|
|
21
21
|
haiku: { diamond: 0.15, gold: 0.4, silver: 1.0, bronze: 2.5 },
|
|
22
22
|
sonnet: { diamond: 0.5, gold: 1.5, silver: 4.0, bronze: 10.0 },
|
|
23
|
+
opusplan: { diamond: 1.5, gold: 4.5, silver: 12.0, bronze: 30.0 },
|
|
23
24
|
opus: { diamond: 2.5, gold: 7.5, silver: 20.0, bronze: 50.0 },
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
export function getModelBudgets(model) {
|
|
27
|
-
const m = (model ||
|
|
28
|
-
if (m.includes(
|
|
29
|
-
if (m.includes(
|
|
28
|
+
const m = (model || '').toLowerCase();
|
|
29
|
+
if (m.includes('haiku')) return MODEL_BUDGET_TIERS.haiku;
|
|
30
|
+
if (m.includes('opusplan')) return MODEL_BUDGET_TIERS.opusplan;
|
|
31
|
+
if (m.includes('opus')) return MODEL_BUDGET_TIERS.opus;
|
|
30
32
|
return MODEL_BUDGET_TIERS.sonnet;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
export const MODEL_CLASSES = {
|
|
34
36
|
haiku: {
|
|
35
|
-
name:
|
|
36
|
-
label:
|
|
37
|
-
emoji:
|
|
38
|
-
difficulty:
|
|
39
|
-
color:
|
|
37
|
+
name: 'Haiku',
|
|
38
|
+
label: 'Rogue',
|
|
39
|
+
emoji: 'ðđ',
|
|
40
|
+
difficulty: 'Hard',
|
|
41
|
+
color: 'red',
|
|
40
42
|
},
|
|
41
43
|
sonnet: {
|
|
42
|
-
name:
|
|
43
|
-
label:
|
|
44
|
-
emoji:
|
|
45
|
-
difficulty:
|
|
46
|
-
color:
|
|
44
|
+
name: 'Sonnet',
|
|
45
|
+
label: 'Fighter',
|
|
46
|
+
emoji: 'âïļ',
|
|
47
|
+
difficulty: 'Normal',
|
|
48
|
+
color: 'cyan',
|
|
49
|
+
},
|
|
50
|
+
opusplan: {
|
|
51
|
+
name: 'Paladin',
|
|
52
|
+
label: 'Paladin',
|
|
53
|
+
emoji: 'âïļ',
|
|
54
|
+
difficulty: 'Calculated',
|
|
55
|
+
color: 'yellow',
|
|
47
56
|
},
|
|
48
57
|
opus: {
|
|
49
|
-
name:
|
|
50
|
-
label:
|
|
51
|
-
emoji:
|
|
52
|
-
difficulty:
|
|
53
|
-
color:
|
|
58
|
+
name: 'Opus',
|
|
59
|
+
label: 'Warlock',
|
|
60
|
+
emoji: 'ð§',
|
|
61
|
+
difficulty: 'Easy',
|
|
62
|
+
color: 'magenta',
|
|
54
63
|
},
|
|
55
64
|
};
|
|
56
65
|
|
|
57
66
|
export const FLOORS = [
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
67
|
+
'Write the code',
|
|
68
|
+
'Write the tests',
|
|
69
|
+
'Fix failing tests',
|
|
70
|
+
'Code review pass',
|
|
71
|
+
'PR merged â BOSS ð',
|
|
63
72
|
];
|
|
64
73
|
|
|
65
74
|
export function getTier(spent) {
|
|
66
|
-
return (
|
|
67
|
-
BUDGET_TIERS.find((t) => spent <= t.max) ||
|
|
68
|
-
BUDGET_TIERS[BUDGET_TIERS.length - 1]
|
|
69
|
-
);
|
|
75
|
+
return BUDGET_TIERS.find((t) => spent <= t.max) || BUDGET_TIERS[BUDGET_TIERS.length - 1];
|
|
70
76
|
}
|
|
71
77
|
|
|
72
|
-
export function getModelClass(model =
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
);
|
|
78
|
+
export function getModelClass(model = '') {
|
|
79
|
+
const m = model.toLowerCase();
|
|
80
|
+
// Check opusplan before opus to avoid substring collision
|
|
81
|
+
if (m.includes('opusplan')) return MODEL_CLASSES.opusplan;
|
|
82
|
+
const key = Object.keys(MODEL_CLASSES).find((k) => m.includes(k));
|
|
76
83
|
return MODEL_CLASSES[key] || MODEL_CLASSES.sonnet;
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
export function getEfficiencyRating(spent, budget) {
|
|
80
87
|
const pct = spent / budget;
|
|
81
|
-
if (pct <= 0.25) return { label:
|
|
82
|
-
if (pct <= 0.5) return { label:
|
|
83
|
-
if (pct <= 0.75) return { label:
|
|
84
|
-
if (pct <= 1.0) return { label:
|
|
85
|
-
return { label:
|
|
88
|
+
if (pct <= 0.25) return { label: 'LEGENDARY', emoji: 'ð', color: 'magenta' };
|
|
89
|
+
if (pct <= 0.5) return { label: 'EFFICIENT', emoji: 'âĄ', color: 'cyan' };
|
|
90
|
+
if (pct <= 0.75) return { label: 'SOLID', emoji: 'â', color: 'green' };
|
|
91
|
+
if (pct <= 1.0) return { label: 'CLOSE CALL', emoji: 'ð
', color: 'yellow' };
|
|
92
|
+
return { label: 'BUSTED', emoji: 'ð', color: 'red' };
|
|
86
93
|
}
|
|
87
94
|
|
|
88
95
|
export function getBudgetPct(spent, budget) {
|
|
@@ -90,13 +97,13 @@ export function getBudgetPct(spent, budget) {
|
|
|
90
97
|
}
|
|
91
98
|
|
|
92
99
|
export function formatCost(amount = 0) {
|
|
93
|
-
if (amount === 0) return
|
|
94
|
-
if (amount < 0.01) return `$${
|
|
100
|
+
if (amount === 0) return '$0.00';
|
|
101
|
+
if (amount < 0.01) return `$${amount.toFixed(5)}`;
|
|
95
102
|
return `$${amount.toFixed(4)}`;
|
|
96
103
|
}
|
|
97
104
|
|
|
98
105
|
export function formatElapsed(startedAt) {
|
|
99
|
-
if (!startedAt) return
|
|
106
|
+
if (!startedAt) return 'â';
|
|
100
107
|
const ms = Date.now() - new Date(startedAt).getTime();
|
|
101
108
|
const s = Math.floor(ms / 1000);
|
|
102
109
|
const m = Math.floor(s / 60);
|
|
@@ -106,11 +113,21 @@ export function formatElapsed(startedAt) {
|
|
|
106
113
|
return `${s}s`;
|
|
107
114
|
}
|
|
108
115
|
|
|
116
|
+
// Returns opus's share of total spend as a 0â100 integer, or null (for Paladin runs)
|
|
117
|
+
export function getOpusPct(modelBreakdown, totalSpent) {
|
|
118
|
+
if (!modelBreakdown || !totalSpent) return null;
|
|
119
|
+
const opusCost = Object.entries(modelBreakdown)
|
|
120
|
+
.filter(([m]) => m.toLowerCase().includes('opus'))
|
|
121
|
+
.reduce((sum, [, c]) => sum + c, 0);
|
|
122
|
+
if (opusCost === 0) return null;
|
|
123
|
+
return Math.round((opusCost / totalSpent) * 100);
|
|
124
|
+
}
|
|
125
|
+
|
|
109
126
|
// Returns haiku's share of total spend as a 0â100 integer, or null
|
|
110
127
|
export function getHaikuPct(modelBreakdown, totalSpent) {
|
|
111
128
|
if (!modelBreakdown || !totalSpent) return null;
|
|
112
129
|
const haikuCost = Object.entries(modelBreakdown)
|
|
113
|
-
.filter(([m]) => m.toLowerCase().includes(
|
|
130
|
+
.filter(([m]) => m.toLowerCase().includes('haiku'))
|
|
114
131
|
.reduce((sum, [, c]) => sum + c, 0);
|
|
115
132
|
if (haikuCost === 0) return null;
|
|
116
133
|
return Math.round((haikuCost / totalSpent) * 100);
|
|
@@ -118,90 +135,144 @@ export function getHaikuPct(modelBreakdown, totalSpent) {
|
|
|
118
135
|
|
|
119
136
|
export function calculateAchievements(run) {
|
|
120
137
|
const achievements = [];
|
|
121
|
-
const won = run.status ===
|
|
138
|
+
const won = run.status === 'won';
|
|
122
139
|
const pct = run.budget ? run.spent / run.budget : null;
|
|
123
140
|
const mc = getModelClass(run.model);
|
|
124
141
|
|
|
142
|
+
const isPaladin = mc === MODEL_CLASSES.opusplan;
|
|
143
|
+
|
|
144
|
+
// Indecisive fires on death too (like Hubris)
|
|
145
|
+
if ((run.modelSwitches ?? 0) >= 3)
|
|
146
|
+
achievements.push({
|
|
147
|
+
key: 'indecisive',
|
|
148
|
+
label: `Indecisive â ${run.modelSwitches} model switches mid-session`,
|
|
149
|
+
emoji: 'ðē',
|
|
150
|
+
});
|
|
151
|
+
|
|
125
152
|
// Hubris fires on death too â ultrathink and still busted
|
|
126
|
-
if (run.thinkingInvocations > 0 && run.status ===
|
|
153
|
+
if (run.thinkingInvocations > 0 && run.status === 'died')
|
|
127
154
|
achievements.push({
|
|
128
|
-
key:
|
|
129
|
-
label:
|
|
130
|
-
emoji:
|
|
155
|
+
key: 'hubris',
|
|
156
|
+
label: 'Hubris â Used ultrathink, busted anyway',
|
|
157
|
+
emoji: 'ðĪĶ',
|
|
131
158
|
});
|
|
132
159
|
|
|
133
|
-
|
|
160
|
+
// Death marks
|
|
161
|
+
if (!won) {
|
|
162
|
+
if (run.budget && run.spent / run.budget >= 2.0)
|
|
163
|
+
achievements.push({ key: 'blowout', label: 'Blowout â Spent 2Ã budget', emoji: 'ðĨ' });
|
|
164
|
+
else if (run.budget && run.spent / run.budget > 1.0 && run.spent / run.budget <= 1.1)
|
|
165
|
+
achievements.push({
|
|
166
|
+
key: 'so_close',
|
|
167
|
+
label: 'So Close â Died within 10% of budget',
|
|
168
|
+
emoji: 'ð',
|
|
169
|
+
});
|
|
170
|
+
if ((run.totalToolCalls || 0) >= 30)
|
|
171
|
+
achievements.push({
|
|
172
|
+
key: 'tool_happy',
|
|
173
|
+
label: `Tool Happy â Died with ${run.totalToolCalls} tool calls`,
|
|
174
|
+
emoji: 'ðĻ',
|
|
175
|
+
});
|
|
176
|
+
if ((run.promptCount || 0) <= 2)
|
|
177
|
+
achievements.push({
|
|
178
|
+
key: 'silent_death',
|
|
179
|
+
label: 'Silent Death â Died with âĪ2 prompts',
|
|
180
|
+
emoji: 'ðŠĶ',
|
|
181
|
+
});
|
|
182
|
+
if ((run.failedToolCalls ?? 0) >= 5)
|
|
183
|
+
achievements.push({
|
|
184
|
+
key: 'fumble',
|
|
185
|
+
label: `Fumble â Died with ${run.failedToolCalls} failed tool calls`,
|
|
186
|
+
emoji: 'ðĪĄ',
|
|
187
|
+
});
|
|
188
|
+
if (run.budget && run.spent / run.budget >= 0.5)
|
|
189
|
+
if ((run.promptCount || 0) >= 3 && run.spent / (run.promptCount || 1) >= 0.5)
|
|
190
|
+
achievements.push({
|
|
191
|
+
key: 'expensive_taste',
|
|
192
|
+
label: 'Expensive Taste â Over $0.50 per prompt',
|
|
193
|
+
emoji: 'ð·',
|
|
194
|
+
});
|
|
195
|
+
return achievements;
|
|
196
|
+
}
|
|
134
197
|
|
|
135
198
|
if (mc === MODEL_CLASSES.haiku) {
|
|
136
199
|
achievements.push({
|
|
137
|
-
key:
|
|
138
|
-
label:
|
|
139
|
-
emoji:
|
|
200
|
+
key: 'gold_haiku',
|
|
201
|
+
label: 'Gold â Completed with Haiku',
|
|
202
|
+
emoji: 'ðĨ',
|
|
140
203
|
});
|
|
141
204
|
if (run.spent < 0.1)
|
|
142
205
|
achievements.push({
|
|
143
|
-
key:
|
|
144
|
-
label:
|
|
145
|
-
emoji:
|
|
206
|
+
key: 'diamond',
|
|
207
|
+
label: 'Diamond â Haiku under $0.10',
|
|
208
|
+
emoji: 'ð',
|
|
146
209
|
});
|
|
147
210
|
} else if (mc === MODEL_CLASSES.sonnet) {
|
|
148
211
|
achievements.push({
|
|
149
|
-
key:
|
|
150
|
-
label:
|
|
151
|
-
emoji:
|
|
212
|
+
key: 'silver_sonnet',
|
|
213
|
+
label: 'Silver â Completed with Sonnet',
|
|
214
|
+
emoji: 'ðĨ',
|
|
152
215
|
});
|
|
216
|
+
} else if (mc === MODEL_CLASSES.opusplan) {
|
|
217
|
+
achievements.push({
|
|
218
|
+
key: 'paladin',
|
|
219
|
+
label: 'Paladin â Completed a run as Paladin',
|
|
220
|
+
emoji: 'âïļ',
|
|
221
|
+
});
|
|
222
|
+
if (pct !== null && pct <= 0.25)
|
|
223
|
+
achievements.push({
|
|
224
|
+
key: 'grand_strategist',
|
|
225
|
+
label: 'Grand Strategist â LEGENDARY efficiency as Paladin',
|
|
226
|
+
emoji: 'âïļ',
|
|
227
|
+
});
|
|
153
228
|
} else if (mc === MODEL_CLASSES.opus) {
|
|
154
229
|
achievements.push({
|
|
155
|
-
key:
|
|
156
|
-
label:
|
|
157
|
-
emoji:
|
|
230
|
+
key: 'bronze_opus',
|
|
231
|
+
label: 'Bronze â Completed with Opus',
|
|
232
|
+
emoji: 'ðĨ',
|
|
158
233
|
});
|
|
159
234
|
}
|
|
160
235
|
|
|
161
236
|
if (pct !== null) {
|
|
162
237
|
if (pct <= 0.25)
|
|
163
238
|
achievements.push({
|
|
164
|
-
key:
|
|
165
|
-
label:
|
|
166
|
-
emoji:
|
|
239
|
+
key: 'sniper',
|
|
240
|
+
label: 'Sniper â Under 25% of budget',
|
|
241
|
+
emoji: 'ðŊ',
|
|
167
242
|
});
|
|
168
243
|
if (pct <= 0.5)
|
|
169
244
|
achievements.push({
|
|
170
|
-
key:
|
|
171
|
-
label:
|
|
172
|
-
emoji:
|
|
245
|
+
key: 'efficient',
|
|
246
|
+
label: 'Efficient â Under 50% of budget',
|
|
247
|
+
emoji: 'âĄ',
|
|
173
248
|
});
|
|
174
249
|
}
|
|
175
250
|
if (run.spent < 0.1)
|
|
176
251
|
achievements.push({
|
|
177
|
-
key:
|
|
178
|
-
label:
|
|
179
|
-
emoji:
|
|
252
|
+
key: 'penny',
|
|
253
|
+
label: 'Penny Pincher â Under $0.10',
|
|
254
|
+
emoji: 'ðŠ',
|
|
180
255
|
});
|
|
181
256
|
|
|
182
257
|
// Effort-based achievements
|
|
183
258
|
if (run.effort) {
|
|
184
|
-
if (run.effort ===
|
|
259
|
+
if (run.effort === 'low' && pct !== null && pct < 1.0)
|
|
185
260
|
achievements.push({
|
|
186
|
-
key:
|
|
187
|
-
label:
|
|
188
|
-
emoji:
|
|
261
|
+
key: 'speedrunner',
|
|
262
|
+
label: 'Speedrunner â Low effort, completed under budget',
|
|
263
|
+
emoji: 'ðïļ',
|
|
189
264
|
});
|
|
190
|
-
if (
|
|
191
|
-
(run.effort === "high" || run.effort === "max") &&
|
|
192
|
-
pct !== null &&
|
|
193
|
-
pct <= 0.25
|
|
194
|
-
)
|
|
265
|
+
if ((run.effort === 'high' || run.effort === 'max') && pct !== null && pct <= 0.25)
|
|
195
266
|
achievements.push({
|
|
196
|
-
key:
|
|
197
|
-
label:
|
|
198
|
-
emoji:
|
|
267
|
+
key: 'tryhard',
|
|
268
|
+
label: 'Tryhard â High effort, LEGENDARY efficiency',
|
|
269
|
+
emoji: 'ðïļ',
|
|
199
270
|
});
|
|
200
|
-
if (run.effort ===
|
|
271
|
+
if (run.effort === 'max' && mc === MODEL_CLASSES.opus)
|
|
201
272
|
achievements.push({
|
|
202
|
-
key:
|
|
203
|
-
label:
|
|
204
|
-
emoji:
|
|
273
|
+
key: 'archmagus',
|
|
274
|
+
label: 'Archmagus â Opus at max effort, completed',
|
|
275
|
+
emoji: 'ð',
|
|
205
276
|
});
|
|
206
277
|
}
|
|
207
278
|
|
|
@@ -209,15 +280,15 @@ export function calculateAchievements(run) {
|
|
|
209
280
|
if (run.fastMode && mc === MODEL_CLASSES.opus) {
|
|
210
281
|
if (pct !== null && pct < 1.0)
|
|
211
282
|
achievements.push({
|
|
212
|
-
key:
|
|
213
|
-
label:
|
|
214
|
-
emoji:
|
|
283
|
+
key: 'lightning',
|
|
284
|
+
label: 'Lightning Run â Opus fast mode, completed under budget',
|
|
285
|
+
emoji: 'âïļ',
|
|
215
286
|
});
|
|
216
287
|
if (pct !== null && pct <= 0.25)
|
|
217
288
|
achievements.push({
|
|
218
|
-
key:
|
|
219
|
-
label:
|
|
220
|
-
emoji:
|
|
289
|
+
key: 'daredevil',
|
|
290
|
+
label: 'Daredevil â Opus fast mode, LEGENDARY efficiency',
|
|
291
|
+
emoji: 'ð°',
|
|
221
292
|
});
|
|
222
293
|
}
|
|
223
294
|
|
|
@@ -225,58 +296,54 @@ export function calculateAchievements(run) {
|
|
|
225
296
|
const sessions = run.sessionCount || 1;
|
|
226
297
|
if (sessions >= 2)
|
|
227
298
|
achievements.push({
|
|
228
|
-
key:
|
|
299
|
+
key: 'made_camp',
|
|
229
300
|
label: `Made Camp â Completed across ${sessions} sessions`,
|
|
230
|
-
emoji:
|
|
301
|
+
emoji: 'ðïļ',
|
|
231
302
|
});
|
|
232
303
|
if (sessions === 1)
|
|
233
304
|
achievements.push({
|
|
234
|
-
key:
|
|
235
|
-
label:
|
|
236
|
-
emoji:
|
|
305
|
+
key: 'no_rest',
|
|
306
|
+
label: 'No Rest for the Wicked â Completed in one session',
|
|
307
|
+
emoji: 'ðĨ',
|
|
237
308
|
});
|
|
238
309
|
if (run.fainted)
|
|
239
310
|
achievements.push({
|
|
240
|
-
key:
|
|
241
|
-
label:
|
|
242
|
-
emoji:
|
|
311
|
+
key: 'came_back',
|
|
312
|
+
label: 'Came Back â Fainted and finished anyway',
|
|
313
|
+
emoji: 'ð§',
|
|
243
314
|
});
|
|
244
315
|
|
|
245
316
|
// Compaction achievements
|
|
246
317
|
const compactionEvents = run.compactionEvents || [];
|
|
247
|
-
const manualCompactions = compactionEvents.filter(
|
|
248
|
-
|
|
249
|
-
);
|
|
250
|
-
const autoCompactions = compactionEvents.filter((e) => e.trigger === "auto");
|
|
318
|
+
const manualCompactions = compactionEvents.filter((e) => e.trigger === 'manual');
|
|
319
|
+
const autoCompactions = compactionEvents.filter((e) => e.trigger === 'auto');
|
|
251
320
|
|
|
252
321
|
if (autoCompactions.length > 0)
|
|
253
322
|
achievements.push({
|
|
254
|
-
key:
|
|
255
|
-
label:
|
|
256
|
-
emoji:
|
|
323
|
+
key: 'overencumbered',
|
|
324
|
+
label: 'Overencumbered â Context auto-compacted during run',
|
|
325
|
+
emoji: 'ðĶ',
|
|
257
326
|
});
|
|
258
327
|
|
|
259
328
|
if (manualCompactions.length > 0) {
|
|
260
|
-
const minPct = Math.min(
|
|
261
|
-
...manualCompactions.map((e) => e.contextPct ?? 100),
|
|
262
|
-
);
|
|
329
|
+
const minPct = Math.min(...manualCompactions.map((e) => e.contextPct ?? 100));
|
|
263
330
|
if (minPct <= 30)
|
|
264
331
|
achievements.push({
|
|
265
|
-
key:
|
|
332
|
+
key: 'ghost_run',
|
|
266
333
|
label: `Ghost Run â Manual compact at ${minPct}% context`,
|
|
267
|
-
emoji:
|
|
334
|
+
emoji: 'ðĨ·',
|
|
268
335
|
});
|
|
269
336
|
else if (minPct <= 40)
|
|
270
337
|
achievements.push({
|
|
271
|
-
key:
|
|
338
|
+
key: 'ultralight',
|
|
272
339
|
label: `Ultralight â Manual compact at ${minPct}% context`,
|
|
273
|
-
emoji:
|
|
340
|
+
emoji: 'ðŠķ',
|
|
274
341
|
});
|
|
275
342
|
else if (minPct <= 50)
|
|
276
343
|
achievements.push({
|
|
277
|
-
key:
|
|
344
|
+
key: 'traveling_light',
|
|
278
345
|
label: `Traveling Light â Manual compact at ${minPct}% context`,
|
|
279
|
-
emoji:
|
|
346
|
+
emoji: 'ð',
|
|
280
347
|
});
|
|
281
348
|
}
|
|
282
349
|
|
|
@@ -284,47 +351,277 @@ export function calculateAchievements(run) {
|
|
|
284
351
|
const ti = run.thinkingInvocations;
|
|
285
352
|
if (ti > 0) {
|
|
286
353
|
achievements.push({
|
|
287
|
-
key:
|
|
354
|
+
key: 'spell_cast',
|
|
288
355
|
label: `Spell Cast â Used extended thinking (${ti}Ã)`,
|
|
289
|
-
emoji:
|
|
356
|
+
emoji: 'ðŪ',
|
|
290
357
|
});
|
|
291
358
|
if (pct !== null && pct <= 0.25)
|
|
292
359
|
achievements.push({
|
|
293
|
-
key:
|
|
294
|
-
label:
|
|
295
|
-
emoji:
|
|
360
|
+
key: 'calculated_risk',
|
|
361
|
+
label: 'Calculated Risk â Ultrathink + LEGENDARY efficiency',
|
|
362
|
+
emoji: 'ð§Ū',
|
|
296
363
|
});
|
|
297
364
|
if (ti >= 3)
|
|
298
365
|
achievements.push({
|
|
299
|
-
key:
|
|
366
|
+
key: 'deep_thinker',
|
|
300
367
|
label: `Deep Thinker â ${ti} ultrathink invocations, completed`,
|
|
301
|
-
emoji:
|
|
368
|
+
emoji: 'ð',
|
|
302
369
|
});
|
|
303
370
|
}
|
|
304
371
|
// Silent Run: thinking was tracked (field exists), zero invocations, SOLID or better, completed
|
|
305
372
|
if (run.thinkingInvocations === 0 && pct !== null && pct <= 0.75)
|
|
306
373
|
achievements.push({
|
|
307
|
-
key:
|
|
308
|
-
label:
|
|
309
|
-
emoji:
|
|
374
|
+
key: 'silent_run',
|
|
375
|
+
label: 'Silent Run â No extended thinking, completed under budget',
|
|
376
|
+
emoji: 'ðĪŦ',
|
|
310
377
|
});
|
|
311
378
|
|
|
379
|
+
// Paladin planning-ratio achievements
|
|
380
|
+
if (mc === MODEL_CLASSES.opusplan) {
|
|
381
|
+
const opusPct = getOpusPct(run.modelBreakdown, run.spent);
|
|
382
|
+
if (opusPct !== null) {
|
|
383
|
+
if (opusPct > 60)
|
|
384
|
+
achievements.push({
|
|
385
|
+
key: 'architect',
|
|
386
|
+
label: `Architect â Opus handled ${opusPct}% of cost (heavy planner)`,
|
|
387
|
+
emoji: 'ðïļ',
|
|
388
|
+
});
|
|
389
|
+
if (opusPct < 25)
|
|
390
|
+
achievements.push({
|
|
391
|
+
key: 'blitz',
|
|
392
|
+
label: `Blitz â Opus handled only ${opusPct}% of cost (light plan, fast execution)`,
|
|
393
|
+
emoji: 'ðĻ',
|
|
394
|
+
});
|
|
395
|
+
if (opusPct >= 40 && opusPct <= 60)
|
|
396
|
+
achievements.push({
|
|
397
|
+
key: 'equilibrium',
|
|
398
|
+
label: `Equilibrium â Opus and Sonnet balanced at ${opusPct}% / ${100 - opusPct}%`,
|
|
399
|
+
emoji: 'âïļ',
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Model-switching achievements (skip for Paladin â multi-model is by design)
|
|
405
|
+
const switches = run.modelSwitches ?? 0;
|
|
406
|
+
const distinct = run.distinctModels ?? 0;
|
|
407
|
+
if (!isPaladin) {
|
|
408
|
+
if (distinct === 1)
|
|
409
|
+
achievements.push({
|
|
410
|
+
key: 'purist',
|
|
411
|
+
label: 'Purist â Single model family throughout',
|
|
412
|
+
emoji: 'ð·',
|
|
413
|
+
});
|
|
414
|
+
if (distinct >= 2 && pct !== null && pct < 1.0)
|
|
415
|
+
achievements.push({
|
|
416
|
+
key: 'chameleon',
|
|
417
|
+
label: `Chameleon â ${distinct} model families used, completed under budget`,
|
|
418
|
+
emoji: 'ðĶ',
|
|
419
|
+
});
|
|
420
|
+
if (switches === 1 && pct !== null && pct < 1.0)
|
|
421
|
+
achievements.push({
|
|
422
|
+
key: 'tactical_switch',
|
|
423
|
+
label: 'Tactical Switch â Exactly 1 model switch, completed under budget',
|
|
424
|
+
emoji: 'ð',
|
|
425
|
+
});
|
|
426
|
+
if (switches === 0 && distinct <= 1)
|
|
427
|
+
achievements.push({
|
|
428
|
+
key: 'committed',
|
|
429
|
+
label: 'Committed â No model switches, one model family',
|
|
430
|
+
emoji: 'ð',
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
// Class Defection: declared one class but leaned heavily on another
|
|
434
|
+
if (run.modelBreakdown && run.spent > 0) {
|
|
435
|
+
const declared = (run.model || '').toLowerCase();
|
|
436
|
+
const isHaikuRun = declared.includes('haiku');
|
|
437
|
+
const isSonnetRun = declared.includes('sonnet') && !declared.includes('opus');
|
|
438
|
+
const opusPct2 = getOpusPct(run.modelBreakdown, run.spent) ?? 0;
|
|
439
|
+
const haikuPct2 = getHaikuPct(run.modelBreakdown, run.spent) ?? 0;
|
|
440
|
+
const nonHaikuPct = 100 - haikuPct2;
|
|
441
|
+
if (isHaikuRun && nonHaikuPct > 50)
|
|
442
|
+
achievements.push({
|
|
443
|
+
key: 'class_defection',
|
|
444
|
+
label: `Class Defection â Declared Haiku but ${nonHaikuPct}% cost on heavier models`,
|
|
445
|
+
emoji: 'â ïļ',
|
|
446
|
+
});
|
|
447
|
+
else if (isSonnetRun && opusPct2 > 40)
|
|
448
|
+
achievements.push({
|
|
449
|
+
key: 'class_defection',
|
|
450
|
+
label: `Class Defection â Declared Sonnet but ${opusPct2}% cost on Opus`,
|
|
451
|
+
emoji: 'â ïļ',
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
|
|
312
456
|
// Multi-model achievements based on Haiku usage ratio
|
|
313
457
|
const haikuPct = getHaikuPct(run.modelBreakdown, run.spent);
|
|
314
458
|
if (haikuPct !== null) {
|
|
315
459
|
if (haikuPct >= 50)
|
|
316
460
|
achievements.push({
|
|
317
|
-
key:
|
|
461
|
+
key: 'frugal',
|
|
318
462
|
label: `Frugal â Haiku handled ${haikuPct}% of session cost`,
|
|
319
|
-
emoji:
|
|
463
|
+
emoji: 'ðđ',
|
|
320
464
|
});
|
|
321
465
|
if (haikuPct >= 75)
|
|
322
466
|
achievements.push({
|
|
323
|
-
key:
|
|
467
|
+
key: 'rogue_run',
|
|
324
468
|
label: `Rogue Run â Haiku handled ${haikuPct}% of session cost`,
|
|
325
|
-
emoji:
|
|
469
|
+
emoji: 'ðē',
|
|
326
470
|
});
|
|
327
471
|
}
|
|
328
472
|
|
|
473
|
+
// Prompting skill achievements
|
|
474
|
+
const promptCount = run.promptCount || 0;
|
|
475
|
+
const totalToolCalls = run.totalToolCalls || 0;
|
|
476
|
+
if (promptCount === 1)
|
|
477
|
+
achievements.push({
|
|
478
|
+
key: 'one_shot',
|
|
479
|
+
label: 'One Shot â Completed in a single prompt',
|
|
480
|
+
emoji: 'ðĨ',
|
|
481
|
+
});
|
|
482
|
+
if (promptCount >= 20)
|
|
483
|
+
achievements.push({
|
|
484
|
+
key: 'conversationalist',
|
|
485
|
+
label: `Conversationalist â ${promptCount} prompts`,
|
|
486
|
+
emoji: 'ðŽ',
|
|
487
|
+
});
|
|
488
|
+
if (promptCount <= 3 && totalToolCalls >= 10)
|
|
489
|
+
achievements.push({
|
|
490
|
+
key: 'terse',
|
|
491
|
+
label: `Terse â ${promptCount} prompts, ${totalToolCalls} tool calls`,
|
|
492
|
+
emoji: 'ðĪ',
|
|
493
|
+
});
|
|
494
|
+
if (promptCount >= 15 && totalToolCalls / promptCount < 1)
|
|
495
|
+
achievements.push({
|
|
496
|
+
key: 'backseat_driver',
|
|
497
|
+
label: 'Backseat Driver â Many prompts, few tool calls',
|
|
498
|
+
emoji: 'ðŠ',
|
|
499
|
+
});
|
|
500
|
+
if (promptCount >= 2 && totalToolCalls / promptCount >= 5)
|
|
501
|
+
achievements.push({
|
|
502
|
+
key: 'high_leverage',
|
|
503
|
+
label: `High Leverage â ${(totalToolCalls / promptCount).toFixed(1)}Ã tools per prompt`,
|
|
504
|
+
emoji: 'ðïļ',
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
// Tool mastery achievements
|
|
508
|
+
const toolCalls = run.toolCalls || {};
|
|
509
|
+
const editCount = toolCalls['Edit'] || 0;
|
|
510
|
+
const writeCount = toolCalls['Write'] || 0;
|
|
511
|
+
const readCount = toolCalls['Read'] || 0;
|
|
512
|
+
const bashCount = toolCalls['Bash'] || 0;
|
|
513
|
+
const distinctTools = Object.keys(toolCalls).filter((k) => toolCalls[k] > 0).length;
|
|
514
|
+
|
|
515
|
+
if (editCount === 0 && writeCount === 0 && readCount >= 1)
|
|
516
|
+
achievements.push({ key: 'read_only', label: 'Read Only â No edits or writes', emoji: 'ðïļ' });
|
|
517
|
+
if (editCount >= 10)
|
|
518
|
+
achievements.push({ key: 'editor', label: `Editor â ${editCount} Edit calls`, emoji: 'âïļ' });
|
|
519
|
+
if (bashCount >= 10 && totalToolCalls >= 1 && bashCount / totalToolCalls >= 0.5)
|
|
520
|
+
achievements.push({
|
|
521
|
+
key: 'bash_warrior',
|
|
522
|
+
label: `Bash Warrior â ${bashCount} Bash calls (${Math.round((bashCount / totalToolCalls) * 100)}% of tools)`,
|
|
523
|
+
emoji: 'ð',
|
|
524
|
+
});
|
|
525
|
+
if (totalToolCalls >= 5 && readCount / totalToolCalls >= 0.6)
|
|
526
|
+
achievements.push({
|
|
527
|
+
key: 'scout',
|
|
528
|
+
label: `Scout â ${Math.round((readCount / totalToolCalls) * 100)}% Read calls`,
|
|
529
|
+
emoji: 'ð',
|
|
530
|
+
});
|
|
531
|
+
if (editCount >= 1 && editCount <= 3 && pct !== null && pct < 1.0)
|
|
532
|
+
achievements.push({
|
|
533
|
+
key: 'surgeon',
|
|
534
|
+
label: `Surgeon â Only ${editCount} Edit call${editCount > 1 ? 's' : ''}, under budget`,
|
|
535
|
+
emoji: 'ðŠ',
|
|
536
|
+
});
|
|
537
|
+
if (distinctTools >= 5)
|
|
538
|
+
achievements.push({
|
|
539
|
+
key: 'toolbox',
|
|
540
|
+
label: `Toolbox â ${distinctTools} distinct tools used`,
|
|
541
|
+
emoji: 'ð§°',
|
|
542
|
+
});
|
|
543
|
+
|
|
544
|
+
// Cost per prompt
|
|
545
|
+
if (promptCount >= 3) {
|
|
546
|
+
const costPerPrompt = run.spent / promptCount;
|
|
547
|
+
if (costPerPrompt < 0.01)
|
|
548
|
+
achievements.push({
|
|
549
|
+
key: 'cheap_shots',
|
|
550
|
+
label: `Cheap Shots â $${costPerPrompt.toFixed(4)} per prompt`,
|
|
551
|
+
emoji: 'ðē',
|
|
552
|
+
});
|
|
553
|
+
if (costPerPrompt >= 0.5)
|
|
554
|
+
achievements.push({
|
|
555
|
+
key: 'expensive_taste',
|
|
556
|
+
label: `Expensive Taste â $${costPerPrompt.toFixed(2)} per prompt`,
|
|
557
|
+
emoji: 'ð·',
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// Time-based achievements
|
|
562
|
+
if (run.startedAt && run.endedAt) {
|
|
563
|
+
const elapsedMs = new Date(run.endedAt).getTime() - new Date(run.startedAt).getTime();
|
|
564
|
+
const elapsedMin = elapsedMs / 60000;
|
|
565
|
+
if (elapsedMin < 5)
|
|
566
|
+
achievements.push({
|
|
567
|
+
key: 'speedrun',
|
|
568
|
+
label: `Speedrun â Completed in ${Math.round(elapsedMin * 60)}s`,
|
|
569
|
+
emoji: 'âąïļ',
|
|
570
|
+
});
|
|
571
|
+
if (elapsedMin > 60 && elapsedMin <= 180)
|
|
572
|
+
achievements.push({
|
|
573
|
+
key: 'marathon',
|
|
574
|
+
label: `Marathon â ${Math.round(elapsedMin)}m session`,
|
|
575
|
+
emoji: 'ð',
|
|
576
|
+
});
|
|
577
|
+
if (elapsedMin > 180)
|
|
578
|
+
achievements.push({
|
|
579
|
+
key: 'endurance',
|
|
580
|
+
label: `Endurance â ${Math.round(elapsedMin / 60)}h session`,
|
|
581
|
+
emoji: 'ðŦ ',
|
|
582
|
+
});
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// Phase 2: new hook fields (default 0 if not present)
|
|
586
|
+
const failedToolCalls = run.failedToolCalls ?? 0;
|
|
587
|
+
const subagentSpawns = run.subagentSpawns ?? 0;
|
|
588
|
+
const turnCount = run.turnCount ?? 0;
|
|
589
|
+
|
|
590
|
+
// Failed tool call achievements
|
|
591
|
+
if (failedToolCalls === 0 && totalToolCalls >= 5)
|
|
592
|
+
achievements.push({ key: 'clean_run', label: 'Clean Run â No tool failures', emoji: 'â
' });
|
|
593
|
+
if (failedToolCalls >= 10)
|
|
594
|
+
achievements.push({
|
|
595
|
+
key: 'stubborn',
|
|
596
|
+
label: `Stubborn â ${failedToolCalls} failed tool calls, still won`,
|
|
597
|
+
emoji: 'ð',
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
// Subagent achievements
|
|
601
|
+
if (subagentSpawns === 0)
|
|
602
|
+
achievements.push({ key: 'lone_wolf', label: 'Lone Wolf â No subagents spawned', emoji: 'ðš' });
|
|
603
|
+
if (subagentSpawns >= 5)
|
|
604
|
+
achievements.push({
|
|
605
|
+
key: 'summoner',
|
|
606
|
+
label: `Summoner â ${subagentSpawns} subagents spawned`,
|
|
607
|
+
emoji: 'ðĄ',
|
|
608
|
+
});
|
|
609
|
+
if (subagentSpawns >= 10 && pct !== null && pct < 0.5)
|
|
610
|
+
achievements.push({
|
|
611
|
+
key: 'army',
|
|
612
|
+
label: `Army of One â ${subagentSpawns} subagents, EFFICIENT cost`,
|
|
613
|
+
emoji: 'ðŠ',
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
// Turn count achievements
|
|
617
|
+
if (promptCount >= 2 && turnCount >= 1 && turnCount / promptCount >= 3)
|
|
618
|
+
achievements.push({
|
|
619
|
+
key: 'agentic',
|
|
620
|
+
label: `Agentic â ${(turnCount / promptCount).toFixed(1)} turns per prompt`,
|
|
621
|
+
emoji: 'ðĪ',
|
|
622
|
+
});
|
|
623
|
+
if (promptCount >= 3 && turnCount === promptCount)
|
|
624
|
+
achievements.push({ key: 'obedient', label: 'Obedient â One turn per prompt', emoji: 'ð' });
|
|
625
|
+
|
|
329
626
|
return achievements;
|
|
330
627
|
}
|