@megasaver/cli 1.2.1 → 1.3.0

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.
Files changed (2) hide show
  1. package/dist-bundle/mega.mjs +447 -261
  2. package/package.json +1 -1
@@ -14,9 +14,9 @@ import 'module';
14
14
  import { homedir } from 'os';
15
15
  import { access, mkdir, writeFile, lstat, readFile, constants, stat, rename, rm, chmod, readdir } from 'fs/promises';
16
16
  import { execFileSync, spawn } from 'child_process';
17
+ import { once } from 'events';
17
18
  import { createServer } from 'http';
18
19
  import { StringDecoder } from 'string_decoder';
19
- import { once } from 'events';
20
20
 
21
21
  const require$1 = createRequire(import.meta.url);
22
22
  const __filename$1 = fileURLToPath(import.meta.url);
@@ -234724,6 +234724,48 @@ function classifyObservation(input) {
234724
234724
  const returnedTokens = eligibility === "eligible" ? input.returnedTokens : input.rawTokens;
234725
234725
  return { rawTokens: input.rawTokens, returnedTokens, eligibility, mediation: input.mediation };
234726
234726
  }
234727
+ function sumBytesSavedSince(events, sinceMs) {
234728
+ let total = 0;
234729
+ for (const e2 of events) {
234730
+ const t2 = Date.parse(e2.createdAt);
234731
+ if (Number.isFinite(t2) && t2 >= sinceMs && Number.isFinite(e2.bytesSaved)) {
234732
+ total += e2.bytesSaved;
234733
+ }
234734
+ }
234735
+ return total;
234736
+ }
234737
+ function proxyUsageSavings(input) {
234738
+ const saved = Math.max(0, Math.round(input.savedTokens));
234739
+ let inputTokens = 0;
234740
+ let outputTokens = 0;
234741
+ let cacheReadTokens = 0;
234742
+ let cacheCreationTokens = 0;
234743
+ for (const u3 of input.usage) {
234744
+ inputTokens += u3.inputTokens;
234745
+ outputTokens += u3.outputTokens;
234746
+ cacheReadTokens += u3.cacheReadTokens;
234747
+ cacheCreationTokens += u3.cacheCreationTokens;
234748
+ }
234749
+ const newContextTokens = inputTokens + cacheCreationTokens;
234750
+ const totalContextTokens = newContextTokens + cacheReadTokens;
234751
+ const shareOf = (actual) => {
234752
+ const wouldHave = saved + actual;
234753
+ return wouldHave === 0 ? 0 : saved / wouldHave;
234754
+ };
234755
+ return {
234756
+ savedTokens: saved,
234757
+ proxyCalls: input.usage.length,
234758
+ inputTokens,
234759
+ cacheCreationTokens,
234760
+ cacheReadTokens,
234761
+ outputTokens,
234762
+ newContextTokens,
234763
+ totalContextTokens,
234764
+ savedShareOfNewContext: shareOf(newContextTokens),
234765
+ savedShareOfTotalContext: shareOf(totalContextTokens),
234766
+ reliable: newContextTokens > 0 && saved <= newContextTokens
234767
+ };
234768
+ }
234727
234769
 
234728
234770
  // ../../packages/content-store/dist/index.js
234729
234771
  init_dist();
@@ -240563,18 +240605,413 @@ var auditSessionCommand = defineCommand({
240563
240605
  }
240564
240606
  });
240565
240607
 
