@hasna/economy 0.2.1 → 0.2.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/dist/cli/index.js +28 -4
- package/dist/lib/config.d.ts +13 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/webhooks.d.ts +3 -0
- package/dist/lib/webhooks.d.ts.map +1 -0
- package/dist/mcp/index.js +99 -75
- package/dist/server/index.js +8 -1
- package/dist/server/serve.d.ts.map +1 -1
- package/package.json +2 -2
package/dist/cli/index.js
CHANGED
|
@@ -844,6 +844,11 @@ function ok(data, meta) {
|
|
|
844
844
|
function err(message, status = 400) {
|
|
845
845
|
return json({ error: message }, status);
|
|
846
846
|
}
|
|
847
|
+
function applyFields(obj, fields) {
|
|
848
|
+
if (!fields || fields.length === 0)
|
|
849
|
+
return obj;
|
|
850
|
+
return Object.fromEntries(fields.map((f) => [f, obj[f] ?? null]));
|
|
851
|
+
}
|
|
847
852
|
function createHandler(db) {
|
|
848
853
|
return async function handler(req) {
|
|
849
854
|
const url = new URL(req.url);
|
|
@@ -867,8 +872,10 @@ function createHandler(db) {
|
|
|
867
872
|
const limit = Number(url.searchParams.get("limit") ?? 50);
|
|
868
873
|
const offset = Number(url.searchParams.get("offset") ?? 0);
|
|
869
874
|
const since = url.searchParams.get("since") ?? undefined;
|
|
875
|
+
const fieldsParam = url.searchParams.get("fields");
|
|
876
|
+
const fields = fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
870
877
|
const sessions = querySessions(db, { agent: agent ?? undefined, project, limit, offset, since });
|
|
871
|
-
return ok(sessions, { limit, offset });
|
|
878
|
+
return ok(fields ? sessions.map((s) => applyFields(s, fields)) : sessions, { limit, offset });
|
|
872
879
|
}
|
|
873
880
|
if (path === "/api/top" && method === "GET") {
|
|
874
881
|
const n = Number(url.searchParams.get("n") ?? 10);
|
|
@@ -1026,7 +1033,7 @@ import chalk2 from "chalk";
|
|
|
1026
1033
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
1027
1034
|
import { execSync } from "child_process";
|
|
1028
1035
|
var program = new Command;
|
|
1029
|
-
program.name("economy").description("AI coding cost tracker \u2014 Claude Code, Codex, and Gemini").version("0.
|
|
1036
|
+
program.name("economy").description("AI coding cost tracker \u2014 Claude Code, Codex, and Gemini").version("0.2.2");
|
|
1030
1037
|
async function autoSync() {
|
|
1031
1038
|
const db = openDatabase();
|
|
1032
1039
|
ensurePricingSeeded(db);
|
|
@@ -1166,7 +1173,7 @@ program.command("month").description("Cost summary for this month").action(async
|
|
|
1166
1173
|
await autoSync();
|
|
1167
1174
|
printSummary("This Month", "month");
|
|
1168
1175
|
});
|
|
1169
|
-
program.command("sessions").description("List coding sessions with costs").option("--agent <agent>", "Filter by agent (claude|codex)").option("--project <path>", "Filter by project path").option("--limit <n>", "Number of sessions", "20").action(async (opts) => {
|
|
1176
|
+
program.command("sessions").description("List coding sessions with costs").option("--agent <agent>", "Filter by agent (claude|codex)").option("--project <path>", "Filter by project path").option("--limit <n>", "Number of sessions", "20").option("--format <fmt>", "Output format: table|compact|csv|json", "table").action(async (opts) => {
|
|
1170
1177
|
await autoSync();
|
|
1171
1178
|
const db = openDatabase();
|
|
1172
1179
|
const sessions = querySessions(db, {
|
|
@@ -1175,7 +1182,24 @@ program.command("sessions").description("List coding sessions with costs").optio
|
|
|
1175
1182
|
limit: Number(opts.limit ?? 20)
|
|
1176
1183
|
});
|
|
1177
1184
|
if (sessions.length === 0) {
|
|
1178
|
-
console.log(chalk2.yellow("No sessions found.
|
|
1185
|
+
console.log(chalk2.yellow("No sessions found."));
|
|
1186
|
+
return;
|
|
1187
|
+
}
|
|
1188
|
+
const f = opts.format ?? "table";
|
|
1189
|
+
if (f === "compact") {
|
|
1190
|
+
for (const s of sessions)
|
|
1191
|
+
process.stdout.write(`${s.id.slice(0, 8)} ${s.agent} ${fmt2(s.total_cost_usd)} ${fmtTokens(s.total_tokens)} ${s.project_name || "\u2014"}
|
|
1192
|
+
`);
|
|
1193
|
+
return;
|
|
1194
|
+
}
|
|
1195
|
+
if (f === "json") {
|
|
1196
|
+
console.log(JSON.stringify(sessions, null, 2));
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
if (f === "csv") {
|
|
1200
|
+
console.log("id,agent,project_name,total_cost_usd,total_tokens,request_count,started_at");
|
|
1201
|
+
for (const s of sessions)
|
|
1202
|
+
console.log(`${s.id},${s.agent},"${s.project_name}",${s.total_cost_usd},${s.total_tokens},${s.request_count},${s.started_at}`);
|
|
1179
1203
|
return;
|
|
1180
1204
|
}
|
|
1181
1205
|
console.log();
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface EconomyConfig {
|
|
2
|
+
port: number;
|
|
3
|
+
'default-period': string;
|
|
4
|
+
'auto-sync': boolean;
|
|
5
|
+
'sync-interval': number;
|
|
6
|
+
'alert-thresholds': number[];
|
|
7
|
+
'webhook-url': string | null;
|
|
8
|
+
}
|
|
9
|
+
export declare function loadConfig(): EconomyConfig;
|
|
10
|
+
export declare function saveConfig(config: EconomyConfig): void;
|
|
11
|
+
export declare function getConfigValue(key: string): unknown;
|
|
12
|
+
export declare function setConfigValue(key: string, value: string): void;
|
|
13
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,gBAAgB,EAAE,MAAM,CAAA;IACxB,WAAW,EAAE,OAAO,CAAA;IACpB,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,MAAM,EAAE,CAAA;IAC5B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B;AAWD,wBAAgB,UAAU,IAAI,aAAa,CAQ1C;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAItD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAGnD;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAW/D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../src/lib/webhooks.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAE1C,wBAAsB,oBAAoB,CAAC,EAAE,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAyBtE"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -596,80 +596,68 @@ async function ingestCodex(db, verbose = false) {
|
|
|
596
596
|
init_pricing();
|
|
597
597
|
var db = openDatabase();
|
|
598
598
|
ensurePricingSeeded(db);
|
|
599
|
-
var server = new Server({ name: "economy", version: "0.
|
|
599
|
+
var server = new Server({ name: "economy", version: "0.2.2" }, { capabilities: { tools: {} } });
|
|
600
|
+
var fmtUsd = (n) => "$" + n.toLocaleString("en-US", { minimumFractionDigits: 2, maximumFractionDigits: 2 });
|
|
601
|
+
var fmtTok = (n) => n >= 1e9 ? `${(n / 1e9).toFixed(1)}B` : n >= 1e6 ? `${(n / 1e6).toFixed(1)}M` : n >= 1000 ? `${(n / 1000).toFixed(1)}k` : String(n);
|
|
602
|
+
function fmtSession(s) {
|
|
603
|
+
const id = String(s["id"] ?? "").slice(0, 8);
|
|
604
|
+
const agent = String(s["agent"] ?? "");
|
|
605
|
+
const proj = String(s["project_name"] || s["project_path"] || "\u2014").slice(0, 20);
|
|
606
|
+
const cost = fmtUsd(Number(s["total_cost_usd"] ?? 0));
|
|
607
|
+
const tok = fmtTok(Number(s["total_tokens"] ?? 0));
|
|
608
|
+
return `${id} ${agent.padEnd(6)} ${cost.padEnd(10)} ${tok.padEnd(8)} ${proj}`;
|
|
609
|
+
}
|
|
600
610
|
var TOOLS = [
|
|
601
|
-
{
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
},
|
|
611
|
-
{
|
|
612
|
-
name: "get_sessions",
|
|
613
|
-
description: "List coding sessions with cost data",
|
|
614
|
-
inputSchema: {
|
|
615
|
-
type: "object",
|
|
616
|
-
properties: {
|
|
617
|
-
agent: { type: "string", enum: ["claude", "codex"], description: "Filter by agent" },
|
|
618
|
-
project: { type: "string", description: "Filter by project path (partial match)" },
|
|
619
|
-
limit: { type: "number", description: "Max results", default: 20 }
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
},
|
|
623
|
-
{
|
|
624
|
-
name: "get_top_sessions",
|
|
625
|
-
description: "Get the most expensive coding sessions",
|
|
626
|
-
inputSchema: {
|
|
627
|
-
type: "object",
|
|
628
|
-
properties: {
|
|
629
|
-
n: { type: "number", description: "Number of sessions to return", default: 10 },
|
|
630
|
-
agent: { type: "string", enum: ["claude", "codex"], description: "Filter by agent" }
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
},
|
|
634
|
-
{
|
|
635
|
-
name: "get_model_breakdown",
|
|
636
|
-
description: "Get cost breakdown by AI model",
|
|
637
|
-
inputSchema: { type: "object", properties: {} }
|
|
638
|
-
},
|
|
639
|
-
{
|
|
640
|
-
name: "get_project_breakdown",
|
|
641
|
-
description: "Get cost breakdown by project",
|
|
642
|
-
inputSchema: { type: "object", properties: {} }
|
|
643
|
-
},
|
|
644
|
-
{
|
|
645
|
-
name: "get_budget_status",
|
|
646
|
-
description: "Get current budget status and spending vs limits",
|
|
647
|
-
inputSchema: { type: "object", properties: {} }
|
|
648
|
-
},
|
|
649
|
-
{
|
|
650
|
-
name: "sync",
|
|
651
|
-
description: "Trigger cost data ingestion from Claude Code and/or Codex",
|
|
652
|
-
inputSchema: {
|
|
653
|
-
type: "object",
|
|
654
|
-
properties: {
|
|
655
|
-
sources: { type: "string", enum: ["all", "claude", "codex"], default: "all" }
|
|
656
|
-
}
|
|
657
|
-
}
|
|
658
|
-
}
|
|
611
|
+
{ name: "get_cost_summary", description: "Cost summary (total_usd, sessions, requests, tokens, human summary). period: today|week|month|all", inputSchema: { type: "object", properties: { period: { type: "string", enum: ["today", "week", "month", "all"] } } } },
|
|
612
|
+
{ name: "get_sessions", description: "List sessions. Returns compact table. Params: agent, project, limit(20)", inputSchema: { type: "object", properties: { agent: { type: "string" }, project: { type: "string" }, limit: { type: "number" } } } },
|
|
613
|
+
{ name: "get_top_sessions", description: "Top sessions by cost. Params: n(10), agent", inputSchema: { type: "object", properties: { n: { type: "number" }, agent: { type: "string" } } } },
|
|
614
|
+
{ name: "get_model_breakdown", description: "Cost per model. No params.", inputSchema: { type: "object", properties: {} } },
|
|
615
|
+
{ name: "get_project_breakdown", description: "Cost per project. No params.", inputSchema: { type: "object", properties: {} } },
|
|
616
|
+
{ name: "get_budget_status", description: "Budget limits vs spend, percent used, alert flags. No params.", inputSchema: { type: "object", properties: {} } },
|
|
617
|
+
{ name: "sync", description: "Ingest new cost data. sources: all|claude|codex", inputSchema: { type: "object", properties: { sources: { type: "string", enum: ["all", "claude", "codex"] } } } },
|
|
618
|
+
{ name: "search_tools", description: "List tool names matching query. Use first to find relevant tools.", inputSchema: { type: "object", properties: { query: { type: "string" } } } },
|
|
619
|
+
{ name: "describe_tools", description: "Get param hints for specific tools by name.", inputSchema: { type: "object", properties: { names: { type: "array", items: { type: "string" } } }, required: ["names"] } }
|
|
659
620
|
];
|
|
621
|
+
var TOOL_DESCRIPTIONS = {
|
|
622
|
+
get_cost_summary: "period(today|week|month|all) \u2192 {total_usd, sessions, requests, tokens, summary}",
|
|
623
|
+
get_sessions: "agent(claude|codex), project(partial), limit(20) \u2192 compact session table",
|
|
624
|
+
get_top_sessions: "n(10), agent(claude|codex) \u2192 top sessions by cost",
|
|
625
|
+
get_model_breakdown: "no params \u2192 model, requests, tokens, cost",
|
|
626
|
+
get_project_breakdown: "no params \u2192 project_name, sessions, cost",
|
|
627
|
+
get_budget_status: "no params \u2192 budget limits, current spend, percent_used, is_over_alert",
|
|
628
|
+
sync: "sources(all|claude|codex) \u2192 {files, requests, sessions} ingested"
|
|
629
|
+
};
|
|
660
630
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
661
631
|
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
662
632
|
const { name, arguments: args } = req.params;
|
|
663
633
|
const a = args ?? {};
|
|
664
634
|
try {
|
|
665
635
|
switch (name) {
|
|
636
|
+
case "search_tools": {
|
|
637
|
+
const q = a["query"]?.toLowerCase();
|
|
638
|
+
const names = TOOLS.map((t) => t.name);
|
|
639
|
+
const matches = q ? names.filter((n) => n.includes(q)) : names;
|
|
640
|
+
return { content: [{ type: "text", text: matches.join(", ") }] };
|
|
641
|
+
}
|
|
642
|
+
case "describe_tools": {
|
|
643
|
+
const names = a["names"] ?? [];
|
|
644
|
+
const result = names.map((n) => `${n}: ${TOOL_DESCRIPTIONS[n] ?? "see tool schema"}`).join(`
|
|
645
|
+
`);
|
|
646
|
+
return { content: [{ type: "text", text: result }] };
|
|
647
|
+
}
|
|
666
648
|
case "get_cost_summary": {
|
|
667
649
|
const period = a["period"] ?? "today";
|
|
668
|
-
const
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
650
|
+
const s = querySummary(db, period);
|
|
651
|
+
const text = [
|
|
652
|
+
`period: ${period}`,
|
|
653
|
+
`cost: ${fmtUsd(s.total_usd)}`,
|
|
654
|
+
`sessions: ${s.sessions}`,
|
|
655
|
+
`requests: ${s.requests.toLocaleString()}`,
|
|
656
|
+
`tokens: ${fmtTok(s.tokens)}`,
|
|
657
|
+
`summary: You've spent ${fmtUsd(s.total_usd)} ${period === "all" ? "total" : period} across ${s.sessions} sessions (${s.requests.toLocaleString()} requests, ${fmtTok(s.tokens)} tokens)`
|
|
658
|
+
].join(`
|
|
659
|
+
`);
|
|
660
|
+
return { content: [{ type: "text", text }] };
|
|
673
661
|
}
|
|
674
662
|
case "get_sessions": {
|
|
675
663
|
const sessions = querySessions(db, {
|
|
@@ -677,29 +665,65 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
677
665
|
project: a["project"],
|
|
678
666
|
limit: Number(a["limit"] ?? 20)
|
|
679
667
|
});
|
|
680
|
-
|
|
668
|
+
const lines = ["id agent cost tokens project"];
|
|
669
|
+
for (const s of sessions)
|
|
670
|
+
lines.push(fmtSession(s));
|
|
671
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
672
|
+
`) }] };
|
|
681
673
|
}
|
|
682
674
|
case "get_top_sessions": {
|
|
683
675
|
const sessions = queryTopSessions(db, Number(a["n"] ?? 10), a["agent"]);
|
|
684
|
-
|
|
676
|
+
const lines = ["rank id agent cost tokens project"];
|
|
677
|
+
sessions.forEach((s, i) => lines.push(`${String(i + 1).padEnd(5)} ${fmtSession(s)}`));
|
|
678
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
679
|
+
`) }] };
|
|
685
680
|
}
|
|
686
681
|
case "get_model_breakdown": {
|
|
687
|
-
|
|
682
|
+
const rows = queryModelBreakdown(db);
|
|
683
|
+
const lines = ["model reqs tokens cost"];
|
|
684
|
+
for (const r of rows) {
|
|
685
|
+
lines.push(`${String(r["model"]).slice(0, 30).padEnd(31)}${String(r["requests"]).padEnd(8)}${fmtTok(Number(r["total_tokens"])).padEnd(9)}${fmtUsd(Number(r["cost_usd"]))}`);
|
|
686
|
+
}
|
|
687
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
688
|
+
`) }] };
|
|
688
689
|
}
|
|
689
690
|
case "get_project_breakdown": {
|
|
690
|
-
|
|
691
|
+
const rows = queryProjectBreakdown(db);
|
|
692
|
+
const lines = ["project sessions tokens cost"];
|
|
693
|
+
for (const r of rows) {
|
|
694
|
+
const name2 = String(r["project_name"] || r["project_path"] || "\u2014").slice(0, 20);
|
|
695
|
+
lines.push(`${name2.padEnd(21)}${String(r["sessions"]).padEnd(9)}${fmtTok(Number(r["total_tokens"])).padEnd(9)}${fmtUsd(Number(r["cost_usd"]))}`);
|
|
696
|
+
}
|
|
697
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
698
|
+
`) }] };
|
|
691
699
|
}
|
|
692
700
|
case "get_budget_status": {
|
|
693
|
-
|
|
701
|
+
const budgets = getBudgetStatuses(db);
|
|
702
|
+
if (budgets.length === 0)
|
|
703
|
+
return { content: [{ type: "text", text: "No budgets set." }] };
|
|
704
|
+
const lines = ["scope period spent limit used% status"];
|
|
705
|
+
for (const b of budgets) {
|
|
706
|
+
const scope = String(b["project_path"] ?? "global").slice(0, 20);
|
|
707
|
+
const pct = Number(b["percent_used"]).toFixed(1);
|
|
708
|
+
const status = b["is_over_limit"] ? "OVER" : b["is_over_alert"] ? "ALERT" : "OK";
|
|
709
|
+
lines.push(`${scope.padEnd(21)}${String(b["period"]).padEnd(9)}${fmtUsd(Number(b["current_spend_usd"])).padEnd(11)}${fmtUsd(Number(b["limit_usd"])).padEnd(11)}${pct}%`.padEnd(49) + ` ${status}`);
|
|
710
|
+
}
|
|
711
|
+
return { content: [{ type: "text", text: lines.join(`
|
|
712
|
+
`) }] };
|
|
694
713
|
}
|
|
695
714
|
case "sync": {
|
|
696
715
|
const sources = a["sources"] ?? "all";
|
|
697
|
-
const
|
|
698
|
-
if (sources === "all" || sources === "claude")
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
716
|
+
const parts = [];
|
|
717
|
+
if (sources === "all" || sources === "claude") {
|
|
718
|
+
const r = await ingestClaude(db);
|
|
719
|
+
parts.push(`claude: ${r["files"]} files, ${r["requests"]} requests, ${r["sessions"]} sessions`);
|
|
720
|
+
}
|
|
721
|
+
if (sources === "all" || sources === "codex") {
|
|
722
|
+
const r = await ingestCodex(db);
|
|
723
|
+
parts.push(`codex: ${r["sessions"]} sessions`);
|
|
724
|
+
}
|
|
725
|
+
return { content: [{ type: "text", text: parts.join(`
|
|
726
|
+
`) || "done" }] };
|
|
703
727
|
}
|
|
704
728
|
default:
|
|
705
729
|
return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
|
package/dist/server/index.js
CHANGED
|
@@ -646,6 +646,11 @@ function ok(data, meta) {
|
|
|
646
646
|
function err(message, status = 400) {
|
|
647
647
|
return json({ error: message }, status);
|
|
648
648
|
}
|
|
649
|
+
function applyFields(obj, fields) {
|
|
650
|
+
if (!fields || fields.length === 0)
|
|
651
|
+
return obj;
|
|
652
|
+
return Object.fromEntries(fields.map((f) => [f, obj[f] ?? null]));
|
|
653
|
+
}
|
|
649
654
|
function createHandler(db) {
|
|
650
655
|
return async function handler(req) {
|
|
651
656
|
const url = new URL(req.url);
|
|
@@ -669,8 +674,10 @@ function createHandler(db) {
|
|
|
669
674
|
const limit = Number(url.searchParams.get("limit") ?? 50);
|
|
670
675
|
const offset = Number(url.searchParams.get("offset") ?? 0);
|
|
671
676
|
const since = url.searchParams.get("since") ?? undefined;
|
|
677
|
+
const fieldsParam = url.searchParams.get("fields");
|
|
678
|
+
const fields = fieldsParam ? fieldsParam.split(",").map((f) => f.trim()).filter(Boolean) : undefined;
|
|
672
679
|
const sessions = querySessions(db, { agent: agent ?? undefined, project, limit, offset, since });
|
|
673
|
-
return ok(sessions, { limit, offset });
|
|
680
|
+
return ok(fields ? sessions.map((s) => applyFields(s, fields)) : sessions, { limit, offset });
|
|
674
681
|
}
|
|
675
682
|
if (path === "/api/top" && method === "GET") {
|
|
676
683
|
const n = Number(url.searchParams.get("n") ?? 10);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/server/serve.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AA0C1C,wBAAgB,aAAa,CAAC,EAAE,EAAE,QAAQ,IACV,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CA6I/D;AAED,wBAAgB,WAAW,CAAC,IAAI,SAAO,GAAG,IAAI,CAuC7C"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/economy",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "AI coding cost tracker — CLI + MCP server + REST API + web dashboard for Claude Code, Codex, and Gemini",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"author": "hasna",
|
|
49
49
|
"license": "Apache-2.0",
|
|
50
50
|
"publishConfig": {
|
|
51
|
-
"access": "
|
|
51
|
+
"access": "public",
|
|
52
52
|
"registry": "https://registry.npmjs.org/"
|
|
53
53
|
},
|
|
54
54
|
"dependencies": {
|