clawculator 2.1.2 → 2.1.3
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/package.json +1 -1
- package/src/analyzer.js +21 -4
- package/src/reporter.js +3 -2
package/package.json
CHANGED
package/src/analyzer.js
CHANGED
|
@@ -141,6 +141,11 @@ function isLocalModel(modelStr) {
|
|
|
141
141
|
['qwen', 'llama', 'mistral', 'phi', 'gemma', 'deepseek', 'kimi'].some(m => lower.includes(m));
|
|
142
142
|
}
|
|
143
143
|
|
|
144
|
+
function isHaikuTier(modelStr) {
|
|
145
|
+
if (!modelStr) return false;
|
|
146
|
+
return modelStr.toLowerCase().includes('haiku');
|
|
147
|
+
}
|
|
148
|
+
|
|
144
149
|
function isOpenRouter(modelStr) {
|
|
145
150
|
return modelStr?.toLowerCase().startsWith('openrouter/');
|
|
146
151
|
}
|
|
@@ -337,25 +342,37 @@ function analyzeConfig(configPath) {
|
|
|
337
342
|
const hooks = config.hooks?.internal?.entries || config.hooks || {};
|
|
338
343
|
const hookNames = Object.keys(hooks).filter(k => k !== 'enabled' && k !== 'token' && k !== 'path');
|
|
339
344
|
let hookIssues = 0;
|
|
345
|
+
let haikuHooks = 0;
|
|
340
346
|
|
|
341
347
|
for (const name of hookNames) {
|
|
342
348
|
const hook = typeof hooks[name] === 'object' ? hooks[name] : {};
|
|
343
349
|
if (hook.enabled === false) continue;
|
|
344
350
|
const hookModel = hook.model || primaryModel;
|
|
345
|
-
if (
|
|
351
|
+
if (isLocalModel(hookModel)) {
|
|
352
|
+
// local = free, no finding needed
|
|
353
|
+
} else if (isHaikuTier(hookModel) && resolveModel(hookModel)) {
|
|
354
|
+
const monthly = costPerCall(resolveModel(hookModel), 1000, 200) * 50 * 30;
|
|
355
|
+
haikuHooks++;
|
|
356
|
+
findings.push({
|
|
357
|
+
severity: 'low', source: 'hooks',
|
|
358
|
+
message: `Hook "${name}" on Haiku — minimal cost, good choice`,
|
|
359
|
+
detail: `~50 fires/day estimated · $${monthly.toFixed(2)}/month`,
|
|
360
|
+
monthlyCost: monthly,
|
|
361
|
+
});
|
|
362
|
+
} else if (resolveModel(hookModel)) {
|
|
346
363
|
const monthly = costPerCall(resolveModel(hookModel), 1000, 200) * 50 * 30;
|
|
347
364
|
hookIssues++;
|
|
348
365
|
findings.push({
|
|
349
366
|
severity: 'high', source: 'hooks',
|
|
350
|
-
message: `Hook "${name}" running on
|
|
367
|
+
message: `Hook "${name}" running on ${hookModel} — switch to Haiku or local`,
|
|
351
368
|
detail: `~50 fires/day estimated · $${monthly.toFixed(2)}/month`,
|
|
352
369
|
monthlyCost: monthly,
|
|
353
370
|
...FIXES.HOOK_PAID_MODEL(name),
|
|
354
371
|
});
|
|
355
372
|
}
|
|
356
373
|
}
|
|
357
|
-
if (hookNames.length > 0 && hookIssues === 0) {
|
|
358
|
-
findings.push({ severity: 'info', source: 'hooks', message: `All ${hookNames.length} hooks on
|
|
374
|
+
if (hookNames.length > 0 && hookIssues === 0 && haikuHooks === 0) {
|
|
375
|
+
findings.push({ severity: 'info', source: 'hooks', message: `All ${hookNames.length} hooks on local models ✓`, monthlyCost: 0 });
|
|
359
376
|
}
|
|
360
377
|
|
|
361
378
|
// ── WhatsApp ───────────────────────────────────────────────────
|
package/src/reporter.js
CHANGED
|
@@ -4,6 +4,7 @@ const SEVERITY_CONFIG = {
|
|
|
4
4
|
critical: { color: '\x1b[31m', icon: '🔴', label: 'CRITICAL' },
|
|
5
5
|
high: { color: '\x1b[33m', icon: '🟠', label: 'HIGH' },
|
|
6
6
|
medium: { color: '\x1b[33m', icon: '🟡', label: 'MEDIUM' },
|
|
7
|
+
low: { color: '\x1b[36m', icon: '🔵', label: 'LOW' },
|
|
7
8
|
info: { color: '\x1b[32m', icon: '✅', label: 'OK' },
|
|
8
9
|
};
|
|
9
10
|
|
|
@@ -54,7 +55,7 @@ function generateTerminalReport(analysis) {
|
|
|
54
55
|
console.log(`${B}${RED}⚠️ Estimated monthly cost exposure: $${bleed.toFixed(2)}/month${R}\n`);
|
|
55
56
|
}
|
|
56
57
|
|
|
57
|
-
for (const severity of ['critical', 'high', 'medium', 'info']) {
|
|
58
|
+
for (const severity of ['critical', 'high', 'medium', 'low', 'info']) {
|
|
58
59
|
const group = findings.filter(f => f.severity === severity);
|
|
59
60
|
if (!group.length) continue;
|
|
60
61
|
|
|
@@ -89,7 +90,7 @@ function generateTerminalReport(analysis) {
|
|
|
89
90
|
|
|
90
91
|
// Summary
|
|
91
92
|
console.log(`${C}━━━ Summary ━━━${R}`);
|
|
92
|
-
console.log(` 🔴 ${RED}${summary.critical}${R} critical 🟠 ${summary.high} high 🟡 ${summary.medium} medium ✅ ${summary.info} ok`);
|
|
93
|
+
console.log(` 🔴 ${RED}${summary.critical}${R} critical 🟠 ${summary.high} high 🟡 ${summary.medium} medium 🔵 ${summary.low||0} low ✅ ${summary.info} ok`);
|
|
93
94
|
console.log(` Sessions analyzed: ${summary.sessionsAnalyzed} · Tokens found: ${(summary.totalTokensFound||0).toLocaleString()}`);
|
|
94
95
|
if (bleed > 0) {
|
|
95
96
|
console.log(` ${RED}${B}Monthly bleed: $${bleed.toFixed(2)}/month${R}`);
|