240608
+ // ../../packages/llm-proxy/dist/index.js
240609
+ init_zod();
240610
+ var proxyUsageEventSchema = external_exports.object({
240611
+ id: external_exports.string().min(1),
240612
+ ts: external_exports.string().datetime({ offset: true }),
240613
+ model: external_exports.string(),
240614
+ inputTokens: external_exports.number().int().nonnegative(),
240615
+ outputTokens: external_exports.number().int().nonnegative(),
240616
+ cacheReadTokens: external_exports.number().int().nonnegative(),
240617
+ cacheCreationTokens: external_exports.number().int().nonnegative(),
240618
+ messageCount: external_exports.number().int().nonnegative(),
240619
+ stream: external_exports.boolean()
240620
+ }).strict();
240621
+ function asObject(value) {
240622
+ return typeof value === "object" && value !== null ? value : null;
240623
+ }
240624
+ function int(value) {
240625
+ return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : 0;
240626
+ }
240627
+ function parseJson2(text) {
240628
+ try {
240629
+ return JSON.parse(text);
240630
+ } catch {
240631
+ return null;
240632
+ }
240633
+ }
240634
+ function usageFromRaw(usage) {
240635
+ return {
240636
+ inputTokens: int(usage.input_tokens),
240637
+ outputTokens: int(usage.output_tokens),
240638
+ cacheReadTokens: int(usage.cache_read_input_tokens),
240639
+ cacheCreationTokens: int(usage.cache_creation_input_tokens)
240640
+ };
240641
+ }
240642
+ function countRequestMessages(bodyText) {
240643
+ const obj = asObject(parseJson2(bodyText));
240644
+ if (obj === null) return { model: "", messageCount: 0 };
240645
+ const model = typeof obj.model === "string" ? obj.model : "";
240646
+ const messageCount = Array.isArray(obj.messages) ? obj.messages.length : 0;
240647
+ return { model, messageCount };
240648
+ }
240649
+ function parseUsageFromJson(bodyText) {
240650
+ const obj = asObject(parseJson2(bodyText));
240651
+ const usage = obj && asObject(obj.usage);
240652
+ return usage ? usageFromRaw(usage) : null;
240653
+ }
240654
+ function consumeSseLine(line2, acc) {
240655
+ const trimmed = line2.trim();
240656
+ if (!trimmed.startsWith("data:")) return false;
240657
+ const payload = trimmed.slice("data:".length).trim();
240658
+ if (payload.length === 0 || payload === "[DONE]") return false;
240659
+ const event = asObject(parseJson2(payload));
240660
+ if (event === null) return false;
240661
+ if (event.type === "message_start") {
240662
+ const message = asObject(event.message);
240663
+ const usage = message && asObject(message.usage);
240664
+ if (usage) {
240665
+ const u3 = usageFromRaw(usage);
240666
+ acc.inputTokens = u3.inputTokens;
240667
+ acc.cacheReadTokens = u3.cacheReadTokens;
240668
+ acc.cacheCreationTokens = u3.cacheCreationTokens;
240669
+ acc.outputTokens = u3.outputTokens;
240670
+ return true;
240671
+ }
240672
+ } else if (event.type === "message_delta") {
240673
+ const usage = asObject(event.usage);
240674
+ if (usage) {
240675
+ acc.outputTokens = int(usage.output_tokens);
240676
+ return true;
240677
+ }
240678
+ }
240679
+ return false;
240680
+ }
240681
+ function createSseUsageScanner() {
240682
+ let leftover = "";
240683
+ let seen = false;
240684
+ const acc = {
240685
+ inputTokens: 0,
240686
+ outputTokens: 0,
240687
+ cacheReadTokens: 0,
240688
+ cacheCreationTokens: 0
240689
+ };
240690
+ return {
240691
+ push(chunk) {
240692
+ leftover += chunk;
240693
+ const lines = leftover.split("\n");
240694
+ leftover = lines.pop() ?? "";
240695
+ for (const line2 of lines) {
240696
+ if (consumeSseLine(line2, acc)) seen = true;
240697
+ }
240698
+ },
240699
+ result() {
240700
+ if (leftover.length > 0 && consumeSseLine(leftover, acc)) seen = true;
240701
+ leftover = "";
240702
+ return seen ? acc : null;
240703
+ }
240704
+ };
240705
+ }
240706
+ var STRIP_REQUEST = /* @__PURE__ */ new Set([
240707
+ "host",
240708
+ "connection",
240709
+ "content-length",
240710
+ "transfer-encoding",
240711
+ "keep-alive",
240712
+ "proxy-connection"
240713
+ ]);
240714
+ var STRIP_RESPONSE = /* @__PURE__ */ new Set([
240715
+ "content-encoding",
240716
+ "content-length",
240717
+ "transfer-encoding",
240718
+ "connection"
240719
+ ]);
240720
+ var MAX_JSON_CAPTURE_BYTES = 5e6;
240721
+ var MAX_REQUEST_BYTES = 5e7;
240722
+ async function readBody(req) {
240723
+ const chunks = [];
240724
+ let total = 0;
240725
+ for await (const chunk of req) {
240726
+ const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
240727
+ total += buf.length;
240728
+ if (total > MAX_REQUEST_BYTES) return null;
240729
+ chunks.push(buf);
240730
+ }
240731
+ return Buffer.concat(chunks);
240732
+ }
240733
+ function filterRequestHeaders(headers) {
240734
+ const out = {};
240735
+ for (const [key, value] of Object.entries(headers)) {
240736
+ if (value === void 0 || STRIP_REQUEST.has(key.toLowerCase())) continue;
240737
+ out[key] = Array.isArray(value) ? value.join(", ") : value;
240738
+ }
240739
+ return out;
240740
+ }
240741
+ function responseHeaders(headers) {
240742
+ const out = {};
240743
+ headers.forEach((value, key) => {
240744
+ if (!STRIP_RESPONSE.has(key.toLowerCase())) out[key] = value;
240745
+ });
240746
+ return out;
240747
+ }
240748
+ function createProxyHandler(deps) {
240749
+ const { upstreamBaseUrl, onUsage, now, newId } = deps;
240750
+ const doFetch = deps.upstreamFetch ?? fetch;
240751
+ return async (req, res) => {
240752
+ const path2 = req.url ?? "/";
240753
+ const method = req.method ?? "GET";
240754
+ const bodyBuf = await readBody(req);
240755
+ if (bodyBuf === null) {
240756
+ res.writeHead(413, { "content-type": "text/plain; charset=utf-8" });
240757
+ res.end("mega proxy: request body too large");
240758
+ return;
240759
+ }
240760
+ const headers = filterRequestHeaders(req.headers);
240761
+ const init2 = bodyBuf.length > 0 ? { method, headers, body: bodyBuf } : { method, headers };
240762
+ let upstream;
240763
+ try {
240764
+ upstream = await doFetch(`${upstreamBaseUrl}${path2}`, init2);
240765
+ } catch {
240766
+ res.writeHead(502, { "content-type": "text/plain; charset=utf-8" });
240767
+ res.end("mega proxy: upstream request failed");
240768
+ return;
240769
+ }
240770
+ const respHeaders = responseHeaders(upstream.headers);
240771
+ res.writeHead(upstream.status, respHeaders);
240772
+ const contentType = String(respHeaders["content-type"] ?? "");
240773
+ const stream = contentType.includes("event-stream");
240774
+ const scanner = stream ? createSseUsageScanner() : null;
240775
+ const decoder = new TextDecoder();
240776
+ const jsonCaptured = [];
240777
+ let jsonLen = 0;
240778
+ if (upstream.body) {
240779
+ const reader = upstream.body.getReader();
240780
+ for (; ; ) {
240781
+ const { done, value } = await reader.read();
240782
+ if (done) break;
240783
+ const buf = Buffer.from(value);
240784
+ if (!res.write(buf)) await once(res, "drain");
240785
+ if (scanner) {
240786
+ scanner.push(decoder.decode(value, { stream: true }));
240787
+ } else if (jsonLen < MAX_JSON_CAPTURE_BYTES) {
240788
+ jsonCaptured.push(buf);
240789
+ jsonLen += buf.length;
240790
+ }
240791
+ }
240792
+ }
240793
+ res.end();
240794
+ try {
240795
+ if (method === "POST" && path2.startsWith("/v1/messages") && onUsage) {
240796
+ const { model, messageCount } = countRequestMessages(bodyBuf.toString("utf8"));
240797
+ const usage = scanner ? scanner.result() : parseUsageFromJson(Buffer.concat(jsonCaptured).toString("utf8"));
240798
+ if (usage) {
240799
+ onUsage({
240800
+ id: newId(),
240801
+ ts: now(),
240802
+ model,
240803
+ inputTokens: usage.inputTokens,
240804
+ outputTokens: usage.outputTokens,
240805
+ cacheReadTokens: usage.cacheReadTokens,
240806
+ cacheCreationTokens: usage.cacheCreationTokens,
240807
+ messageCount,
240808
+ stream
240809
+ });
240810
+ }
240811
+ }
240812
+ } catch {
240813
+ }
240814
+ };
240815
+ }
240816
+ var LOOPBACK_HOST = "127.0.0.1";
240817
+ function startProxyServer(opts) {
240818
+ const host = LOOPBACK_HOST;
240819
+ const handler = createProxyHandler({
240820
+ upstreamBaseUrl: opts.upstreamBaseUrl,
240821
+ ...opts.upstreamFetch ? { upstreamFetch: opts.upstreamFetch } : {},
240822
+ ...opts.onUsage ? { onUsage: opts.onUsage } : {},
240823
+ now: opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString()),
240824
+ newId: opts.newId ?? (() => randomUUID())
240825
+ });
240826
+ const server2 = createServer((req, res) => {
240827
+ void handler(req, res).catch(() => {
240828
+ if (!res.headersSent) res.writeHead(502, { "content-type": "text/plain; charset=utf-8" });
240829
+ res.end();
240830
+ });
240831
+ });
240832
+ return new Promise((resolve8, reject) => {
240833
+ server2.once("error", reject);
240834
+ server2.listen(opts.port, host, () => {
240835
+ server2.removeListener("error", reject);
240836
+ const addr = server2.address();
240837
+ const port = typeof addr === "object" && addr !== null ? addr.port : opts.port;
240838
+ resolve8({
240839
+ url: `http://${host}:${port}`,
240840
+ port,
240841
+ close: () => new Promise((res) => {
240842
+ server2.close(() => res());
240843
+ })
240844
+ });
240845
+ });
240846
+ });
240847
+ }
240848
+ function usagePath(storeRoot) {
240849
+ return join(storeRoot, "proxy-usage", "usage.jsonl");
240850
+ }
240851
+ function isErrno5(e2) {
240852
+ return e2 instanceof Error && "code" in e2;
240853
+ }
240854
+ async function appendProxyUsage(input) {
240855
+ const event = proxyUsageEventSchema.parse(input.event);
240856
+ const path2 = usagePath(input.storeRoot);
240857
+ mkdirSync(dirname$1(path2), { recursive: true });
240858
+ appendFileSync(path2, `${JSON.stringify(event)}
240859
+ `);
240860
+ }
240861
+ async function listProxyUsage(input) {
240862
+ let raw;
240863
+ try {
240864
+ raw = readFileSync(usagePath(input.storeRoot), "utf8");
240865
+ } catch (e2) {
240866
+ if (isErrno5(e2) && e2.code === "ENOENT") return [];
240867
+ throw e2;
240868
+ }
240869
+ const out = [];
240870
+ for (const line2 of raw.split("\n")) {
240871
+ const trimmed = line2.trim();
240872
+ if (trimmed.length === 0) continue;
240873
+ out.push(proxyUsageEventSchema.parse(JSON.parse(trimmed)));
240874
+ }
240875
+ return out;
240876
+ }
240877
+
240878
+ // src/commands/audit/usage.ts
240879
+ init_dist();
240880
+ function readWorkspaceSavedTokensSince(storeRoot, workspaceKey, sinceMs) {
240881
+ const dir = join(storeRoot, "stats", workspaceKey);
240882
+ let names;
240883
+ try {
240884
+ names = readdirSync(dir);
240885
+ } catch {
240886
+ return 0;
240887
+ }
240888
+ const events = [];
240889
+ for (const name of names) {
240890
+ if (!name.endsWith(".events.jsonl")) continue;
240891
+ let raw;
240892
+ try {
240893
+ raw = readFileSync(join(dir, name), "utf8");
240894
+ } catch {
240895
+ continue;
240896
+ }
240897
+ for (const line2 of raw.split("\n")) {
240898
+ const trimmed = line2.trim();
240899
+ if (trimmed.length === 0) continue;
240900
+ let ev;
240901
+ try {
240902
+ ev = JSON.parse(trimmed);
240903
+ } catch {
240904
+ continue;
240905
+ }
240906
+ if (typeof ev === "object" && ev !== null && typeof ev.createdAt === "string" && typeof ev.bytesSaved === "number") {
240907
+ const e2 = ev;
240908
+ events.push({ createdAt: e2.createdAt, bytesSaved: e2.bytesSaved });
240909
+ }
240910
+ }
240911
+ }
240912
+ return tokensFromBytes(sumBytesSavedSince(events, sinceMs));
240913
+ }
240914
+ function renderUsageReport(m2) {
240915
+ const pct = (n3) => `${(n3 * 100).toFixed(1)}%`;
240916
+ const n2 = (x2) => x2.toLocaleString("en-US");
240917
+ if (m2.proxyCalls === 0) {
240918
+ return [
240919
+ "No proxy usage recorded yet.",
240920
+ "Run `mega proxy start`, point your agent at it (export ANTHROPIC_BASE_URL),",
240921
+ "then this reports savings against your real Claude token usage."
240922
+ ].join("\n");
240923
+ }
240924
+ const rawLines = [
240925
+ `saved (tool output): ~${n2(m2.savedTokens)} tokens (est, bytes/4)`,
240926
+ `real new context: ${n2(m2.newContextTokens)} tokens (input + cache-creation)`,
240927
+ `real cache re-reads: ${n2(m2.cacheReadTokens)} tokens`,
240928
+ `real output: ${n2(m2.outputTokens)} tokens`,
240929
+ `proxy calls: ${n2(m2.proxyCalls)}`
240930
+ ];
240931
+ if (!m2.reliable) {
240932
+ return [
240933
+ ...rawLines,
240934
+ "",
240935
+ "% suppressed: not enough matched proxy coverage for a trustworthy ratio",
240936
+ "(tokens saved exceed the new context the proxy measured \u2014 the proxy saw only",
240937
+ "part of your traffic, so any % would overstate the saving). Route your agent",
240938
+ "through `mega proxy` for your whole workload, then re-run for a real figure."
240939
+ ].join("\n");
240940
+ }
240941
+ return [
240942
+ ...rawLines,
240943
+ "",
240944
+ `saved of new context: ${pct(m2.savedShareOfNewContext)} (saved / (saved + new context))`,
240945
+ `saved of total processed: ${pct(m2.savedShareOfTotalContext)} (adds cache re-reads)`,
240946
+ "",
240947
+ "Scope: savings are windowed to the period since your first recorded proxy",
240948
+ "call, to match the usage denominator. One-shot estimate (a floor): a saved",
240949
+ "token also avoids cache re-reads on every later turn, so real impact is larger."
240950
+ ].join("\n");
240951
+ }
240952
+ async function runAuditUsage(input) {
240953
+ const workspaceKey = encodeWorkspaceKey(input.cwd);
240954
+ const readSaved = input.readSaved ?? readWorkspaceSavedTokensSince;
240955
+ const listUsage = input.listUsage ?? listProxyUsage;
240956
+ let usage = [];
240957
+ try {
240958
+ usage = await listUsage({ storeRoot: input.storeRoot });
240959
+ } catch {
240960
+ }
240961
+ const sinceMs = usage.reduce((min, u3) => {
240962
+ const t2 = Date.parse(u3.ts);
240963
+ return Number.isFinite(t2) ? Math.min(min, t2) : min;
240964
+ }, Number.POSITIVE_INFINITY);
240965
+ let savedTokens = 0;
240966
+ if (usage.length > 0) {
240967
+ try {
240968
+ savedTokens = readSaved(input.storeRoot, workspaceKey, sinceMs);
240969
+ } catch {
240970
+ }
240971
+ }
240972
+ const savings = proxyUsageSavings({ savedTokens, usage });
240973
+ return input.json ? JSON.stringify(savings) : renderUsageReport(savings);
240974
+ }
240975
+ var auditUsageCommand = defineCommand({
240976
+ meta: {
240977
+ name: "usage",
240978
+ description: "Estimated savings vs your real total Claude usage (needs `mega proxy`)."
240979
+ },
240980
+ args: {
240981
+ store: { type: "string", description: "Override store directory." },
240982
+ json: { type: "boolean", default: false, description: "Emit JSON output." }
240983
+ },
240984
+ async run({ args }) {
240985
+ const storeEnv = readStoreEnv(typeof args.store === "string" ? args.store : void 0);
240986
+ let storeRoot;
240987
+ try {
240988
+ storeRoot = resolveStorePath(storeEnv);
240989
+ } catch {
240990
+ storeRoot = "";
240991
+ }
240992
+ const out = await runAuditUsage({
240993
+ storeRoot,
240994
+ cwd: process.cwd(),
240995
+ json: args.json ?? false
240996
+ });
240997
+ process.stdout.write(`${out}
240998
+ `);
240999
+ }
241000
+ });
241001
+
240566
241002
  // src/commands/audit/index.ts
