@hasna/economy 0.5.8 → 0.5.9
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 +6 -0
- package/dist/chunks/{index-a1gh3d6t.js → index-92x56q4h.js} +1 -1
- package/dist/chunks/{index-9za4cmq2.js → index-970htsxe.js} +1 -1
- package/dist/chunks/{index-h2mcj7gv.js → index-spwpgdbb.js} +1 -1
- package/dist/chunks/{index-gf3kan31.js → index-twkdyrw4.js} +1 -1
- package/dist/chunks/{serve-14cgmx02.js → serve-tmv8zgvh.js} +2 -2
- package/dist/chunks/{tui-s6tpce3h.js → tui-j8brj3wf.js} +3 -3
- package/dist/chunks/{watch-cv5va8x6.js → watch-ksn2mezm.js} +3 -3
- package/dist/cli/index.js +16 -14
- package/dist/index.js +7 -5
- package/dist/lib/ingest-journal-maintenance.d.ts.map +1 -1
- package/dist/mcp/index.js +7 -5
- package/dist/otel/index.js +7 -5
- package/dist/server/index.js +1 -1
- package/dist/server/service-worker.js +1 -1
- package/docs/ingest-journal.md +5 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.9
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Give each journal recovery transaction its own bounded deadline so slow storage does not interrupt healthy collection, and stop ingestion whenever cleanup leaves unresolved recovery state.
|
|
8
|
+
|
|
3
9
|
## 0.5.8
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -86,7 +86,7 @@ function comparisonValueChange(left, right) {
|
|
|
86
86
|
// package.json
|
|
87
87
|
var package_default = {
|
|
88
88
|
name: "@hasna/economy",
|
|
89
|
-
version: "0.5.
|
|
89
|
+
version: "0.5.9",
|
|
90
90
|
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",
|
|
91
91
|
repository: {
|
|
92
92
|
type: "git",
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
} from "./index-w3bvv0ns.js";
|
|
6
6
|
import {
|
|
7
7
|
syncAll
|
|
8
|
-
} from "./index-
|
|
8
|
+
} from "./index-970htsxe.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-spwpgdbb.js";
|
|
20
20
|
import {
|
|
21
21
|
AGENTS,
|
|
22
22
|
INGEST_SCHEMA_SQL,
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
printStatusLine,
|
|
7
7
|
printWaybarJson,
|
|
8
8
|
runTui
|
|
9
|
-
} from "./index-
|
|
9
|
+
} from "./index-twkdyrw4.js";
|
|
10
10
|
import"./index-w3bvv0ns.js";
|
|
11
|
-
import"./index-
|
|
12
|
-
import"./index-
|
|
11
|
+
import"./index-92x56q4h.js";
|
|
12
|
+
import"./index-spwpgdbb.js";
|
|
13
13
|
import"./index-zgvmrqyc.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-970htsxe.js";
|
|
6
6
|
import {
|
|
7
7
|
getStore,
|
|
8
8
|
isCloudStore
|
|
9
|
-
} from "./index-
|
|
10
|
-
import"./index-
|
|
9
|
+
} from "./index-92x56q4h.js";
|
|
10
|
+
import"./index-spwpgdbb.js";
|
|
11
11
|
import {
|
|
12
12
|
formatSummaryValue
|
|
13
13
|
} from "./index-zgvmrqyc.js";
|
package/dist/cli/index.js
CHANGED
|
@@ -8,16 +8,16 @@ import {
|
|
|
8
8
|
import {
|
|
9
9
|
buildStatusLine,
|
|
10
10
|
gatherStatusData
|
|
11
|
-
} from "../chunks/index-
|
|
11
|
+
} from "../chunks/index-twkdyrw4.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-970htsxe.js";
|
|
17
17
|
import {
|
|
18
18
|
getStore,
|
|
19
19
|
isCloudStore
|
|
20
|
-
} from "../chunks/index-
|
|
20
|
+
} from "../chunks/index-92x56q4h.js";
|
|
21
21
|
import {
|
|
22
22
|
billingDriftCheck,
|
|
23
23
|
comparisonValueChange,
|
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
economyTransportReport,
|
|
26
26
|
formatComparisonValue,
|
|
27
27
|
packageMetadata
|
|
28
|
-
} from "../chunks/index-
|
|
28
|
+
} from "../chunks/index-spwpgdbb.js";
|
|
29
29
|
import {
|
|
30
30
|
AGENTS,
|
|
31
31
|
MAX_INGEST_BYTES,
|
|
@@ -1359,23 +1359,23 @@ function registerExtendedCommands(program) {
|
|
|
1359
1359
|
console.log();
|
|
1360
1360
|
});
|
|
1361
1361
|
program.command("tui").description("Terminal status dashboard (Linux/SSH friendly)").option("--watch", "Live refresh").option("--interval <seconds>", "Refresh interval", "30").action(async (opts) => {
|
|
1362
|
-
const { runTui } = await import("../chunks/tui-
|
|
1362
|
+
const { runTui } = await import("../chunks/tui-j8brj3wf.js");
|
|
1363
1363
|
await runTui({
|
|
1364
1364
|
watch: Boolean(opts.watch),
|
|
1365
1365
|
interval: Number(opts.interval ?? 30)
|
|
1366
1366
|
});
|
|
1367
1367
|
});
|
|
1368
1368
|
program.command("waybar").description("Print waybar-compatible JSON status line").action(async () => {
|
|
1369
|
-
const { printWaybarJson } = await import("../chunks/tui-
|
|
1369
|
+
const { printWaybarJson } = await import("../chunks/tui-j8brj3wf.js");
|
|
1370
1370
|
await printWaybarJson();
|
|
1371
1371
|
});
|
|
1372
1372
|
const barCmd = program.command("bar").description("Status bar helpers (Linux)");
|
|
1373
1373
|
barCmd.command("tui").description("Alias for economy tui").option("--watch", "Live refresh").action(async (opts) => {
|
|
1374
|
-
const { runTui } = await import("../chunks/tui-
|
|
1374
|
+
const { runTui } = await import("../chunks/tui-j8brj3wf.js");
|
|
1375
1375
|
await runTui({ watch: Boolean(opts.watch) });
|
|
1376
1376
|
});
|
|
1377
1377
|
barCmd.command("waybar").description("Alias for economy waybar").action(async () => {
|
|
1378
|
-
const { printWaybarJson } = await import("../chunks/tui-
|
|
1378
|
+
const { printWaybarJson } = await import("../chunks/tui-j8brj3wf.js");
|
|
1379
1379
|
await printWaybarJson();
|
|
1380
1380
|
});
|
|
1381
1381
|
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) => {
|
|
@@ -2024,18 +2024,19 @@ class IngestJournalMaintenance {
|
|
|
2024
2024
|
throw new Error("Journal maintenance limit must be 1\u201332");
|
|
2025
2025
|
await this.recover();
|
|
2026
2026
|
await verifyJournalAuthority(this.journal, this.cloud);
|
|
2027
|
-
const
|
|
2027
|
+
const sweepDeadline = Date.now() + 30000;
|
|
2028
2028
|
let retired = 0, bytes = 0;
|
|
2029
2029
|
let backend;
|
|
2030
2030
|
try {
|
|
2031
2031
|
const names = this.journal.names();
|
|
2032
2032
|
for (const name of names.filter((n) => n.endsWith(".intent.json"))) {
|
|
2033
|
-
if (retired >= limit || Date.now() >=
|
|
2033
|
+
if (retired >= limit || Date.now() >= sweepDeadline || retired > 0 && bytes >= 1048576)
|
|
2034
2034
|
break;
|
|
2035
2035
|
if (!names.includes(name.replace(".intent.", ".receipt.")))
|
|
2036
2036
|
continue;
|
|
2037
2037
|
const intent = this.journal.intent(name), receipt = this.journal.receipt(intent.command);
|
|
2038
|
-
|
|
2038
|
+
const deadline = Date.now() + 30000;
|
|
2039
|
+
backend = await this.backend(deadline);
|
|
2039
2040
|
const m = {
|
|
2040
2041
|
version: 1,
|
|
2041
2042
|
target: this.journal.target,
|
|
@@ -2071,7 +2072,8 @@ class IngestJournalMaintenance {
|
|
|
2071
2072
|
try {
|
|
2072
2073
|
await this.maintain();
|
|
2073
2074
|
} catch (error) {
|
|
2074
|
-
|
|
2075
|
+
const deferrable = error instanceof JournalMaintenanceError && ["recovery_not_configured", "self_host_trash_authority_required", "trash_version_mismatch", "recovery_authority_unavailable"].includes(error.reason);
|
|
2076
|
+
if (!deferrable || exists(this.control) || !this.journal.canStage(command))
|
|
2075
2077
|
throw error;
|
|
2076
2078
|
}
|
|
2077
2079
|
if (!this.journal.canStage(command))
|
|
@@ -3200,7 +3202,7 @@ program.command("accounts [period]").description("List account usage by email ad
|
|
|
3200
3202
|
console.log();
|
|
3201
3203
|
});
|
|
3202
3204
|
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) => {
|
|
3203
|
-
const { watchCosts } = await import("../chunks/watch-
|
|
3205
|
+
const { watchCosts } = await import("../chunks/watch-ksn2mezm.js");
|
|
3204
3206
|
await watchCosts({
|
|
3205
3207
|
interval: parsePositiveCliInteger(opts.interval ?? "10", "--interval"),
|
|
3206
3208
|
daemon: Boolean(opts.daemon),
|
|
@@ -3436,7 +3438,7 @@ pricingCmd.command("remove <model>").description("Remove pricing for a model").a
|
|
|
3436
3438
|
});
|
|
3437
3439
|
program.command("serve").description("Start the REST API server").option("-p, --port <port>", "Port", "3456").action(async (opts) => {
|
|
3438
3440
|
const port = parseCliPort(opts.port ?? "3456", "--port");
|
|
3439
|
-
const { startServer } = await import("../chunks/serve-
|
|
3441
|
+
const { startServer } = await import("../chunks/serve-tmv8zgvh.js");
|
|
3440
3442
|
startServer(port);
|
|
3441
3443
|
});
|
|
3442
3444
|
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) => {
|
package/dist/index.js
CHANGED
|
@@ -111,7 +111,7 @@ import { randomUUID } from "crypto";
|
|
|
111
111
|
// package.json
|
|
112
112
|
var package_default = {
|
|
113
113
|
name: "@hasna/economy",
|
|
114
|
-
version: "0.5.
|
|
114
|
+
version: "0.5.9",
|
|
115
115
|
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",
|
|
116
116
|
repository: {
|
|
117
117
|
type: "git",
|
|
@@ -2345,18 +2345,19 @@ class IngestJournalMaintenance {
|
|
|
2345
2345
|
throw new Error("Journal maintenance limit must be 1\u201332");
|
|
2346
2346
|
await this.recover();
|
|
2347
2347
|
await verifyJournalAuthority(this.journal, this.cloud);
|
|
2348
|
-
const
|
|
2348
|
+
const sweepDeadline = Date.now() + 30000;
|
|
2349
2349
|
let retired = 0, bytes = 0;
|
|
2350
2350
|
let backend;
|
|
2351
2351
|
try {
|
|
2352
2352
|
const names = this.journal.names();
|
|
2353
2353
|
for (const name of names.filter((n) => n.endsWith(".intent.json"))) {
|
|
2354
|
-
if (retired >= limit || Date.now() >=
|
|
2354
|
+
if (retired >= limit || Date.now() >= sweepDeadline || retired > 0 && bytes >= 1048576)
|
|
2355
2355
|
break;
|
|
2356
2356
|
if (!names.includes(name.replace(".intent.", ".receipt.")))
|
|
2357
2357
|
continue;
|
|
2358
2358
|
const intent = this.journal.intent(name), receipt = this.journal.receipt(intent.command);
|
|
2359
|
-
|
|
2359
|
+
const deadline = Date.now() + 30000;
|
|
2360
|
+
backend = await this.backend(deadline);
|
|
2360
2361
|
const m = {
|
|
2361
2362
|
version: 1,
|
|
2362
2363
|
target: this.journal.target,
|
|
@@ -2392,7 +2393,8 @@ class IngestJournalMaintenance {
|
|
|
2392
2393
|
try {
|
|
2393
2394
|
await this.maintain();
|
|
2394
2395
|
} catch (error) {
|
|
2395
|
-
|
|
2396
|
+
const deferrable = error instanceof JournalMaintenanceError && ["recovery_not_configured", "self_host_trash_authority_required", "trash_version_mismatch", "recovery_authority_unavailable"].includes(error.reason);
|
|
2397
|
+
if (!deferrable || exists(this.control) || !this.journal.canStage(command))
|
|
2396
2398
|
throw error;
|
|
2397
2399
|
}
|
|
2398
2400
|
if (!this.journal.canStage(command))
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ingest-journal-maintenance.d.ts","sourceRoot":"","sources":["../../src/lib/ingest-journal-maintenance.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"ingest-journal-maintenance.d.ts","sourceRoot":"","sources":["../../src/lib/ingest-journal-maintenance.ts"],"names":[],"mappings":"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"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -86,7 +86,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
86
86
|
// package.json
|
|
87
87
|
var package_default = {
|
|
88
88
|
name: "@hasna/economy",
|
|
89
|
-
version: "0.5.
|
|
89
|
+
version: "0.5.9",
|
|
90
90
|
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",
|
|
91
91
|
repository: {
|
|
92
92
|
type: "git",
|
|
@@ -1343,18 +1343,19 @@ class IngestJournalMaintenance {
|
|
|
1343
1343
|
throw new Error("Journal maintenance limit must be 1\u201332");
|
|
1344
1344
|
await this.recover();
|
|
1345
1345
|
await verifyJournalAuthority(this.journal, this.cloud);
|
|
1346
|
-
const
|
|
1346
|
+
const sweepDeadline = Date.now() + 30000;
|
|
1347
1347
|
let retired = 0, bytes = 0;
|
|
1348
1348
|
let backend;
|
|
1349
1349
|
try {
|
|
1350
1350
|
const names = this.journal.names();
|
|
1351
1351
|
for (const name of names.filter((n) => n.endsWith(".intent.json"))) {
|
|
1352
|
-
if (retired >= limit || Date.now() >=
|
|
1352
|
+
if (retired >= limit || Date.now() >= sweepDeadline || retired > 0 && bytes >= 1048576)
|
|
1353
1353
|
break;
|
|
1354
1354
|
if (!names.includes(name.replace(".intent.", ".receipt.")))
|
|
1355
1355
|
continue;
|
|
1356
1356
|
const intent = this.journal.intent(name), receipt = this.journal.receipt(intent.command);
|
|
1357
|
-
|
|
1357
|
+
const deadline = Date.now() + 30000;
|
|
1358
|
+
backend = await this.backend(deadline);
|
|
1358
1359
|
const m = {
|
|
1359
1360
|
version: 1,
|
|
1360
1361
|
target: this.journal.target,
|
|
@@ -1390,7 +1391,8 @@ class IngestJournalMaintenance {
|
|
|
1390
1391
|
try {
|
|
1391
1392
|
await this.maintain();
|
|
1392
1393
|
} catch (error) {
|
|
1393
|
-
|
|
1394
|
+
const deferrable = error instanceof JournalMaintenanceError && ["recovery_not_configured", "self_host_trash_authority_required", "trash_version_mismatch", "recovery_authority_unavailable"].includes(error.reason);
|
|
1395
|
+
if (!deferrable || exists(this.control) || !this.journal.canStage(command))
|
|
1394
1396
|
throw error;
|
|
1395
1397
|
}
|
|
1396
1398
|
if (!this.journal.canStage(command))
|
package/dist/otel/index.js
CHANGED
|
@@ -3281,18 +3281,19 @@ class IngestJournalMaintenance {
|
|
|
3281
3281
|
throw new Error("Journal maintenance limit must be 1\u201332");
|
|
3282
3282
|
await this.recover();
|
|
3283
3283
|
await verifyJournalAuthority(this.journal, this.cloud);
|
|
3284
|
-
const
|
|
3284
|
+
const sweepDeadline = Date.now() + 30000;
|
|
3285
3285
|
let retired = 0, bytes = 0;
|
|
3286
3286
|
let backend;
|
|
3287
3287
|
try {
|
|
3288
3288
|
const names = this.journal.names();
|
|
3289
3289
|
for (const name of names.filter((n) => n.endsWith(".intent.json"))) {
|
|
3290
|
-
if (retired >= limit || Date.now() >=
|
|
3290
|
+
if (retired >= limit || Date.now() >= sweepDeadline || retired > 0 && bytes >= 1048576)
|
|
3291
3291
|
break;
|
|
3292
3292
|
if (!names.includes(name.replace(".intent.", ".receipt.")))
|
|
3293
3293
|
continue;
|
|
3294
3294
|
const intent = this.journal.intent(name), receipt = this.journal.receipt(intent.command);
|
|
3295
|
-
|
|
3295
|
+
const deadline = Date.now() + 30000;
|
|
3296
|
+
backend = await this.backend(deadline);
|
|
3296
3297
|
const m = {
|
|
3297
3298
|
version: 1,
|
|
3298
3299
|
target: this.journal.target,
|
|
@@ -3328,7 +3329,8 @@ class IngestJournalMaintenance {
|
|
|
3328
3329
|
try {
|
|
3329
3330
|
await this.maintain();
|
|
3330
3331
|
} catch (error) {
|
|
3331
|
-
|
|
3332
|
+
const deferrable = error instanceof JournalMaintenanceError && ["recovery_not_configured", "self_host_trash_authority_required", "trash_version_mismatch", "recovery_authority_unavailable"].includes(error.reason);
|
|
3333
|
+
if (!deferrable || exists(this.control) || !this.journal.canStage(command))
|
|
3332
3334
|
throw error;
|
|
3333
3335
|
}
|
|
3334
3336
|
if (!this.journal.canStage(command))
|
|
@@ -3480,7 +3482,7 @@ async function pushIngestRows(cloud, scratch) {
|
|
|
3480
3482
|
// package.json
|
|
3481
3483
|
var package_default = {
|
|
3482
3484
|
name: "@hasna/economy",
|
|
3483
|
-
version: "0.5.
|
|
3485
|
+
version: "0.5.9",
|
|
3484
3486
|
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",
|
|
3485
3487
|
repository: {
|
|
3486
3488
|
type: "git",
|
package/dist/server/index.js
CHANGED
|
@@ -5578,7 +5578,7 @@ function isAuthorizedRequest(req, path) {
|
|
|
5578
5578
|
// package.json
|
|
5579
5579
|
var package_default = {
|
|
5580
5580
|
name: "@hasna/economy",
|
|
5581
|
-
version: "0.5.
|
|
5581
|
+
version: "0.5.9",
|
|
5582
5582
|
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",
|
|
5583
5583
|
repository: {
|
|
5584
5584
|
type: "git",
|
|
@@ -7454,7 +7454,7 @@ import { randomUUID } from "crypto";
|
|
|
7454
7454
|
// package.json
|
|
7455
7455
|
var package_default = {
|
|
7456
7456
|
name: "@hasna/economy",
|
|
7457
|
-
version: "0.5.
|
|
7457
|
+
version: "0.5.9",
|
|
7458
7458
|
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",
|
|
7459
7459
|
repository: {
|
|
7460
7460
|
type: "git",
|
package/docs/ingest-journal.md
CHANGED
|
@@ -35,7 +35,11 @@ closed. No operator input can relabel an uncertain intent as rejected.
|
|
|
35
35
|
|
|
36
36
|
A bounded sweep starts at 64 commands, 48 MiB, or insufficient next-command
|
|
37
37
|
headroom. It retires at most 32 pairs or approximately 1 MiB per pass; a single
|
|
38
|
-
large pair is handled individually.
|
|
38
|
+
large pair is handled individually. A sweep admits new transactions for up to
|
|
39
|
+
30 seconds; each admitted transaction has its own 30-second deadline for all
|
|
40
|
+
three captures. The last transaction may finish after admission closes, so this
|
|
41
|
+
phase can take up to 60 seconds. Prerequisite recovery and authority checks have
|
|
42
|
+
their own bounds.
|
|
39
43
|
The active journal remains bounded; Trash's recoverable remote retention and
|
|
40
44
|
unfinished transfer staging are governed by Trash's own policy.
|
|
41
45
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hasna/economy",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.9",
|
|
4
4
|
"description": "AI coding cost tracker — CLI + MCP server + REST API for Claude Code, Codex, OpenCode, Cursor, Pi, and Hermes, with legacy Gemini CLI session and Gemini API billing ingestion",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|