@bhaskarauthor/llm-spend 0.1.0-alpha.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/LICENSE ADDED
@@ -0,0 +1,17 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bhaskar Pandey
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -0,0 +1,38 @@
1
+ # Product cycle — llm-spend
2
+
3
+ | Field | Value |
4
+ |-------|--------|
5
+ | **Track** | Alpha (`alpha`) |
6
+ | **Version** | `0.1.0-alpha.1` |
7
+ | **Cycle** | **CLOSED** (Alpha) |
8
+ | **Closed at** | 2026-07-12T04:12:35.713Z |
9
+ | **Publish** | **Not published** — local workspace only until explicit go-ahead |
10
+
11
+ ## Closed-cycle checklist
12
+
13
+ - [x] `package.json` name + version set
14
+ - [x] MIT LICENSE
15
+ - [x] README documents scope + limitations
16
+ - [x] Automated tests exist and pass under suite litmus
17
+ - [x] Cycle smoke tests (`tests/cycle.test.mjs`) for core entrypoints
18
+ - [x] Demo or usage path documented
19
+ - [x] Zero runtime dependencies (suite convention)
20
+ - [x] Known limitations listed (below)
21
+ - [ ] npm publish (blocked until owner says go)
22
+ - [ ] git remote push (blocked until owner says go)
23
+
24
+ ## Known limitations (Alpha)
25
+
26
+ - Offline domain MVP — no live cloud / WhatsApp / payments integrations.
27
+ - Litmus + cycle smoke tests, not full E2E or load tests.
28
+ - Commercial hosted layers are future work; OSS core stays free.
29
+
30
+ ## How to verify
31
+
32
+ ```bash
33
+ cd llm-spend
34
+ npm test
35
+ npm run cycle:check 2>/dev/null || node --test tests/*.test.mjs tests/**/*.test.mjs
36
+ ```
37
+
38
+ Suite: `node scripts/suite-litmus.mjs` from workspace root.
package/README.md ADDED
@@ -0,0 +1,35 @@
1
+ # llm-spend
2
+
3
+ > P05 · AI Tooling / FinOps
4
+
5
+ **Unified LLM cost, token, and budget observability across OpenAI, Anthropic, Google, Azure, open models**
6
+
7
+ ## Status
8
+
9
+ Offline **MVP core** (v0.1.0-beta.0) — zero runtime dependencies, litmus-tested, demo-ready.
10
+ Part of the Bhaskar Pandey product portfolio under `Documents/development`.
11
+
12
+ ## Quick start
13
+
14
+ ```bash
15
+ cd llm-spend
16
+ npm test
17
+ npm run demo
18
+ node src/cli.js --help
19
+ ```
20
+
21
+ ## MVP scope
22
+
23
+ Proxy + per-key budgets + simple dashboard + alerts
24
+
25
+ ## Open source → commercial
26
+
27
+ | Layer | Now | Later |
28
+ |-------|-----|-------|
29
+ | Core algorithms / CLI | OSS MIT | remains OSS |
30
+ | Hosted / team / SSO | — | commercial |
31
+ | Support / SLAs | community | paid |
32
+
33
+ ## License
34
+
35
+ MIT
package/demo/DEMO.md ADDED
@@ -0,0 +1,24 @@
1
+ # llm-spend (P05) — Demo
2
+
3
+ Unified LLM cost, token, and budget observability across OpenAI, Anthropic, Google, Azure, open models
4
+
5
+ ## Run
6
+
7
+ ```bash
8
+ cd llm-spend
9
+ node demo/run-demo.mjs
10
+ node src/cli.js --json fixtures/sample.json
11
+ npm test
12
+ ```
13
+
14
+ ## MVP
15
+
16
+ Proxy + per-key budgets + simple dashboard + alerts
17
+
18
+ ## Platforms
19
+
20
+ Web,API,CLI
21
+
22
+ ## Commercial path (later)
23
+
24
+ OSS core stays free; paid layer = team dashboard / hosted / compliance export.
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import { spawnSync } from "node:child_process";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ const root = path.join(path.dirname(fileURLToPath(import.meta.url)), "..");
6
+ console.log("=== DEMO P05 llm-spend ===");
7
+ console.log("Unified LLM cost, token, and budget observability across OpenAI, Anthropic, Google, Azure, open models");
8
+ const r = spawnSync(process.execPath, [path.join(root, "src/cli.js"), "--json", path.join(root, "fixtures/sample.json")], {
9
+ encoding: "utf8",
10
+ });
11
+ console.log(r.stdout || r.stderr);
12
+ process.exit(r.status ?? 0);
@@ -0,0 +1,9 @@
1
+ {
2
+ "events": [
3
+ {
4
+ "provider": "openai",
5
+ "tokens": 5000,
6
+ "pricePer1k": 0.01
7
+ }
8
+ ]
9
+ }
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@bhaskarauthor/llm-spend",
3
+ "version": "0.1.0-alpha.1",
4
+ "private": false,
5
+ "description": "Unified LLM cost, token, and budget observability across OpenAI, Anthropic, Google, Azure, open models",
6
+ "type": "module",
7
+ "bin": {
8
+ "llm-spend": "src/cli.js",
9
+ "ai-llm-spend": "src/cli.js"
10
+ },
11
+ "scripts": {
12
+ "test": "node --test tests/litmus.test.mjs tests/cycle.test.mjs",
13
+ "demo": "node demo/run-demo.mjs",
14
+ "litmus": "node --test tests/litmus.test.mjs",
15
+ "cycle:check": "node --test tests/litmus.test.mjs tests/cycle.test.mjs"
16
+ },
17
+ "engines": {
18
+ "node": ">=20"
19
+ },
20
+ "keywords": [
21
+ "AI",
22
+ "FinOps",
23
+ "observability",
24
+ "cost"
25
+ ],
26
+ "license": "MIT",
27
+ "author": "Bhaskar Pandey <bhaskarauthor@gmail.com>",
28
+ "files": [
29
+ "src",
30
+ "README.md",
31
+ "LICENSE",
32
+ "PRODUCT_CYCLE.md",
33
+ "demo",
34
+ "fixtures"
35
+ ],
36
+ "publishConfig": {
37
+ "access": "public"
38
+ }
39
+ }
package/src/cli.js ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ import { readFileSync, existsSync } from "node:fs";
3
+ import { resolve } from "node:path";
4
+ import * as core from "./core.js";
5
+
6
+ const args = process.argv.slice(2);
7
+ if (args.includes("--help") || args.includes("-h")) {
8
+ console.log(`llm-spend (P05) — Unified LLM cost, token, and budget observability across OpenAI, Anthropic, Google, Azure, open models
9
+
10
+ Usage:
11
+ llm-spend [--json] [fixture.json]
12
+ llm-spend --help
13
+
14
+ Offline MVP core for OSS shipping; commercial layers later.
15
+ `);
16
+ process.exit(0);
17
+ }
18
+ const json = args.includes("--json");
19
+ const file = args.find((a) => !a.startsWith("-"));
20
+ let input = {};
21
+ if (file && existsSync(file)) input = JSON.parse(readFileSync(resolve(file), "utf8"));
22
+ else if (existsSync(new URL("../fixtures/sample.json", import.meta.url))) {
23
+ input = JSON.parse(readFileSync(new URL("../fixtures/sample.json", import.meta.url), "utf8"));
24
+ }
25
+ const result = typeof core.main === "function" ? core.main(input) : { ok: true };
26
+ if (json) console.log(JSON.stringify({ product: "llm-spend", id: "P05", result }, null, 2));
27
+ else {
28
+ console.log("llm-spend · P05");
29
+ console.log(JSON.stringify(result, null, 2));
30
+ }
package/src/core.js ADDED
@@ -0,0 +1,28 @@
1
+ /** P05 llm-spend — offline MVP core (zero deps) */
2
+ export function main(input) {
3
+ const events = (Array.isArray(input.events) ? input.events : Array.isArray(input) ? input : []);
4
+ const usage = parseUsageEvents(Array.isArray(events) ? events : []);
5
+ const budget = input.budgetUsd || 100;
6
+ return { usage, budget: budgetStatus(usage.totalCostUsd, budget) };
7
+ }
8
+ export function parseUsageEvents(events) {
9
+ const byProvider = {};
10
+ let totalTokens = 0, totalCost = 0;
11
+ for (const e of (Array.isArray(events) ? events : [])) {
12
+ const p = e.provider || "unknown";
13
+ const tokens = Number(e.tokens || 0);
14
+ const cost = Number(e.costUsd ?? tokens * (e.pricePer1k || 0.002) / 1000);
15
+ byProvider[p] = byProvider[p] || { tokens: 0, costUsd: 0, calls: 0 };
16
+ byProvider[p].tokens += tokens;
17
+ byProvider[p].costUsd += cost;
18
+ byProvider[p].calls += 1;
19
+ totalTokens += tokens;
20
+ totalCost += cost;
21
+ }
22
+ return { byProvider, totalTokens, totalCostUsd: round(totalCost), eventCount: events.length };
23
+ }
24
+ export function budgetStatus(totalCostUsd, budgetUsd) {
25
+ const used = totalCostUsd / budgetUsd;
26
+ return { budgetUsd, totalCostUsd, usedPct: round(used * 100), over: totalCostUsd > budgetUsd };
27
+ }
28
+ function round(n) { return Math.round(n * 10000) / 10000; }