240567
241003
  var auditCommand = defineCommand({
240568
241004
  meta: {
240569
241005
  name: "audit",
240570
- description: "Token-savings dashboard: report, last, session, export, honest."
241006
+ description: "Token-savings dashboard: report, last, session, export, honest, usage."
240571
241007
  },
240572
241008
  subCommands: {
240573
241009
  report: auditReportCommand,
240574
241010
  last: auditLastCommand,
240575
241011
  session: auditSessionCommand,
240576
241012
  export: auditExportCommand,
240577
- honest: auditHonestCommand
241013
+ honest: auditHonestCommand,
241014
+ usage: auditUsageCommand
240578
241015
  }
240579
241016
  });
240580
241017
 
@@ -242788,20 +243225,20 @@ var TOOL_CATEGORY = {
242788
243225
  };
242789
243226
  new Set(Object.keys(TOOL_CATEGORY));
242790
243227
  var HOOK_LOG_RELATIVE_PATH = join(".megasaver", "hooks", "claude-tool-calls.jsonl");
242791
- function asObject(value) {
243228
+ function asObject2(value) {
242792
243229
  return typeof value === "object" && value !== null ? value : null;
242793
243230
  }
242794
243231
  function asString(value) {
242795
243232
  return typeof value === "string" ? value : void 0;
242796
243233
  }
242797
243234
  function buildHookLine(payload, now) {
242798
- const record2 = asObject(payload);
243235
+ const record2 = asObject2(payload);
242799
243236
  if (record2 === null) return null;
242800
243237
  const tool = asString(record2.tool_name);
242801
243238
  if (tool === void 0) return null;
242802
243239
  const category = TOOL_CATEGORY[tool];
242803
243240
  if (category === void 0) return null;
242804
- const input = asObject(record2.tool_input);
243241
+ const input = asObject2(record2.tool_input);
242805
243242
  const filePath = input ? asString(input.file_path) ?? asString(input.path) : void 0;
242806
243243
  const sessionId = asString(record2.session_id);
242807
243244
  const line2 = {
@@ -247502,8 +247939,8 @@ var ZodNumber2 = /* @__PURE__ */ $constructor("ZodNumber", (inst, def) => {
247502
247939
  inst.lt = (value, params) => inst.check(_lt(value, params));
247503
247940
  inst.lte = (value, params) => inst.check(_lte(value, params));
247504
247941
  inst.max = (value, params) => inst.check(_lte(value, params));
247505
- inst.int = (params) => inst.check(int(params));
247506
- inst.safe = (params) => inst.check(int(params));
247942
+ inst.int = (params) => inst.check(int2(params));
247943
+ inst.safe = (params) => inst.check(int2(params));
247507
247944
  inst.positive = (params) => inst.check(_gt(0, params));
247508
247945
  inst.nonnegative = (params) => inst.check(_gte(0, params));
247509
247946
  inst.negative = (params) => inst.check(_lt(0, params));
@@ -247525,7 +247962,7 @@ var ZodNumberFormat = /* @__PURE__ */ $constructor("ZodNumberFormat", (inst, def
247525
247962
  $ZodNumberFormat.init(inst, def);
247526
247963
  ZodNumber2.init(inst, def);
247527
247964
  });
247528
- function int(params) {
247965
+ function int2(params) {
247529
247966
  return _int(ZodNumberFormat, params);
247530
247967
  }
247531
247968
  var ZodBoolean2 = /* @__PURE__ */ $constructor("ZodBoolean", (inst, def) => {
@@ -257154,257 +257591,6 @@ var projectCommand = defineCommand({
257154
257591
  }
257155
257592
  });
257156
257593
 
257157
- // ../../packages/llm-proxy/dist/index.js
257158
- init_zod();
257159
- var proxyUsageEventSchema = external_exports.object({
257160
- id: external_exports.string().min(1),
257161
- ts: external_exports.string().datetime({ offset: true }),
257162
- model: external_exports.string(),
257163
- inputTokens: external_exports.number().int().nonnegative(),
257164
- outputTokens: external_exports.number().int().nonnegative(),
257165
- cacheReadTokens: external_exports.number().int().nonnegative(),
257166
- cacheCreationTokens: external_exports.number().int().nonnegative(),
257167
- messageCount: external_exports.number().int().nonnegative(),
257168
- stream: external_exports.boolean()
257169
- }).strict();
257170
- function asObject2(value) {
257171
- return typeof value === "object" && value !== null ? value : null;
257172
- }
257173
- function int2(value) {
257174
- return typeof value === "number" && Number.isFinite(value) ? Math.max(0, Math.trunc(value)) : 0;
257175
- }
257176
- function parseJson2(text) {
257177
- try {
257178
- return JSON.parse(text);
257179
- } catch {
257180
- return null;
257181
- }
257182
- }
257183
- function usageFromRaw(usage) {
257184
- return {
257185
- inputTokens: int2(usage.input_tokens),
257186
- outputTokens: int2(usage.output_tokens),
257187
- cacheReadTokens: int2(usage.cache_read_input_tokens),
257188
- cacheCreationTokens: int2(usage.cache_creation_input_tokens)
257189
- };
257190
- }
257191
- function countRequestMessages(bodyText) {
257192
- const obj = asObject2(parseJson2(bodyText));
257193
- if (obj === null) return { model: "", messageCount: 0 };
257194
- const model = typeof obj.model === "string" ? obj.model : "";
257195
- const messageCount = Array.isArray(obj.messages) ? obj.messages.length : 0;
257196
- return { model, messageCount };
257197
- }
257198
- function parseUsageFromJson(bodyText) {
257199
- const obj = asObject2(parseJson2(bodyText));
257200
- const usage = obj && asObject2(obj.usage);
257201
- return usage ? usageFromRaw(usage) : null;
257202
- }
257203
- function consumeSseLine(line2, acc) {
257204
- const trimmed = line2.trim();
257205
- if (!trimmed.startsWith("data:")) return false;
257206
- const payload = trimmed.slice("data:".length).trim();
257207
- if (payload.length === 0 || payload === "[DONE]") return false;
257208
- const event = asObject2(parseJson2(payload));
257209
- if (event === null) return false;
257210
- if (event.type === "message_start") {
257211
- const message = asObject2(event.message);
257212
- const usage = message && asObject2(message.usage);
257213
- if (usage) {
257214
- const u3 = usageFromRaw(usage);
257215
- acc.inputTokens = u3.inputTokens;
257216
- acc.cacheReadTokens = u3.cacheReadTokens;
257217
- acc.cacheCreationTokens = u3.cacheCreationTokens;
257218
- acc.outputTokens = u3.outputTokens;
257219
- return true;
257220
- }
257221
- } else if (event.type === "message_delta") {
257222
- const usage = asObject2(event.usage);
257223
- if (usage) {
257224
- acc.outputTokens = int2(usage.output_tokens);
257225
- return true;
257226
- }
257227
- }
257228
- return false;
257229
- }
257230
- function createSseUsageScanner() {
257231
- let leftover = "";
257232
- let seen = false;
257233
- const acc = {
257234
- inputTokens: 0,
257235
- outputTokens: 0,
257236
- cacheReadTokens: 0,
257237
- cacheCreationTokens: 0
257238
- };
257239
- return {
257240
- push(chunk) {
257241
- leftover += chunk;
257242
- const lines = leftover.split("\n");
257243
- leftover = lines.pop() ?? "";
257244
- for (const line2 of lines) {
257245
- if (consumeSseLine(line2, acc)) seen = true;
257246
- }
257247
- },
257248
- result() {
257249
- if (leftover.length > 0 && consumeSseLine(leftover, acc)) seen = true;
257250
- leftover = "";
257251
- return seen ? acc : null;
257252
- }
257253
- };
257254
- }
257255
- var STRIP_REQUEST = /* @__PURE__ */ new Set([
257256
- "host",
257257
- "connection",
257258
- "content-length",
257259
- "transfer-encoding",
257260
- "keep-alive",
257261
- "proxy-connection"
257262
- ]);
257263
- var STRIP_RESPONSE = /* @__PURE__ */ new Set([
257264
- "content-encoding",
257265
- "content-length",
257266
- "transfer-encoding",
257267
- "connection"
257268
- ]);
257269
- var MAX_JSON_CAPTURE_BYTES = 5e6;
257270
- var MAX_REQUEST_BYTES = 5e7;
257271
- async function readBody(req) {
257272
- const chunks = [];
257273
- let total = 0;
257274
- for await (const chunk of req) {
257275
- const buf = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
257276
- total += buf.length;
257277
- if (total > MAX_REQUEST_BYTES) return null;
257278
- chunks.push(buf);
257279
- }
257280
- return Buffer.concat(chunks);
257281
- }
257282
- function filterRequestHeaders(headers) {
257283
- const out = {};
257284
- for (const [key, value] of Object.entries(headers)) {
257285
- if (value === void 0 || STRIP_REQUEST.has(key.toLowerCase())) continue;
257286
- out[key] = Array.isArray(value) ? value.join(", ") : value;
257287
- }
257288
- return out;
257289
- }
257290
- function responseHeaders(headers) {
257291
- const out = {};
257292
- headers.forEach((value, key) => {
257293
- if (!STRIP_RESPONSE.has(key.toLowerCase())) out[key] = value;
257294
- });
257295
- return out;
257296
- }
257297
- function createProxyHandler(deps) {
257298
- const { upstreamBaseUrl, onUsage, now, newId } = deps;
257299
- const doFetch = deps.upstreamFetch ?? fetch;
257300
- return async (req, res) => {
257301
- const path2 = req.url ?? "/";
257302
- const method = req.method ?? "GET";
257303
- const bodyBuf = await readBody(req);
257304
- if (bodyBuf === null) {
257305
- res.writeHead(413, { "content-type": "text/plain; charset=utf-8" });
257306
- res.end("mega proxy: request body too large");
257307
- return;
257308
- }
257309
- const headers = filterRequestHeaders(req.headers);
257310
- const init2 = bodyBuf.length > 0 ? { method, headers, body: bodyBuf } : { method, headers };
257311
- let upstream;
257312
- try {
257313
- upstream = await doFetch(`${upstreamBaseUrl}${path2}`, init2);
257314
- } catch {
257315
- res.writeHead(502, { "content-type": "text/plain; charset=utf-8" });
257316
- res.end("mega proxy: upstream request failed");
257317
- return;
257318
- }
257319
- const respHeaders = responseHeaders(upstream.headers);
257320
- res.writeHead(upstream.status, respHeaders);
257321
- const contentType = String(respHeaders["content-type"] ?? "");
257322
- const stream = contentType.includes("event-stream");
257323
- const scanner = stream ? createSseUsageScanner() : null;
257324
- const decoder = new TextDecoder();
257325
- const jsonCaptured = [];
257326
- let jsonLen = 0;
257327
- if (upstream.body) {
257328
- const reader = upstream.body.getReader();
257329
- for (; ; ) {
257330
- const { done, value } = await reader.read();
257331
- if (done) break;
257332
- const buf = Buffer.from(value);
257333
- if (!res.write(buf)) await once(res, "drain");
257334
- if (scanner) {
257335
- scanner.push(decoder.decode(value, { stream: true }));
257336
- } else if (jsonLen < MAX_JSON_CAPTURE_BYTES) {
257337
- jsonCaptured.push(buf);
257338
- jsonLen += buf.length;
257339
- }
257340
- }
257341
- }
257342
- res.end();
257343
- try {
257344
- if (method === "POST" && path2.startsWith("/v1/messages") && onUsage) {
257345
- const { model, messageCount } = countRequestMessages(bodyBuf.toString("utf8"));
257346
- const usage = scanner ? scanner.result() : parseUsageFromJson(Buffer.concat(jsonCaptured).toString("utf8"));
257347
- if (usage) {
257348
- onUsage({
257349
- id: newId(),
257350
- ts: now(),
257351
- model,
257352
- inputTokens: usage.inputTokens,
257353
- outputTokens: usage.outputTokens,
257354
- cacheReadTokens: usage.cacheReadTokens,
257355
- cacheCreationTokens: usage.cacheCreationTokens,
257356
- messageCount,
257357
- stream
257358
- });
257359
- }
257360
- }
257361
- } catch {
257362
- }
257363
- };
257364
- }
257365
- var LOOPBACK_HOST = "127.0.0.1";
257366
- function startProxyServer(opts) {
257367
- const host = LOOPBACK_HOST;
257368
- const handler = createProxyHandler({
257369
- upstreamBaseUrl: opts.upstreamBaseUrl,
257370
- ...opts.upstreamFetch ? { upstreamFetch: opts.upstreamFetch } : {},
257371
- ...opts.onUsage ? { onUsage: opts.onUsage } : {},
257372
- now: opts.now ?? (() => (/* @__PURE__ */ new Date()).toISOString()),
257373
- newId: opts.newId ?? (() => randomUUID())
257374
- });
257375
- const server2 = createServer((req, res) => {
257376
- void handler(req, res).catch(() => {
257377
- if (!res.headersSent) res.writeHead(502, { "content-type": "text/plain; charset=utf-8" });
257378
- res.end();
257379
- });
257380
- });
257381
- return new Promise((resolve8, reject) => {
257382
- server2.once("error", reject);
257383
- server2.listen(opts.port, host, () => {
257384
- server2.removeListener("error", reject);
257385
- const addr = server2.address();
257386
- const port = typeof addr === "object" && addr !== null ? addr.port : opts.port;
257387
- resolve8({
257388
- url: `http://${host}:${port}`,
257389
- port,
257390
- close: () => new Promise((res) => {
257391
- server2.close(() => res());
257392
- })
257393
- });
257394
- });
257395
- });
257396
- }
257397
- function usagePath(storeRoot) {
257398
- return join(storeRoot, "proxy-usage", "usage.jsonl");
257399
- }
257400
- async function appendProxyUsage(input) {
257401
- const event = proxyUsageEventSchema.parse(input.event);
257402
- const path2 = usagePath(input.storeRoot);
257403
- mkdirSync(dirname$1(path2), { recursive: true });
257404
- appendFileSync(path2, `${JSON.stringify(event)}
257405
- `);
257406
- }
257407
-
257408
257594
  // src/commands/proxy/start.ts
257409
257595
  var DEFAULT_PORT = 8787;
257410
257596
  var DEFAULT_UPSTREAM = "https://api.anthropic.com";
@@ -259572,7 +259758,7 @@ var toolsCommand = defineCommand({
259572
259758
  });
259573
259759
 
259574
259760
  // src/main.ts
259575
- var version2 = "1.2.1" ;
259761
+ var version2 = "1.3.0" ;
259576
259762
  var mainCommand = defineCommand({
259577
259763
  meta: {
259578
259764
  name: "mega",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@megasaver/cli",
3
- "version": "1.2.1",
3
+ "version": "1.3.0",
4
4
  "description": "Mega Saver CLI - the `mega` command.",
5
5
  "type": "module",
6
6
  "bin": {