@hasna/economy 0.5.0 → 0.5.2
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/CHANGELOG.md +13 -0
- package/dist/chunks/{index-kgy9b6bf.js → index-9d2aky06.js} +1 -1
- package/dist/chunks/{index-axh32d30.js → index-dj3tctqh.js} +11 -2
- package/dist/chunks/{index-kn5572kd.js → index-kzwqw3ve.js} +1 -1
- package/dist/chunks/{index-emvs5ph2.js → index-npsjjv96.js} +1 -1
- package/dist/chunks/{serve-0k69e4h9.js → serve-p2yarhm8.js} +28 -3
- package/dist/chunks/{tui-7f8f951w.js → tui-x64hjfrh.js} +3 -3
- package/dist/chunks/{watch-mm1j39vy.js → watch-bxstjpbx.js} +3 -3
- package/dist/cli/index.js +10 -10
- package/dist/db/legacy-large-schema.d.ts +6 -0
- package/dist/db/legacy-large-schema.d.ts.map +1 -0
- package/dist/db/pg-legacy-schema.d.ts +12 -0
- package/dist/db/pg-legacy-schema.d.ts.map +1 -0
- package/dist/db/pg-migrations.d.ts.map +1 -1
- package/dist/index.js +11 -2
- package/dist/mcp/index.js +11 -2
- package/dist/otel/index.js +11 -2
- package/dist/server/index.js +358 -51
- package/dist/server/legacy-limits.d.ts +51 -0
- package/dist/server/legacy-limits.d.ts.map +1 -0
- package/dist/server/legacy-operations.d.ts +2 -1
- package/dist/server/legacy-operations.d.ts.map +1 -1
- package/dist/server/legacy-plan.d.ts +2 -1
- package/dist/server/legacy-plan.d.ts.map +1 -1
- package/dist/server/legacy-preservation.d.ts +2 -1
- package/dist/server/legacy-preservation.d.ts.map +1 -1
- package/dist/server/service-worker.js +11 -2
- package/docs/historical-data-reconciliation.md +38 -0
- package/docs/postgresql-legacy-schema-repair.md +30 -0
- package/package.json +11 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Support an explicit, bounded single-session reconciliation mode for large historical sessions. Preserve and verify every original before atomically recording dispositions, retain ordinary artifact limits, and optimize PostgreSQL overlap checks without weakening conflict protection.
|
|
8
|
+
|
|
9
|
+
## 0.5.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Update the hosted container to the pinned Alpine runtime and age-eligible security fixes, with exact standalone dependency overrides and reproducible lockfile resolution.
|
|
14
|
+
- Repair missing legacy PostgreSQL cost-center schema during explicit migration, preserving original rows and migration history with an atomic, validated completion receipt.
|
|
15
|
+
|
|
3
16
|
## 0.5.0
|
|
4
17
|
|
|
5
18
|
### Minor Changes
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
// package.json
|
|
20
20
|
var package_default = {
|
|
21
21
|
name: "@hasna/economy",
|
|
22
|
-
version: "0.5.
|
|
22
|
+
version: "0.5.2",
|
|
23
23
|
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
24
24
|
repository: {
|
|
25
25
|
type: "git",
|
|
@@ -114,7 +114,16 @@ var package_default = {
|
|
|
114
114
|
},
|
|
115
115
|
trustedDependencies: [
|
|
116
116
|
"@hasna/projects"
|
|
117
|
-
]
|
|
117
|
+
],
|
|
118
|
+
overrides: {
|
|
119
|
+
"fast-uri": "3.1.8",
|
|
120
|
+
hono: "4.13.7",
|
|
121
|
+
"ip-address": "10.7.1",
|
|
122
|
+
nanoid: "5.1.16",
|
|
123
|
+
"path-to-regexp": "8.4.0",
|
|
124
|
+
undici: "6.28.1",
|
|
125
|
+
"express-rate-limit": "8.7.0"
|
|
126
|
+
}
|
|
118
127
|
};
|
|
119
128
|
|
|
120
129
|
// src/lib/package-metadata.ts
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./index-w3bvv0ns.js";
|
|
6
6
|
import {
|
|
7
7
|
syncAll
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-npsjjv96.js";
|
|
9
9
|
import {
|
|
10
10
|
buildBrief,
|
|
11
11
|
packageMetadata,
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
queryProjectDetail,
|
|
17
17
|
queryRangeStats,
|
|
18
18
|
querySavingsSummary
|
|
19
|
-
} from "./index-
|
|
19
|
+
} from "./index-dj3tctqh.js";
|
|
20
20
|
import {
|
|
21
21
|
AGENTS,
|
|
22
22
|
INGEST_SCHEMA_SQL,
|
|
@@ -348,6 +348,30 @@ function resolvePgConnection(dsn) {
|
|
|
348
348
|
}
|
|
349
349
|
}
|
|
350
350
|
|
|
351
|
+
// src/db/legacy-large-schema.ts
|
|
352
|
+
var LEGACY_LARGE_SESSION_PG_SQL = `
|
|
353
|
+
CREATE INDEX idx_legacy_targets_session_operation
|
|
354
|
+
ON legacy_reconciliation_targets(session_id,operation_key);
|
|
355
|
+
CREATE OR REPLACE FUNCTION economy_legacy_target_guard() RETURNS trigger LANGUAGE plpgsql AS $body$
|
|
356
|
+
BEGIN
|
|
357
|
+
IF EXISTS(
|
|
358
|
+
SELECT 1 FROM (SELECT DISTINCT session_id,operation_key FROM inserted_legacy_targets) n
|
|
359
|
+
JOIN economy_legacy_active a ON a.session_id=n.session_id AND a.operation_key<>n.operation_key
|
|
360
|
+
) OR EXISTS(
|
|
361
|
+
SELECT 1 FROM inserted_legacy_targets n
|
|
362
|
+
JOIN economy_legacy_active a ON a.request_id=n.request_id AND a.operation_key<>n.operation_key
|
|
363
|
+
) THEN
|
|
364
|
+
RAISE EXCEPTION 'legacy reconciliation is already active for this session' USING ERRCODE='23000';
|
|
365
|
+
END IF;
|
|
366
|
+
RETURN NULL;
|
|
367
|
+
END
|
|
368
|
+
$body$;
|
|
369
|
+
DROP TRIGGER legacy_target_no_overlap ON legacy_reconciliation_targets;
|
|
370
|
+
CREATE TRIGGER legacy_target_no_overlap AFTER INSERT ON legacy_reconciliation_targets
|
|
371
|
+
REFERENCING NEW TABLE AS inserted_legacy_targets
|
|
372
|
+
FOR EACH STATEMENT EXECUTE FUNCTION economy_legacy_target_guard();
|
|
373
|
+
`;
|
|
374
|
+
|
|
351
375
|
// src/db/pg-migrations.ts
|
|
352
376
|
var PG_MIGRATIONS = [
|
|
353
377
|
`CREATE TABLE IF NOT EXISTS cost_centers (
|
|
@@ -579,7 +603,8 @@ var PG_MIGRATIONS = [
|
|
|
579
603
|
...OBSERVATION_PG_MIGRATIONS,
|
|
580
604
|
`ALTER TABLE budgets ADD COLUMN IF NOT EXISTS metric TEXT NOT NULL DEFAULT 'legacy_request_cost_usd'
|
|
581
605
|
CHECK (metric IN ('legacy_request_cost_usd', 'metered_api_usd'))`,
|
|
582
|
-
LEGACY_PG_SQL
|
|
606
|
+
LEGACY_PG_SQL,
|
|
607
|
+
LEGACY_LARGE_SESSION_PG_SQL
|
|
583
608
|
];
|
|
584
609
|
|
|
585
610
|
// src/db/cloud.ts
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
printStatusLine,
|
|
7
7
|
printWaybarJson,
|
|
8
8
|
runTui
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-kzwqw3ve.js";
|
|
10
10
|
import"./index-w3bvv0ns.js";
|
|
11
|
-
import"./index-
|
|
12
|
-
import"./index-
|
|
11
|
+
import"./index-9d2aky06.js";
|
|
12
|
+
import"./index-dj3tctqh.js";
|
|
13
13
|
import"./index-ez9thsr7.js";
|
|
14
14
|
import"./index-p35cyhc4.js";
|
|
15
15
|
export {
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
import {
|
|
3
3
|
agentPaths,
|
|
4
4
|
syncAll
|
|
5
|
-
} from "./index-
|
|
5
|
+
} from "./index-npsjjv96.js";
|
|
6
6
|
import {
|
|
7
7
|
getStore,
|
|
8
8
|
isCloudStore
|
|
9
|
-
} from "./index-
|
|
10
|
-
import"./index-
|
|
9
|
+
} from "./index-9d2aky06.js";
|
|
10
|
+
import"./index-dj3tctqh.js";
|
|
11
11
|
import {
|
|
12
12
|
formatSummaryValue
|
|
13
13
|
} from "./index-ez9thsr7.js";
|
package/dist/cli/index.js
CHANGED
|
@@ -8,22 +8,22 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
buildStatusLine,
|
|
10
10
|
gatherStatusData
|
|
11
|
-
} from "../chunks/index-
|
|
11
|
+
} from "../chunks/index-kzwqw3ve.js";
|
|
12
12
|
import"../chunks/index-w3bvv0ns.js";
|
|
13
13
|
import {
|
|
14
14
|
agentPaths,
|
|
15
15
|
syncAll
|
|
16
|
-
} from "../chunks/index-
|
|
16
|
+
} from "../chunks/index-npsjjv96.js";
|
|
17
17
|
import {
|
|
18
18
|
getStore,
|
|
19
19
|
isCloudStore
|
|
20
|
-
} from "../chunks/index-
|
|
20
|
+
} from "../chunks/index-9d2aky06.js";
|
|
21
21
|
import {
|
|
22
22
|
billingDriftCheck,
|
|
23
23
|
economyCloudStorage,
|
|
24
24
|
economyTransportReport,
|
|
25
25
|
packageMetadata
|
|
26
|
-
} from "../chunks/index-
|
|
26
|
+
} from "../chunks/index-dj3tctqh.js";
|
|
27
27
|
import {
|
|
28
28
|
AGENTS,
|
|
29
29
|
MAX_INGEST_BYTES,
|
|
@@ -1357,23 +1357,23 @@ function registerExtendedCommands(program) {
|
|
|
1357
1357
|
console.log();
|
|
1358
1358
|
});
|
|
1359
1359
|
program.command("tui").description("Terminal status dashboard (Linux/SSH friendly)").option("--watch", "Live refresh").option("--interval <seconds>", "Refresh interval", "30").action(async (opts) => {
|
|
1360
|
-
const { runTui } = await import("../chunks/tui-
|
|
1360
|
+
const { runTui } = await import("../chunks/tui-x64hjfrh.js");
|
|
1361
1361
|
await runTui({
|
|
1362
1362
|
watch: Boolean(opts.watch),
|
|
1363
1363
|
interval: Number(opts.interval ?? 30)
|
|
1364
1364
|
});
|
|
1365
1365
|
});
|
|
1366
1366
|
program.command("waybar").description("Print waybar-compatible JSON status line").action(async () => {
|
|
1367
|
-
const { printWaybarJson } = await import("../chunks/tui-
|
|
1367
|
+
const { printWaybarJson } = await import("../chunks/tui-x64hjfrh.js");
|
|
1368
1368
|
await printWaybarJson();
|
|
1369
1369
|
});
|
|
1370
1370
|
const barCmd = program.command("bar").description("Status bar helpers (Linux)");
|
|
1371
1371
|
barCmd.command("tui").description("Alias for economy tui").option("--watch", "Live refresh").action(async (opts) => {
|
|
1372
|
-
const { runTui } = await import("../chunks/tui-
|
|
1372
|
+
const { runTui } = await import("../chunks/tui-x64hjfrh.js");
|
|
1373
1373
|
await runTui({ watch: Boolean(opts.watch) });
|
|
1374
1374
|
});
|
|
1375
1375
|
barCmd.command("waybar").description("Alias for economy waybar").action(async () => {
|
|
1376
|
-
const { printWaybarJson } = await import("../chunks/tui-
|
|
1376
|
+
const { printWaybarJson } = await import("../chunks/tui-x64hjfrh.js");
|
|
1377
1377
|
await printWaybarJson();
|
|
1378
1378
|
});
|
|
1379
1379
|
program.command("estimate").description("Estimate cost for token counts").requiredOption("--model <model>", "Model name").option("--input <n>", "Input tokens", "0").option("--output <n>", "Output tokens", "0").action(async (opts) => {
|
|
@@ -3198,7 +3198,7 @@ program.command("accounts [period]").description("List account usage by email ad
|
|
|
3198
3198
|
console.log();
|
|
3199
3199
|
});
|
|
3200
3200
|
program.command("watch").description("Live stream of incoming costs").option("--interval <seconds>", "Poll interval in seconds", "10").option("--daemon", "Watch agent data directories and sync on change").option("--agent <agent>", `Filter by agent (${AGENTS.join("|")})`).option("--notify <amount>", "Fire macOS notification when cumulative cost crosses this USD threshold").action(async (opts) => {
|
|
3201
|
-
const { watchCosts } = await import("../chunks/watch-
|
|
3201
|
+
const { watchCosts } = await import("../chunks/watch-bxstjpbx.js");
|
|
3202
3202
|
await watchCosts({
|
|
3203
3203
|
interval: parsePositiveCliInteger(opts.interval ?? "10", "--interval"),
|
|
3204
3204
|
daemon: Boolean(opts.daemon),
|
|
@@ -3434,7 +3434,7 @@ pricingCmd.command("remove <model>").description("Remove pricing for a model").a
|
|
|
3434
3434
|
});
|
|
3435
3435
|
program.command("serve").description("Start the REST API server").option("-p, --port <port>", "Port", "3456").action(async (opts) => {
|
|
3436
3436
|
const port = parseCliPort(opts.port ?? "3456", "--port");
|
|
3437
|
-
const { startServer } = await import("../chunks/serve-
|
|
3437
|
+
const { startServer } = await import("../chunks/serve-p2yarhm8.js");
|
|
3438
3438
|
startServer(port);
|
|
3439
3439
|
});
|
|
3440
3440
|
program.command("mcp").description("Show MCP server install commands").option("--claude", "Install into Claude Code").option("--codex", "Install into Codex").option("--gemini", "Install into Gemini CLI").option("--all", "Install into all agents").action(async (opts) => {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Append-only PostgreSQL optimization. Keep the original migration bytes fixed.
|
|
2
|
+
* Check the complete inserted set once: per-row checks can become quadratic
|
|
3
|
+
* with stale or small-table statistics even when suitable indexes exist.
|
|
4
|
+
* Same-operation request duplicates remain prohibited by the primary key. */
|
|
5
|
+
export declare const LEGACY_LARGE_SESSION_PG_SQL = "\nCREATE INDEX idx_legacy_targets_session_operation\n ON legacy_reconciliation_targets(session_id,operation_key);\nCREATE OR REPLACE FUNCTION economy_legacy_target_guard() RETURNS trigger LANGUAGE plpgsql AS $body$\nBEGIN\n IF EXISTS(\n SELECT 1 FROM (SELECT DISTINCT session_id,operation_key FROM inserted_legacy_targets) n\n JOIN economy_legacy_active a ON a.session_id=n.session_id AND a.operation_key<>n.operation_key\n ) OR EXISTS(\n SELECT 1 FROM inserted_legacy_targets n\n JOIN economy_legacy_active a ON a.request_id=n.request_id AND a.operation_key<>n.operation_key\n ) THEN\n RAISE EXCEPTION 'legacy reconciliation is already active for this session' USING ERRCODE='23000';\n END IF;\n RETURN NULL;\nEND\n$body$;\nDROP TRIGGER legacy_target_no_overlap ON legacy_reconciliation_targets;\nCREATE TRIGGER legacy_target_no_overlap AFTER INSERT ON legacy_reconciliation_targets\n REFERENCING NEW TABLE AS inserted_legacy_targets\n FOR EACH STATEMENT EXECUTE FUNCTION economy_legacy_target_guard();\n";
|
|
6
|
+
//# sourceMappingURL=legacy-large-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"legacy-large-schema.d.ts","sourceRoot":"","sources":["../../src/db/legacy-large-schema.ts"],"names":[],"mappings":"AAAA;;;6EAG6E;AAC7E,eAAO,MAAM,2BAA2B,ygCAqBvC,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface LegacySchemaRepairResult {
|
|
2
|
+
id: string;
|
|
3
|
+
status: 'not_needed' | 'applied' | 'already_applied';
|
|
4
|
+
added: string[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Repair one known additive schema gap before the existing numbered migration
|
|
8
|
+
* sequence. Only the explicit migration command calls this; server startup
|
|
9
|
+
* never repairs a store. Originals and their migration markers are untouched.
|
|
10
|
+
*/
|
|
11
|
+
export declare function repairLegacyCostCenterSchema(dsn: string): Promise<LegacySchemaRepairResult>;
|
|
12
|
+
//# sourceMappingURL=pg-legacy-schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pg-legacy-schema.d.ts","sourceRoot":"","sources":["../../src/db/pg-legacy-schema.ts"],"names":[],"mappings":"AAkBA,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,YAAY,GAAG,SAAS,GAAG,iBAAiB,CAAA;IACpD,KAAK,EAAE,MAAM,EAAE,CAAA;CAChB;AA6HD;;;;GAIG;AACH,wBAAsB,4BAA4B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC,CA8DjG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pg-migrations.d.ts","sourceRoot":"","sources":["../../src/db/pg-migrations.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pg-migrations.d.ts","sourceRoot":"","sources":["../../src/db/pg-migrations.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH,eAAO,MAAM,aAAa,EAAE,MAAM,EAiRjC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -61,7 +61,7 @@ import { randomUUID } from "crypto";
|
|
|
61
61
|
// package.json
|
|
62
62
|
var package_default = {
|
|
63
63
|
name: "@hasna/economy",
|
|
64
|
-
version: "0.5.
|
|
64
|
+
version: "0.5.2",
|
|
65
65
|
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
66
66
|
repository: {
|
|
67
67
|
type: "git",
|
|
@@ -156,7 +156,16 @@ var package_default = {
|
|
|
156
156
|
},
|
|
157
157
|
trustedDependencies: [
|
|
158
158
|
"@hasna/projects"
|
|
159
|
-
]
|
|
159
|
+
],
|
|
160
|
+
overrides: {
|
|
161
|
+
"fast-uri": "3.1.8",
|
|
162
|
+
hono: "4.13.7",
|
|
163
|
+
"ip-address": "10.7.1",
|
|
164
|
+
nanoid: "5.1.16",
|
|
165
|
+
"path-to-regexp": "8.4.0",
|
|
166
|
+
undici: "6.28.1",
|
|
167
|
+
"express-rate-limit": "8.7.0"
|
|
168
|
+
}
|
|
160
169
|
};
|
|
161
170
|
|
|
162
171
|
// src/lib/package-metadata.ts
|
package/dist/mcp/index.js
CHANGED
|
@@ -84,7 +84,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
84
84
|
// package.json
|
|
85
85
|
var package_default = {
|
|
86
86
|
name: "@hasna/economy",
|
|
87
|
-
version: "0.5.
|
|
87
|
+
version: "0.5.2",
|
|
88
88
|
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
89
89
|
repository: {
|
|
90
90
|
type: "git",
|
|
@@ -179,7 +179,16 @@ var package_default = {
|
|
|
179
179
|
},
|
|
180
180
|
trustedDependencies: [
|
|
181
181
|
"@hasna/projects"
|
|
182
|
-
]
|
|
182
|
+
],
|
|
183
|
+
overrides: {
|
|
184
|
+
"fast-uri": "3.1.8",
|
|
185
|
+
hono: "4.13.7",
|
|
186
|
+
"ip-address": "10.7.1",
|
|
187
|
+
nanoid: "5.1.16",
|
|
188
|
+
"path-to-regexp": "8.4.0",
|
|
189
|
+
undici: "6.28.1",
|
|
190
|
+
"express-rate-limit": "8.7.0"
|
|
191
|
+
}
|
|
183
192
|
};
|
|
184
193
|
|
|
185
194
|
// src/lib/package-metadata.ts
|
package/dist/otel/index.js
CHANGED
|
@@ -3458,7 +3458,7 @@ async function pushIngestRows(cloud, scratch) {
|
|
|
3458
3458
|
// package.json
|
|
3459
3459
|
var package_default = {
|
|
3460
3460
|
name: "@hasna/economy",
|
|
3461
|
-
version: "0.5.
|
|
3461
|
+
version: "0.5.2",
|
|
3462
3462
|
description: "AI coding cost tracker \u2014 CLI + MCP server + REST API for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
3463
3463
|
repository: {
|
|
3464
3464
|
type: "git",
|
|
@@ -3553,7 +3553,16 @@ var package_default = {
|
|
|
3553
3553
|
},
|
|
3554
3554
|
trustedDependencies: [
|
|
3555
3555
|
"@hasna/projects"
|
|
3556
|
-
]
|
|
3556
|
+
],
|
|
3557
|
+
overrides: {
|
|
3558
|
+
"fast-uri": "3.1.8",
|
|
3559
|
+
hono: "4.13.7",
|
|
3560
|
+
"ip-address": "10.7.1",
|
|
3561
|
+
nanoid: "5.1.16",
|
|
3562
|
+
"path-to-regexp": "8.4.0",
|
|
3563
|
+
undici: "6.28.1",
|
|
3564
|
+
"express-rate-limit": "8.7.0"
|
|
3565
|
+
}
|
|
3557
3566
|
};
|
|
3558
3567
|
|
|
3559
3568
|
// src/lib/package-metadata.ts
|