@node9/proxy 2.7.3 → 2.7.4

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.js CHANGED
@@ -11883,6 +11883,132 @@ var init_cost_codex = __esm({
11883
11883
  }
11884
11884
  });
11885
11885
 
11886
+ // src/cost-copilot.ts
11887
+ function copilotSessionsDir() {
11888
+ return import_path22.default.join(import_os19.default.homedir(), ".copilot", "session-state");
11889
+ }
11890
+ function safeReaddir3(dir) {
11891
+ try {
11892
+ return import_fs20.default.readdirSync(dir);
11893
+ } catch {
11894
+ return [];
11895
+ }
11896
+ }
11897
+ function priceTokens(model, u) {
11898
+ const tuple = pricingFor(model);
11899
+ if (!tuple || !u) return 0;
11900
+ const [pin, pout, pcw, pcr] = tuple;
11901
+ return (u.inputTokens ?? 0) * pin + (u.outputTokens ?? 0) * pout + (u.cacheWriteTokens ?? 0) * pcw + (u.cacheReadTokens ?? 0) * pcr;
11902
+ }
11903
+ function parseCopilotSession(lines) {
11904
+ let sessionId = "";
11905
+ let cwd = "";
11906
+ let startDate = "";
11907
+ let shutdownDate = "";
11908
+ let modelMetrics = null;
11909
+ for (const raw of lines) {
11910
+ if (!raw.trim()) continue;
11911
+ let o;
11912
+ try {
11913
+ o = JSON.parse(raw);
11914
+ } catch {
11915
+ continue;
11916
+ }
11917
+ const d = o.data ?? {};
11918
+ if (o.type === "session.start") {
11919
+ if (typeof d["sessionId"] === "string") sessionId = d["sessionId"];
11920
+ if (typeof d["startTime"] === "string") startDate = d["startTime"];
11921
+ const ctx = d["context"] ?? {};
11922
+ if (typeof ctx["cwd"] === "string") cwd = ctx["cwd"];
11923
+ } else if (o.type === "session.shutdown") {
11924
+ if (d["modelMetrics"] && typeof d["modelMetrics"] === "object") {
11925
+ modelMetrics = d["modelMetrics"];
11926
+ }
11927
+ if (typeof o.timestamp === "string") shutdownDate = o.timestamp;
11928
+ }
11929
+ }
11930
+ if (!modelMetrics) return [];
11931
+ const date = (startDate || shutdownDate).slice(0, 10);
11932
+ if (!date) return [];
11933
+ const rows = [];
11934
+ for (const [rawModel, m] of Object.entries(modelMetrics)) {
11935
+ const u = m.usage ?? {};
11936
+ const inputTokens = u.inputTokens ?? 0;
11937
+ const outputTokens = u.outputTokens ?? 0;
11938
+ const cacheReadTokens = u.cacheReadTokens ?? 0;
11939
+ const cacheWriteTokens = u.cacheWriteTokens ?? 0;
11940
+ if (inputTokens === 0 && outputTokens === 0 && cacheReadTokens === 0 && cacheWriteTokens === 0) {
11941
+ continue;
11942
+ }
11943
+ const model = normalizeModel(rawModel);
11944
+ const costUSD = typeof m.requests?.cost === "number" && m.requests.cost > 0 ? m.requests.cost : priceTokens(rawModel, u);
11945
+ rows.push({
11946
+ date,
11947
+ model,
11948
+ workingDir: cwd,
11949
+ runId: sessionId,
11950
+ costUSD,
11951
+ inputTokens,
11952
+ outputTokens,
11953
+ cacheReadTokens,
11954
+ cacheWriteTokens
11955
+ });
11956
+ }
11957
+ return rows;
11958
+ }
11959
+ var import_fs20, import_os19, import_path22, copilotSource;
11960
+ var init_cost_copilot = __esm({
11961
+ "src/cost-copilot.ts"() {
11962
+ "use strict";
11963
+ import_fs20 = __toESM(require("fs"));
11964
+ import_os19 = __toESM(require("os"));
11965
+ import_path22 = __toESM(require("path"));
11966
+ init_litellm();
11967
+ copilotSource = {
11968
+ id: "copilot",
11969
+ available() {
11970
+ try {
11971
+ return import_fs20.default.existsSync(copilotSessionsDir());
11972
+ } catch {
11973
+ return false;
11974
+ }
11975
+ },
11976
+ collect(sinceMs) {
11977
+ const base = copilotSessionsDir();
11978
+ const combined = /* @__PURE__ */ new Map();
11979
+ for (const sid of safeReaddir3(base)) {
11980
+ const file = import_path22.default.join(base, sid, "events.jsonl");
11981
+ try {
11982
+ if (sinceMs !== void 0 && import_fs20.default.statSync(file).mtimeMs < sinceMs) continue;
11983
+ } catch {
11984
+ continue;
11985
+ }
11986
+ let content;
11987
+ try {
11988
+ content = import_fs20.default.readFileSync(file, "utf8");
11989
+ } catch {
11990
+ continue;
11991
+ }
11992
+ for (const e of parseCopilotSession(content.split("\n"))) {
11993
+ const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
11994
+ const prev = combined.get(key);
11995
+ if (prev) {
11996
+ prev.costUSD += e.costUSD;
11997
+ prev.inputTokens += e.inputTokens;
11998
+ prev.outputTokens += e.outputTokens;
11999
+ prev.cacheReadTokens += e.cacheReadTokens;
12000
+ prev.cacheWriteTokens += e.cacheWriteTokens;
12001
+ } else {
12002
+ combined.set(key, { ...e });
12003
+ }
12004
+ }
12005
+ }
12006
+ return [...combined.values()];
12007
+ }
12008
+ };
12009
+ }
12010
+ });
12011
+
11886
12012
  // src/utils/hook-payload.ts
