codeslop 0.1.0 → 0.1.1

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/lib/cost.js CHANGED
@@ -1,2 +1 @@
1
- // Re-export from shared pricing module.
2
- export { wasteCost } from '../../shared/pricing.js';
1
+ export { wasteCost } from '../shared/pricing.js';
package/lib/store.js CHANGED
@@ -3,7 +3,7 @@ import { mkdirSync } from 'fs';
3
3
  import { join } from 'path';
4
4
  import { homedir } from 'os';
5
5
  import { randomUUID } from 'crypto';
6
- import { wasteCost } from '../../shared/pricing.js';
6
+ import { wasteCost } from '../shared/pricing.js';
7
7
 
8
8
  const DIR = join(homedir(), '.wasted');
9
9
  const DB_PATH = join(DIR, 'wasted.db');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeslop",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Track every dollar your AI agent lights on fire. Works with Claude Code, Cursor, Windsurf, Copilot, Aider, OpenCode. codeslop.org",
5
5
  "bin": {
6
6
  "codeslop": "./bin/wasted.js"
@@ -8,7 +8,7 @@
8
8
  "type": "module",
9
9
  "keywords": ["ai", "tokens", "waste", "slop", "codeslop", "llm", "claude", "cursor", "copilot", "windsurf", "opencode", "aider"],
10
10
  "license": "MIT",
11
- "files": ["bin/", "lib/"],
11
+ "files": ["bin/", "lib/", "shared/"],
12
12
  "dependencies": {
13
13
  "better-sqlite3": "^11.6.0"
14
14
  }
@@ -0,0 +1,71 @@
1
+ // Model name resolution: normalize user input to canonical model IDs.
2
+
3
+ const MODEL_ALIASES = {
4
+ // Anthropic short names
5
+ 'opus': 'claude-opus-4-6',
6
+ 'claude-opus': 'claude-opus-4-6',
7
+ 'claude-opus-4': 'claude-opus-4-6',
8
+ 'sonnet': 'claude-sonnet-4-6',
9
+ 'claude-sonnet': 'claude-sonnet-4-6',
10
+ 'claude-sonnet-4': 'claude-sonnet-4-6',
11
+ 'claude-sonnet-4-5': 'claude-sonnet-4-5',
12
+ 'haiku': 'claude-haiku-4-5',
13
+ 'claude-haiku': 'claude-haiku-4-5',
14
+ 'claude-haiku-3-5': 'claude-haiku-3-5',
15
+
16
+ // OpenAI short names
17
+ 'gpt4o': 'gpt-4o',
18
+ 'gpt4': 'gpt-4',
19
+ '4o': 'gpt-4o',
20
+ '4o-mini': 'gpt-4o-mini',
21
+ 'gpt-4o-mini': 'gpt-4o-mini',
22
+ 'gpt-3.5': 'gpt-3.5-turbo',
23
+ 'gpt-3.5-turbo': 'gpt-3.5-turbo',
24
+
25
+ // Google short names
26
+ 'gemini-pro': 'gemini-2.5-pro',
27
+ 'gemini-flash': 'gemini-2.5-flash',
28
+ 'gemini': 'gemini-2.5-pro',
29
+ };
30
+
31
+ const PROVIDER_PREFIXES = ['anthropic/', 'openai/', 'google/', 'gemini/', 'vertex_ai/'];
32
+
33
+ const CANONICAL_IDS = new Set([
34
+ 'claude-opus-4-6', 'claude-opus-4', 'claude-sonnet-4-6', 'claude-sonnet-4-5',
35
+ 'claude-sonnet-4', 'claude-haiku-4-5', 'claude-haiku-3-5',
36
+ 'gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo',
37
+ 'o1', 'o1-mini', 'o3', 'o3-mini',
38
+ 'gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.5-flash-lite',
39
+ 'gemini-3-flash', 'gemini-3.1-pro',
40
+ ]);
41
+
42
+ /**
43
+ * Resolve a model name to its canonical ID.
44
+ * Handles aliases, provider prefixes, and case insensitivity.
45
+ */
46
+ export function resolveModel(input) {
47
+ if (!input) return 'unknown';
48
+
49
+ let key = input.toLowerCase().trim();
50
+
51
+ // Strip provider prefixes
52
+ for (const prefix of PROVIDER_PREFIXES) {
53
+ if (key.startsWith(prefix)) {
54
+ key = key.slice(prefix.length);
55
+ break;
56
+ }
57
+ }
58
+
59
+ // Exact alias match
60
+ if (MODEL_ALIASES[key]) return MODEL_ALIASES[key];
61
+
62
+ // Already a canonical ID
63
+ if (CANONICAL_IDS.has(key)) return key;
64
+
65
+ // Substring match as last resort
66
+ for (const id of CANONICAL_IDS) {
67
+ if (id.includes(key) || key.includes(id)) return id;
68
+ }
69
+
70
+ return 'unknown';
71
+ }
@@ -0,0 +1,92 @@
1
+ // ============================================================================
2
+ // PRICING — single source of truth for all model token costs
3
+ // ============================================================================
4
+ //
5
+ // All prices in USD per 1 token (NOT per 1M tokens).
6
+ // Update this table when providers change prices — it's rare.
7
+ //
8
+ // Sources:
9
+ // Anthropic: https://platform.claude.com/docs/en/about-claude/pricing
10
+ // OpenAI: https://openai.com/api/pricing/
11
+ // Google: https://ai.google.dev/gemini-api/docs/pricing
12
+ //
13
+ // Last updated: 2026-03-18
14
+ //
15
+ // ============================================================================
16
+
17
+ import { resolveModel } from './aliases.js';
18
+ import { CATEGORY_TOKEN_PROFILE } from './token-profiles.js';
19
+
20
+ export const PRICING = {
21
+ // --- Anthropic Claude ---
22
+ 'claude-opus-4-6': { input: 5.00 / 1e6, output: 25.00 / 1e6 },
23
+ 'claude-opus-4': { input: 5.00 / 1e6, output: 25.00 / 1e6 },
24
+ 'claude-sonnet-4-6': { input: 3.00 / 1e6, output: 15.00 / 1e6 },
25
+ 'claude-sonnet-4-5': { input: 3.00 / 1e6, output: 15.00 / 1e6 },
26
+ 'claude-sonnet-4': { input: 3.00 / 1e6, output: 15.00 / 1e6 },
27
+ 'claude-haiku-4-5': { input: 1.00 / 1e6, output: 5.00 / 1e6 },
28
+ 'claude-haiku-3-5': { input: 0.80 / 1e6, output: 4.00 / 1e6 },
29
+
30
+ // --- OpenAI ---
31
+ 'gpt-4o': { input: 2.50 / 1e6, output: 10.00 / 1e6 },
32
+ 'gpt-4o-mini': { input: 0.15 / 1e6, output: 0.60 / 1e6 },
33
+ 'gpt-4-turbo': { input: 10.0 / 1e6, output: 30.00 / 1e6 },
34
+ 'gpt-4': { input: 30.0 / 1e6, output: 60.00 / 1e6 },
35
+ 'gpt-3.5-turbo': { input: 0.50 / 1e6, output: 1.50 / 1e6 },
36
+ 'o1': { input: 15.0 / 1e6, output: 60.00 / 1e6 },
37
+ 'o1-mini': { input: 1.10 / 1e6, output: 4.40 / 1e6 },
38
+ 'o3': { input: 10.0 / 1e6, output: 40.00 / 1e6 },
39
+ 'o3-mini': { input: 1.10 / 1e6, output: 4.40 / 1e6 },
40
+
41
+ // --- Google Gemini ---
42
+ 'gemini-2.5-pro': { input: 1.25 / 1e6, output: 10.00 / 1e6 },
43
+ 'gemini-2.5-flash': { input: 0.30 / 1e6, output: 2.50 / 1e6 },
44
+ 'gemini-2.5-flash-lite': { input: 0.10 / 1e6, output: 0.40 / 1e6 },
45
+ 'gemini-3-flash': { input: 0.50 / 1e6, output: 3.00 / 1e6 },
46
+ 'gemini-3.1-pro': { input: 2.00 / 1e6, output: 12.00 / 1e6 },
47
+
48
+ // --- Fallback ---
49
+ 'unknown': { input: 2.50 / 1e6, output: 10.00 / 1e6 },
50
+ };
51
+
52
+ /**
53
+ * Get price rates for a model. Resolves aliases automatically.
54
+ */
55
+ export function getPrice(model) {
56
+ const id = resolveModel(model);
57
+ return PRICING[id] || PRICING['unknown'];
58
+ }
59
+
60
+ /**
61
+ * Calculate cost for known input/output token counts.
62
+ */
63
+ export function calculateCost(model, inputTokens, outputTokens) {
64
+ const price = getPrice(model);
65
+ const inputCost = inputTokens * price.input;
66
+ const outputCost = outputTokens * price.output;
67
+ return {
68
+ cost: inputCost + outputCost,
69
+ breakdown: { input: inputCost, output: outputCost },
70
+ rates: price,
71
+ };
72
+ }
73
+
74
+ /**
75
+ * Estimate cost when input/output split is unknown (40/60 heuristic).
76
+ */
77
+ export function estimateCost(model, totalTokens) {
78
+ const inputTokens = Math.round(totalTokens * 0.4);
79
+ const outputTokens = totalTokens - inputTokens;
80
+ return calculateCost(model, inputTokens, outputTokens);
81
+ }
82
+
83
+ /**
84
+ * Calculate waste cost using model pricing + category token profile.
85
+ */
86
+ export function wasteCost(model, category, tokens) {
87
+ const price = getPrice(model);
88
+ const prof = CATEGORY_TOKEN_PROFILE[category] || { inputRatio: 0.4, outputRatio: 0.6 };
89
+ const inp = Math.round(tokens * prof.inputRatio);
90
+ const out = tokens - inp;
91
+ return inp * price.input + out * price.output;
92
+ }
@@ -0,0 +1,8 @@
1
+ // Severity multipliers reduce waste token count for lower-confidence detections.
2
+ // A "mild" detection counts only 30% of tokens as waste, reducing false-positive inflation.
3
+
4
+ export const SEVERITY_MULTIPLIER = {
5
+ severe: 1.0,
6
+ moderate: 0.7,
7
+ mild: 0.3,
8
+ };
@@ -0,0 +1,15 @@
1
+ // Category → input/output token split for waste cost calculation.
2
+ // Yapping = mostly output tokens (expensive). Context stuffing = mostly input (cheaper per token).
3
+
4
+ export const CATEGORY_TOKEN_PROFILE = {
5
+ yapping: { inputRatio: 0.1, outputRatio: 0.9 },
6
+ groundhog_day: { inputRatio: 0.5, outputRatio: 0.5 },
7
+ ghost_agent: { inputRatio: 0.4, outputRatio: 0.6 },
8
+ prompt_salad: { inputRatio: 0.3, outputRatio: 0.7 },
9
+ tool_spam: { inputRatio: 0.7, outputRatio: 0.3 },
10
+ context_stuffing: { inputRatio: 0.95, outputRatio: 0.05 },
11
+ hallucination_trip: { inputRatio: 0.1, outputRatio: 0.9 },
12
+ ping_pong: { inputRatio: 0.5, outputRatio: 0.5 },
13
+ skill_issue: { inputRatio: 0.4, outputRatio: 0.6 },
14
+ overthink: { inputRatio: 0.1, outputRatio: 0.9 },
15
+ };