@node9/proxy 2.43.0 → 2.44.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.
@@ -881,12 +881,12 @@ function judgeInlineCode(language, code, isProtected) {
881
881
  category
882
882
  };
883
883
  }
884
- const path44 = protectedLiteral(text, isProtected);
885
- if (path44) {
884
+ const path45 = protectedLiteral(text, isProtected);
885
+ if (path45) {
886
886
  return {
887
887
  outcome: "dangerous",
888
888
  what: WHAT["reads-protected"],
889
- evidence: path44.slice(0, 60),
889
+ evidence: path45.slice(0, 60),
890
890
  category: "reads-protected"
891
891
  };
892
892
  }
@@ -3049,9 +3049,9 @@ function ruleServerMatches(rule, serverLabel) {
3049
3049
  if (rule.notServer && label2 && matchesPattern(label2, rule.notServer)) return false;
3050
3050
  return true;
3051
3051
  }
3052
- function getNestedValue(obj, path44) {
3052
+ function getNestedValue(obj, path45) {
3053
3053
  if (!obj || typeof obj !== "object") return null;
3054
- const segments2 = path44.split(".");
3054
+ const segments2 = path45.split(".");
3055
3055
  for (const seg of segments2) {
3056
3056
  if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
3057
3057
  }
@@ -4031,8 +4031,8 @@ function collectFileAccesses(tool, args, context = {}, inspection = {}) {
4031
4031
  }
4032
4032
  return out;
4033
4033
  }
4034
- function within(path44, root) {
4035
- return path44 === root || path44.startsWith(root === "/" ? "/" : root + "/");
4034
+ function within(path45, root) {
4035
+ return path45 === root || path45.startsWith(root === "/" ? "/" : root + "/");
4036
4036
  }
4037
4037
  function hits(access, paths, directories, context) {
4038
4038
  const home = context.homeDirs?.[0] ?? "~";
@@ -5420,7 +5420,10 @@ function classify(inv) {
5420
5420
  out.push({ ...f, shown: inv.shown, reason: `${f.reason}: ${inv.shown}` });
5421
5421
  };
5422
5422
  if (hooksBypass(inv)) found(HOOKS_BYPASS);
5423
- if (stagesEverything(inv)) found(STAGE_ALL);
5423
+ const staged = stagesEverything(inv);
5424
+ if (staged) {
5425
+ found(staged.ifWorkTreeTop === void 0 ? STAGE_ALL : { ...STAGE_ALL, ...staged });
5426
+ }
5424
5427
  if (inv.sub === null) {
5425
5428
  found(UNREADABLE);
5426
5429
  return out;
@@ -5481,12 +5484,35 @@ function appliedValue(env, name) {
5481
5484
  const word = f?.Stmts?.[0]?.Cmd?.Args?.[1];
5482
5485
  return word ? resolveWordLiteral(word) : null;
5483
5486
  }
5487
+ function lexicalPath(p) {
5488
+ if (/^[\\/~$]/.test(p) || /^[A-Za-z]:/.test(p)) return null;
5489
+ const parts = [];
5490
+ let climbed = false;
5491
+ for (const part of p.split(/[\\/]+/)) {
5492
+ if (part === "" || part === ".") continue;
5493
+ if (part === "..") {
5494
+ if (parts.length === 0) climbed = true;
5495
+ else parts.pop();
5496
+ } else parts.push(part);
5497
+ }
5498
+ return { parts, climbed };
5499
+ }
5500
+ function hooksPathBypasses(value) {
5501
+ if (value === null || value === void 0) return true;
5502
+ const v = value.trim();
5503
+ if (v === "" || v === "true") return true;
5504
+ const lp = lexicalPath(v);
5505
+ if (lp === null || lp.climbed || lp.parts.length === 0) return true;
5506
+ return lp.parts[0] === ".git" && lp.parts[1] !== "hooks";
5507
+ }
5484
5508
  function hooksBypass(inv) {
5485
- if (inv.config.has("core.hookspath")) return true;
5509
+ if (inv.config.has("core.hookspath") && hooksPathBypasses(inv.config.get("core.hookspath")))
5510
+ return true;
5486
5511
  for (const [name, value] of inv.env) {
5487
5512
  if (name === "GIT_CONFIG_PARAMETERS" && value !== null && /core\.hookspath/i.test(value))
5488
5513
  return true;
5489
- if (/^GIT_CONFIG_KEY_\d+$/.test(name) && value !== null && value.toLowerCase() === "core.hookspath")
5514
+ const key = /^GIT_CONFIG_KEY_(\d+)$/.exec(name);
5515
+ if (key && value !== null && value.toLowerCase() === "core.hookspath" && hooksPathBypasses(inv.env.get(`GIT_CONFIG_VALUE_${key[1]}`)))
5490
5516
  return true;
5491
5517
  }
5492
5518
  for (const name of HOOK_KILL_SWITCHES) {
@@ -5528,7 +5554,10 @@ function configWritesHooksPath(args) {
5528
5554
  }
5529
5555
  const key = args[i];
5530
5556
  if (key === null || key === void 0 || key.toLowerCase() !== "core.hookspath") return false;
5531
- return write || i + 1 < args.length;
5557
+ const unset = args.slice(0, i).some((w) => w === "--unset" || w === "--unset-all") || args[0] === "unset";
5558
+ if (unset) return true;
5559
+ if (i + 1 < args.length) return hooksPathBypasses(args[i + 1]);
5560
+ return write;
5532
5561
  }
5533
5562
  function isHookPath(word) {
5534
5563
  return /(^|[\\/])(\.git[\\/]hooks|\.husky)([\\/]|$)/.test(word);
@@ -5563,31 +5592,49 @@ function chmodDisarmsHook(args, shown) {
5563
5592
  function wholeTree(operand) {
5564
5593
  if (/^:\(top\)\.?$/.test(operand) || operand === ":/" || operand === "*") return true;
5565
5594
  if (operand.startsWith(":")) return false;
5595
+ const lp = lexicalPath(operand);
5596
+ return lp !== null && lp.parts.length === 0;
5597
+ }
5598
+ function chdirPrefix(inv) {
5599
+ const dirs = inv.chdir ?? [];
5600
+ if (dirs.length === 0) return null;
5566
5601
  const parts = [];
5567
- for (const part of operand.split("/")) {
5568
- if (!part || part === ".") continue;
5569
- if (part === "..") parts.pop();
5570
- else parts.push(part);
5602
+ for (const d of dirs) {
5603
+ if (d === null || d === "") return null;
5604
+ const lp = lexicalPath(d);
5605
+ if (lp === null || lp.climbed) return null;
5606
+ parts.push(...lp.parts);
5571
5607
  }
5572
- return parts.length === 0 && !operand.startsWith("/");
5608
+ return parts.length === 0 ? null : parts.join("/");
5573
5609
  }
5574
5610
  function stagesEverything(inv) {
5575
5611
  const sub = inv.sub?.toLowerCase();
5612
+ const prefix = chdirPrefix(inv);
5613
+ const judge = (operands2) => {
5614
+ let conditional = false;
5615
+ for (const operand of operands2) {
5616
+ if (!wholeTree(operand)) continue;
5617
+ if (prefix === null || operand.startsWith(":") || operand.startsWith("/")) return {};
5618
+ if (wholeTree(`${prefix}/${operand === "*" ? "." : operand}`)) return {};
5619
+ conditional = true;
5620
+ }
5621
+ return conditional && prefix !== null ? { ifWorkTreeTop: prefix } : null;
5622
+ };
5576
5623
  if (sub === "add") {
5577
5624
  const o = parseOptions(inv.args, "", ADD_LONG_VALUE);
5578
5625
  if (o.flags.has("-n") || o.flags.has("--dry-run") || o.flags.has("-i") || o.flags.has("--interactive") || o.flags.has("-p") || o.flags.has("--patch") || o.flags.has("-e") || o.flags.has("--edit"))
5579
- return false;
5626
+ return null;
5580
5627
  const all = o.flags.has("-A") || o.flags.has("--all") || o.flags.has("--no-ignore-removal") || o.flags.has("-u") || o.flags.has("--update");
5581
- if (all && o.operands.length === 0) return true;
5582
- return o.operands.some(wholeTree);
5628
+ if (all && o.operands.length === 0) return {};
5629
+ return judge(o.operands);
5583
5630
  }
5584
5631
  if (sub === "commit") {
5585
5632
  const o = parseOptions(inv.args, "mFCcut", COMMIT_LONG_VALUE);
5586
- if (o.flags.has("--dry-run")) return false;
5587
- if (o.flags.has("-a") || o.flags.has("--all")) return true;
5588
- return o.operands.some(wholeTree);
5633
+ if (o.flags.has("--dry-run")) return null;
5634
+ if (o.flags.has("-a") || o.flags.has("--all")) return {};
5635
+ return judge(o.operands);
5589
5636
  }
5590
- return false;
5637
+ return null;
5591
5638
  }
5592
5639
  function hookTextRunsNothing(text) {
5593
5640
  return text.split(/\r?\n/).every((line) => INERT_LINE_RE.test(line.trim()));
@@ -7243,9 +7290,9 @@ function bareToolName(toolName) {
7243
7290
  const parts = toolName.split("__");
7244
7291
  return (parts.length >= 3 ? parts.slice(2).join("__") : toolName).toLowerCase();
7245
7292
  }
7246
- function valuesAt(args, path44) {
7293
+ function valuesAt(args, path45) {
7247
7294
  let cursors = [args];
7248
- for (const rawSegment of path44.split(".")) {
7295
+ for (const rawSegment of path45.split(".")) {
7249
7296
  const isArray = rawSegment.endsWith("[]");
7250
7297
  const key = isArray ? rawSegment.slice(0, -2) : rawSegment;
7251
7298
  const next = [];
@@ -7276,8 +7323,8 @@ function extractToolDestinations(toolName, args) {
7276
7323
  try {
7277
7324
  const out = [];
7278
7325
  const paths = DESTINATION_ARGS.get(bareToolName(toolName)) ?? [];
7279
- for (const path44 of paths) {
7280
- for (const value of valuesAt(args, path44)) {
7326
+ for (const path45 of paths) {
7327
+ for (const value of valuesAt(args, path45)) {
7281
7328
  const host2 = hostOf(value);
7282
7329
  if (host2) out.push({ host: host2, binary: toolName, raw: value });
7283
7330
  }
@@ -7303,8 +7350,8 @@ function ssrfDestinationFloor(toolName, args, opts = {}) {
7303
7350
  try {
7304
7351
  const paths = DESTINATION_ARGS.get(bareToolName(toolName));
7305
7352
  if (!paths) return null;
7306
- for (const path44 of paths) {
7307
- for (const value of valuesAt(args, path44)) {
7353
+ for (const path45 of paths) {
7354
+ for (const value of valuesAt(args, path45)) {
7308
7355
  const host2 = hostOf(value);
7309
7356
  if (!host2) continue;
7310
7357
  const m = classifySsrf(host2);
@@ -7313,7 +7360,7 @@ function ssrfDestinationFloor(toolName, args, opts = {}) {
7313
7360
  const decision = ssrfFloorDecision(m, written, opts);
7314
7361
  if (decision === null) continue;
7315
7362
  const reason = decision === "review" ? ssrfDisguisedReason(m, written) : ssrfReason(m, host2);
7316
- return { ...m, argPath: path44, host: host2, reason, decision };
7363
+ return { ...m, argPath: path45, host: host2, reason, decision };
7317
7364
  }
7318
7365
  }
7319
7366
  return null;
@@ -7595,7 +7642,7 @@ async function evaluatePolicy(config, toolName, args, context = {}, hostHooks =
7595
7642
  }
7596
7643
  async function evaluatePolicyCore(config, toolName, args, context = {}, hooks = {}) {
7597
7644
  const { agent, cwd, activeEnvironment } = context;
7598
- const { checkProvenance: checkProvenance2, isTrustedHost: isTrustedHost2, isConfiguredRegistry } = hooks;
7645
+ const { checkProvenance: checkProvenance2, isTrustedHost: isTrustedHost2, isConfiguredRegistry, isGitWorkTreeTop: isGitWorkTreeTop2 } = hooks;
7599
7646
  const settingsView = catalogSettings(config);
7600
7647
  const layers = inspectionLayers(config.policy);
7601
7648
  const cv = (id) => checkValue(settingsView, id);
@@ -7749,6 +7796,8 @@ async function evaluatePolicyCore(config, toolName, args, context = {}, hooks =
7749
7796
  const action = cv(id);
7750
7797
  const finding = action === "off" ? void 0 : git.findings.find((f) => f.checkId === id);
7751
7798
  if (!finding) continue;
7799
+ if (finding.ifWorkTreeTop !== void 0 && isGitWorkTreeTop2 && cwd && !isGitWorkTreeTop2(finding.ifWorkTreeTop, cwd))
7800
+ continue;
7752
7801
  const v = applyCheckValue(action, {
7753
7802
  decision: "review",
7754
7803
  blockedByLabel: `Node9 (AST): ${finding.ruleName}`,
@@ -16360,6 +16409,7 @@ zoo`.split("\n");
16360
16409
  /** The words after `git`: global options, then the subcommand. */
16361
16410
  visitGit(rest, env, depth, viaXargs, fromAlias, shown) {
16362
16411
  const config = /* @__PURE__ */ new Map();
16412
+ const chdir = [];
16363
16413
  let i = 0;
16364
16414
  while (i < rest.length) {
16365
16415
  const w = rest[i];
@@ -16374,6 +16424,7 @@ zoo`.split("\n");
16374
16424
  i++;
16375
16425
  value = i < rest.length ? rest[i] : null;
16376
16426
  }
16427
+ if (name === "-C") chdir.push(viaXargs || (value ?? "").includes("{}") ? null : value);
16377
16428
  if (name === "-c" && value !== null) {
16378
16429
  const ceq = value.indexOf("=");
16379
16430
  const key = (ceq > 0 ? value.slice(0, ceq) : value).toLowerCase();
@@ -16390,7 +16441,7 @@ zoo`.split("\n");
16390
16441
  }
16391
16442
  const subWord = i < rest.length ? rest[i] : void 0;
16392
16443
  const args = rest.slice(i + 1);
16393
- const inv = { sub: null, args, config, env, shown };
16444
+ const inv = { sub: null, args, config, env, shown, chdir };
16394
16445
  if (subWord === void 0) {
16395
16446
  if (!viaXargs) return;
16396
16447
  this.emit(inv);
@@ -16404,16 +16455,23 @@ zoo`.split("\n");
16404
16455
  const fromConfig = config.get(`alias.${subWord.toLowerCase()}`);
16405
16456
  const alias = fromConfig !== void 0 ? fromConfig : this.aliases.get(subWord);
16406
16457
  if (alias !== void 0 && !fromAlias) {
16407
- this.expandAlias(subWord, alias, args, env, depth, 0, shown);
16458
+ this.expandAlias(subWord, alias, args, env, depth, 0, shown, chdir);
16408
16459
  return;
16409
16460
  }
16410
16461
  inv.sub = subWord;
16411
16462
  this.emit(inv);
16412
16463
  this.recordAliasDefinition(inv, env, depth);
16413
16464
  }
16414
- expandAlias(name, value, args, env, depth, level, shown) {
16465
+ expandAlias(name, value, args, env, depth, level, shown, chdir) {
16415
16466
  if (value === null) {
16416
- this.emit({ sub: null, args, config: /* @__PURE__ */ new Map(), env, shown: `${shown} (alias ${name})` });
16467
+ this.emit({
16468
+ sub: null,
16469
+ args,
16470
+ config: /* @__PURE__ */ new Map(),
16471
+ env,
16472
+ shown: `${shown} (alias ${name})`,
16473
+ chdir
16474
+ });
16417
16475
  return;
16418
16476
  }
16419
16477
  if (value.startsWith("!")) {
@@ -16427,7 +16485,16 @@ zoo`.split("\n");
16427
16485
  const nested = this.aliases.get(sub);
16428
16486
  const expandedShown = `${shown} (alias ${name} = ${value})`;
16429
16487
  if (nested !== void 0 && level < MAX_ALIAS_DEPTH) {
16430
- this.expandAlias(sub, nested, [...words.slice(1), ...args], env, depth, level + 1, shown);
16488
+ this.expandAlias(
16489
+ sub,
16490
+ nested,
16491
+ [...words.slice(1), ...args],
16492
+ env,
16493
+ depth,
16494
+ level + 1,
16495
+ shown,
16496
+ chdir
16497
+ );
16431
16498
  return;
16432
16499
  }
16433
16500
  this.emit({
@@ -16435,7 +16502,8 @@ zoo`.split("\n");
16435
16502
  args: [...words.slice(1), ...args],
16436
16503
  config: /* @__PURE__ */ new Map(),
16437
16504
  env,
16438
- shown: expandedShown
16505
+ shown: expandedShown,
16506
+ chdir
16439
16507
  });
16440
16508
  }
16441
16509
  /**
@@ -16469,7 +16537,7 @@ zoo`.split("\n");
16469
16537
  if (i + 1 >= args.length) return;
16470
16538
  const value = args[i + 1];
16471
16539
  this.aliases.set(m[1], value);
16472
- this.expandAlias(m[1], value, [], env, depth, 0, `${inv.shown}`);
16540
+ this.expandAlias(m[1], value, [], env, depth, 0, `${inv.shown}`, []);
16473
16541
  }
16474
16542
  };
16475
16543
  POSITIONAL2 = "\0positional";
@@ -17971,7 +18039,7 @@ zoo`.split("\n");
17971
18039
  { view: "separators-stripped", decoder: "separators", stripped: true }
17972
18040
  ];
17973
18041
  LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
17974
- CANONICAL_EXTRACTOR_VERSION = "canonical-v34";
18042
+ CANONICAL_EXTRACTOR_VERSION = "canonical-v35";
17975
18043
  }
17976
18044
  });
17977
18045
 
@@ -18666,8 +18734,7 @@ function homeCredentialFiles(home) {
18666
18734
  ),
18667
18735
  f([".docker", "config.json"], "Docker registry auth tokens", 10),
18668
18736
  f([".netrc"], "FTP/HTTP credentials in plain text", 15),
18669
- f([".npmrc"], "npm auth token: can publish packages as you", 10),
18670
- f([".node9", "credentials.json"], "Node9 cloud API key", 10)
18737
+ f([".npmrc"], "npm auth token: can publish packages as you", 10)
18671
18738
  ];
18672
18739
  }
18673
18740
  var init_credential_files = __esm({
@@ -19316,8 +19383,8 @@ var init_daemon = __esm({
19316
19383
  import { z } from "zod";
19317
19384
  function formatIssues(issues) {
19318
19385
  const lines = issues.map((issue) => {
19319
- const path44 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
19320
- return ` \u2022 ${path44}: ${issue.message}`;
19386
+ const path45 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
19387
+ return ` \u2022 ${path45}: ${issue.message}`;
19321
19388
  });
19322
19389
  return `Invalid config:
19323
19390
  ${lines.join("\n")}`;
@@ -19330,9 +19397,9 @@ function prunePaths(root, paths) {
19330
19397
  const yi = y[y.length - 1];
19331
19398
  return typeof xi === "number" && typeof yi === "number" ? yi - xi : 0;
19332
19399
  });
19333
- for (const path44 of ordered) {
19400
+ for (const path45 of ordered) {
19334
19401
  let cur = root;
19335
- for (const key of path44.slice(0, -1)) {
19402
+ for (const key of path45.slice(0, -1)) {
19336
19403
  if (cur === null || typeof cur !== "object") {
19337
19404
  cur = void 0;
19338
19405
  break;
@@ -19340,7 +19407,7 @@ function prunePaths(root, paths) {
19340
19407
  cur = cur[key];
19341
19408
  }
19342
19409
  if (cur === null || typeof cur !== "object") continue;
19343
- const last = path44[path44.length - 1];
19410
+ const last = path45[path45.length - 1];
19344
19411
  if (Array.isArray(cur)) {
19345
19412
  const i = Number(last);
19346
19413
  if (Number.isInteger(i) && i >= 0 && i < cur.length) {
@@ -19376,7 +19443,7 @@ function sanitizeConfig(raw) {
19376
19443
  return issue.keys.map((k) => [...at, k]);
19377
19444
  }
19378
19445
  return [at.slice(0, -level || void 0)];
19379
- }).filter((path44) => path44.length > 0);
19446
+ }).filter((path45) => path45.length > 0);
19380
19447
  if (paths.length === 0 || !prunePaths(working, paths)) break;
19381
19448
  }
19382
19449
  if (ConfigFileSchema.safeParse(working).success) break;
@@ -20700,13 +20767,13 @@ function getConfig(cwd) {
20700
20767
  }
20701
20768
  if (Array.isArray(mc.jailPaths)) {
20702
20769
  for (const jp of mc.jailPaths) {
20703
- const path44 = typeof jp?.path === "string" ? jp.path.trim() : "";
20704
- if (!path44) continue;
20770
+ const path45 = typeof jp?.path === "string" ? jp.path.trim() : "";
20771
+ if (!path45) continue;
20705
20772
  const verdict = jp?.verdict === "review" ? "review" : "block";
20706
- for (const r of pathRules(path44, verdict, "org-managed jail")) {
20773
+ for (const r of pathRules(path45, verdict, "org-managed jail")) {
20707
20774
  mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
20708
20775
  }
20709
- mergedPolicy.managedJailPaths.push({ path: path44, verdict });
20776
+ mergedPolicy.managedJailPaths.push({ path: path45, verdict });
20710
20777
  }
20711
20778
  }
20712
20779
  if (Array.isArray(mc.trustedHosts)) {
@@ -21417,6 +21484,68 @@ var init_cost_gemini = __esm({
21417
21484
  });
21418
21485
 
21419
21486
  // src/cost-copilot.ts
21487
+ function priceTokens(model, u) {
21488
+ const tuple = pricingFor(model);
21489
+ if (!tuple || !u) return 0;
21490
+ const [pin, pout, pcw, pcr] = tuple;
21491
+ return (u.inputTokens ?? 0) * pin + (u.outputTokens ?? 0) * pout + (u.cacheWriteTokens ?? 0) * pcw + (u.cacheReadTokens ?? 0) * pcr;
21492
+ }
21493
+ function parseCopilotSession(lines) {
21494
+ let sessionId = "";
21495
+ let cwd = "";
21496
+ let startDate = "";
21497
+ let shutdownDate = "";
21498
+ let modelMetrics = null;
21499
+ for (const raw of lines) {
21500
+ if (!raw.trim()) continue;
21501
+ let o;
21502
+ try {
21503
+ o = JSON.parse(raw);
21504
+ } catch {
21505
+ continue;
21506
+ }
21507
+ const d = o.data ?? {};
21508
+ if (o.type === "session.start") {
21509
+ if (typeof d["sessionId"] === "string") sessionId = d["sessionId"];
21510
+ if (typeof d["startTime"] === "string") startDate = d["startTime"];
21511
+ const ctx = d["context"] ?? {};
21512
+ if (typeof ctx["cwd"] === "string") cwd = ctx["cwd"];
21513
+ } else if (o.type === "session.shutdown") {
21514
+ if (d["modelMetrics"] && typeof d["modelMetrics"] === "object") {
21515
+ modelMetrics = d["modelMetrics"];
21516
+ }
21517
+ if (typeof o.timestamp === "string") shutdownDate = o.timestamp;
21518
+ }
21519
+ }
21520
+ if (!modelMetrics) return [];
21521
+ const date = (startDate || shutdownDate).slice(0, 10);
21522
+ if (!date) return [];
21523
+ const rows = [];
21524
+ for (const [rawModel, m] of Object.entries(modelMetrics)) {
21525
+ const u = m.usage ?? {};
21526
+ const inputTokens = u.inputTokens ?? 0;
21527
+ const outputTokens = u.outputTokens ?? 0;
21528
+ const cacheReadTokens = u.cacheReadTokens ?? 0;
21529
+ const cacheWriteTokens = u.cacheWriteTokens ?? 0;
21530
+ if (inputTokens === 0 && outputTokens === 0 && cacheReadTokens === 0 && cacheWriteTokens === 0) {
21531
+ continue;
21532
+ }
21533
+ const model = normalizeModel(rawModel);
21534
+ const costUSD = typeof m.requests?.cost === "number" && m.requests.cost > 0 ? m.requests.cost : priceTokens(rawModel, u);
21535
+ rows.push({
21536
+ date,
21537
+ model,
21538
+ workingDir: cwd,
21539
+ runId: sessionId,
21540
+ costUSD,
21541
+ inputTokens,
21542
+ outputTokens,
21543
+ cacheReadTokens,
21544
+ cacheWriteTokens
21545
+ });
21546
+ }
21547
+ return rows;
21548
+ }
21420
21549
  var init_cost_copilot = __esm({
21421
21550
  "src/cost-copilot.ts"() {
21422
21551
  "use strict";
@@ -24920,6 +25049,7 @@ var init_provenance2 = __esm({
24920
25049
 
24921
25050
  // src/policy/index.ts
24922
25051
  import fs30 from "fs";
25052
+ import path32 from "path";
24923
25053
  async function evaluatePolicy2(toolName, args, agent, cwd, opts) {
24924
25054
  const config = opts?.config ?? getConfig(cwd);
24925
25055
  const prepared = opts?.fileAccess ?? prepareFileAccesses(toolName, args, cwd, inspectionLayers(config.policy));
@@ -24945,10 +25075,19 @@ async function evaluatePolicy2(toolName, args, agent, cwd, opts) {
24945
25075
  // reaches a long-lived in-process authorizer (the gateway) within seconds.
24946
25076
  isTrustedHost: config.policy.trustedHostsManaged ? (host2) => matchesTrustedHost(host2, config.policy.trustedHosts) : isTrustedHost,
24947
25077
  readAgentSettings,
24948
- isConfiguredRegistry: (host2, at) => configuredRegistryHosts(at).has(host2)
25078
+ isConfiguredRegistry: (host2, at) => configuredRegistryHosts(at).has(host2),
25079
+ isGitWorkTreeTop
24949
25080
  }
24950
25081
  );
24951
25082
  }
25083
+ function isGitWorkTreeTop(dir2, cwd) {
25084
+ if (!path32.isAbsolute(cwd)) return true;
25085
+ try {
25086
+ return fs30.existsSync(path32.join(path32.resolve(cwd, dir2), ".git"));
25087
+ } catch {
25088
+ return true;
25089
+ }
25090
+ }
24952
25091
  function readAgentSettings(absPath) {
24953
25092
  const r = readCappedText(
24954
25093
  absPath,
@@ -24983,7 +25122,7 @@ var init_policy = __esm({
24983
25122
 
24984
25123
  // src/auth/state.ts
24985
25124
  import fs31 from "fs";
24986
- import path32 from "path";
25125
+ import path33 from "path";
24987
25126
  import os22 from "os";
24988
25127
  function extractCommandPattern(toolName, args) {
24989
25128
  const lower2 = toolName.toLowerCase();
@@ -25061,7 +25200,7 @@ function writeTrustSession(toolName, durationMs, args) {
25061
25200
  }
25062
25201
  function getPersistentDecision(toolName) {
25063
25202
  try {
25064
- const file2 = path32.join(os22.homedir(), ".node9", "decisions.json");
25203
+ const file2 = path33.join(os22.homedir(), ".node9", "decisions.json");
25065
25204
  if (!fs31.existsSync(file2)) return null;
25066
25205
  const decisions = JSON.parse(fs31.readFileSync(file2, "utf-8"));
25067
25206
  const d = decisions[toolName];
@@ -25077,15 +25216,15 @@ var init_state2 = __esm({
25077
25216
  init_policy();
25078
25217
  init_atomic_write();
25079
25218
  init_forecast_context();
25080
- PAUSED_FILE = path32.join(os22.homedir(), ".node9", "PAUSED");
25081
- TRUST_FILE = path32.join(os22.homedir(), ".node9", "trust.json");
25219
+ PAUSED_FILE = path33.join(os22.homedir(), ".node9", "PAUSED");
25220
+ TRUST_FILE = path33.join(os22.homedir(), ".node9", "trust.json");
25082
25221
  }
25083
25222
  });
25084
25223
 
25085
25224
  // src/auth/cloud.ts
25086
25225
  import fs32 from "fs";
25087
25226
  import os23 from "os";
25088
- import path33 from "path";
25227
+ import path34 from "path";
25089
25228
  function maskArgsForCloud(args) {
25090
25229
  if (args === void 0 || args === null) return args;
25091
25230
  try {
@@ -25118,7 +25257,7 @@ async function initNode9SaaS(toolName, args, creds, meta, riskMetadata, agentPol
25118
25257
  let ciContext;
25119
25258
  if (process.env.CI) {
25120
25259
  try {
25121
- const ciContextPath = path33.join(os23.homedir(), ".node9", "ci-context.json");
25260
+ const ciContextPath = path34.join(os23.homedir(), ".node9", "ci-context.json");
25122
25261
  const ci = readCappedText(ciContextPath, 1e4);
25123
25262
  if (!ci) throw new Error("ci-context.json unreadable");
25124
25263
  if (ci.truncated) throw new Error("ci-context.json exceeds 10 KB");
@@ -25265,10 +25404,10 @@ var init_cloud = __esm({
25265
25404
 
25266
25405
  // src/loop-detector.ts
25267
25406
  import fs33 from "fs";
25268
- import path34 from "path";
25407
+ import path35 from "path";
25269
25408
  import os24 from "os";
25270
25409
  function loopStateFile() {
25271
- return path34.join(os24.homedir(), ".node9", "loop-state.json");
25410
+ return path35.join(os24.homedir(), ".node9", "loop-state.json");
25272
25411
  }
25273
25412
  function readState() {
25274
25413
  try {
@@ -25282,7 +25421,7 @@ function readState() {
25282
25421
  }
25283
25422
  }
25284
25423
  function writeState(records) {
25285
- const dir2 = path34.dirname(loopStateFile());
25424
+ const dir2 = path35.dirname(loopStateFile());
25286
25425
  if (!fs33.existsSync(dir2)) fs33.mkdirSync(dir2, { recursive: true });
25287
25426
  const tmpPath = `${loopStateFile()}.${os24.hostname()}.${process.pid}.tmp`;
25288
25427
  fs33.writeFileSync(tmpPath, JSON.stringify(records));
@@ -25445,7 +25584,7 @@ var init_card_result = __esm({
25445
25584
 
25446
25585
  // src/auth/orchestrator.ts
25447
25586
  import os25 from "os";
25448
- import path35 from "path";
25587
+ import path36 from "path";
25449
25588
  function isProtectedPathRule(ruleName) {
25450
25589
  if (!ruleName) return false;
25451
25590
  return /^(?:org:)?block-path-/.test(ruleName) || /^shield:project-jail:block-read-/.test(ruleName);
@@ -25492,9 +25631,9 @@ function isMcpToolName(toolName) {
25492
25631
  return /^mcp__[^_](?:[^_]|_(?!_))*?__/i.test(toolName);
25493
25632
  }
25494
25633
  function absoluteUploadPath(spelled, cwd) {
25495
- const expanded = spelled === "~" || spelled.startsWith("~/") ? path35.join(os25.homedir(), spelled.slice(1)) : spelled;
25496
- if (path35.isAbsolute(expanded)) return expanded;
25497
- return cwd && path35.isAbsolute(cwd) ? path35.resolve(cwd, expanded) : expanded;
25634
+ const expanded = spelled === "~" || spelled.startsWith("~/") ? path36.join(os25.homedir(), spelled.slice(1)) : spelled;
25635
+ if (path36.isAbsolute(expanded)) return expanded;
25636
+ return cwd && path36.isAbsolute(cwd) ? path36.resolve(cwd, expanded) : expanded;
25498
25637
  }
25499
25638
  function extractFilePaths(toolName, args, shellCommand) {
25500
25639
  const paths = [];
@@ -27111,17 +27250,17 @@ var init_forecast = __esm({
27111
27250
 
27112
27251
  // src/version.ts
27113
27252
  import fs34 from "fs";
27114
- import path36 from "path";
27253
+ import path37 from "path";
27115
27254
  function readVersion() {
27116
27255
  let dir2 = __dirname;
27117
27256
  for (let i = 0; i < 5; i++) {
27118
- const p = path36.join(dir2, "package.json");
27257
+ const p = path37.join(dir2, "package.json");
27119
27258
  try {
27120
27259
  const pkg = JSON.parse(fs34.readFileSync(p, "utf-8"));
27121
27260
  if (pkg.name === "@node9/proxy" && typeof pkg.version === "string") return pkg.version;
27122
27261
  } catch {
27123
27262
  }
27124
- const parent = path36.dirname(dir2);
27263
+ const parent = path37.dirname(dir2);
27125
27264
  if (parent === dir2) break;
27126
27265
  dir2 = parent;
27127
27266
  }
@@ -27138,10 +27277,10 @@ var init_version = __esm({
27138
27277
  // src/cli/commands/scan-cache.ts
27139
27278
  import fs35 from "fs";
27140
27279
  import os26 from "os";
27141
- import path37 from "path";
27280
+ import path38 from "path";
27142
27281
  import { createHash as createHash5 } from "crypto";
27143
27282
  function scanCacheRoot() {
27144
- return path37.join(os26.homedir(), ".node9", "scan-cache");
27283
+ return path38.join(os26.homedir(), ".node9", "scan-cache");
27145
27284
  }
27146
27285
  function configHashOf(config) {
27147
27286
  const h = createHash5("sha256");
@@ -27149,7 +27288,7 @@ function configHashOf(config) {
27149
27288
  h.update(JSON.stringify(config.policySource));
27150
27289
  h.update(JSON.stringify(config.policy));
27151
27290
  for (const name of SIDECAR_FILES) {
27152
- const st = fileStamp(path37.join(os26.homedir(), ".node9", name));
27291
+ const st = fileStamp(path38.join(os26.homedir(), ".node9", name));
27153
27292
  h.update(`|${name}:${st ? `${st.size}:${st.mtimeMs}` : "absent"}`);
27154
27293
  }
27155
27294
  return h.digest("hex").slice(0, 16);
@@ -27180,8 +27319,8 @@ var init_scan_cache = __esm({
27180
27319
  "trusted-hosts.json",
27181
27320
  "trusted-recipients.json",
27182
27321
  "rules-cache.json",
27183
- path37.join("osv", "npm", "meta.json"),
27184
- path37.join("osv", "PyPI", "meta.json")
27322
+ path38.join("osv", "npm", "meta.json"),
27323
+ path38.join("osv", "PyPI", "meta.json")
27185
27324
  ];
27186
27325
  ScanCache = class {
27187
27326
  root;
@@ -27210,7 +27349,7 @@ var init_scan_cache = __esm({
27210
27349
  if (!this.enabled) return fresh;
27211
27350
  try {
27212
27351
  const raw = JSON.parse(
27213
- fs35.readFileSync(path37.join(this.root, "index.json"), "utf8")
27352
+ fs35.readFileSync(path38.join(this.root, "index.json"), "utf8")
27214
27353
  );
27215
27354
  if (raw.cacheVersion !== SCAN_CACHE_VERSION || raw.engineVersion !== CANONICAL_EXTRACTOR_VERSION || raw.proxyVersion !== PROXY_VERSION || raw.configHash !== configHash || typeof raw.files !== "object") {
27216
27355
  this.dropAll();
@@ -27247,7 +27386,7 @@ var init_scan_cache = __esm({
27247
27386
  }
27248
27387
  }
27249
27388
  try {
27250
- const stored = JSON.parse(fs35.readFileSync(path37.join(this.root, e.result), "utf8"));
27389
+ const stored = JSON.parse(fs35.readFileSync(path38.join(this.root, e.result), "utf8"));
27251
27390
  if ((stored.judgedFrom ?? null) !== (e.judgedFrom ?? null) || !stored.result) {
27252
27391
  this.misses++;
27253
27392
  return null;
@@ -27262,13 +27401,13 @@ var init_scan_cache = __esm({
27262
27401
  put(filePath, stamp, agent, result, hasher, judgeFrom = null) {
27263
27402
  if (!this.enabled) return;
27264
27403
  const name = createHash5("sha256").update(`${agent}|${filePath}`).digest("hex").slice(0, 40);
27265
- const rel = path37.join("files", name.slice(0, 2), `${name}.json`);
27404
+ const rel = path38.join("files", name.slice(0, 2), `${name}.json`);
27266
27405
  const configHashes = {};
27267
27406
  if (hasher)
27268
27407
  for (const cwd of result.configCwds ?? []) configHashes[cwd] = hasher.configHashFor(cwd);
27269
27408
  try {
27270
- const abs = path37.join(this.root, rel);
27271
- fs35.mkdirSync(path37.dirname(abs), { recursive: true, mode: 448 });
27409
+ const abs = path38.join(this.root, rel);
27410
+ fs35.mkdirSync(path38.dirname(abs), { recursive: true, mode: 448 });
27272
27411
  fs35.writeFileSync(
27273
27412
  abs,
27274
27413
  JSON.stringify({ judgedFrom: judgeFrom ? judgeFrom.toISOString() : null, result }),
@@ -27294,7 +27433,7 @@ var init_scan_cache = __esm({
27294
27433
  for (const [key, e] of Object.entries(this.index.files)) {
27295
27434
  if (fs35.existsSync(key)) continue;
27296
27435
  try {
27297
- fs35.rmSync(path37.join(this.root, e.result), { force: true });
27436
+ fs35.rmSync(path38.join(this.root, e.result), { force: true });
27298
27437
  } catch {
27299
27438
  }
27300
27439
  delete this.index.files[key];
@@ -27316,9 +27455,9 @@ var init_scan_cache = __esm({
27316
27455
  if (!this.dirty) return;
27317
27456
  try {
27318
27457
  fs35.mkdirSync(this.root, { recursive: true, mode: 448 });
27319
- const tmp = path37.join(this.root, `index.${process.pid}.tmp`);
27458
+ const tmp = path38.join(this.root, `index.${process.pid}.tmp`);
27320
27459
  fs35.writeFileSync(tmp, JSON.stringify(this.index), { mode: 384 });
27321
- fs35.renameSync(tmp, path37.join(this.root, "index.json"));
27460
+ fs35.renameSync(tmp, path38.join(this.root, "index.json"));
27322
27461
  this.dirty = false;
27323
27462
  } catch {
27324
27463
  }
@@ -27330,7 +27469,7 @@ var init_scan_cache = __esm({
27330
27469
  // src/cli/commands/scan-judge.ts
27331
27470
  import fs36 from "fs";
27332
27471
  import os27 from "os";
27333
- import path38 from "path";
27472
+ import path39 from "path";
27334
27473
  function findingDedupKey(f) {
27335
27474
  return `${f.source.rule.name ?? "<unnamed>"}|${preview(f.input)}|${f.project}|${f.repo ?? ""}`;
27336
27475
  }
@@ -27429,20 +27568,20 @@ var init_scan_judge = __esm({
27429
27568
  * file, so worktrees count), home-relative; undefined when none. Cached per
27430
27569
  * directory: history repeats the same few cwds thousands of times. */
27431
27570
  repoOf(cwd) {
27432
- if (!cwd || !path38.isAbsolute(cwd)) return void 0;
27571
+ if (!cwd || !path39.isAbsolute(cwd)) return void 0;
27433
27572
  if (this.repos.has(cwd)) return this.repos.get(cwd);
27434
27573
  let dir2 = cwd;
27435
27574
  let found;
27436
27575
  for (; ; ) {
27437
27576
  try {
27438
- if (fs36.existsSync(path38.join(dir2, ".git"))) {
27577
+ if (fs36.existsSync(path39.join(dir2, ".git"))) {
27439
27578
  found = dir2;
27440
27579
  break;
27441
27580
  }
27442
27581
  } catch {
27443
27582
  break;
27444
27583
  }
27445
- const parent = path38.dirname(dir2);
27584
+ const parent = path39.dirname(dir2);
27446
27585
  if (parent === dir2) break;
27447
27586
  dir2 = parent;
27448
27587
  }
@@ -27591,6 +27730,16 @@ var init_scan_judge = __esm({
27591
27730
  });
27592
27731
 
27593
27732
  // src/utils/hook-payload.ts
27733
+ function canonicalToolInput(rawToolName, input) {
27734
+ if (rawToolName !== "run_command") return input;
27735
+ if (typeof input !== "object" || input === null || Array.isArray(input)) return input;
27736
+ const args = input;
27737
+ if (typeof args.CommandLine !== "string") return input;
27738
+ const { CommandLine, Cwd, ...rest } = args;
27739
+ const canonical = { ...rest, command: CommandLine };
27740
+ if (typeof Cwd === "string" && Cwd.length > 0) canonical.cwd = Cwd;
27741
+ return canonical;
27742
+ }
27594
27743
  var init_hook_payload = __esm({
27595
27744
  "src/utils/hook-payload.ts"() {
27596
27745
  "use strict";
@@ -27609,7 +27758,7 @@ var init_scan_summary = __esm({
27609
27758
 
27610
27759
  // src/agent-wiring.ts
27611
27760
  import fs37 from "fs";
27612
- import path39 from "path";
27761
+ import path40 from "path";
27613
27762
  import * as yaml from "yaml";
27614
27763
  import { parse as parseToml } from "smol-toml";
27615
27764
  var exists, ck, lg, AGENT_SPECS;
@@ -27631,55 +27780,55 @@ var init_agent_wiring = __esm({
27631
27780
  id: "claude",
27632
27781
  label: "Claude Code",
27633
27782
  setupCommand: "node9 agents add claude",
27634
- hookFile: (h) => path39.join(h, ".claude", "settings.json"),
27783
+ hookFile: (h) => path40.join(h, ".claude", "settings.json"),
27635
27784
  hookFormat: "matcher",
27636
27785
  // UserPromptSubmit is prompt DLP. setup.ts has written it for Claude since
27637
27786
  // that shipped; the spec must name it too, or status/doctor never show the
27638
27787
  // row and heal (which repairs via setupAgent) has no signal it is missing.
27639
27788
  hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
27640
- mcpFile: (h) => path39.join(h, ".claude.json"),
27641
- present: (h) => exists(path39.join(h, ".claude", "settings.json")) || exists(path39.join(h, ".claude.json"))
27789
+ mcpFile: (h) => path40.join(h, ".claude.json"),
27790
+ present: (h) => exists(path40.join(h, ".claude", "settings.json")) || exists(path40.join(h, ".claude.json"))
27642
27791
  },
27643
27792
  {
27644
27793
  id: "gemini",
27645
27794
  label: "Gemini CLI",
27646
27795
  setupCommand: "node9 agents add gemini",
27647
- hookFile: (h) => path39.join(h, ".gemini", "settings.json"),
27796
+ hookFile: (h) => path40.join(h, ".gemini", "settings.json"),
27648
27797
  hookFormat: "matcher",
27649
27798
  hookEvents: [ck("BeforeTool"), lg("AfterTool")],
27650
- mcpFile: (h) => path39.join(h, ".gemini", "settings.json"),
27651
- present: (h) => exists(path39.join(h, ".gemini", "settings.json"))
27799
+ mcpFile: (h) => path40.join(h, ".gemini", "settings.json"),
27800
+ present: (h) => exists(path40.join(h, ".gemini", "settings.json"))
27652
27801
  },
27653
27802
  {
27654
27803
  id: "codex",
27655
27804
  label: "Codex",
27656
27805
  setupCommand: "node9 agents add codex",
27657
- hookFile: (h) => path39.join(h, ".codex", "hooks.json"),
27806
+ hookFile: (h) => path40.join(h, ".codex", "hooks.json"),
27658
27807
  hookFormat: "matcher",
27659
27808
  hookEvents: [ck("PreToolUse"), ck("UserPromptSubmit")],
27660
- mcpFile: (h) => path39.join(h, ".codex", "config.toml"),
27809
+ mcpFile: (h) => path40.join(h, ".codex", "config.toml"),
27661
27810
  mcpFormat: "toml",
27662
- present: (h) => exists(path39.join(h, ".codex"))
27811
+ present: (h) => exists(path40.join(h, ".codex"))
27663
27812
  },
27664
27813
  {
27665
27814
  id: "antigravity",
27666
27815
  label: "Antigravity",
27667
27816
  setupCommand: "node9 agents add antigravity",
27668
- hookFile: (h) => path39.join(h, ".gemini", "config", "hooks.json"),
27817
+ hookFile: (h) => path40.join(h, ".gemini", "config", "hooks.json"),
27669
27818
  hookFormat: "matcher",
27670
27819
  hookEvents: [ck("PreToolUse"), lg("PostToolUse")],
27671
- mcpFile: (h) => path39.join(h, ".gemini", "config", "mcp_config.json"),
27672
- present: (h) => exists(path39.join(h, ".gemini", "config", "hooks.json")) || exists(path39.join(h, ".gemini", "antigravity-cli")) || exists(path39.join(h, ".gemini", "antigravity-ide"))
27820
+ mcpFile: (h) => path40.join(h, ".gemini", "config", "mcp_config.json"),
27821
+ present: (h) => exists(path40.join(h, ".gemini", "config", "hooks.json")) || exists(path40.join(h, ".gemini", "antigravity-cli")) || exists(path40.join(h, ".gemini", "antigravity-ide"))
27673
27822
  },
27674
27823
  {
27675
27824
  id: "copilot",
27676
27825
  label: "GitHub Copilot",
27677
27826
  setupCommand: "node9 agents add copilot",
27678
- hookFile: (h) => path39.join(h, ".copilot", "hooks", "node9.json"),
27827
+ hookFile: (h) => path40.join(h, ".copilot", "hooks", "node9.json"),
27679
27828
  hookFormat: "flat",
27680
27829
  hookEvents: [ck("PreToolUse"), lg("PostToolUse"), ck("UserPromptSubmit")],
27681
- mcpFile: (h) => path39.join(h, ".copilot", "mcp-config.json"),
27682
- present: (h) => exists(path39.join(h, ".copilot"))
27830
+ mcpFile: (h) => path40.join(h, ".copilot", "mcp-config.json"),
27831
+ present: (h) => exists(path40.join(h, ".copilot"))
27683
27832
  },
27684
27833
  {
27685
27834
  id: "cursor",
@@ -27688,8 +27837,8 @@ var init_agent_wiring = __esm({
27688
27837
  // MCP-only — no hook file (see note above).
27689
27838
  hookFormat: "flat",
27690
27839
  hookEvents: [],
27691
- mcpFile: (h) => path39.join(h, ".cursor", "mcp.json"),
27692
- present: (h) => exists(path39.join(h, ".cursor", "mcp.json"))
27840
+ mcpFile: (h) => path40.join(h, ".cursor", "mcp.json"),
27841
+ present: (h) => exists(path40.join(h, ".cursor", "mcp.json"))
27693
27842
  },
27694
27843
  {
27695
27844
  id: "hermes",
@@ -27710,8 +27859,8 @@ var init_agent_wiring = __esm({
27710
27859
  setupCommand: "node9 agents add opencode",
27711
27860
  hookFormat: "flat",
27712
27861
  hookEvents: [],
27713
- shimFile: (h) => path39.join(opencodeConfigDir(h), "plugins", "node9.js"),
27714
- present: (h) => exists(opencodeConfigDir(h)) || exists(path39.join(opencodeConfigDir(h), "plugins", "node9.js"))
27862
+ shimFile: (h) => path40.join(opencodeConfigDir(h), "plugins", "node9.js"),
27863
+ present: (h) => exists(opencodeConfigDir(h)) || exists(path40.join(opencodeConfigDir(h), "plugins", "node9.js"))
27715
27864
  },
27716
27865
  {
27717
27866
  id: "pi",
@@ -27719,8 +27868,8 @@ var init_agent_wiring = __esm({
27719
27868
  setupCommand: "node9 agents add pi",
27720
27869
  hookFormat: "flat",
27721
27870
  hookEvents: [],
27722
- shimFile: (h) => path39.join(h, ".pi", "agent", "extensions", "node9.js"),
27723
- present: (h) => exists(path39.join(h, ".pi", "agent")) || exists(path39.join(h, ".pi", "agent", "extensions", "node9.js"))
27871
+ shimFile: (h) => path40.join(h, ".pi", "agent", "extensions", "node9.js"),
27872
+ present: (h) => exists(path40.join(h, ".pi", "agent")) || exists(path40.join(h, ".pi", "agent", "extensions", "node9.js"))
27724
27873
  }
27725
27874
  ];
27726
27875
  }
@@ -27771,14 +27920,14 @@ var init_codex_trust = __esm({
27771
27920
  });
27772
27921
 
27773
27922
  // src/daemon/hook-baseline.ts
27774
- import path40 from "path";
27923
+ import path41 from "path";
27775
27924
  import os28 from "os";
27776
27925
  var BASELINE_FILE, NOTIFIED_FILE;
27777
27926
  var init_hook_baseline = __esm({
27778
27927
  "src/daemon/hook-baseline.ts"() {
27779
27928
  "use strict";
27780
- BASELINE_FILE = path40.join(os28.homedir(), ".node9", "hooks-baseline.json");
27781
- NOTIFIED_FILE = path40.join(os28.homedir(), ".node9", "hook-heal-notified.json");
27929
+ BASELINE_FILE = path41.join(os28.homedir(), ".node9", "hooks-baseline.json");
27930
+ NOTIFIED_FILE = path41.join(os28.homedir(), ".node9", "hook-heal-notified.json");
27782
27931
  }
27783
27932
  });
27784
27933
 
@@ -27797,7 +27946,7 @@ var init_setup_pi_shim = __esm({
27797
27946
  });
27798
27947
 
27799
27948
  // src/setup.ts
27800
- import path41 from "path";
27949
+ import path42 from "path";
27801
27950
  import os29 from "os";
27802
27951
  import chalk3 from "chalk";
27803
27952
  import { confirm as rawConfirm } from "@inquirer/prompts";
@@ -27805,16 +27954,16 @@ import { parse as parseToml5, stringify as stringifyToml2 } from "smol-toml";
27805
27954
  import * as yaml2 from "yaml";
27806
27955
  function opencodeConfigDir(home = os29.homedir()) {
27807
27956
  const xdg = process.env.XDG_CONFIG_HOME;
27808
- const base2 = xdg && path41.isAbsolute(xdg) ? xdg : path41.join(home, ".config");
27809
- return path41.join(base2, "opencode");
27957
+ const base2 = xdg && path42.isAbsolute(xdg) ? xdg : path42.join(home, ".config");
27958
+ return path42.join(base2, "opencode");
27810
27959
  }
27811
27960
  function hermesHomeDir(homeDir = os29.homedir()) {
27812
27961
  const env = process.env.HERMES_HOME?.trim();
27813
- if (env && path41.isAbsolute(env)) return env;
27814
- return path41.join(homeDir, ".hermes");
27962
+ if (env && path42.isAbsolute(env)) return env;
27963
+ return path42.join(homeDir, ".hermes");
27815
27964
  }
27816
27965
  function hermesConfigPath(homeDir = os29.homedir()) {
27817
- return path41.join(hermesHomeDir(homeDir), HERMES_CONFIG_FILENAME);
27966
+ return path42.join(hermesHomeDir(homeDir), HERMES_CONFIG_FILENAME);
27818
27967
  }
27819
27968
  var HERMES_CONFIG_FILENAME;
27820
27969
  var init_setup = __esm({
@@ -27860,7 +28009,7 @@ var init_scan_history = __esm({
27860
28009
  // src/cli/commands/scan.ts
27861
28010
  import chalk5 from "chalk";
27862
28011
  import fs38 from "fs";
27863
- import path42 from "path";
28012
+ import path43 from "path";
27864
28013
  import os30 from "os";
27865
28014
  import stringWidth2 from "string-width";
27866
28015
  function dayKey(ts) {
@@ -28074,7 +28223,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
28074
28223
  const session = { sessionId, costUSD: 0, toolCalls: 0 };
28075
28224
  let raw;
28076
28225
  try {
28077
- raw = fs38.readFileSync(path42.join(projPath, file2), "utf-8");
28226
+ raw = fs38.readFileSync(path43.join(projPath, file2), "utf-8");
28078
28227
  } catch {
28079
28228
  return false;
28080
28229
  }
@@ -28143,7 +28292,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
28143
28292
  if (block.type !== "tool_result") continue;
28144
28293
  const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
28145
28294
  if (filePath) {
28146
- const ext = path42.extname(filePath).toLowerCase();
28295
+ const ext = path43.extname(filePath).toLowerCase();
28147
28296
  if (CODE_EXTENSIONS.has(ext)) continue;
28148
28297
  }
28149
28298
  const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
@@ -28263,7 +28412,7 @@ async function processClaudeFile(file2, projPath, projLabel, judge, judgeFrom, r
28263
28412
  return true;
28264
28413
  }
28265
28414
  async function processClaudeProjectAsync(proj, projectsDir, judge, cache7, startDate, result, dedup, canaryVals, onProgress, onLine) {
28266
- const projPath = path42.join(projectsDir, proj);
28415
+ const projPath = path43.join(projectsDir, proj);
28267
28416
  try {
28268
28417
  if (!fs38.statSync(projPath).isDirectory()) return;
28269
28418
  } catch {
@@ -28277,7 +28426,7 @@ async function processClaudeProjectAsync(proj, projectsDir, judge, cache7, start
28277
28426
  return;
28278
28427
  }
28279
28428
  for (const file2 of files) {
28280
- const filePath = path42.join(projPath, file2);
28429
+ const filePath = path43.join(projPath, file2);
28281
28430
  const stamp = fileStamp(filePath);
28282
28431
  if (!fileMayHoldWindow(stamp, startDate)) continue;
28283
28432
  result.filesScanned++;
@@ -28420,7 +28569,7 @@ function mergeFileScan(result, file2, dedup, startDate = null) {
28420
28569
  }
28421
28570
  }
28422
28571
  async function scanClaudeHistoryAsync(startDate, onProgress, onLine, opts = {}) {
28423
- const projectsDir = path42.join(os30.homedir(), ".claude", "projects");
28572
+ const projectsDir = path43.join(os30.homedir(), ".claude", "projects");
28424
28573
  const result = emptyClaudeScan();
28425
28574
  if (!fs38.existsSync(projectsDir)) return result;
28426
28575
  let projDirs;
@@ -28453,7 +28602,7 @@ async function scanClaudeHistoryAsync(startDate, onProgress, onLine, opts = {})
28453
28602
  }
28454
28603
  async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
28455
28604
  const canaryVals = safeCanaryScanValues();
28456
- const tmpDir = path42.join(os30.homedir(), ".gemini", "tmp");
28605
+ const tmpDir = path43.join(os30.homedir(), ".gemini", "tmp");
28457
28606
  const result = {
28458
28607
  filesScanned: 0,
28459
28608
  sessions: 0,
@@ -28480,7 +28629,7 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
28480
28629
  const judge = new HistoryJudge();
28481
28630
  const cache7 = openScanCache(judge, opts);
28482
28631
  for (const slug2 of slugDirs) {
28483
- const slugPath = path42.join(tmpDir, slug2);
28632
+ const slugPath = path43.join(tmpDir, slug2);
28484
28633
  try {
28485
28634
  if (!fs38.statSync(slugPath).isDirectory()) continue;
28486
28635
  } catch {
@@ -28489,11 +28638,11 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
28489
28638
  let projLabel = stripTerminalEscapes(slug2).slice(0, 40);
28490
28639
  try {
28491
28640
  projLabel = stripTerminalEscapes(
28492
- fs38.readFileSync(path42.join(slugPath, ".project_root"), "utf-8").trim()
28641
+ fs38.readFileSync(path43.join(slugPath, ".project_root"), "utf-8").trim()
28493
28642
  ).replace(os30.homedir(), "~").slice(0, 40);
28494
28643
  } catch {
28495
28644
  }
28496
- const chatsDir = path42.join(slugPath, "chats");
28645
+ const chatsDir = path43.join(slugPath, "chats");
28497
28646
  if (!fs38.existsSync(chatsDir)) continue;
28498
28647
  let chatFiles;
28499
28648
  try {
@@ -28503,7 +28652,7 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
28503
28652
  }
28504
28653
  for (const chatFile of chatFiles) {
28505
28654
  const sessionId = chatFile.replace(/\.jsonl?$/, "");
28506
- const filePath = path42.join(chatsDir, chatFile);
28655
+ const filePath = path43.join(chatsDir, chatFile);
28507
28656
  const stamp = fileStamp(filePath);
28508
28657
  if (!fileMayHoldWindow(stamp, startDate)) continue;
28509
28658
  result.filesScanned++;
@@ -28517,7 +28666,7 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
28517
28666
  const fileDedup = emptyScanDedup();
28518
28667
  let raw;
28519
28668
  try {
28520
- raw = fs38.readFileSync(path42.join(chatsDir, chatFile), "utf-8");
28669
+ raw = fs38.readFileSync(path43.join(chatsDir, chatFile), "utf-8");
28521
28670
  } catch {
28522
28671
  continue;
28523
28672
  }
@@ -28653,6 +28802,360 @@ async function scanGeminiHistory(startDate, onProgress, onLine, opts = {}) {
28653
28802
  result.policy = judge.policy(result.unknownInputs ?? {});
28654
28803
  return result;
28655
28804
  }
28805
+ function antigravityBrainDirs() {
28806
+ return ["antigravity-cli", "antigravity-ide"].map((surface) => path43.join(os30.homedir(), ".gemini", surface, "brain")).filter((p) => fs38.existsSync(p));
28807
+ }
28808
+ function antigravityTranscriptPath(convPath) {
28809
+ const logsDir = path43.join(convPath, ".system_generated", "logs");
28810
+ for (const name of ["transcript_full.jsonl", "transcript.jsonl"]) {
28811
+ const p = path43.join(logsDir, name);
28812
+ if (fs38.existsSync(p)) return p;
28813
+ }
28814
+ return null;
28815
+ }
28816
+ async function scanAntigravityHistory(startDate, onProgress, onLine, opts = {}) {
28817
+ const canaryVals = safeCanaryScanValues();
28818
+ const result = {
28819
+ filesScanned: 0,
28820
+ sessions: 0,
28821
+ totalToolCalls: 0,
28822
+ bashCalls: 0,
28823
+ findings: [],
28824
+ dlpFindings: [],
28825
+ canaryFindings: [],
28826
+ loopFindings: [],
28827
+ totalCostUSD: 0,
28828
+ // transcripts carry no token/model data
28829
+ firstDate: null,
28830
+ lastDate: null,
28831
+ sessionsWithEarlySecrets: 0,
28832
+ perSession: []
28833
+ };
28834
+ const dedup = emptyScanDedup();
28835
+ const brainDirs = antigravityBrainDirs();
28836
+ if (brainDirs.length === 0) return result;
28837
+ const judge = new HistoryJudge();
28838
+ const cache7 = openScanCache(judge, opts);
28839
+ for (const brainDir of brainDirs) {
28840
+ let convDirs;
28841
+ try {
28842
+ convDirs = fs38.readdirSync(brainDir);
28843
+ } catch {
28844
+ continue;
28845
+ }
28846
+ for (const conv of convDirs) {
28847
+ const convPath = path43.join(brainDir, conv);
28848
+ try {
28849
+ if (!fs38.statSync(convPath).isDirectory()) continue;
28850
+ } catch {
28851
+ continue;
28852
+ }
28853
+ const transcriptFile = antigravityTranscriptPath(convPath);
28854
+ if (!transcriptFile) continue;
28855
+ const stamp = fileStamp(transcriptFile);
28856
+ if (!fileMayHoldWindow(stamp, startDate)) continue;
28857
+ result.filesScanned++;
28858
+ onProgress?.(result.filesScanned);
28859
+ const cached = stamp ? cache7.get(transcriptFile, stamp, judge, judgeFromFor(startDate)) : null;
28860
+ if (cached) {
28861
+ mergeFileScan(result, cached, dedup, startDate);
28862
+ continue;
28863
+ }
28864
+ const fileResult = emptyScan();
28865
+ const fileDedup = emptyScanDedup();
28866
+ let raw;
28867
+ try {
28868
+ raw = fs38.readFileSync(transcriptFile, "utf-8");
28869
+ } catch {
28870
+ continue;
28871
+ }
28872
+ const sessionId = conv;
28873
+ let projLabel = conv.slice(0, 8);
28874
+ const sessionCalls = [];
28875
+ for (const line of raw.split("\n")) {
28876
+ if (!line.trim()) continue;
28877
+ onLine?.();
28878
+ let step;
28879
+ try {
28880
+ step = JSON.parse(line);
28881
+ } catch {
28882
+ continue;
28883
+ }
28884
+ const timestamp2 = step.created_at ?? "";
28885
+ if (beforeJudged(judgeFromFor(startDate), timestamp2 || void 0)) continue;
28886
+ const day = dayOf(fileResult, timestamp2 || void 0);
28887
+ if (fileResult.sessions === 0) fileResult.sessions = 1;
28888
+ if (step.type === "USER_INPUT") {
28889
+ const text = typeof step.content === "string" ? step.content : "";
28890
+ if (text) {
28891
+ const decoysHere5 = recordCanaries(
28892
+ { text },
28893
+ "user-prompt",
28894
+ timestamp2,
28895
+ projLabel,
28896
+ sessionId,
28897
+ "antigravity",
28898
+ fileResult,
28899
+ fileDedup,
28900
+ canaryVals
28901
+ );
28902
+ const dlpMatch = scanArgs(scrubDecoys({ text }, decoysHere5));
28903
+ if (dlpMatch) {
28904
+ const k = dlpKey(dlpMatch.patternName, dlpMatch.redactedSample, projLabel, timestamp2);
28905
+ if (!fileDedup.dlpKeys.has(k)) {
28906
+ fileDedup.dlpKeys.add(k);
28907
+ fileResult.dlpFindings.push({
28908
+ patternName: dlpMatch.patternName,
28909
+ redactedSample: dlpMatch.redactedSample,
28910
+ toolName: "user-prompt",
28911
+ timestamp: timestamp2,
28912
+ project: projLabel,
28913
+ sessionId,
28914
+ agent: "antigravity"
28915
+ });
28916
+ }
28917
+ }
28918
+ }
28919
+ continue;
28920
+ }
28921
+ if (!Array.isArray(step.tool_calls) || step.tool_calls.length === 0) continue;
28922
+ if (timestamp2) {
28923
+ if (!fileResult.firstDate || timestamp2 < fileResult.firstDate)
28924
+ fileResult.firstDate = timestamp2;
28925
+ if (!fileResult.lastDate || timestamp2 > fileResult.lastDate)
28926
+ fileResult.lastDate = timestamp2;
28927
+ }
28928
+ for (const tc of step.tool_calls) {
28929
+ fileResult.totalToolCalls++;
28930
+ day.toolCalls++;
28931
+ const toolName = tc.name ?? "";
28932
+ countMcpCall(fileResult, toolName, day);
28933
+ const toolNameLower = toolName.toLowerCase();
28934
+ const input = canonicalToolInput(toolName, tc.args ?? {});
28935
+ sessionCalls.push({ toolName, input, timestamp: timestamp2 });
28936
+ const shellInput = resolveShellInput(toolNameLower, input, toolInspectionMap);
28937
+ const isShellTool = shellInput.kind === "shell";
28938
+ if (isShellTool) {
28939
+ fileResult.bashCalls++;
28940
+ day.bashCalls++;
28941
+ const cwd = String(input.cwd ?? "");
28942
+ if (cwd && projLabel === conv.slice(0, 8)) {
28943
+ projLabel = stripTerminalEscapes(cwd).replace(os30.homedir(), "~").slice(0, 40);
28944
+ }
28945
+ }
28946
+ const rawCmd = String(input.command ?? "").trimStart();
28947
+ if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd))
28948
+ continue;
28949
+ const decoysHere6 = recordCanaries(
28950
+ input,
28951
+ toolName,
28952
+ timestamp2,
28953
+ projLabel,
28954
+ sessionId,
28955
+ "antigravity",
28956
+ fileResult,
28957
+ fileDedup,
28958
+ canaryVals
28959
+ );
28960
+ const judged = await judge.judge(
28961
+ {
28962
+ agent: "antigravity",
28963
+ toolName,
28964
+ input,
28965
+ scrubbed: decoysHere6.length ? scrubDecoys(input, decoysHere6) : void 0,
28966
+ timestamp: timestamp2,
28967
+ sessionId,
28968
+ project: projLabel,
28969
+ cwd: typeof input.cwd === "string" && path43.isAbsolute(input.cwd) ? input.cwd : void 0
28970
+ },
28971
+ fileResult,
28972
+ fileDedup
28973
+ );
28974
+ addUnknown(day, judged.verdict.unknown);
28975
+ }
28976
+ }
28977
+ fileResult.loopFindings.push(
28978
+ ...detectLoops(sessionCalls, projLabel, sessionId, "antigravity")
28979
+ );
28980
+ if (stamp)
28981
+ cache7.put(transcriptFile, stamp, "antigravity", fileResult, judge, judgeFromFor(startDate));
28982
+ mergeFileScan(result, fileResult, dedup, startDate);
28983
+ await yieldTick();
28984
+ }
28985
+ }
28986
+ cache7.close();
28987
+ result.policy = judge.policy(result.unknownInputs ?? {});
28988
+ return result;
28989
+ }
28990
+ async function scanCopilotHistory(startDate, onProgress, onLine, opts = {}) {
28991
+ const canaryVals = safeCanaryScanValues();
28992
+ const sessionDir = path43.join(os30.homedir(), ".copilot", "session-state");
28993
+ const result = {
28994
+ filesScanned: 0,
28995
+ sessions: 0,
28996
+ totalToolCalls: 0,
28997
+ bashCalls: 0,
28998
+ findings: [],
28999
+ dlpFindings: [],
29000
+ canaryFindings: [],
29001
+ loopFindings: [],
29002
+ totalCostUSD: 0,
29003
+ // event logs carry no token/cost rollup
29004
+ firstDate: null,
29005
+ lastDate: null,
29006
+ sessionsWithEarlySecrets: 0,
29007
+ perSession: []
29008
+ };
29009
+ const dedup = emptyScanDedup();
29010
+ if (!fs38.existsSync(sessionDir)) return result;
29011
+ let sessionIds;
29012
+ try {
29013
+ sessionIds = fs38.readdirSync(sessionDir);
29014
+ } catch {
29015
+ return result;
29016
+ }
29017
+ const judge = new HistoryJudge();
29018
+ const cache7 = openScanCache(judge, opts);
29019
+ for (const sessionId of sessionIds) {
29020
+ const eventsPath = path43.join(sessionDir, sessionId, "events.jsonl");
29021
+ if (!fs38.existsSync(eventsPath)) continue;
29022
+ const stamp = fileStamp(eventsPath);
29023
+ if (!fileMayHoldWindow(stamp, startDate)) continue;
29024
+ result.filesScanned++;
29025
+ onProgress?.(result.filesScanned);
29026
+ const cached = stamp ? cache7.get(eventsPath, stamp, judge, judgeFromFor(startDate)) : null;
29027
+ if (cached) {
29028
+ mergeFileScan(result, cached, dedup, startDate);
29029
+ continue;
29030
+ }
29031
+ const fileResult = emptyScan();
29032
+ const fileDedup = emptyScanDedup();
29033
+ let raw;
29034
+ try {
29035
+ raw = fs38.readFileSync(eventsPath, "utf-8");
29036
+ } catch {
29037
+ continue;
29038
+ }
29039
+ let projLabel = sessionId.slice(0, 8);
29040
+ let sessionCwd;
29041
+ const sessionCalls = [];
29042
+ for (const row of parseCopilotSession(raw.split("\n"))) {
29043
+ if (beforeJudged(judgeFromFor(startDate), row.date || void 0)) continue;
29044
+ fileResult.totalCostUSD += row.costUSD;
29045
+ dayOf(fileResult, row.date || void 0, false).costUSD += row.costUSD;
29046
+ }
29047
+ for (const line of raw.split("\n")) {
29048
+ if (!line.trim()) continue;
29049
+ onLine?.();
29050
+ let ev;
29051
+ try {
29052
+ ev = JSON.parse(line);
29053
+ } catch {
29054
+ continue;
29055
+ }
29056
+ const timestamp2 = ev.timestamp ?? "";
29057
+ if (ev.type === "session.start") {
29058
+ const cwd = ev.data?.context?.cwd;
29059
+ if (typeof cwd === "string" && cwd) {
29060
+ projLabel = stripTerminalEscapes(cwd).replace(os30.homedir(), "~").slice(0, 40);
29061
+ if (path43.isAbsolute(cwd)) sessionCwd = cwd;
29062
+ }
29063
+ continue;
29064
+ }
29065
+ if (beforeJudged(judgeFromFor(startDate), timestamp2 || void 0)) continue;
29066
+ const day = dayOf(fileResult, timestamp2 || void 0);
29067
+ if (fileResult.sessions === 0) fileResult.sessions = 1;
29068
+ if (ev.type === "user.message") {
29069
+ const text = ev.data?.content ?? ev.data?.text ?? "";
29070
+ if (typeof text === "string" && text) {
29071
+ const decoysHere7 = recordCanaries(
29072
+ { text },
29073
+ "user-prompt",
29074
+ timestamp2,
29075
+ projLabel,
29076
+ sessionId,
29077
+ "copilot",
29078
+ fileResult,
29079
+ fileDedup,
29080
+ canaryVals
29081
+ );
29082
+ const dlpMatch = scanArgs(scrubDecoys({ text }, decoysHere7));
29083
+ if (dlpMatch) {
29084
+ const k = dlpKey(dlpMatch.patternName, dlpMatch.redactedSample, projLabel, timestamp2);
29085
+ if (!fileDedup.dlpKeys.has(k)) {
29086
+ fileDedup.dlpKeys.add(k);
29087
+ fileResult.dlpFindings.push({
29088
+ patternName: dlpMatch.patternName,
29089
+ redactedSample: dlpMatch.redactedSample,
29090
+ toolName: "user-prompt",
29091
+ timestamp: timestamp2,
29092
+ project: projLabel,
29093
+ sessionId,
29094
+ agent: "copilot"
29095
+ });
29096
+ }
29097
+ }
29098
+ }
29099
+ continue;
29100
+ }
29101
+ if (ev.type !== "tool.execution_start") continue;
29102
+ const toolName = ev.data?.toolName ?? "";
29103
+ const toolNameLower = toolName.toLowerCase();
29104
+ const input = ev.data?.arguments ?? {};
29105
+ fileResult.totalToolCalls++;
29106
+ day.toolCalls++;
29107
+ countMcpCall(fileResult, toolName, day);
29108
+ sessionCalls.push({ toolName, input, timestamp: timestamp2 });
29109
+ const shellInput = resolveShellInput(toolNameLower, input, toolInspectionMap);
29110
+ const isShellTool = shellInput.kind === "shell";
29111
+ if (isShellTool) {
29112
+ fileResult.bashCalls++;
29113
+ day.bashCalls++;
29114
+ }
29115
+ if (timestamp2) {
29116
+ if (!fileResult.firstDate || timestamp2 < fileResult.firstDate)
29117
+ fileResult.firstDate = timestamp2;
29118
+ if (!fileResult.lastDate || timestamp2 > fileResult.lastDate)
29119
+ fileResult.lastDate = timestamp2;
29120
+ }
29121
+ const rawCmd = String(input.command ?? "").trimStart();
29122
+ if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
29123
+ const decoysHere8 = recordCanaries(
29124
+ input,
29125
+ toolName,
29126
+ timestamp2,
29127
+ projLabel,
29128
+ sessionId,
29129
+ "copilot",
29130
+ fileResult,
29131
+ fileDedup,
29132
+ canaryVals
29133
+ );
29134
+ const judged = await judge.judge(
29135
+ {
29136
+ agent: "copilot",
29137
+ toolName,
29138
+ input,
29139
+ scrubbed: decoysHere8.length ? scrubDecoys(input, decoysHere8) : void 0,
29140
+ timestamp: timestamp2,
29141
+ sessionId,
29142
+ project: projLabel,
29143
+ cwd: sessionCwd
29144
+ },
29145
+ fileResult,
29146
+ fileDedup
29147
+ );
29148
+ addUnknown(day, judged.verdict.unknown);
29149
+ }
29150
+ fileResult.loopFindings.push(...detectLoops(sessionCalls, projLabel, sessionId, "copilot"));
29151
+ if (stamp) cache7.put(eventsPath, stamp, "copilot", fileResult, judge, judgeFromFor(startDate));
29152
+ mergeFileScan(result, fileResult, dedup, startDate);
29153
+ await yieldTick();
29154
+ }
29155
+ cache7.close();
29156
+ result.policy = judge.policy(result.unknownInputs ?? {});
29157
+ return result;
29158
+ }
28656
29159
  async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
28657
29160
  const canaryVals = safeCanaryScanValues();
28658
29161
  const result = {
@@ -28712,7 +29215,7 @@ async function scanCodexHistory(startDate, onProgress, onLine, opts = {}) {
28712
29215
  startTime = String(payload["timestamp"] ?? "");
28713
29216
  const cwd = String(payload["cwd"] ?? "");
28714
29217
  projLabel = stripTerminalEscapes(cwd.replace(os30.homedir(), "~")).slice(0, 40);
28715
- if (path42.isAbsolute(cwd)) sessionCwd = cwd;
29218
+ if (path43.isAbsolute(cwd)) sessionCwd = cwd;
28716
29219
  continue;
28717
29220
  }
28718
29221
  if (entry.type === "event_msg" && payload["type"] === "user_message") {
@@ -28912,10 +29415,10 @@ var init_scan = __esm({
28912
29415
  // src/tui/dashboard/data.ts
28913
29416
  import fs39 from "fs";
28914
29417
  import os31 from "os";
28915
- import path43 from "path";
29418
+ import path44 from "path";
28916
29419
  import http2 from "http";
28917
29420
  function auditLogPath() {
28918
- return path43.join(os31.homedir(), ".node9", "audit.log");
29421
+ return path44.join(os31.homedir(), ".node9", "audit.log");
28919
29422
  }
28920
29423
  function readAuditEntriesAsync(chunkSize = 1e3, customPath) {
28921
29424
  return new Promise((resolve) => {
@@ -29062,9 +29565,9 @@ function shortenPath(p) {
29062
29565
  return p.startsWith(home) ? p.replace(home, "~") : p;
29063
29566
  }
29064
29567
  async function loadReportAuditAsync(period) {
29065
- const claudeProjectsDir = path43.join(os31.homedir(), ".claude", "projects");
29568
+ const claudeProjectsDir = path44.join(os31.homedir(), ".claude", "projects");
29066
29569
  const codexSessionsDir2 = codexSessionsDir();
29067
- const geminiTmpDir = path43.join(os31.homedir(), ".gemini", "tmp");
29570
+ const geminiTmpDir = path44.join(os31.homedir(), ".gemini", "tmp");
29068
29571
  const { start, end } = getDateRange(period, /* @__PURE__ */ new Date());
29069
29572
  const entries = await readAuditEntriesAsync();
29070
29573
  void ensurePricingLoaded();
@@ -29103,9 +29606,17 @@ function startScanWalk(onUpdate) {
29103
29606
  if (cancelled) return;
29104
29607
  const codex = await scanCodexHistory(lookbackStart);
29105
29608
  if (cancelled) return;
29609
+ await yieldToEventLoop();
29610
+ if (cancelled) return;
29611
+ const copilot = await scanCopilotHistory(lookbackStart);
29612
+ if (cancelled) return;
29613
+ await yieldToEventLoop();
29614
+ if (cancelled) return;
29615
+ const antigravity = await scanAntigravityHistory(lookbackStart);
29616
+ if (cancelled) return;
29106
29617
  onUpdate({
29107
29618
  status: "ready",
29108
- results: { claude, gemini, codex },
29619
+ results: { claude, gemini, codex, copilot, antigravity },
29109
29620
  readyAt: Date.now()
29110
29621
  });
29111
29622
  } catch (err) {
@@ -30034,7 +30545,7 @@ var init_util = __esm({
30034
30545
  BLOCK_REASON_LABELS = {
30035
30546
  timeout: "Approval timeout",
30036
30547
  "smart-rule-block": "Smart rule",
30037
- "observe-mode-dlp-would-block": "DLP (observe)",
30548
+ "observe-mode-dlp-would-block": "DLP (audit)",
30038
30549
  "persistent-deny": "Persistent deny",
30039
30550
  "local-decision": "User denied",
30040
30551
  "dlp-block": "DLP block",
@@ -30176,8 +30687,8 @@ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-run
30176
30687
  function TopToolsProjects({ audit }) {
30177
30688
  const data = audit?.data;
30178
30689
  const tools = data ? [...data.toolMap.entries()].sort(([, a], [, b]) => b.calls - a.calls).slice(0, ROW_LIMIT) : [];
30179
- const projects = data ? [...data.cost.byProject.entries()].map(([path44, r]) => ({
30180
- name: basenameOf(path44),
30690
+ const projects = data ? [...data.cost.byProject.entries()].map(([path45, r]) => ({
30691
+ name: basenameOf(path45),
30181
30692
  cost: r.cost,
30182
30693
  tokens: r.inputTokens + r.outputTokens
30183
30694
  })).sort((a, b) => b.cost - a.cost).slice(0, ROW_LIMIT) : [];
@@ -30546,23 +31057,12 @@ function filterScanByPeriod(ready, period, now = /* @__PURE__ */ new Date()) {
30546
31057
  if (Number.isNaN(t)) return false;
30547
31058
  return t >= startMs && t <= endMs;
30548
31059
  };
30549
- const allLeaks = [
30550
- ...ready.results.claude.dlpFindings,
30551
- ...ready.results.gemini.dlpFindings,
30552
- ...ready.results.codex.dlpFindings
30553
- ].filter((f) => inPeriod(f.timestamp));
30554
- const allLoops = [
30555
- ...ready.results.claude.loopFindings,
30556
- ...ready.results.gemini.loopFindings,
30557
- ...ready.results.codex.loopFindings
30558
- ].filter((f) => inPeriod(f.timestamp));
30559
- const allFindings = [
30560
- ...ready.results.claude.findings,
30561
- ...ready.results.gemini.findings,
30562
- ...ready.results.codex.findings
30563
- ].filter((f) => inPeriod(f.timestamp));
30564
- const totalToolCalls = ready.results.claude.totalToolCalls + ready.results.gemini.totalToolCalls + ready.results.codex.totalToolCalls;
30565
- const sessionsWithEarlySecrets = ready.results.claude.sessionsWithEarlySecrets + ready.results.gemini.sessionsWithEarlySecrets + ready.results.codex.sessionsWithEarlySecrets;
31060
+ const slots = Object.values(ready.results);
31061
+ const allLeaks = slots.flatMap((r) => r.dlpFindings).filter((f) => inPeriod(f.timestamp));
31062
+ const allLoops = slots.flatMap((r) => r.loopFindings).filter((f) => inPeriod(f.timestamp));
31063
+ const allFindings = slots.flatMap((r) => r.findings).filter((f) => inPeriod(f.timestamp));
31064
+ const totalToolCalls = slots.reduce((n, r) => n + r.totalToolCalls, 0);
31065
+ const sessionsWithEarlySecrets = slots.reduce((n, r) => n + r.sessionsWithEarlySecrets, 0);
30566
31066
  return {
30567
31067
  leaks: allLeaks,
30568
31068
  loops: allLoops,
@@ -30614,8 +31114,8 @@ function pickTopLoopFile(loops) {
30614
31114
  map.set(k, (map.get(k) ?? 0) + (l.count ?? 0));
30615
31115
  }
30616
31116
  if (map.size === 0) return void 0;
30617
- const [path44, count] = [...map.entries()].sort((a, b) => b[1] - a[1])[0];
30618
- return { path: path44, count };
31117
+ const [path45, count] = [...map.entries()].sort((a, b) => b[1] - a[1])[0];
31118
+ return { path: path45, count };
30619
31119
  }
30620
31120
  var EMPTY_FILTERED_SCAN;
30621
31121
  var init_derive = __esm({