@node9/proxy 2.7.0 → 2.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -228,9 +228,9 @@ function matchesPattern(text, patterns) {
228
228
  const withoutDotSlash = text.replace(/^\.\//, "");
229
229
  return isMatch(withoutDotSlash) || isMatch(`./${withoutDotSlash}`);
230
230
  }
231
- function getNestedValue(obj, path12) {
231
+ function getNestedValue(obj, path13) {
232
232
  if (!obj || typeof obj !== "object") return null;
233
- const segments = path12.split(".");
233
+ const segments = path13.split(".");
234
234
  for (const seg of segments) {
235
235
  if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
236
236
  }
@@ -712,7 +712,7 @@ function assertBuiltinShieldRegexesAreSafe() {
712
712
  }
713
713
  }
714
714
  }
715
- var ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, FS_OP_CACHE_MAX, fsOpCache, REDIR_TRUNCATE_OPS, REDIR_HEREDOC_OPS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, COST_PER_LOOP_ITER_USD, LONG_OUTPUT_THRESHOLD_BYTES;
715
+ var ASSIGNMENT_CONTEXT_RE, DLP_STOPWORDS, DLP_PATTERNS, DLP_PATTERNS_GLOBAL, SENSITIVE_PATH_PATTERNS, MAX_DEPTH, MAX_STRING_BYTES, MAX_JSON_PARSE_BYTES, MAX_REGEX_LENGTH, REGEX_CACHE_MAX, regexCache, FORBIDDEN_PATH_SEGMENTS, syntax, sharedParser, MESSAGE_FLAGS, SHELL_INTERPRETERS, DOWNLOAD_CMDS, NORMALIZE_CACHE_MAX, normalizeCache, AST_CACHE_MAX, astCache, PARSE_FAIL, FS_READ_TOOLS, FS_OP_PRESCREEN_RE, HOME_CACHE_ALLOWLIST, SENSITIVE_PATH_RULES, BASH_TOOL_NAMES, AST_FS_REGEX_RULES, FS_OP_CACHE_MAX, fsOpCache, REDIR_TRUNCATE_OPS, REDIR_HEREDOC_OPS, aws_default, bash_safe_default, docker_default, filesystem_default, github_default, k8s_default, mongodb_default, postgres_default, project_jail_default, redis_default, BUILTIN_SHIELDS, LONG_OUTPUT_THRESHOLD_BYTES;
716
716
  var init_dist = __esm({
717
717
  "packages/policy-engine/dist/index.mjs"() {
718
718
  "use strict";
@@ -2150,7 +2150,6 @@ var init_dist = __esm({
2150
2150
  [redis_default.name]: redis_default
2151
2151
  };
2152
2152
  assertBuiltinShieldRegexesAreSafe();
2153
- COST_PER_LOOP_ITER_USD = 6e-3;
2154
2153
  LONG_OUTPUT_THRESHOLD_BYTES = 100 * 1024;
2155
2154
  }
2156
2155
  });
@@ -2333,8 +2332,8 @@ function sanitizeConfig(raw) {
2333
2332
  }
2334
2333
  }
2335
2334
  const lines = result.error.issues.map((issue) => {
2336
- const path12 = issue.path.length > 0 ? issue.path.join(".") : "root";
2337
- return ` \u2022 ${path12}: ${issue.message}`;
2335
+ const path13 = issue.path.length > 0 ? issue.path.join(".") : "root";
2336
+ return ` \u2022 ${path13}: ${issue.message}`;
2338
2337
  });
2339
2338
  return {
2340
2339
  sanitized,
@@ -3213,13 +3212,13 @@ function getConfig(cwd) {
3213
3212
  }
3214
3213
  if (Array.isArray(mc.jailPaths)) {
3215
3214
  for (const jp of mc.jailPaths) {
3216
- const path12 = typeof jp?.path === "string" ? jp.path.trim() : "";
3217
- if (!path12) continue;
3215
+ const path13 = typeof jp?.path === "string" ? jp.path.trim() : "";
3216
+ if (!path13) continue;
3218
3217
  const verdict = jp?.verdict === "review" ? "review" : "block";
3219
- for (const r of pathRules(path12, verdict, "org-managed jail")) {
3218
+ for (const r of pathRules(path13, verdict, "org-managed jail")) {
3220
3219
  mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
3221
3220
  }
3222
- mergedPolicy.managedJailPaths.push({ path: path12, verdict });
3221
+ mergedPolicy.managedJailPaths.push({ path: path13, verdict });
3223
3222
  }
3224
3223
  }
3225
3224
  if (Array.isArray(mc.trustedHosts)) {
@@ -3718,14 +3717,15 @@ import os6 from "os";
3718
3717
  function normalizeModel(raw) {
3719
3718
  return raw.replace(/-\d{8}$/, "").toLowerCase();
3720
3719
  }
3721
- function readCache() {
3720
+ function readCache(opts) {
3722
3721
  try {
3723
3722
  const raw = JSON.parse(fs5.readFileSync(CACHE_FILE(), "utf-8"));
3724
3723
  if (typeof raw.fetchedAt !== "string" || typeof raw.prices !== "object" || raw.prices === null) {
3725
3724
  return null;
3726
3725
  }
3727
3726
  const ageMs = Date.now() - new Date(raw.fetchedAt).getTime();
3728
- if (ageMs < 0 || ageMs > TTL_MS) return null;
3727
+ if (!Number.isFinite(ageMs) || ageMs < 0) return null;
3728
+ if (opts.requireFresh && ageMs > TTL_MS) return null;
3729
3729
  return raw.prices;
3730
3730
  } catch {
3731
3731
  return null;
@@ -3791,7 +3791,7 @@ async function fetchLiteLLMPricing() {
3791
3791
  }
3792
3792
  async function ensurePricingLoaded() {
3793
3793
  if (memCache !== null && Date.now() - memCacheAt < TTL_MS) return;
3794
- const fromDisk = readCache();
3794
+ const fromDisk = readCache({ requireFresh: true });
3795
3795
  if (fromDisk && Object.keys(fromDisk).length > 0) {
3796
3796
  memCache = fromDisk;
3797
3797
  memCacheAt = Date.now();
@@ -3816,7 +3816,7 @@ function pricingFor(model) {
3816
3816
  if (cached !== void 0) return cached;
3817
3817
  if (memCache === null && !diskChecked) {
3818
3818
  diskChecked = true;
3819
- const disk = readCache();
3819
+ const disk = readCache({ requireFresh: false });
3820
3820
  if (disk && Object.keys(disk).length > 0) {
3821
3821
  memCache = disk;
3822
3822
  memCacheAt = Date.now();
@@ -3945,6 +3945,37 @@ var init_cost_copilot = __esm({
3945
3945
  }
3946
3946
  });
3947
3947
 
3948
+ // src/session-files.ts
3949
+ import * as fs6 from "fs";
3950
+ import * as path7 from "path";
3951
+ function listSessionFiles(dir, maxDepth = 6) {
3952
+ const out = [];
3953
+ const walk = (d, rel, depth) => {
3954
+ if (depth > maxDepth) return;
3955
+ let entries;
3956
+ try {
3957
+ entries = fs6.readdirSync(d, { withFileTypes: true });
3958
+ } catch {
3959
+ return;
3960
+ }
3961
+ for (const e of entries) {
3962
+ const childRel = rel ? path7.join(rel, e.name) : e.name;
3963
+ if (e.isDirectory()) walk(path7.join(d, e.name), childRel, depth + 1);
3964
+ else if (e.name.endsWith(".jsonl")) out.push(childRel);
3965
+ }
3966
+ };
3967
+ walk(dir, "", 0);
3968
+ return out;
3969
+ }
3970
+ function sessionIdOf(relPath) {
3971
+ return path7.basename(relPath).replace(/\.jsonl$/, "");
3972
+ }
3973
+ var init_session_files = __esm({
3974
+ "src/session-files.ts"() {
3975
+ "use strict";
3976
+ }
3977
+ });
3978
+
3948
3979
  // src/costSync.ts
3949
3980
  function decodeProjectDirName(dirName) {
3950
3981
  return dirName.replace(/-/g, "/");
@@ -3959,6 +3990,7 @@ var init_costSync = __esm({
3959
3990
  init_cost_codex();
3960
3991
  init_cost_gemini();
3961
3992
  init_cost_copilot();
3993
+ init_session_files();
3962
3994
  SYNC_INTERVAL_MS = 10 * 60 * 1e3;
3963
3995
  }
3964
3996
  });
@@ -4031,9 +4063,9 @@ var init_scan_watermark = __esm({
4031
4063
  });
4032
4064
 
4033
4065
  // src/cli/aggregate/report-audit.ts
4034
- import fs6 from "fs";
4066
+ import fs7 from "fs";
4035
4067
  import os7 from "os";
4036
- import path7 from "path";
4068
+ import path8 from "path";
4037
4069
  function buildTestTimestamps(allEntries) {
4038
4070
  const testTs = /* @__PURE__ */ new Set();
4039
4071
  for (const e of allEntries) {
@@ -4114,8 +4146,8 @@ function getDateRange(period, now) {
4114
4146
  }
4115
4147
  }
4116
4148
  function parseAuditLog(logPath) {
4117
- if (!fs6.existsSync(logPath)) return [];
4118
- const raw = fs6.readFileSync(logPath, "utf-8");
4149
+ if (!fs7.existsSync(logPath)) return [];
4150
+ const raw = fs7.readFileSync(logPath, "utf-8");
4119
4151
  return raw.split("\n").flatMap((line) => {
4120
4152
  if (!line.trim()) return [];
4121
4153
  try {
@@ -4169,25 +4201,25 @@ function freezeClaudeCost(acc) {
4169
4201
  };
4170
4202
  }
4171
4203
  function processClaudeCostProject(proj, projectsDir, start, end, acc) {
4172
- const projPath = path7.join(projectsDir, proj);
4204
+ const projPath = path8.join(projectsDir, proj);
4173
4205
  let files;
4174
4206
  try {
4175
- const stat = fs6.statSync(projPath);
4207
+ const stat = fs7.statSync(projPath);
4176
4208
  if (!stat.isDirectory()) return;
4177
- files = fs6.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
4209
+ files = listSessionFiles(projPath);
4178
4210
  } catch {
4179
4211
  return;
4180
4212
  }
4181
4213
  const startMs = start.getTime();
4182
4214
  for (const file of files) {
4183
- const filePath = path7.join(projPath, file);
4215
+ const filePath = path8.join(projPath, file);
4184
4216
  try {
4185
- if (fs6.statSync(filePath).mtimeMs < startMs) continue;
4217
+ if (fs7.statSync(filePath).mtimeMs < startMs) continue;
4186
4218
  } catch {
4187
4219
  continue;
4188
4220
  }
4189
4221
  try {
4190
- const raw = fs6.readFileSync(filePath, "utf-8");
4222
+ const raw = fs7.readFileSync(filePath, "utf-8");
4191
4223
  for (const line of raw.split("\n")) {
4192
4224
  if (!line.trim()) continue;
4193
4225
  let entry;
@@ -4237,10 +4269,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
4237
4269
  }
4238
4270
  function loadClaudeCost(start, end, projectsDir) {
4239
4271
  const acc = emptyClaudeCostAccumulator();
4240
- if (!fs6.existsSync(projectsDir)) return freezeClaudeCost(acc);
4272
+ if (!fs7.existsSync(projectsDir)) return freezeClaudeCost(acc);
4241
4273
  let dirs;
4242
4274
  try {
4243
- dirs = fs6.readdirSync(projectsDir);
4275
+ dirs = fs7.readdirSync(projectsDir);
4244
4276
  } catch {
4245
4277
  return freezeClaudeCost(acc);
4246
4278
  }
@@ -4251,10 +4283,10 @@ function loadClaudeCost(start, end, projectsDir) {
4251
4283
  }
4252
4284
  async function loadClaudeCostAsync(start, end, projectsDir) {
4253
4285
  const acc = emptyClaudeCostAccumulator();
4254
- if (!fs6.existsSync(projectsDir)) return freezeClaudeCost(acc);
4286
+ if (!fs7.existsSync(projectsDir)) return freezeClaudeCost(acc);
4255
4287
  let dirs;
4256
4288
  try {
4257
- dirs = fs6.readdirSync(projectsDir);
4289
+ dirs = fs7.readdirSync(projectsDir);
4258
4290
  } catch {
4259
4291
  return freezeClaudeCost(acc);
4260
4292
  }
@@ -4267,7 +4299,7 @@ async function loadClaudeCostAsync(start, end, projectsDir) {
4267
4299
  function processCodexCostFile(filePath, start, end, acc) {
4268
4300
  let lines;
4269
4301
  try {
4270
- lines = fs6.readFileSync(filePath, "utf-8").split("\n");
4302
+ lines = fs7.readFileSync(filePath, "utf-8").split("\n");
4271
4303
  } catch {
4272
4304
  return;
4273
4305
  }
@@ -4322,31 +4354,31 @@ function processCodexCostFile(filePath, start, end, acc) {
4322
4354
  }
4323
4355
  function listCodexSessionFiles(sessionsBase) {
4324
4356
  const jsonlFiles = [];
4325
- if (!fs6.existsSync(sessionsBase)) return jsonlFiles;
4357
+ if (!fs7.existsSync(sessionsBase)) return jsonlFiles;
4326
4358
  try {
4327
- for (const year of fs6.readdirSync(sessionsBase)) {
4328
- const yearPath = path7.join(sessionsBase, year);
4359
+ for (const year of fs7.readdirSync(sessionsBase)) {
4360
+ const yearPath = path8.join(sessionsBase, year);
4329
4361
  try {
4330
- if (!fs6.statSync(yearPath).isDirectory()) continue;
4362
+ if (!fs7.statSync(yearPath).isDirectory()) continue;
4331
4363
  } catch {
4332
4364
  continue;
4333
4365
  }
4334
- for (const month of fs6.readdirSync(yearPath)) {
4335
- const monthPath = path7.join(yearPath, month);
4366
+ for (const month of fs7.readdirSync(yearPath)) {
4367
+ const monthPath = path8.join(yearPath, month);
4336
4368
  try {
4337
- if (!fs6.statSync(monthPath).isDirectory()) continue;
4369
+ if (!fs7.statSync(monthPath).isDirectory()) continue;
4338
4370
  } catch {
4339
4371
  continue;
4340
4372
  }
4341
- for (const day of fs6.readdirSync(monthPath)) {
4342
- const dayPath = path7.join(monthPath, day);
4373
+ for (const day of fs7.readdirSync(monthPath)) {
4374
+ const dayPath = path8.join(monthPath, day);
4343
4375
  try {
4344
- if (!fs6.statSync(dayPath).isDirectory()) continue;
4376
+ if (!fs7.statSync(dayPath).isDirectory()) continue;
4345
4377
  } catch {
4346
4378
  continue;
4347
4379
  }
4348
- for (const file of fs6.readdirSync(dayPath)) {
4349
- if (file.endsWith(".jsonl")) jsonlFiles.push(path7.join(dayPath, file));
4380
+ for (const file of fs7.readdirSync(dayPath)) {
4381
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path8.join(dayPath, file));
4350
4382
  }
4351
4383
  }
4352
4384
  }
@@ -4427,13 +4459,13 @@ function freezeGeminiCost(acc) {
4427
4459
  function processGeminiCostFile(filePath, projectKey, start, end, acc) {
4428
4460
  const startMs = start.getTime();
4429
4461
  try {
4430
- if (fs6.statSync(filePath).mtimeMs < startMs) return;
4462
+ if (fs7.statSync(filePath).mtimeMs < startMs) return;
4431
4463
  } catch {
4432
4464
  return;
4433
4465
  }
4434
4466
  let raw;
4435
4467
  try {
4436
- raw = fs6.readFileSync(filePath, "utf-8");
4468
+ raw = fs7.readFileSync(filePath, "utf-8");
4437
4469
  } catch {
4438
4470
  return;
4439
4471
  }
@@ -4482,30 +4514,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
4482
4514
  const out = [];
4483
4515
  let dirs;
4484
4516
  try {
4485
- if (!fs6.statSync(geminiTmpDir).isDirectory()) return out;
4486
- dirs = fs6.readdirSync(geminiTmpDir);
4517
+ if (!fs7.statSync(geminiTmpDir).isDirectory()) return out;
4518
+ dirs = fs7.readdirSync(geminiTmpDir);
4487
4519
  } catch {
4488
4520
  return out;
4489
4521
  }
4490
4522
  for (const proj of dirs) {
4491
- const chatsDir = path7.join(geminiTmpDir, proj, "chats");
4523
+ const chatsDir = path8.join(geminiTmpDir, proj, "chats");
4492
4524
  let files;
4493
4525
  try {
4494
- if (!fs6.statSync(chatsDir).isDirectory()) continue;
4495
- files = fs6.readdirSync(chatsDir);
4526
+ if (!fs7.statSync(chatsDir).isDirectory()) continue;
4527
+ files = fs7.readdirSync(chatsDir);
4496
4528
  } catch {
4497
4529
  continue;
4498
4530
  }
4499
4531
  for (const f of files) {
4500
4532
  if (!f.endsWith(".jsonl")) continue;
4501
- out.push({ projectKey: proj, file: path7.join(chatsDir, f) });
4533
+ out.push({ projectKey: proj, file: path8.join(chatsDir, f) });
4502
4534
  }
4503
4535
  }
4504
4536
  return out;
4505
4537
  }
4506
4538
  function loadGeminiCost(start, end, geminiTmpDir) {
4507
4539
  const acc = emptyGeminiAccumulator();
4508
- if (!fs6.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
4540
+ if (!fs7.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
4509
4541
  for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
4510
4542
  processGeminiCostFile(file, projectKey, start, end, acc);
4511
4543
  }
@@ -4513,7 +4545,7 @@ function loadGeminiCost(start, end, geminiTmpDir) {
4513
4545
  }
4514
4546
  async function loadGeminiCostAsync(start, end, geminiTmpDir) {
4515
4547
  const acc = emptyGeminiAccumulator();
4516
- if (!fs6.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
4548
+ if (!fs7.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
4517
4549
  const files = listGeminiSessionFiles(geminiTmpDir);
4518
4550
  const CHUNK_SIZE = 5;
4519
4551
  for (let i = 0; i < files.length; i++) {
@@ -4536,11 +4568,11 @@ function dimensionOfBlock(checkedBy, ruleName) {
4536
4568
  }
4537
4569
  function aggregateReportFromAudit(period, opts = {}) {
4538
4570
  const now = opts.now ?? /* @__PURE__ */ new Date();
4539
- const auditLogPath2 = opts.auditLogPath ?? path7.join(os7.homedir(), ".node9", "audit.log");
4540
- const claudeProjectsDir = opts.claudeProjectsDir ?? path7.join(os7.homedir(), ".claude", "projects");
4541
- const codexSessionsDir = opts.codexSessionsDir ?? path7.join(os7.homedir(), ".codex", "sessions");
4542
- const geminiTmpDir = opts.geminiTmpDir ?? path7.join(os7.homedir(), ".gemini", "tmp");
4543
- const hasAuditFile = fs6.existsSync(auditLogPath2);
4571
+ const auditLogPath2 = opts.auditLogPath ?? path8.join(os7.homedir(), ".node9", "audit.log");
4572
+ const claudeProjectsDir = opts.claudeProjectsDir ?? path8.join(os7.homedir(), ".claude", "projects");
4573
+ const codexSessionsDir = opts.codexSessionsDir ?? path8.join(os7.homedir(), ".codex", "sessions");
4574
+ const geminiTmpDir = opts.geminiTmpDir ?? path8.join(os7.homedir(), ".gemini", "tmp");
4575
+ const hasAuditFile = fs7.existsSync(auditLogPath2);
4544
4576
  const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath2);
4545
4577
  const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
4546
4578
  const { start, end } = getDateRange(period, now);
@@ -4770,6 +4802,7 @@ var init_report_audit = __esm({
4770
4802
  init_litellm();
4771
4803
  init_cost_codex();
4772
4804
  init_decision();
4805
+ init_session_files();
4773
4806
  TEST_COMMAND_RE = /(?:^|\s)(npm\s+(?:run\s+)?test|npx\s+(?:vitest|jest|mocha)|yarn\s+(?:run\s+)?test|pnpm\s+(?:run\s+)?test|vitest|jest|mocha|pytest|py\.test|cargo\s+test|go\s+test|bundle\s+exec\s+rspec|rspec|phpunit|dotnet\s+test)\b/i;
4774
4807
  SUPERSEDE_WINDOW_MS = 6e4;
4775
4808
  GEMINI_FALLBACK_MODELS2 = ["gemini-2.5-flash", "gemini-2.0-flash"];
@@ -4777,18 +4810,18 @@ var init_report_audit = __esm({
4777
4810
  });
4778
4811
 
4779
4812
  // src/utils/provenance.ts
4780
- import path8 from "path";
4813
+ import path9 from "path";
4781
4814
  import os8 from "os";
4782
4815
  var USER_PREFIXES;
4783
4816
  var init_provenance = __esm({
4784
4817
  "src/utils/provenance.ts"() {
4785
4818
  "use strict";
4786
4819
  USER_PREFIXES = [
4787
- path8.join(os8.homedir(), "bin"),
4788
- path8.join(os8.homedir(), ".local", "bin"),
4789
- path8.join(os8.homedir(), ".cargo", "bin"),
4790
- path8.join(os8.homedir(), ".npm-global", "bin"),
4791
- path8.join(os8.homedir(), ".volta", "bin")
4820
+ path9.join(os8.homedir(), "bin"),
4821
+ path9.join(os8.homedir(), ".local", "bin"),
4822
+ path9.join(os8.homedir(), ".cargo", "bin"),
4823
+ path9.join(os8.homedir(), ".npm-global", "bin"),
4824
+ path9.join(os8.homedir(), ".volta", "bin")
4792
4825
  ];
4793
4826
  }
4794
4827
  });
@@ -4832,14 +4865,14 @@ var init_mcp_pin = __esm({
4832
4865
  });
4833
4866
 
4834
4867
  // src/daemon/hook-baseline.ts
4835
- import path9 from "path";
4868
+ import path10 from "path";
4836
4869
  import os9 from "os";
4837
4870
  var BASELINE_FILE, NOTIFIED_FILE;
4838
4871
  var init_hook_baseline = __esm({
4839
4872
  "src/daemon/hook-baseline.ts"() {
4840
4873
  "use strict";
4841
- BASELINE_FILE = path9.join(os9.homedir(), ".node9", "hooks-baseline.json");
4842
- NOTIFIED_FILE = path9.join(os9.homedir(), ".node9", "hook-heal-notified.json");
4874
+ BASELINE_FILE = path10.join(os9.homedir(), ".node9", "hooks-baseline.json");
4875
+ NOTIFIED_FILE = path10.join(os9.homedir(), ".node9", "hook-heal-notified.json");
4843
4876
  }
4844
4877
  });
4845
4878
 
@@ -4898,8 +4931,8 @@ var init_scan_history = __esm({
4898
4931
 
4899
4932
  // src/cli/commands/scan.ts
4900
4933
  import chalk4 from "chalk";
4901
- import fs7 from "fs";
4902
- import path10 from "path";
4934
+ import fs8 from "fs";
4935
+ import path11 from "path";
4903
4936
  import os10 from "os";
4904
4937
  import stringWidth2 from "string-width";
4905
4938
  function claudeModelPrice2(model) {
@@ -5046,11 +5079,11 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
5046
5079
  result.filesScanned++;
5047
5080
  result.sessions++;
5048
5081
  onProgress?.(result.filesScanned);
5049
- const sessionId = file.replace(/\.jsonl$/, "");
5082
+ const sessionId = sessionIdOf(file);
5050
5083
  const session = { sessionId, costUSD: 0, toolCalls: 0 };
5051
5084
  let raw;
5052
5085
  try {
5053
- raw = fs7.readFileSync(path10.join(projPath, file), "utf-8");
5086
+ raw = fs8.readFileSync(path11.join(projPath, file), "utf-8");
5054
5087
  } catch {
5055
5088
  return;
5056
5089
  }
@@ -5102,7 +5135,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
5102
5135
  if (block.type !== "tool_result") continue;
5103
5136
  const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
5104
5137
  if (filePath) {
5105
- const ext = path10.extname(filePath).toLowerCase();
5138
+ const ext = path11.extname(filePath).toLowerCase();
5106
5139
  if (CODE_EXTENSIONS.has(ext)) continue;
5107
5140
  }
5108
5141
  const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
@@ -5162,7 +5195,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
5162
5195
  const rawCmd = String(input.command ?? "").trimStart();
5163
5196
  if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
5164
5197
  const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
5165
- const inputFileExt = inputFilePath ? path10.extname(inputFilePath).toLowerCase() : "";
5198
+ const inputFileExt = inputFilePath ? path11.extname(inputFilePath).toLowerCase() : "";
5166
5199
  if (CODE_EXTENSIONS.has(inputFileExt)) continue;
5167
5200
  const dlpMatch = scanArgs(input);
5168
5201
  if (dlpMatch) {
@@ -5260,9 +5293,9 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
5260
5293
  result.perSession.push(session);
5261
5294
  }
5262
5295
  async function processClaudeProjectAsync(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
5263
- const projPath = path10.join(projectsDir, proj);
5296
+ const projPath = path11.join(projectsDir, proj);
5264
5297
  try {
5265
- if (!fs7.statSync(projPath).isDirectory()) return;
5298
+ if (!fs8.statSync(projPath).isDirectory()) return;
5266
5299
  } catch {
5267
5300
  return;
5268
5301
  }
@@ -5272,7 +5305,7 @@ async function processClaudeProjectAsync(proj, projectsDir, ruleSources, startDa
5272
5305
  );
5273
5306
  let files;
5274
5307
  try {
5275
- files = fs7.readdirSync(projPath).filter((f) => f.endsWith(".jsonl") && !f.startsWith("agent-"));
5308
+ files = listSessionFiles(projPath);
5276
5309
  } catch {
5277
5310
  return;
5278
5311
  }
@@ -5311,12 +5344,12 @@ function emptyClaudeScan() {
5311
5344
  };
5312
5345
  }
5313
5346
  async function scanClaudeHistoryAsync(startDate, onProgress, onLine) {
5314
- const projectsDir = path10.join(os10.homedir(), ".claude", "projects");
5347
+ const projectsDir = path11.join(os10.homedir(), ".claude", "projects");
5315
5348
  const result = emptyClaudeScan();
5316
- if (!fs7.existsSync(projectsDir)) return result;
5349
+ if (!fs8.existsSync(projectsDir)) return result;
5317
5350
  let projDirs;
5318
5351
  try {
5319
- projDirs = fs7.readdirSync(projectsDir);
5352
+ projDirs = fs8.readdirSync(projectsDir);
5320
5353
  } catch {
5321
5354
  return result;
5322
5355
  }
@@ -5337,7 +5370,7 @@ async function scanClaudeHistoryAsync(startDate, onProgress, onLine) {
5337
5370
  return result;
5338
5371
  }
5339
5372
  function scanGeminiHistory(startDate, onProgress, onLine) {
5340
- const tmpDir = path10.join(os10.homedir(), ".gemini", "tmp");
5373
+ const tmpDir = path11.join(os10.homedir(), ".gemini", "tmp");
5341
5374
  const result = {
5342
5375
  filesScanned: 0,
5343
5376
  sessions: 0,
@@ -5353,33 +5386,33 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
5353
5386
  perSession: []
5354
5387
  };
5355
5388
  const dedup = emptyScanDedup();
5356
- if (!fs7.existsSync(tmpDir)) return result;
5389
+ if (!fs8.existsSync(tmpDir)) return result;
5357
5390
  let slugDirs;
5358
5391
  try {
5359
- slugDirs = fs7.readdirSync(tmpDir);
5392
+ slugDirs = fs8.readdirSync(tmpDir);
5360
5393
  } catch {
5361
5394
  return result;
5362
5395
  }
5363
5396
  const ruleSources = buildRuleSources();
5364
5397
  for (const slug2 of slugDirs) {
5365
- const slugPath = path10.join(tmpDir, slug2);
5398
+ const slugPath = path11.join(tmpDir, slug2);
5366
5399
  try {
5367
- if (!fs7.statSync(slugPath).isDirectory()) continue;
5400
+ if (!fs8.statSync(slugPath).isDirectory()) continue;
5368
5401
  } catch {
5369
5402
  continue;
5370
5403
  }
5371
5404
  let projLabel = stripTerminalEscapes(slug2).slice(0, 40);
5372
5405
  try {
5373
5406
  projLabel = stripTerminalEscapes(
5374
- fs7.readFileSync(path10.join(slugPath, ".project_root"), "utf-8").trim()
5407
+ fs8.readFileSync(path11.join(slugPath, ".project_root"), "utf-8").trim()
5375
5408
  ).replace(os10.homedir(), "~").slice(0, 40);
5376
5409
  } catch {
5377
5410
  }
5378
- const chatsDir = path10.join(slugPath, "chats");
5379
- if (!fs7.existsSync(chatsDir)) continue;
5411
+ const chatsDir = path11.join(slugPath, "chats");
5412
+ if (!fs8.existsSync(chatsDir)) continue;
5380
5413
  let chatFiles;
5381
5414
  try {
5382
- chatFiles = fs7.readdirSync(chatsDir).filter((f) => f.endsWith(".json") || f.endsWith(".jsonl")).sort((a, b) => Number(b.endsWith(".jsonl")) - Number(a.endsWith(".jsonl")));
5415
+ chatFiles = fs8.readdirSync(chatsDir).filter((f) => f.endsWith(".json") || f.endsWith(".jsonl")).sort((a, b) => Number(b.endsWith(".jsonl")) - Number(a.endsWith(".jsonl")));
5383
5416
  } catch {
5384
5417
  continue;
5385
5418
  }
@@ -5392,7 +5425,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
5392
5425
  onProgress?.(result.filesScanned);
5393
5426
  let raw;
5394
5427
  try {
5395
- raw = fs7.readFileSync(path10.join(chatsDir, chatFile), "utf-8");
5428
+ raw = fs8.readFileSync(path11.join(chatsDir, chatFile), "utf-8");
5396
5429
  } catch {
5397
5430
  continue;
5398
5431
  }
@@ -5565,7 +5598,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
5565
5598
  return result;
5566
5599
  }
5567
5600
  function scanCodexHistory(startDate, onProgress, onLine) {
5568
- const sessionsBase = path10.join(os10.homedir(), ".codex", "sessions");
5601
+ const sessionsBase = path11.join(os10.homedir(), ".codex", "sessions");
5569
5602
  const result = {
5570
5603
  filesScanned: 0,
5571
5604
  sessions: 0,
@@ -5581,32 +5614,32 @@ function scanCodexHistory(startDate, onProgress, onLine) {
5581
5614
  perSession: []
5582
5615
  };
5583
5616
  const dedup = emptyScanDedup();
5584
- if (!fs7.existsSync(sessionsBase)) return result;
5617
+ if (!fs8.existsSync(sessionsBase)) return result;
5585
5618
  const jsonlFiles = [];
5586
5619
  try {
5587
- for (const year of fs7.readdirSync(sessionsBase)) {
5588
- const yearPath = path10.join(sessionsBase, year);
5620
+ for (const year of fs8.readdirSync(sessionsBase)) {
5621
+ const yearPath = path11.join(sessionsBase, year);
5589
5622
  try {
5590
- if (!fs7.statSync(yearPath).isDirectory()) continue;
5623
+ if (!fs8.statSync(yearPath).isDirectory()) continue;
5591
5624
  } catch {
5592
5625
  continue;
5593
5626
  }
5594
- for (const month of fs7.readdirSync(yearPath)) {
5595
- const monthPath = path10.join(yearPath, month);
5627
+ for (const month of fs8.readdirSync(yearPath)) {
5628
+ const monthPath = path11.join(yearPath, month);
5596
5629
  try {
5597
- if (!fs7.statSync(monthPath).isDirectory()) continue;
5630
+ if (!fs8.statSync(monthPath).isDirectory()) continue;
5598
5631
  } catch {
5599
5632
  continue;
5600
5633
  }
5601
- for (const day of fs7.readdirSync(monthPath)) {
5602
- const dayPath = path10.join(monthPath, day);
5634
+ for (const day of fs8.readdirSync(monthPath)) {
5635
+ const dayPath = path11.join(monthPath, day);
5603
5636
  try {
5604
- if (!fs7.statSync(dayPath).isDirectory()) continue;
5637
+ if (!fs8.statSync(dayPath).isDirectory()) continue;
5605
5638
  } catch {
5606
5639
  continue;
5607
5640
  }
5608
- for (const file of fs7.readdirSync(dayPath)) {
5609
- if (file.endsWith(".jsonl")) jsonlFiles.push(path10.join(dayPath, file));
5641
+ for (const file of fs8.readdirSync(dayPath)) {
5642
+ if (file.endsWith(".jsonl")) jsonlFiles.push(path11.join(dayPath, file));
5610
5643
  }
5611
5644
  }
5612
5645
  }
@@ -5620,7 +5653,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
5620
5653
  onProgress?.(result.filesScanned);
5621
5654
  let lines;
5622
5655
  try {
5623
- lines = fs7.readFileSync(filePath, "utf-8").split("\n");
5656
+ lines = fs8.readFileSync(filePath, "utf-8").split("\n");
5624
5657
  } catch {
5625
5658
  continue;
5626
5659
  }
@@ -5825,6 +5858,7 @@ var init_scan = __esm({
5825
5858
  init_scan_derive();
5826
5859
  init_protection();
5827
5860
  init_scan_json();
5861
+ init_session_files();
5828
5862
  init_scan_history();
5829
5863
  toolInspectionMap = DEFAULT_CONFIG.policy.toolInspection;
5830
5864
  CODE_EXTENSIONS = /* @__PURE__ */ new Set([
@@ -5889,23 +5923,23 @@ var init_scan = __esm({
5889
5923
  });
5890
5924
 
5891
5925
  // src/tui/dashboard/data.ts
5892
- import fs8 from "fs";
5926
+ import fs9 from "fs";
5893
5927
  import os11 from "os";
5894
- import path11 from "path";
5928
+ import path12 from "path";
5895
5929
  import http from "http";
5896
5930
  function auditLogPath() {
5897
- return path11.join(os11.homedir(), ".node9", "audit.log");
5931
+ return path12.join(os11.homedir(), ".node9", "audit.log");
5898
5932
  }
5899
5933
  function readAuditEntriesAsync(chunkSize = 1e3, customPath) {
5900
5934
  return new Promise((resolve) => {
5901
5935
  const p = customPath ?? auditLogPath();
5902
- if (!fs8.existsSync(p)) {
5936
+ if (!fs9.existsSync(p)) {
5903
5937
  resolve([]);
5904
5938
  return;
5905
5939
  }
5906
5940
  let raw;
5907
5941
  try {
5908
- raw = fs8.readFileSync(p, "utf8");
5942
+ raw = fs9.readFileSync(p, "utf8");
5909
5943
  } catch {
5910
5944
  resolve([]);
5911
5945
  return;
@@ -6041,9 +6075,9 @@ function shortenPath(p) {
6041
6075
  return p.startsWith(home) ? p.replace(home, "~") : p;
6042
6076
  }
6043
6077
  async function loadReportAuditAsync(period) {
6044
- const claudeProjectsDir = path11.join(os11.homedir(), ".claude", "projects");
6045
- const codexSessionsDir = path11.join(os11.homedir(), ".codex", "sessions");
6046
- const geminiTmpDir = path11.join(os11.homedir(), ".gemini", "tmp");
6078
+ const claudeProjectsDir = path12.join(os11.homedir(), ".claude", "projects");
6079
+ const codexSessionsDir = path12.join(os11.homedir(), ".codex", "sessions");
6080
+ const geminiTmpDir = path12.join(os11.homedir(), ".gemini", "tmp");
6047
6081
  const { start, end } = getDateRange(period, /* @__PURE__ */ new Date());
6048
6082
  const entries = await readAuditEntriesAsync();
6049
6083
  void ensurePricingLoaded();
@@ -7124,8 +7158,8 @@ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-run
7124
7158
  function TopToolsProjects({ audit }) {
7125
7159
  const data = audit?.data;
7126
7160
  const tools = data ? [...data.toolMap.entries()].sort(([, a], [, b]) => b.calls - a.calls).slice(0, ROW_LIMIT) : [];
7127
- const projects = data ? [...data.cost.byProject.entries()].map(([path12, r]) => ({
7128
- name: basenameOf(path12),
7161
+ const projects = data ? [...data.cost.byProject.entries()].map(([path13, r]) => ({
7162
+ name: basenameOf(path13),
7129
7163
  cost: r.cost,
7130
7164
  tokens: r.inputTokens + r.outputTokens
7131
7165
  })).sort((a, b) => b.cost - a.cost).slice(0, ROW_LIMIT) : [];
@@ -7562,8 +7596,8 @@ function pickTopLoopFile(loops) {
7562
7596
  map.set(k, (map.get(k) ?? 0) + (l.count ?? 0));
7563
7597
  }
7564
7598
  if (map.size === 0) return void 0;
7565
- const [path12, count] = [...map.entries()].sort((a, b) => b[1] - a[1])[0];
7566
- return { path: path12, count };
7599
+ const [path13, count] = [...map.entries()].sort((a, b) => b[1] - a[1])[0];
7600
+ return { path: path13, count };
7567
7601
  }
7568
7602
  var EMPTY_FILTERED_SCAN;
7569
7603
  var init_derive = __esm({
@@ -7729,9 +7763,9 @@ function computeHeadline(scanCache, filtered, blast) {
7729
7763
  };
7730
7764
  }
7731
7765
  if (filtered.loops.length > 100) {
7732
- const wasted = filtered.loops.reduce((s, l) => s + (l.count ?? 0) * COST_PER_LOOP_ITER_USD, 0);
7766
+ const stuck = filtered.loops.filter((l) => l.kind !== "long-iteration").length;
7733
7767
  return {
7734
- text: `\u{1F4CC} ${filtered.loops.length} loops \xB7 ~${fmtCost(wasted)} wasted`,
7768
+ text: `\u{1F4CC} ${filtered.loops.length} repeated patterns \xB7 ${stuck} stuck`,
7735
7769
  color: "yellow"
7736
7770
  };
7737
7771
  }
@@ -7775,7 +7809,6 @@ var init_report = __esm({
7775
7809
  "use strict";
7776
7810
  init_panels();
7777
7811
  init_data();
7778
- init_dist();
7779
7812
  init_Protection();
7780
7813
  init_Cost();
7781
7814
  init_TopToolsProjects();