11887
12013
  function extractToolName(payload, defaultValue = "") {
11888
12014
  return payload.tool_name ?? payload.name ?? payload.toolCall?.name ?? defaultValue;
@@ -12197,79 +12323,79 @@ var init_scan_summary = __esm({
12197
12323
  function buildSensitivePaths(home, cwd) {
12198
12324
  return [
12199
12325
  {
12200
- full: import_path22.default.join(home, ".ssh", "id_rsa"),
12326
+ full: import_path23.default.join(home, ".ssh", "id_rsa"),
12201
12327
  label: "~/.ssh/id_rsa",
12202
12328
  description: "RSA private key \u2014 grants SSH access to your servers",
12203
12329
  score: 20
12204
12330
  },
12205
12331
  {
12206
- full: import_path22.default.join(home, ".ssh", "id_ed25519"),
12332
+ full: import_path23.default.join(home, ".ssh", "id_ed25519"),
12207
12333
  label: "~/.ssh/id_ed25519",
12208
12334
  description: "Ed25519 private key \u2014 grants SSH access to your servers",
12209
12335
  score: 20
12210
12336
  },
12211
12337
  {
12212
- full: import_path22.default.join(home, ".ssh", "id_ecdsa"),
12338
+ full: import_path23.default.join(home, ".ssh", "id_ecdsa"),
12213
12339
  label: "~/.ssh/id_ecdsa",
12214
12340
  description: "ECDSA private key \u2014 grants SSH access to your servers",
12215
12341
  score: 20
12216
12342
  },
12217
12343
  {
12218
- full: import_path22.default.join(home, ".aws", "credentials"),
12344
+ full: import_path23.default.join(home, ".aws", "credentials"),
12219
12345
  label: "~/.aws/credentials",
12220
12346
  description: "AWS access keys \u2014 full cloud account access",
12221
12347
  score: 20
12222
12348
  },
12223
12349
  {
12224
- full: import_path22.default.join(home, ".aws", "config"),
12350
+ full: import_path23.default.join(home, ".aws", "config"),
12225
12351
  label: "~/.aws/config",
12226
12352
  description: "AWS configuration \u2014 account and region settings",
12227
12353
  score: 5
12228
12354
  },
12229
12355
  {
12230
- full: import_path22.default.join(home, ".config", "gcloud", "credentials.db"),
12356
+ full: import_path23.default.join(home, ".config", "gcloud", "credentials.db"),
12231
12357
  label: "~/.config/gcloud/credentials.db",
12232
12358
  description: "Google Cloud credentials",
12233
12359
  score: 15
12234
12360
  },
12235
12361
  {
12236
- full: import_path22.default.join(home, ".docker", "config.json"),
12362
+ full: import_path23.default.join(home, ".docker", "config.json"),
12237
12363
  label: "~/.docker/config.json",
12238
12364
  description: "Docker registry auth tokens",
12239
12365
  score: 10
12240
12366
  },
12241
12367
  {
12242
- full: import_path22.default.join(home, ".netrc"),
12368
+ full: import_path23.default.join(home, ".netrc"),
12243
12369
  label: "~/.netrc",
12244
12370
  description: "FTP/HTTP credentials in plain text",
12245
12371
  score: 15
12246
12372
  },
12247
12373
  {
12248
- full: import_path22.default.join(home, ".npmrc"),
12374
+ full: import_path23.default.join(home, ".npmrc"),
12249
12375
  label: "~/.npmrc",
12250
12376
  description: "npm auth token \u2014 can publish packages as you",
12251
12377
  score: 10
12252
12378
  },
12253
12379
  {
12254
- full: import_path22.default.join(home, ".node9", "credentials.json"),
12380
+ full: import_path23.default.join(home, ".node9", "credentials.json"),
12255
12381
  label: "~/.node9/credentials.json",
12256
12382
  description: "Node9 cloud API key",
12257
12383
  score: 10
12258
12384
  },
12259
12385
  {
12260
- full: import_path22.default.join(cwd, ".env"),
12386
+ full: import_path23.default.join(cwd, ".env"),
12261
12387
  label: ".env (current folder)",
12262
12388
  description: "App secrets \u2014 database passwords, API keys",
12263
12389
  score: 20
12264
12390
  },
12265
12391
  {
12266
- full: import_path22.default.join(cwd, ".env.local"),
12392
+ full: import_path23.default.join(cwd, ".env.local"),
12267
12393
  label: ".env.local (current folder)",
12268
12394
  description: "Local overrides \u2014 often contains real credentials",
12269
12395
  score: 15
12270
12396
  },
12271
12397
  {
12272
- full: import_path22.default.join(cwd, ".env.production"),
12398
+ full: import_path23.default.join(cwd, ".env.production"),
12273
12399
  label: ".env.production (current folder)",
12274
12400
  description: "Production secrets",
12275
12401
  score: 20
@@ -12278,7 +12404,7 @@ function buildSensitivePaths(home, cwd) {
12278
12404
  }
12279
12405
  function isReadable(filePath) {
12280
12406
  try {
12281
- import_fs20.default.accessSync(filePath, import_fs20.default.constants.R_OK);
12407
+ import_fs21.default.accessSync(filePath, import_fs21.default.constants.R_OK);
12282
12408
  return true;
12283
12409
  } catch {
12284
12410
  return false;
@@ -12291,13 +12417,13 @@ function scoreLabel(score) {
12291
12417
  return import_chalk3.default.red.bold(`${score}/100 Critical`);
12292
12418
  }
12293
12419
  function runBlast() {
12294
- const home = import_os19.default.homedir();
12420
+ const home = import_os20.default.homedir();
12295
12421
  const cwd = process.cwd();
12296
12422
  const paths = buildSensitivePaths(home, cwd);
12297
12423
  let scoreDeduction = 0;
12298
12424
  const reachable = [];
12299
12425
  for (const p of paths) {
12300
- if (import_fs20.default.existsSync(p.full) && isReadable(p.full)) {
12426
+ if (import_fs21.default.existsSync(p.full) && isReadable(p.full)) {
12301
12427
  reachable.push(p);
12302
12428
  scoreDeduction += p.score;
12303
12429
  }
@@ -12315,7 +12441,7 @@ function runBlast() {
12315
12441
  }
12316
12442
  function registerBlastCommand(program2) {
12317
12443
  program2.command("blast").description("Map what an AI agent can currently reach on this machine").action(() => {
12318
- const home = import_os19.default.homedir();
12444
+ const home = import_os20.default.homedir();
12319
12445
  const cwd = process.cwd();
12320
12446
  const { reachable, envFindings, score } = runBlast();
12321
12447
  console.log("");
@@ -12362,14 +12488,14 @@ function registerBlastCommand(program2) {
12362
12488
  console.log("");
12363
12489
  });
12364
12490
  }
12365
- var import_chalk3, import_fs20, import_path22, import_os19;
12491
+ var import_chalk3, import_fs21, import_path23, import_os20;
12366
12492
  var init_blast = __esm({
12367
12493
  "src/cli/commands/blast.ts"() {
12368
12494
  "use strict";
12369
12495
  import_chalk3 = __toESM(require("chalk"));
12370
- import_fs20 = __toESM(require("fs"));
12371
- import_path22 = __toESM(require("path"));
12372
- import_os19 = __toESM(require("os"));
12496
+ import_fs21 = __toESM(require("fs"));
12497
+ import_path23 = __toESM(require("path"));
12498
+ import_os20 = __toESM(require("os"));
12373
12499
  init_dlp();
12374
12500
  }
12375
12501
  });
@@ -12514,13 +12640,13 @@ function listSessionFiles(dir, maxDepth = 6) {
12514
12640
  if (depth > maxDepth) return;
12515
12641
  let entries;
12516
12642
  try {
12517
- entries = fs22.readdirSync(d, { withFileTypes: true });
12643
+ entries = fs23.readdirSync(d, { withFileTypes: true });
12518
12644
  } catch {
12519
12645
  return;
12520
12646
  }
12521
12647
  for (const e of entries) {
12522
- const childRel = rel ? path24.join(rel, e.name) : e.name;
12523
- if (e.isDirectory()) walk(path24.join(d, e.name), childRel, depth + 1);
12648
+ const childRel = rel ? path25.join(rel, e.name) : e.name;
12649
+ if (e.isDirectory()) walk(path25.join(d, e.name), childRel, depth + 1);
12524
12650
  else if (e.name.endsWith(".jsonl")) out.push(childRel);
12525
12651
  }
12526
12652
  };
@@ -12528,26 +12654,26 @@ function listSessionFiles(dir, maxDepth = 6) {
12528
12654
  return out;
12529
12655
  }
12530
12656
  function sessionIdOf(relPath) {
12531
- return path24.basename(relPath).replace(/\.jsonl$/, "");
12657
+ return path25.basename(relPath).replace(/\.jsonl$/, "");
12532
12658
  }
12533
- var fs22, path24;
12659
+ var fs23, path25;
12534
12660
  var init_session_files = __esm({
12535
12661
  "src/session-files.ts"() {
12536
12662
  "use strict";
12537
- fs22 = __toESM(require("fs"));
12538
- path24 = __toESM(require("path"));
12663
+ fs23 = __toESM(require("fs"));
12664
+ path25 = __toESM(require("path"));
12539
12665
  }
12540
12666
  });
12541
12667
 
12542
12668
  // src/cli/render/scan-history.ts
12543
12669
  function defaultHistoryPath() {
12544
- return import_path23.default.join(import_os20.default.homedir(), ".node9", "scan-history.json");
12670
+ return import_path24.default.join(import_os21.default.homedir(), ".node9", "scan-history.json");
12545
12671
  }
12546
12672
  function readPreviousScan(opts = {}) {
12547
12673
  const filePath = opts.path ?? defaultHistoryPath();
12548
12674
  try {
12549
- if (!import_fs21.default.existsSync(filePath)) return null;
12550
- const raw = import_fs21.default.readFileSync(filePath, "utf8");
12675
+ if (!import_fs22.default.existsSync(filePath)) return null;
12676
+ const raw = import_fs22.default.readFileSync(filePath, "utf8");
12551
12677
  const parsed = JSON.parse(raw);
12552
12678
  if (!Array.isArray(parsed) || parsed.length === 0) return null;
12553
12679
  const last = parsed[parsed.length - 1];
@@ -12561,11 +12687,11 @@ function appendScanHistory(record, opts = {}) {
12561
12687
  const filePath = opts.path ?? defaultHistoryPath();
12562
12688
  const cap = opts.cap ?? SCAN_HISTORY_CAP;
12563
12689
  try {
12564
- import_fs21.default.mkdirSync(import_path23.default.dirname(filePath), { recursive: true });
12690
+ import_fs22.default.mkdirSync(import_path24.default.dirname(filePath), { recursive: true });
12565
12691
  let history = [];
12566
- if (import_fs21.default.existsSync(filePath)) {
12692
+ if (import_fs22.default.existsSync(filePath)) {
12567
12693
  try {
12568
- const parsed = JSON.parse(import_fs21.default.readFileSync(filePath, "utf8"));
12694
+ const parsed = JSON.parse(import_fs22.default.readFileSync(filePath, "utf8"));
12569
12695
  if (Array.isArray(parsed)) {
12570
12696
  history = parsed.filter(isValidRecord);
12571
12697
  }
@@ -12576,7 +12702,7 @@ function appendScanHistory(record, opts = {}) {
12576
12702
  if (history.length > cap) {
12577
12703
  history = history.slice(history.length - cap);
12578
12704
  }
12579
- import_fs21.default.writeFileSync(filePath, JSON.stringify(history, null, 2));
12705
+ import_fs22.default.writeFileSync(filePath, JSON.stringify(history, null, 2));
12580
12706
  } catch (err2) {
12581
12707
  process.stderr.write(
12582
12708
  `[node9] Warning: could not write scan-history.json: ${err2.message}
@@ -12598,140 +12724,14 @@ function isValidRecord(x) {
12598
12724
  const r = x;
12599
12725
  return typeof r.timestamp === "string" && typeof r.score === "number" && typeof r.blocked === "number" && typeof r.review === "number" && typeof r.leaks === "number" && typeof r.loops === "number" && typeof r.totalCalls === "number";
12600
12726
  }
12601
- var import_fs21, import_path23, import_os20, SCAN_HISTORY_CAP;
12727
+ var import_fs22, import_path24, import_os21, SCAN_HISTORY_CAP;
12602
12728
  var init_scan_history = __esm({
12603
12729
  "src/cli/render/scan-history.ts"() {
12604
- "use strict";
12605
- import_fs21 = __toESM(require("fs"));
12606
- import_path23 = __toESM(require("path"));
12607
- import_os20 = __toESM(require("os"));
12608
- SCAN_HISTORY_CAP = 30;
12609
- }
12610
- });
12611
-
12612
- // src/cost-copilot.ts
12613
- function copilotSessionsDir() {
12614
- return import_path24.default.join(import_os21.default.homedir(), ".copilot", "session-state");
12615
- }
12616
- function safeReaddir3(dir) {
12617
- try {
12618
- return import_fs22.default.readdirSync(dir);
12619
- } catch {
12620
- return [];
12621
- }
12622
- }
12623
- function priceTokens(model, u) {
12624
- const tuple = pricingFor(model);
12625
- if (!tuple || !u) return 0;
12626
- const [pin, pout, pcw, pcr] = tuple;
12627
- return (u.inputTokens ?? 0) * pin + (u.outputTokens ?? 0) * pout + (u.cacheWriteTokens ?? 0) * pcw + (u.cacheReadTokens ?? 0) * pcr;
12628
- }
12629
- function parseCopilotSession(lines) {
12630
- let sessionId = "";
12631
- let cwd = "";
12632
- let startDate = "";
12633
- let shutdownDate = "";
12634
- let modelMetrics = null;
12635
- for (const raw of lines) {
12636
- if (!raw.trim()) continue;
12637
- let o;
12638
- try {
12639
- o = JSON.parse(raw);
12640
- } catch {
12641
- continue;
12642
- }
12643
- const d = o.data ?? {};
12644
- if (o.type === "session.start") {
12645
- if (typeof d["sessionId"] === "string") sessionId = d["sessionId"];
12646
- if (typeof d["startTime"] === "string") startDate = d["startTime"];
12647
- const ctx = d["context"] ?? {};
12648
- if (typeof ctx["cwd"] === "string") cwd = ctx["cwd"];
12649
- } else if (o.type === "session.shutdown") {
12650
- if (d["modelMetrics"] && typeof d["modelMetrics"] === "object") {
12651
- modelMetrics = d["modelMetrics"];
12652
- }
12653
- if (typeof o.timestamp === "string") shutdownDate = o.timestamp;
12654
- }
12655
- }
12656
- if (!modelMetrics) return [];
12657
- const date = (startDate || shutdownDate).slice(0, 10);
12658
- if (!date) return [];
12659
- const rows = [];
12660
- for (const [rawModel, m] of Object.entries(modelMetrics)) {
12661
- const u = m.usage ?? {};
12662
- const inputTokens = u.inputTokens ?? 0;
12663
- const outputTokens = u.outputTokens ?? 0;
12664
- const cacheReadTokens = u.cacheReadTokens ?? 0;
12665
- const cacheWriteTokens = u.cacheWriteTokens ?? 0;
12666
- if (inputTokens === 0 && outputTokens === 0 && cacheReadTokens === 0 && cacheWriteTokens === 0) {
12667
- continue;
12668
- }
12669
- const model = normalizeModel(rawModel);
12670
- const costUSD = typeof m.requests?.cost === "number" && m.requests.cost > 0 ? m.requests.cost : priceTokens(rawModel, u);
12671
- rows.push({
12672
- date,
12673
- model,
12674
- workingDir: cwd,
12675
- runId: sessionId,
12676
- costUSD,
12677
- inputTokens,
12678
- outputTokens,
12679
- cacheReadTokens,
12680
- cacheWriteTokens
12681
- });
12682
- }
12683
- return rows;
12684
- }
12685
- var import_fs22, import_os21, import_path24, copilotSource;
12686
- var init_cost_copilot = __esm({
12687
- "src/cost-copilot.ts"() {
12688
12730
  "use strict";
12689
12731
  import_fs22 = __toESM(require("fs"));
12690
- import_os21 = __toESM(require("os"));
12691
12732
  import_path24 = __toESM(require("path"));
12692
- init_litellm();
12693
- copilotSource = {
12694
- id: "copilot",
12695
- available() {
12696
- try {
12697
- return import_fs22.default.existsSync(copilotSessionsDir());
12698
- } catch {
12699
- return false;
12700
- }
12701
- },
12702
- collect(sinceMs) {
12703
- const base = copilotSessionsDir();
12704
- const combined = /* @__PURE__ */ new Map();
12705
- for (const sid of safeReaddir3(base)) {
12706
- const file = import_path24.default.join(base, sid, "events.jsonl");
12707
- try {
12708
- if (sinceMs !== void 0 && import_fs22.default.statSync(file).mtimeMs < sinceMs) continue;
12709
- } catch {
12710
- continue;
12711
- }
12712
- let content;
12713
- try {
12714
- content = import_fs22.default.readFileSync(file, "utf8");
12715
- } catch {
12716
- continue;
12717
- }
12718
- for (const e of parseCopilotSession(content.split("\n"))) {
12719
- const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
12720
- const prev = combined.get(key);
12721
- if (prev) {
12722
- prev.costUSD += e.costUSD;
12723
- prev.inputTokens += e.inputTokens;
12724
- prev.outputTokens += e.outputTokens;
12725
- prev.cacheReadTokens += e.cacheReadTokens;
12726
- prev.cacheWriteTokens += e.cacheWriteTokens;
12727
- } else {
12728
- combined.set(key, { ...e });
12729
- }
12730
- }
12731
- }
12732
- return [...combined.values()];
12733
- }
12734
- };
12733
+ import_os21 = __toESM(require("os"));
12734
+ SCAN_HISTORY_CAP = 30;
12735
12735
  }
12736
12736
  });
12737
12737
 
@@ -14776,6 +14776,10 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
14776
14776
  let projLabel = sessionId.slice(0, 8);
14777
14777
  const sessionCalls = [];
14778
14778
  result.sessions++;
14779
+ for (const row of parseCopilotSession(raw.split("\n"))) {
14780
+ if (startDate && row.date && new Date(row.date) < startDate) continue;
14781
+ result.totalCostUSD += row.costUSD;
14782
+ }
14779
14783
  for (const line of raw.split("\n")) {
14780
14784
  if (!line.trim()) continue;
14781
14785
  onLine?.();
@@ -16256,6 +16260,7 @@ var init_scan = __esm({
16256
16260
  init_litellm();
16257
16261
  init_cost_gemini();
16258
16262
  init_cost_codex();
16263
+ init_cost_copilot();
16259
16264
  init_hook_payload();
16260
16265
  init_dist();
16261
16266
  init_scan_summary();
package/dist/cli.mjs CHANGED
@@ -11884,6 +11884,132 @@ var init_cost_codex = __esm({
11884
11884
  }
11885
11885
  });
11886
11886
 
11887
+ // src/cost-copilot.ts
11888
+ import fs21 from "fs";
11889
+ import os20 from "os";
11890
+ import path23 from "path";
11891
+ function copilotSessionsDir() {
11892
+ return path23.join(os20.homedir(), ".copilot", "session-state");
11893
+ }
11894
+ function safeReaddir3(dir) {
11895
+ try {
11896
+ return fs21.readdirSync(dir);
11897
+ } catch {
11898
+ return [];
11899
+ }
11900
+ }
11901
+ function priceTokens(model, u) {
11902
+ const tuple = pricingFor(model);
11903
+ if (!tuple || !u) return 0;
11904
+ const [pin, pout, pcw, pcr] = tuple;
11905
+ return (u.inputTokens ?? 0) * pin + (u.outputTokens ?? 0) * pout + (u.cacheWriteTokens ?? 0) * pcw + (u.cacheReadTokens ?? 0) * pcr;
11906
+ }
11907
+ function parseCopilotSession(lines) {
11908
+ let sessionId = "";
11909
+ let cwd = "";
11910
+ let startDate = "";
11911
+ let shutdownDate = "";
11912
+ let modelMetrics = null;
11913
+ for (const raw of lines) {
11914
+ if (!raw.trim()) continue;
11915
+ let o;
11916
+ try {
11917
+ o = JSON.parse(raw);
11918
+ } catch {
11919
+ continue;
11920
+ }
11921
+ const d = o.data ?? {};
11922
+ if (o.type === "session.start") {
11923
+ if (typeof d["sessionId"] === "string") sessionId = d["sessionId"];
11924
+ if (typeof d["startTime"] === "string") startDate = d["startTime"];
11925
+ const ctx = d["context"] ?? {};
11926
+ if (typeof ctx["cwd"] === "string") cwd = ctx["cwd"];
11927
+ } else if (o.type === "session.shutdown") {
11928
+ if (d["modelMetrics"] && typeof d["modelMetrics"] === "object") {
11929
+ modelMetrics = d["modelMetrics"];
11930
+ }
11931
+ if (typeof o.timestamp === "string") shutdownDate = o.timestamp;
11932
+ }
11933
+ }
11934
+ if (!modelMetrics) return [];
11935
+ const date = (startDate || shutdownDate).slice(0, 10);
11936
+ if (!date) return [];
11937
+ const rows = [];
11938
+ for (const [rawModel, m] of Object.entries(modelMetrics)) {
11939
+ const u = m.usage ?? {};
11940
+ const inputTokens = u.inputTokens ?? 0;
11941
+ const outputTokens = u.outputTokens ?? 0;
11942
+ const cacheReadTokens = u.cacheReadTokens ?? 0;
11943
+ const cacheWriteTokens = u.cacheWriteTokens ?? 0;
11944
+ if (inputTokens === 0 && outputTokens === 0 && cacheReadTokens === 0 && cacheWriteTokens === 0) {
11945
+ continue;
11946
+ }
11947
+ const model = normalizeModel(rawModel);
11948
+ const costUSD = typeof m.requests?.cost === "number" && m.requests.cost > 0 ? m.requests.cost : priceTokens(rawModel, u);
11949
+ rows.push({
11950
+ date,
11951
+ model,
11952
+ workingDir: cwd,
11953
+ runId: sessionId,
11954
+ costUSD,
11955
+ inputTokens,
11956
+ outputTokens,
11957
+ cacheReadTokens,
11958
+ cacheWriteTokens
11959
+ });
11960
+ }
11961
+ return rows;
11962
+ }
11963
+ var copilotSource;
11964
+ var init_cost_copilot = __esm({
11965
+ "src/cost-copilot.ts"() {
11966
+ "use strict";
11967
+ init_litellm();
11968
+ copilotSource = {
11969
+ id: "copilot",
11970
+ available() {
11971
+ try {
11972
+ return fs21.existsSync(copilotSessionsDir());
11973
+ } catch {
11974
+ return false;
11975
+ }
11976
+ },
11977
+ collect(sinceMs) {
11978
+ const base = copilotSessionsDir();
11979
+ const combined = /* @__PURE__ */ new Map();
11980
+ for (const sid of safeReaddir3(base)) {
11981
+ const file = path23.join(base, sid, "events.jsonl");
11982
+ try {
11983
+ if (sinceMs !== void 0 && fs21.statSync(file).mtimeMs < sinceMs) continue;
11984
+ } catch {
11985
+ continue;
11986
+ }
11987
+ let content;
11988
+ try {
11989
+ content = fs21.readFileSync(file, "utf8");
11990
+ } catch {
11991
+ continue;
11992
+ }
11993
+ for (const e of parseCopilotSession(content.split("\n"))) {
11994
+ const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
11995
+ const prev = combined.get(key);
11996
+ if (prev) {
11997
+ prev.costUSD += e.costUSD;
11998
+ prev.inputTokens += e.inputTokens;
11999
+ prev.outputTokens += e.outputTokens;
12000
+ prev.cacheReadTokens += e.cacheReadTokens;
12001
+ prev.cacheWriteTokens += e.cacheWriteTokens;
12002
+ } else {
12003
+ combined.set(key, { ...e });
12004
+ }
12005
+ }
12006
+ }
12007
+ return [...combined.values()];
12008
+ }
12009
+ };
12010
+ }
12011
+ });
12012
+
11887
12013
  // src/utils/hook-payload.ts
11888
12014
  function extractToolName(payload, defaultValue = "") {
11889
12015
  return payload.tool_name ?? payload.name ?? payload.toolCall?.name ?? defaultValue;
@@ -12196,85 +12322,85 @@ var init_scan_summary = __esm({
12196
12322
 
12197
12323
  // src/cli/commands/blast.ts
12198
12324
  import chalk3 from "chalk";
12199
- import fs21 from "fs";
12200
- import path23 from "path";
12201
- import os20 from "os";
12325
+ import fs22 from "fs";
12326
+ import path24 from "path";
12327
+ import os21 from "os";
12202
12328
  function buildSensitivePaths(home, cwd) {
12203
12329
  return [
12204
12330
  {
12205
- full: path23.join(home, ".ssh", "id_rsa"),
12331
+ full: path24.join(home, ".ssh", "id_rsa"),
12206
12332
  label: "~/.ssh/id_rsa",
12207
12333
  description: "RSA private key \u2014 grants SSH access to your servers",
12208
12334
  score: 20
12209
12335
  },
12210
12336
  {
12211
- full: path23.join(home, ".ssh", "id_ed25519"),
12337
+ full: path24.join(home, ".ssh", "id_ed25519"),
12212
12338
  label: "~/.ssh/id_ed25519",
12213
12339
  description: "Ed25519 private key \u2014 grants SSH access to your servers",
12214
12340
  score: 20
12215
12341
  },
12216
12342
  {
12217
- full: path23.join(home, ".ssh", "id_ecdsa"),
12343
+ full: path24.join(home, ".ssh", "id_ecdsa"),
12218
12344
  label: "~/.ssh/id_ecdsa",
12219
12345
  description: "ECDSA private key \u2014 grants SSH access to your servers",
12220
12346
  score: 20
12221
12347
  },
12222
12348
  {
12223
- full: path23.join(home, ".aws", "credentials"),
12349
+ full: path24.join(home, ".aws", "credentials"),
12224
12350
  label: "~/.aws/credentials",
12225
12351
  description: "AWS access keys \u2014 full cloud account access",
12226
12352
  score: 20
12227
12353
  },
12228
12354
  {
12229
- full: path23.join(home, ".aws", "config"),
12355
+ full: path24.join(home, ".aws", "config"),
12230
12356
  label: "~/.aws/config",
12231
12357
  description: "AWS configuration \u2014 account and region settings",
12232
12358
  score: 5
12233
12359
  },
12234
12360
  {
12235
- full: path23.join(home, ".config", "gcloud", "credentials.db"),
12361
+ full: path24.join(home, ".config", "gcloud", "credentials.db"),
12236
12362
  label: "~/.config/gcloud/credentials.db",
12237
12363
  description: "Google Cloud credentials",
12238
12364
  score: 15
12239
12365
  },
12240
12366
  {
12241
- full: path23.join(home, ".docker", "config.json"),
12367
+ full: path24.join(home, ".docker", "config.json"),
12242
12368
  label: "~/.docker/config.json",
12243
12369
  description: "Docker registry auth tokens",
12244
12370
  score: 10
12245
12371
  },
12246
12372
  {
12247
- full: path23.join(home, ".netrc"),
12373
+ full: path24.join(home, ".netrc"),
12248
12374
  label: "~/.netrc",
12249
12375
  description: "FTP/HTTP credentials in plain text",
12250
12376
  score: 15
12251
12377
  },
12252
12378
  {
12253
- full: path23.join(home, ".npmrc"),
12379
+ full: path24.join(home, ".npmrc"),
12254
12380
  label: "~/.npmrc",
12255
12381
  description: "npm auth token \u2014 can publish packages as you",
12256
12382
  score: 10
12257
12383
  },
12258
12384
  {
12259
- full: path23.join(home, ".node9", "credentials.json"),
12385
+ full: path24.join(home, ".node9", "credentials.json"),
12260
12386
  label: "~/.node9/credentials.json",
12261
12387
  description: "Node9 cloud API key",
12262
12388
  score: 10
12263
12389
  },
12264
12390
  {
12265
- full: path23.join(cwd, ".env"),
12391
+ full: path24.join(cwd, ".env"),
12266
12392
  label: ".env (current folder)",
12267
12393
  description: "App secrets \u2014 database passwords, API keys",
12268
12394
  score: 20
12269
12395
  },
12270
12396
  {
12271
- full: path23.join(cwd, ".env.local"),
12397
+ full: path24.join(cwd, ".env.local"),
12272
12398
  label: ".env.local (current folder)",
12273
12399
  description: "Local overrides \u2014 often contains real credentials",
12274
12400
  score: 15
12275
12401
  },
12276
12402
  {
12277
- full: path23.join(cwd, ".env.production"),
12403
+ full: path24.join(cwd, ".env.production"),
12278
12404
  label: ".env.production (current folder)",
12279
12405
  description: "Production secrets",
12280
12406
  score: 20
@@ -12283,7 +12409,7 @@ function buildSensitivePaths(home, cwd) {
12283
12409
  }
12284
12410
  function isReadable(filePath) {
12285
12411
  try {
12286
- fs21.accessSync(filePath, fs21.constants.R_OK);
12412
+ fs22.accessSync(filePath, fs22.constants.R_OK);
12287
12413
  return true;
12288
12414
  } catch {
12289
12415
  return false;
@@ -12296,13 +12422,13 @@ function scoreLabel(score) {
12296
12422
  return chalk3.red.bold(`${score}/100 Critical`);
12297
12423
  }
12298
12424
  function runBlast() {
12299
- const home = os20.homedir();
12425
+ const home = os21.homedir();
12300
12426
  const cwd = process.cwd();
12301
12427
  const paths = buildSensitivePaths(home, cwd);
12302
12428
  let scoreDeduction = 0;
12303
12429
  const reachable = [];
12304
12430
  for (const p of paths) {
12305
- if (fs21.existsSync(p.full) && isReadable(p.full)) {
12431
+ if (fs22.existsSync(p.full) && isReadable(p.full)) {
12306
12432
  reachable.push(p);
12307
12433
  scoreDeduction += p.score;
12308
12434
  }
@@ -12320,7 +12446,7 @@ function runBlast() {
12320
12446
  }
12321
12447
  function registerBlastCommand(program2) {
12322
12448
  program2.command("blast").description("Map what an AI agent can currently reach on this machine").action(() => {
12323
- const home = os20.homedir();
12449
+ const home = os21.homedir();
12324
12450
  const cwd = process.cwd();
12325
12451
  const { reachable, envFindings, score } = runBlast();
12326
12452
  console.log("");
@@ -12508,21 +12634,21 @@ var init_scan_json = __esm({
12508
12634
  });
12509
12635
 
12510
12636
  // src/session-files.ts
12511
- import * as fs22 from "fs";
12512
- import * as path24 from "path";
12637
+ import * as fs23 from "fs";
12638
+ import * as path25 from "path";
12513
12639
  function listSessionFiles(dir, maxDepth = 6) {
12514
12640
  const out = [];
12515
12641
  const walk = (d, rel, depth) => {
12516
12642
  if (depth > maxDepth) return;
12517
12643
  let entries;
12518
12644
  try {
12519
- entries = fs22.readdirSync(d, { withFileTypes: true });
12645
+ entries = fs23.readdirSync(d, { withFileTypes: true });
12520
12646
  } catch {
12521
12647
  return;
12522
12648
  }
12523
12649
  for (const e of entries) {
12524
- const childRel = rel ? path24.join(rel, e.name) : e.name;
12525
- if (e.isDirectory()) walk(path24.join(d, e.name), childRel, depth + 1);
12650
+ const childRel = rel ? path25.join(rel, e.name) : e.name;
12651
+ if (e.isDirectory()) walk(path25.join(d, e.name), childRel, depth + 1);
12526
12652
  else if (e.name.endsWith(".jsonl")) out.push(childRel);
12527
12653
  }
12528
12654
  };
@@ -12530,7 +12656,7 @@ function listSessionFiles(dir, maxDepth = 6) {
12530
12656
  return out;
12531
12657
  }
12532
12658
  function sessionIdOf(relPath) {
12533
- return path24.basename(relPath).replace(/\.jsonl$/, "");
12659
+ return path25.basename(relPath).replace(/\.jsonl$/, "");
12534
12660
  }
12535
12661
  var init_session_files = __esm({
12536
12662
  "src/session-files.ts"() {
@@ -12539,17 +12665,17 @@ var init_session_files = __esm({
12539
12665
  });
12540
12666
 
12541
12667
  // src/cli/render/scan-history.ts
12542
- import fs23 from "fs";
12543
- import path25 from "path";
12544
- import os21 from "os";
12668
+ import fs24 from "fs";
12669
+ import path26 from "path";
12670
+ import os22 from "os";
12545
12671
  function defaultHistoryPath() {
12546
- return path25.join(os21.homedir(), ".node9", "scan-history.json");
12672
+ return path26.join(os22.homedir(), ".node9", "scan-history.json");
12547
12673
  }
12548
12674
  function readPreviousScan(opts = {}) {
12549
12675
  const filePath = opts.path ?? defaultHistoryPath();
12550
12676
  try {
12551
- if (!fs23.existsSync(filePath)) return null;
12552
- const raw = fs23.readFileSync(filePath, "utf8");
12677
+ if (!fs24.existsSync(filePath)) return null;
12678
+ const raw = fs24.readFileSync(filePath, "utf8");
12553
12679
  const parsed = JSON.parse(raw);
12554
12680
  if (!Array.isArray(parsed) || parsed.length === 0) return null;
12555
12681
  const last = parsed[parsed.length - 1];
@@ -12563,11 +12689,11 @@ function appendScanHistory(record, opts = {}) {
12563
12689
  const filePath = opts.path ?? defaultHistoryPath();
12564
12690
  const cap = opts.cap ?? SCAN_HISTORY_CAP;
12565
12691
  try {
12566
- fs23.mkdirSync(path25.dirname(filePath), { recursive: true });
12692
+ fs24.mkdirSync(path26.dirname(filePath), { recursive: true });
12567
12693
  let history = [];
12568
- if (fs23.existsSync(filePath)) {
12694
+ if (fs24.existsSync(filePath)) {
12569
12695
  try {
12570
- const parsed = JSON.parse(fs23.readFileSync(filePath, "utf8"));
12696
+ const parsed = JSON.parse(fs24.readFileSync(filePath, "utf8"));
12571
12697
  if (Array.isArray(parsed)) {
12572
12698
  history = parsed.filter(isValidRecord);
12573
12699
  }
@@ -12578,7 +12704,7 @@ function appendScanHistory(record, opts = {}) {
12578
12704
  if (history.length > cap) {
12579
12705
  history = history.slice(history.length - cap);
12580
12706
  }
12581
- fs23.writeFileSync(filePath, JSON.stringify(history, null, 2));
12707
+ fs24.writeFileSync(filePath, JSON.stringify(history, null, 2));
12582
12708
  } catch (err2) {
12583
12709
  process.stderr.write(
12584
12710
  `[node9] Warning: could not write scan-history.json: ${err2.message}
@@ -12608,132 +12734,6 @@ var init_scan_history = __esm({
12608
12734
  }
12609
12735
  });
12610
12736
 
12611
- // src/cost-copilot.ts
12612
- import fs24 from "fs";
12613
- import os22 from "os";
12614
- import path26 from "path";
12615
- function copilotSessionsDir() {
12616
- return path26.join(os22.homedir(), ".copilot", "session-state");
12617
- }
12618
- function safeReaddir3(dir) {
12619
- try {
12620
- return fs24.readdirSync(dir);
12621
- } catch {
12622
- return [];
12623
- }
12624
- }
12625
- function priceTokens(model, u) {
12626
- const tuple = pricingFor(model);
12627
- if (!tuple || !u) return 0;
12628
- const [pin, pout, pcw, pcr] = tuple;
12629
- return (u.inputTokens ?? 0) * pin + (u.outputTokens ?? 0) * pout + (u.cacheWriteTokens ?? 0) * pcw + (u.cacheReadTokens ?? 0) * pcr;
12630
- }
12631
- function parseCopilotSession(lines) {
12632
- let sessionId = "";
12633
- let cwd = "";
12634
- let startDate = "";
12635
- let shutdownDate = "";
12636
- let modelMetrics = null;
12637
- for (const raw of lines) {
12638
- if (!raw.trim()) continue;
12639
- let o;
12640
- try {
12641
- o = JSON.parse(raw);
12642
- } catch {
12643
- continue;
12644
- }
12645
- const d = o.data ?? {};
12646
- if (o.type === "session.start") {
12647
- if (typeof d["sessionId"] === "string") sessionId = d["sessionId"];
12648
- if (typeof d["startTime"] === "string") startDate = d["startTime"];
12649
- const ctx = d["context"] ?? {};
12650
- if (typeof ctx["cwd"] === "string") cwd = ctx["cwd"];
12651
- } else if (o.type === "session.shutdown") {
12652
- if (d["modelMetrics"] && typeof d["modelMetrics"] === "object") {
12653
- modelMetrics = d["modelMetrics"];
12654
- }
12655
- if (typeof o.timestamp === "string") shutdownDate = o.timestamp;
12656
- }
12657
- }
12658
- if (!modelMetrics) return [];
12659
- const date = (startDate || shutdownDate).slice(0, 10);
12660
- if (!date) return [];
12661
- const rows = [];
12662
- for (const [rawModel, m] of Object.entries(modelMetrics)) {
12663
- const u = m.usage ?? {};
12664
- const inputTokens = u.inputTokens ?? 0;
12665
- const outputTokens = u.outputTokens ?? 0;
12666
- const cacheReadTokens = u.cacheReadTokens ?? 0;
12667
- const cacheWriteTokens = u.cacheWriteTokens ?? 0;
12668
- if (inputTokens === 0 && outputTokens === 0 && cacheReadTokens === 0 && cacheWriteTokens === 0) {
12669
- continue;
12670
- }
12671
- const model = normalizeModel(rawModel);
12672
- const costUSD = typeof m.requests?.cost === "number" && m.requests.cost > 0 ? m.requests.cost : priceTokens(rawModel, u);
12673
- rows.push({
12674
- date,
12675
- model,
12676
- workingDir: cwd,
12677
- runId: sessionId,
12678
- costUSD,
12679
- inputTokens,
12680
- outputTokens,
12681
- cacheReadTokens,
12682
- cacheWriteTokens
12683
- });
12684
- }
12685
- return rows;
12686
- }
12687
- var copilotSource;
12688
- var init_cost_copilot = __esm({
12689
- "src/cost-copilot.ts"() {
12690
- "use strict";
12691
- init_litellm();
12692
- copilotSource = {
12693
- id: "copilot",
12694
- available() {
12695
- try {
12696
- return fs24.existsSync(copilotSessionsDir());
12697
- } catch {
12698
- return false;
12699
- }
12700
- },
12701
- collect(sinceMs) {
12702
- const base = copilotSessionsDir();
12703
- const combined = /* @__PURE__ */ new Map();
12704
- for (const sid of safeReaddir3(base)) {
12705
- const file = path26.join(base, sid, "events.jsonl");
12706
- try {
12707
- if (sinceMs !== void 0 && fs24.statSync(file).mtimeMs < sinceMs) continue;
12708
- } catch {
12709
- continue;
12710
- }
12711
- let content;
12712
- try {
12713
- content = fs24.readFileSync(file, "utf8");
12714
- } catch {
12715
- continue;
12716
- }
12717
- for (const e of parseCopilotSession(content.split("\n"))) {
12718
- const key = `${e.date}::${e.model}::${e.workingDir ?? ""}::${e.runId ?? ""}`;
12719
- const prev = combined.get(key);
12720
- if (prev) {
12721
- prev.costUSD += e.costUSD;
12722
- prev.inputTokens += e.inputTokens;
12723
- prev.outputTokens += e.outputTokens;
12724
- prev.cacheReadTokens += e.cacheReadTokens;
12725
- prev.cacheWriteTokens += e.cacheWriteTokens;
12726
- } else {
12727
- combined.set(key, { ...e });
12728
- }
12729
- }
12730
- }
12731
- return [...combined.values()];
12732
- }
12733
- };
12734
- }
12735
- });
12736
-
12737
12737
  // src/costSync.ts
12738
12738
  import fs25 from "fs";
12739
12739
  import path27 from "path";
@@ -14780,6 +14780,10 @@ function scanCopilotHistory(startDate, onProgress, onLine) {
14780
14780
  let projLabel = sessionId.slice(0, 8);
14781
14781
  const sessionCalls = [];
14782
14782
  result.sessions++;
14783
+ for (const row of parseCopilotSession(raw.split("\n"))) {
14784
+ if (startDate && row.date && new Date(row.date) < startDate) continue;
14785
+ result.totalCostUSD += row.costUSD;
14786
+ }
14783
14787
  for (const line of raw.split("\n")) {
14784
14788
  if (!line.trim()) continue;
14785
14789
  onLine?.();
@@ -16256,6 +16260,7 @@ var init_scan = __esm({
16256
16260
  init_litellm();
16257
16261
  init_cost_gemini();
16258
16262
  init_cost_codex();
16263
+ init_cost_copilot();
16259
16264
  init_hook_payload();
16260
16265
  init_dist();
16261
16266
  init_scan_summary();
@@ -5853,6 +5853,7 @@ var init_scan = __esm({
5853
5853
  init_litellm();
5854
5854
  init_cost_gemini();
5855
5855
  init_cost_codex();
5856
+ init_cost_copilot();
5856
5857
  init_hook_payload();
5857
5858
  init_dist();
5858
5859
  init_scan_summary();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@node9/proxy",
3
- "version": "2.7.3",
3
+ "version": "2.7.4",
4
4
  "description": "The Sudo Command for AI Agents. Execution Security for Claude Code, Codex, Gemini, Cursor, Opencode, Pi, and any MCP server.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",