@node9/proxy 2.6.2 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +221 -145
- package/dist/cli.mjs +1009 -934
- package/dist/dashboard.mjs +159 -116
- package/dist/scan-ink.mjs +2 -2
- package/package.json +1 -1
package/dist/dashboard.mjs
CHANGED
|
@@ -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,
|
|
231
|
+
function getNestedValue(obj, path13) {
|
|
232
232
|
if (!obj || typeof obj !== "object") return null;
|
|
233
|
-
const segments =
|
|
233
|
+
const segments = path13.split(".");
|
|
234
234
|
for (const seg of segments) {
|
|
235
235
|
if (FORBIDDEN_PATH_SEGMENTS.has(seg)) return null;
|
|
236
236
|
}
|
|
@@ -2333,8 +2333,8 @@ function sanitizeConfig(raw) {
|
|
|
2333
2333
|
}
|
|
2334
2334
|
}
|
|
2335
2335
|
const lines = result.error.issues.map((issue) => {
|
|
2336
|
-
const
|
|
2337
|
-
return ` \u2022 ${
|
|
2336
|
+
const path13 = issue.path.length > 0 ? issue.path.join(".") : "root";
|
|
2337
|
+
return ` \u2022 ${path13}: ${issue.message}`;
|
|
2338
2338
|
});
|
|
2339
2339
|
return {
|
|
2340
2340
|
sanitized,
|
|
@@ -3213,13 +3213,13 @@ function getConfig(cwd) {
|
|
|
3213
3213
|
}
|
|
3214
3214
|
if (Array.isArray(mc.jailPaths)) {
|
|
3215
3215
|
for (const jp of mc.jailPaths) {
|
|
3216
|
-
const
|
|
3217
|
-
if (!
|
|
3216
|
+
const path13 = typeof jp?.path === "string" ? jp.path.trim() : "";
|
|
3217
|
+
if (!path13) continue;
|
|
3218
3218
|
const verdict = jp?.verdict === "review" ? "review" : "block";
|
|
3219
|
-
for (const r of pathRules(
|
|
3219
|
+
for (const r of pathRules(path13, verdict, "org-managed jail")) {
|
|
3220
3220
|
mergedPolicy.smartRules.push({ ...r, name: `org:${r.name}` });
|
|
3221
3221
|
}
|
|
3222
|
-
mergedPolicy.managedJailPaths.push({ path:
|
|
3222
|
+
mergedPolicy.managedJailPaths.push({ path: path13, verdict });
|
|
3223
3223
|
}
|
|
3224
3224
|
}
|
|
3225
3225
|
if (Array.isArray(mc.trustedHosts)) {
|
|
@@ -3718,14 +3718,15 @@ import os6 from "os";
|
|
|
3718
3718
|
function normalizeModel(raw) {
|
|
3719
3719
|
return raw.replace(/-\d{8}$/, "").toLowerCase();
|
|
3720
3720
|
}
|
|
3721
|
-
function readCache() {
|
|
3721
|
+
function readCache(opts) {
|
|
3722
3722
|
try {
|
|
3723
3723
|
const raw = JSON.parse(fs5.readFileSync(CACHE_FILE(), "utf-8"));
|
|
3724
3724
|
if (typeof raw.fetchedAt !== "string" || typeof raw.prices !== "object" || raw.prices === null) {
|
|
3725
3725
|
return null;
|
|
3726
3726
|
}
|
|
3727
3727
|
const ageMs = Date.now() - new Date(raw.fetchedAt).getTime();
|
|
3728
|
-
if (ageMs
|
|
3728
|
+
if (!Number.isFinite(ageMs) || ageMs < 0) return null;
|
|
3729
|
+
if (opts.requireFresh && ageMs > TTL_MS) return null;
|
|
3729
3730
|
return raw.prices;
|
|
3730
3731
|
} catch {
|
|
3731
3732
|
return null;
|
|
@@ -3791,7 +3792,7 @@ async function fetchLiteLLMPricing() {
|
|
|
3791
3792
|
}
|
|
3792
3793
|
async function ensurePricingLoaded() {
|
|
3793
3794
|
if (memCache !== null && Date.now() - memCacheAt < TTL_MS) return;
|
|
3794
|
-
const fromDisk = readCache();
|
|
3795
|
+
const fromDisk = readCache({ requireFresh: true });
|
|
3795
3796
|
if (fromDisk && Object.keys(fromDisk).length > 0) {
|
|
3796
3797
|
memCache = fromDisk;
|
|
3797
3798
|
memCacheAt = Date.now();
|
|
@@ -3816,7 +3817,7 @@ function pricingFor(model) {
|
|
|
3816
3817
|
if (cached !== void 0) return cached;
|
|
3817
3818
|
if (memCache === null && !diskChecked) {
|
|
3818
3819
|
diskChecked = true;
|
|
3819
|
-
const disk = readCache();
|
|
3820
|
+
const disk = readCache({ requireFresh: false });
|
|
3820
3821
|
if (disk && Object.keys(disk).length > 0) {
|
|
3821
3822
|
memCache = disk;
|
|
3822
3823
|
memCacheAt = Date.now();
|
|
@@ -3945,6 +3946,37 @@ var init_cost_copilot = __esm({
|
|
|
3945
3946
|
}
|
|
3946
3947
|
});
|
|
3947
3948
|
|
|
3949
|
+
// src/session-files.ts
|
|
3950
|
+
import * as fs6 from "fs";
|
|
3951
|
+
import * as path7 from "path";
|
|
3952
|
+
function listSessionFiles(dir, maxDepth = 6) {
|
|
3953
|
+
const out = [];
|
|
3954
|
+
const walk = (d, rel, depth) => {
|
|
3955
|
+
if (depth > maxDepth) return;
|
|
3956
|
+
let entries;
|
|
3957
|
+
try {
|
|
3958
|
+
entries = fs6.readdirSync(d, { withFileTypes: true });
|
|
3959
|
+
} catch {
|
|
3960
|
+
return;
|
|
3961
|
+
}
|
|
3962
|
+
for (const e of entries) {
|
|
3963
|
+
const childRel = rel ? path7.join(rel, e.name) : e.name;
|
|
3964
|
+
if (e.isDirectory()) walk(path7.join(d, e.name), childRel, depth + 1);
|
|
3965
|
+
else if (e.name.endsWith(".jsonl")) out.push(childRel);
|
|
3966
|
+
}
|
|
3967
|
+
};
|
|
3968
|
+
walk(dir, "", 0);
|
|
3969
|
+
return out;
|
|
3970
|
+
}
|
|
3971
|
+
function sessionIdOf(relPath) {
|
|
3972
|
+
return path7.basename(relPath).replace(/\.jsonl$/, "");
|
|
3973
|
+
}
|
|
3974
|
+
var init_session_files = __esm({
|
|
3975
|
+
"src/session-files.ts"() {
|
|
3976
|
+
"use strict";
|
|
3977
|
+
}
|
|
3978
|
+
});
|
|
3979
|
+
|
|
3948
3980
|
// src/costSync.ts
|
|
3949
3981
|
function decodeProjectDirName(dirName) {
|
|
3950
3982
|
return dirName.replace(/-/g, "/");
|
|
@@ -3959,6 +3991,7 @@ var init_costSync = __esm({
|
|
|
3959
3991
|
init_cost_codex();
|
|
3960
3992
|
init_cost_gemini();
|
|
3961
3993
|
init_cost_copilot();
|
|
3994
|
+
init_session_files();
|
|
3962
3995
|
SYNC_INTERVAL_MS = 10 * 60 * 1e3;
|
|
3963
3996
|
}
|
|
3964
3997
|
});
|
|
@@ -4031,9 +4064,9 @@ var init_scan_watermark = __esm({
|
|
|
4031
4064
|
});
|
|
4032
4065
|
|
|
4033
4066
|
// src/cli/aggregate/report-audit.ts
|
|
4034
|
-
import
|
|
4067
|
+
import fs7 from "fs";
|
|
4035
4068
|
import os7 from "os";
|
|
4036
|
-
import
|
|
4069
|
+
import path8 from "path";
|
|
4037
4070
|
function buildTestTimestamps(allEntries) {
|
|
4038
4071
|
const testTs = /* @__PURE__ */ new Set();
|
|
4039
4072
|
for (const e of allEntries) {
|
|
@@ -4114,8 +4147,8 @@ function getDateRange(period, now) {
|
|
|
4114
4147
|
}
|
|
4115
4148
|
}
|
|
4116
4149
|
function parseAuditLog(logPath) {
|
|
4117
|
-
if (!
|
|
4118
|
-
const raw =
|
|
4150
|
+
if (!fs7.existsSync(logPath)) return [];
|
|
4151
|
+
const raw = fs7.readFileSync(logPath, "utf-8");
|
|
4119
4152
|
return raw.split("\n").flatMap((line) => {
|
|
4120
4153
|
if (!line.trim()) return [];
|
|
4121
4154
|
try {
|
|
@@ -4169,25 +4202,25 @@ function freezeClaudeCost(acc) {
|
|
|
4169
4202
|
};
|
|
4170
4203
|
}
|
|
4171
4204
|
function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
4172
|
-
const projPath =
|
|
4205
|
+
const projPath = path8.join(projectsDir, proj);
|
|
4173
4206
|
let files;
|
|
4174
4207
|
try {
|
|
4175
|
-
const stat =
|
|
4208
|
+
const stat = fs7.statSync(projPath);
|
|
4176
4209
|
if (!stat.isDirectory()) return;
|
|
4177
|
-
files =
|
|
4210
|
+
files = listSessionFiles(projPath);
|
|
4178
4211
|
} catch {
|
|
4179
4212
|
return;
|
|
4180
4213
|
}
|
|
4181
4214
|
const startMs = start.getTime();
|
|
4182
4215
|
for (const file of files) {
|
|
4183
|
-
const filePath =
|
|
4216
|
+
const filePath = path8.join(projPath, file);
|
|
4184
4217
|
try {
|
|
4185
|
-
if (
|
|
4218
|
+
if (fs7.statSync(filePath).mtimeMs < startMs) continue;
|
|
4186
4219
|
} catch {
|
|
4187
4220
|
continue;
|
|
4188
4221
|
}
|
|
4189
4222
|
try {
|
|
4190
|
-
const raw =
|
|
4223
|
+
const raw = fs7.readFileSync(filePath, "utf-8");
|
|
4191
4224
|
for (const line of raw.split("\n")) {
|
|
4192
4225
|
if (!line.trim()) continue;
|
|
4193
4226
|
let entry;
|
|
@@ -4237,10 +4270,10 @@ function processClaudeCostProject(proj, projectsDir, start, end, acc) {
|
|
|
4237
4270
|
}
|
|
4238
4271
|
function loadClaudeCost(start, end, projectsDir) {
|
|
4239
4272
|
const acc = emptyClaudeCostAccumulator();
|
|
4240
|
-
if (!
|
|
4273
|
+
if (!fs7.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
4241
4274
|
let dirs;
|
|
4242
4275
|
try {
|
|
4243
|
-
dirs =
|
|
4276
|
+
dirs = fs7.readdirSync(projectsDir);
|
|
4244
4277
|
} catch {
|
|
4245
4278
|
return freezeClaudeCost(acc);
|
|
4246
4279
|
}
|
|
@@ -4251,10 +4284,10 @@ function loadClaudeCost(start, end, projectsDir) {
|
|
|
4251
4284
|
}
|
|
4252
4285
|
async function loadClaudeCostAsync(start, end, projectsDir) {
|
|
4253
4286
|
const acc = emptyClaudeCostAccumulator();
|
|
4254
|
-
if (!
|
|
4287
|
+
if (!fs7.existsSync(projectsDir)) return freezeClaudeCost(acc);
|
|
4255
4288
|
let dirs;
|
|
4256
4289
|
try {
|
|
4257
|
-
dirs =
|
|
4290
|
+
dirs = fs7.readdirSync(projectsDir);
|
|
4258
4291
|
} catch {
|
|
4259
4292
|
return freezeClaudeCost(acc);
|
|
4260
4293
|
}
|
|
@@ -4267,7 +4300,7 @@ async function loadClaudeCostAsync(start, end, projectsDir) {
|
|
|
4267
4300
|
function processCodexCostFile(filePath, start, end, acc) {
|
|
4268
4301
|
let lines;
|
|
4269
4302
|
try {
|
|
4270
|
-
lines =
|
|
4303
|
+
lines = fs7.readFileSync(filePath, "utf-8").split("\n");
|
|
4271
4304
|
} catch {
|
|
4272
4305
|
return;
|
|
4273
4306
|
}
|
|
@@ -4322,31 +4355,31 @@ function processCodexCostFile(filePath, start, end, acc) {
|
|
|
4322
4355
|
}
|
|
4323
4356
|
function listCodexSessionFiles(sessionsBase) {
|
|
4324
4357
|
const jsonlFiles = [];
|
|
4325
|
-
if (!
|
|
4358
|
+
if (!fs7.existsSync(sessionsBase)) return jsonlFiles;
|
|
4326
4359
|
try {
|
|
4327
|
-
for (const year of
|
|
4328
|
-
const yearPath =
|
|
4360
|
+
for (const year of fs7.readdirSync(sessionsBase)) {
|
|
4361
|
+
const yearPath = path8.join(sessionsBase, year);
|
|
4329
4362
|
try {
|
|
4330
|
-
if (!
|
|
4363
|
+
if (!fs7.statSync(yearPath).isDirectory()) continue;
|
|
4331
4364
|
} catch {
|
|
4332
4365
|
continue;
|
|
4333
4366
|
}
|
|
4334
|
-
for (const month of
|
|
4335
|
-
const monthPath =
|
|
4367
|
+
for (const month of fs7.readdirSync(yearPath)) {
|
|
4368
|
+
const monthPath = path8.join(yearPath, month);
|
|
4336
4369
|
try {
|
|
4337
|
-
if (!
|
|
4370
|
+
if (!fs7.statSync(monthPath).isDirectory()) continue;
|
|
4338
4371
|
} catch {
|
|
4339
4372
|
continue;
|
|
4340
4373
|
}
|
|
4341
|
-
for (const day of
|
|
4342
|
-
const dayPath =
|
|
4374
|
+
for (const day of fs7.readdirSync(monthPath)) {
|
|
4375
|
+
const dayPath = path8.join(monthPath, day);
|
|
4343
4376
|
try {
|
|
4344
|
-
if (!
|
|
4377
|
+
if (!fs7.statSync(dayPath).isDirectory()) continue;
|
|
4345
4378
|
} catch {
|
|
4346
4379
|
continue;
|
|
4347
4380
|
}
|
|
4348
|
-
for (const file of
|
|
4349
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
4381
|
+
for (const file of fs7.readdirSync(dayPath)) {
|
|
4382
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path8.join(dayPath, file));
|
|
4350
4383
|
}
|
|
4351
4384
|
}
|
|
4352
4385
|
}
|
|
@@ -4427,13 +4460,13 @@ function freezeGeminiCost(acc) {
|
|
|
4427
4460
|
function processGeminiCostFile(filePath, projectKey, start, end, acc) {
|
|
4428
4461
|
const startMs = start.getTime();
|
|
4429
4462
|
try {
|
|
4430
|
-
if (
|
|
4463
|
+
if (fs7.statSync(filePath).mtimeMs < startMs) return;
|
|
4431
4464
|
} catch {
|
|
4432
4465
|
return;
|
|
4433
4466
|
}
|
|
4434
4467
|
let raw;
|
|
4435
4468
|
try {
|
|
4436
|
-
raw =
|
|
4469
|
+
raw = fs7.readFileSync(filePath, "utf-8");
|
|
4437
4470
|
} catch {
|
|
4438
4471
|
return;
|
|
4439
4472
|
}
|
|
@@ -4482,30 +4515,30 @@ function listGeminiSessionFiles(geminiTmpDir) {
|
|
|
4482
4515
|
const out = [];
|
|
4483
4516
|
let dirs;
|
|
4484
4517
|
try {
|
|
4485
|
-
if (!
|
|
4486
|
-
dirs =
|
|
4518
|
+
if (!fs7.statSync(geminiTmpDir).isDirectory()) return out;
|
|
4519
|
+
dirs = fs7.readdirSync(geminiTmpDir);
|
|
4487
4520
|
} catch {
|
|
4488
4521
|
return out;
|
|
4489
4522
|
}
|
|
4490
4523
|
for (const proj of dirs) {
|
|
4491
|
-
const chatsDir =
|
|
4524
|
+
const chatsDir = path8.join(geminiTmpDir, proj, "chats");
|
|
4492
4525
|
let files;
|
|
4493
4526
|
try {
|
|
4494
|
-
if (!
|
|
4495
|
-
files =
|
|
4527
|
+
if (!fs7.statSync(chatsDir).isDirectory()) continue;
|
|
4528
|
+
files = fs7.readdirSync(chatsDir);
|
|
4496
4529
|
} catch {
|
|
4497
4530
|
continue;
|
|
4498
4531
|
}
|
|
4499
4532
|
for (const f of files) {
|
|
4500
4533
|
if (!f.endsWith(".jsonl")) continue;
|
|
4501
|
-
out.push({ projectKey: proj, file:
|
|
4534
|
+
out.push({ projectKey: proj, file: path8.join(chatsDir, f) });
|
|
4502
4535
|
}
|
|
4503
4536
|
}
|
|
4504
4537
|
return out;
|
|
4505
4538
|
}
|
|
4506
4539
|
function loadGeminiCost(start, end, geminiTmpDir) {
|
|
4507
4540
|
const acc = emptyGeminiAccumulator();
|
|
4508
|
-
if (!
|
|
4541
|
+
if (!fs7.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
|
|
4509
4542
|
for (const { projectKey, file } of listGeminiSessionFiles(geminiTmpDir)) {
|
|
4510
4543
|
processGeminiCostFile(file, projectKey, start, end, acc);
|
|
4511
4544
|
}
|
|
@@ -4513,7 +4546,7 @@ function loadGeminiCost(start, end, geminiTmpDir) {
|
|
|
4513
4546
|
}
|
|
4514
4547
|
async function loadGeminiCostAsync(start, end, geminiTmpDir) {
|
|
4515
4548
|
const acc = emptyGeminiAccumulator();
|
|
4516
|
-
if (!
|
|
4549
|
+
if (!fs7.existsSync(geminiTmpDir)) return freezeGeminiCost(acc);
|
|
4517
4550
|
const files = listGeminiSessionFiles(geminiTmpDir);
|
|
4518
4551
|
const CHUNK_SIZE = 5;
|
|
4519
4552
|
for (let i = 0; i < files.length; i++) {
|
|
@@ -4536,11 +4569,11 @@ function dimensionOfBlock(checkedBy, ruleName) {
|
|
|
4536
4569
|
}
|
|
4537
4570
|
function aggregateReportFromAudit(period, opts = {}) {
|
|
4538
4571
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
4539
|
-
const auditLogPath2 = opts.auditLogPath ??
|
|
4540
|
-
const claudeProjectsDir = opts.claudeProjectsDir ??
|
|
4541
|
-
const codexSessionsDir = opts.codexSessionsDir ??
|
|
4542
|
-
const geminiTmpDir = opts.geminiTmpDir ??
|
|
4543
|
-
const hasAuditFile =
|
|
4572
|
+
const auditLogPath2 = opts.auditLogPath ?? path8.join(os7.homedir(), ".node9", "audit.log");
|
|
4573
|
+
const claudeProjectsDir = opts.claudeProjectsDir ?? path8.join(os7.homedir(), ".claude", "projects");
|
|
4574
|
+
const codexSessionsDir = opts.codexSessionsDir ?? path8.join(os7.homedir(), ".codex", "sessions");
|
|
4575
|
+
const geminiTmpDir = opts.geminiTmpDir ?? path8.join(os7.homedir(), ".gemini", "tmp");
|
|
4576
|
+
const hasAuditFile = fs7.existsSync(auditLogPath2);
|
|
4544
4577
|
const allEntries = opts.preloadedAuditEntries ?? parseAuditLog(auditLogPath2);
|
|
4545
4578
|
const unackedDlp = allEntries.filter((e) => e.source === "response-dlp");
|
|
4546
4579
|
const { start, end } = getDateRange(period, now);
|
|
@@ -4770,6 +4803,7 @@ var init_report_audit = __esm({
|
|
|
4770
4803
|
init_litellm();
|
|
4771
4804
|
init_cost_codex();
|
|
4772
4805
|
init_decision();
|
|
4806
|
+
init_session_files();
|
|
4773
4807
|
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
4808
|
SUPERSEDE_WINDOW_MS = 6e4;
|
|
4775
4809
|
GEMINI_FALLBACK_MODELS2 = ["gemini-2.5-flash", "gemini-2.0-flash"];
|
|
@@ -4777,18 +4811,18 @@ var init_report_audit = __esm({
|
|
|
4777
4811
|
});
|
|
4778
4812
|
|
|
4779
4813
|
// src/utils/provenance.ts
|
|
4780
|
-
import
|
|
4814
|
+
import path9 from "path";
|
|
4781
4815
|
import os8 from "os";
|
|
4782
4816
|
var USER_PREFIXES;
|
|
4783
4817
|
var init_provenance = __esm({
|
|
4784
4818
|
"src/utils/provenance.ts"() {
|
|
4785
4819
|
"use strict";
|
|
4786
4820
|
USER_PREFIXES = [
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
4790
|
-
|
|
4791
|
-
|
|
4821
|
+
path9.join(os8.homedir(), "bin"),
|
|
4822
|
+
path9.join(os8.homedir(), ".local", "bin"),
|
|
4823
|
+
path9.join(os8.homedir(), ".cargo", "bin"),
|
|
4824
|
+
path9.join(os8.homedir(), ".npm-global", "bin"),
|
|
4825
|
+
path9.join(os8.homedir(), ".volta", "bin")
|
|
4792
4826
|
];
|
|
4793
4827
|
}
|
|
4794
4828
|
});
|
|
@@ -4832,14 +4866,14 @@ var init_mcp_pin = __esm({
|
|
|
4832
4866
|
});
|
|
4833
4867
|
|
|
4834
4868
|
// src/daemon/hook-baseline.ts
|
|
4835
|
-
import
|
|
4869
|
+
import path10 from "path";
|
|
4836
4870
|
import os9 from "os";
|
|
4837
4871
|
var BASELINE_FILE, NOTIFIED_FILE;
|
|
4838
4872
|
var init_hook_baseline = __esm({
|
|
4839
4873
|
"src/daemon/hook-baseline.ts"() {
|
|
4840
4874
|
"use strict";
|
|
4841
|
-
BASELINE_FILE =
|
|
4842
|
-
NOTIFIED_FILE =
|
|
4875
|
+
BASELINE_FILE = path10.join(os9.homedir(), ".node9", "hooks-baseline.json");
|
|
4876
|
+
NOTIFIED_FILE = path10.join(os9.homedir(), ".node9", "hook-heal-notified.json");
|
|
4843
4877
|
}
|
|
4844
4878
|
});
|
|
4845
4879
|
|
|
@@ -4898,8 +4932,8 @@ var init_scan_history = __esm({
|
|
|
4898
4932
|
|
|
4899
4933
|
// src/cli/commands/scan.ts
|
|
4900
4934
|
import chalk4 from "chalk";
|
|
4901
|
-
import
|
|
4902
|
-
import
|
|
4935
|
+
import fs8 from "fs";
|
|
4936
|
+
import path11 from "path";
|
|
4903
4937
|
import os10 from "os";
|
|
4904
4938
|
import stringWidth2 from "string-width";
|
|
4905
4939
|
function claudeModelPrice2(model) {
|
|
@@ -5046,10 +5080,11 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
5046
5080
|
result.filesScanned++;
|
|
5047
5081
|
result.sessions++;
|
|
5048
5082
|
onProgress?.(result.filesScanned);
|
|
5049
|
-
const sessionId = file
|
|
5083
|
+
const sessionId = sessionIdOf(file);
|
|
5084
|
+
const session = { sessionId, costUSD: 0, toolCalls: 0 };
|
|
5050
5085
|
let raw;
|
|
5051
5086
|
try {
|
|
5052
|
-
raw =
|
|
5087
|
+
raw = fs8.readFileSync(path11.join(projPath, file), "utf-8");
|
|
5053
5088
|
} catch {
|
|
5054
5089
|
return;
|
|
5055
5090
|
}
|
|
@@ -5101,7 +5136,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
5101
5136
|
if (block.type !== "tool_result") continue;
|
|
5102
5137
|
const filePath = block.tool_use_id ? toolUseFilePaths.get(block.tool_use_id) : void 0;
|
|
5103
5138
|
if (filePath) {
|
|
5104
|
-
const ext =
|
|
5139
|
+
const ext = path11.extname(filePath).toLowerCase();
|
|
5105
5140
|
if (CODE_EXTENSIONS.has(ext)) continue;
|
|
5106
5141
|
}
|
|
5107
5142
|
const resultText = typeof block.content === "string" ? block.content : Array.isArray(block.content) ? block.content.map((c) => c.text ?? "").join("\n") : null;
|
|
@@ -5134,7 +5169,9 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
5134
5169
|
if (usage && model) {
|
|
5135
5170
|
const p = claudeModelPrice2(model);
|
|
5136
5171
|
if (p) {
|
|
5137
|
-
|
|
5172
|
+
const rowCost = (usage.input_tokens ?? 0) * p.i + (usage.output_tokens ?? 0) * p.o + (usage.cache_creation_input_tokens ?? 0) * p.cw + (usage.cache_read_input_tokens ?? 0) * p.cr;
|
|
5173
|
+
result.totalCostUSD += rowCost;
|
|
5174
|
+
session.costUSD += rowCost;
|
|
5138
5175
|
}
|
|
5139
5176
|
}
|
|
5140
5177
|
const content = entry.message?.content;
|
|
@@ -5142,6 +5179,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
5142
5179
|
for (const block of content) {
|
|
5143
5180
|
if (block.type !== "tool_use") continue;
|
|
5144
5181
|
result.totalToolCalls++;
|
|
5182
|
+
session.toolCalls++;
|
|
5145
5183
|
const toolName = block.name ?? "";
|
|
5146
5184
|
const toolNameLower = toolName.toLowerCase();
|
|
5147
5185
|
const input = block.input ?? {};
|
|
@@ -5158,7 +5196,7 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
5158
5196
|
const rawCmd = String(input.command ?? "").trimStart();
|
|
5159
5197
|
if (/^node9\s+(scan|explain|report|tail|dlp|status|sessions|audit)\b/.test(rawCmd)) continue;
|
|
5160
5198
|
const inputFilePath = typeof input.file_path === "string" ? input.file_path : "";
|
|
5161
|
-
const inputFileExt = inputFilePath ?
|
|
5199
|
+
const inputFileExt = inputFilePath ? path11.extname(inputFilePath).toLowerCase() : "";
|
|
5162
5200
|
if (CODE_EXTENSIONS.has(inputFileExt)) continue;
|
|
5163
5201
|
const dlpMatch = scanArgs(input);
|
|
5164
5202
|
if (dlpMatch) {
|
|
@@ -5253,11 +5291,12 @@ function processClaudeFile(file, projPath, projLabel, ruleSources, startDate, re
|
|
|
5253
5291
|
if (firstDlpTs !== null && (firstEditTs === null || firstDlpTs < firstEditTs)) {
|
|
5254
5292
|
result.sessionsWithEarlySecrets++;
|
|
5255
5293
|
}
|
|
5294
|
+
result.perSession.push(session);
|
|
5256
5295
|
}
|
|
5257
5296
|
async function processClaudeProjectAsync(proj, projectsDir, ruleSources, startDate, result, dedup, onProgress, onLine) {
|
|
5258
|
-
const projPath =
|
|
5297
|
+
const projPath = path11.join(projectsDir, proj);
|
|
5259
5298
|
try {
|
|
5260
|
-
if (!
|
|
5299
|
+
if (!fs8.statSync(projPath).isDirectory()) return;
|
|
5261
5300
|
} catch {
|
|
5262
5301
|
return;
|
|
5263
5302
|
}
|
|
@@ -5267,7 +5306,7 @@ async function processClaudeProjectAsync(proj, projectsDir, ruleSources, startDa
|
|
|
5267
5306
|
);
|
|
5268
5307
|
let files;
|
|
5269
5308
|
try {
|
|
5270
|
-
files =
|
|
5309
|
+
files = listSessionFiles(projPath);
|
|
5271
5310
|
} catch {
|
|
5272
5311
|
return;
|
|
5273
5312
|
}
|
|
@@ -5301,16 +5340,17 @@ function emptyClaudeScan() {
|
|
|
5301
5340
|
totalCostUSD: 0,
|
|
5302
5341
|
firstDate: null,
|
|
5303
5342
|
lastDate: null,
|
|
5304
|
-
sessionsWithEarlySecrets: 0
|
|
5343
|
+
sessionsWithEarlySecrets: 0,
|
|
5344
|
+
perSession: []
|
|
5305
5345
|
};
|
|
5306
5346
|
}
|
|
5307
5347
|
async function scanClaudeHistoryAsync(startDate, onProgress, onLine) {
|
|
5308
|
-
const projectsDir =
|
|
5348
|
+
const projectsDir = path11.join(os10.homedir(), ".claude", "projects");
|
|
5309
5349
|
const result = emptyClaudeScan();
|
|
5310
|
-
if (!
|
|
5350
|
+
if (!fs8.existsSync(projectsDir)) return result;
|
|
5311
5351
|
let projDirs;
|
|
5312
5352
|
try {
|
|
5313
|
-
projDirs =
|
|
5353
|
+
projDirs = fs8.readdirSync(projectsDir);
|
|
5314
5354
|
} catch {
|
|
5315
5355
|
return result;
|
|
5316
5356
|
}
|
|
@@ -5331,7 +5371,7 @@ async function scanClaudeHistoryAsync(startDate, onProgress, onLine) {
|
|
|
5331
5371
|
return result;
|
|
5332
5372
|
}
|
|
5333
5373
|
function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
5334
|
-
const tmpDir =
|
|
5374
|
+
const tmpDir = path11.join(os10.homedir(), ".gemini", "tmp");
|
|
5335
5375
|
const result = {
|
|
5336
5376
|
filesScanned: 0,
|
|
5337
5377
|
sessions: 0,
|
|
@@ -5343,36 +5383,37 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
5343
5383
|
totalCostUSD: 0,
|
|
5344
5384
|
firstDate: null,
|
|
5345
5385
|
lastDate: null,
|
|
5346
|
-
sessionsWithEarlySecrets: 0
|
|
5386
|
+
sessionsWithEarlySecrets: 0,
|
|
5387
|
+
perSession: []
|
|
5347
5388
|
};
|
|
5348
5389
|
const dedup = emptyScanDedup();
|
|
5349
|
-
if (!
|
|
5390
|
+
if (!fs8.existsSync(tmpDir)) return result;
|
|
5350
5391
|
let slugDirs;
|
|
5351
5392
|
try {
|
|
5352
|
-
slugDirs =
|
|
5393
|
+
slugDirs = fs8.readdirSync(tmpDir);
|
|
5353
5394
|
} catch {
|
|
5354
5395
|
return result;
|
|
5355
5396
|
}
|
|
5356
5397
|
const ruleSources = buildRuleSources();
|
|
5357
5398
|
for (const slug2 of slugDirs) {
|
|
5358
|
-
const slugPath =
|
|
5399
|
+
const slugPath = path11.join(tmpDir, slug2);
|
|
5359
5400
|
try {
|
|
5360
|
-
if (!
|
|
5401
|
+
if (!fs8.statSync(slugPath).isDirectory()) continue;
|
|
5361
5402
|
} catch {
|
|
5362
5403
|
continue;
|
|
5363
5404
|
}
|
|
5364
5405
|
let projLabel = stripTerminalEscapes(slug2).slice(0, 40);
|
|
5365
5406
|
try {
|
|
5366
5407
|
projLabel = stripTerminalEscapes(
|
|
5367
|
-
|
|
5408
|
+
fs8.readFileSync(path11.join(slugPath, ".project_root"), "utf-8").trim()
|
|
5368
5409
|
).replace(os10.homedir(), "~").slice(0, 40);
|
|
5369
5410
|
} catch {
|
|
5370
5411
|
}
|
|
5371
|
-
const chatsDir =
|
|
5372
|
-
if (!
|
|
5412
|
+
const chatsDir = path11.join(slugPath, "chats");
|
|
5413
|
+
if (!fs8.existsSync(chatsDir)) continue;
|
|
5373
5414
|
let chatFiles;
|
|
5374
5415
|
try {
|
|
5375
|
-
chatFiles =
|
|
5416
|
+
chatFiles = fs8.readdirSync(chatsDir).filter((f) => f.endsWith(".json") || f.endsWith(".jsonl")).sort((a, b) => Number(b.endsWith(".jsonl")) - Number(a.endsWith(".jsonl")));
|
|
5376
5417
|
} catch {
|
|
5377
5418
|
continue;
|
|
5378
5419
|
}
|
|
@@ -5385,7 +5426,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
5385
5426
|
onProgress?.(result.filesScanned);
|
|
5386
5427
|
let raw;
|
|
5387
5428
|
try {
|
|
5388
|
-
raw =
|
|
5429
|
+
raw = fs8.readFileSync(path11.join(chatsDir, chatFile), "utf-8");
|
|
5389
5430
|
} catch {
|
|
5390
5431
|
continue;
|
|
5391
5432
|
}
|
|
@@ -5558,7 +5599,7 @@ function scanGeminiHistory(startDate, onProgress, onLine) {
|
|
|
5558
5599
|
return result;
|
|
5559
5600
|
}
|
|
5560
5601
|
function scanCodexHistory(startDate, onProgress, onLine) {
|
|
5561
|
-
const sessionsBase =
|
|
5602
|
+
const sessionsBase = path11.join(os10.homedir(), ".codex", "sessions");
|
|
5562
5603
|
const result = {
|
|
5563
5604
|
filesScanned: 0,
|
|
5564
5605
|
sessions: 0,
|
|
@@ -5570,35 +5611,36 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
5570
5611
|
totalCostUSD: 0,
|
|
5571
5612
|
firstDate: null,
|
|
5572
5613
|
lastDate: null,
|
|
5573
|
-
sessionsWithEarlySecrets: 0
|
|
5614
|
+
sessionsWithEarlySecrets: 0,
|
|
5615
|
+
perSession: []
|
|
5574
5616
|
};
|
|
5575
5617
|
const dedup = emptyScanDedup();
|
|
5576
|
-
if (!
|
|
5618
|
+
if (!fs8.existsSync(sessionsBase)) return result;
|
|
5577
5619
|
const jsonlFiles = [];
|
|
5578
5620
|
try {
|
|
5579
|
-
for (const year of
|
|
5580
|
-
const yearPath =
|
|
5621
|
+
for (const year of fs8.readdirSync(sessionsBase)) {
|
|
5622
|
+
const yearPath = path11.join(sessionsBase, year);
|
|
5581
5623
|
try {
|
|
5582
|
-
if (!
|
|
5624
|
+
if (!fs8.statSync(yearPath).isDirectory()) continue;
|
|
5583
5625
|
} catch {
|
|
5584
5626
|
continue;
|
|
5585
5627
|
}
|
|
5586
|
-
for (const month of
|
|
5587
|
-
const monthPath =
|
|
5628
|
+
for (const month of fs8.readdirSync(yearPath)) {
|
|
5629
|
+
const monthPath = path11.join(yearPath, month);
|
|
5588
5630
|
try {
|
|
5589
|
-
if (!
|
|
5631
|
+
if (!fs8.statSync(monthPath).isDirectory()) continue;
|
|
5590
5632
|
} catch {
|
|
5591
5633
|
continue;
|
|
5592
5634
|
}
|
|
5593
|
-
for (const day of
|
|
5594
|
-
const dayPath =
|
|
5635
|
+
for (const day of fs8.readdirSync(monthPath)) {
|
|
5636
|
+
const dayPath = path11.join(monthPath, day);
|
|
5595
5637
|
try {
|
|
5596
|
-
if (!
|
|
5638
|
+
if (!fs8.statSync(dayPath).isDirectory()) continue;
|
|
5597
5639
|
} catch {
|
|
5598
5640
|
continue;
|
|
5599
5641
|
}
|
|
5600
|
-
for (const file of
|
|
5601
|
-
if (file.endsWith(".jsonl")) jsonlFiles.push(
|
|
5642
|
+
for (const file of fs8.readdirSync(dayPath)) {
|
|
5643
|
+
if (file.endsWith(".jsonl")) jsonlFiles.push(path11.join(dayPath, file));
|
|
5602
5644
|
}
|
|
5603
5645
|
}
|
|
5604
5646
|
}
|
|
@@ -5612,7 +5654,7 @@ function scanCodexHistory(startDate, onProgress, onLine) {
|
|
|
5612
5654
|
onProgress?.(result.filesScanned);
|
|
5613
5655
|
let lines;
|
|
5614
5656
|
try {
|
|
5615
|
-
lines =
|
|
5657
|
+
lines = fs8.readFileSync(filePath, "utf-8").split("\n");
|
|
5616
5658
|
} catch {
|
|
5617
5659
|
continue;
|
|
5618
5660
|
}
|
|
@@ -5817,6 +5859,7 @@ var init_scan = __esm({
|
|
|
5817
5859
|
init_scan_derive();
|
|
5818
5860
|
init_protection();
|
|
5819
5861
|
init_scan_json();
|
|
5862
|
+
init_session_files();
|
|
5820
5863
|
init_scan_history();
|
|
5821
5864
|
toolInspectionMap = DEFAULT_CONFIG.policy.toolInspection;
|
|
5822
5865
|
CODE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
@@ -5881,23 +5924,23 @@ var init_scan = __esm({
|
|
|
5881
5924
|
});
|
|
5882
5925
|
|
|
5883
5926
|
// src/tui/dashboard/data.ts
|
|
5884
|
-
import
|
|
5927
|
+
import fs9 from "fs";
|
|
5885
5928
|
import os11 from "os";
|
|
5886
|
-
import
|
|
5929
|
+
import path12 from "path";
|
|
5887
5930
|
import http from "http";
|
|
5888
5931
|
function auditLogPath() {
|
|
5889
|
-
return
|
|
5932
|
+
return path12.join(os11.homedir(), ".node9", "audit.log");
|
|
5890
5933
|
}
|
|
5891
5934
|
function readAuditEntriesAsync(chunkSize = 1e3, customPath) {
|
|
5892
5935
|
return new Promise((resolve) => {
|
|
5893
5936
|
const p = customPath ?? auditLogPath();
|
|
5894
|
-
if (!
|
|
5937
|
+
if (!fs9.existsSync(p)) {
|
|
5895
5938
|
resolve([]);
|
|
5896
5939
|
return;
|
|
5897
5940
|
}
|
|
5898
5941
|
let raw;
|
|
5899
5942
|
try {
|
|
5900
|
-
raw =
|
|
5943
|
+
raw = fs9.readFileSync(p, "utf8");
|
|
5901
5944
|
} catch {
|
|
5902
5945
|
resolve([]);
|
|
5903
5946
|
return;
|
|
@@ -6033,9 +6076,9 @@ function shortenPath(p) {
|
|
|
6033
6076
|
return p.startsWith(home) ? p.replace(home, "~") : p;
|
|
6034
6077
|
}
|
|
6035
6078
|
async function loadReportAuditAsync(period) {
|
|
6036
|
-
const claudeProjectsDir =
|
|
6037
|
-
const codexSessionsDir =
|
|
6038
|
-
const geminiTmpDir =
|
|
6079
|
+
const claudeProjectsDir = path12.join(os11.homedir(), ".claude", "projects");
|
|
6080
|
+
const codexSessionsDir = path12.join(os11.homedir(), ".codex", "sessions");
|
|
6081
|
+
const geminiTmpDir = path12.join(os11.homedir(), ".gemini", "tmp");
|
|
6039
6082
|
const { start, end } = getDateRange(period, /* @__PURE__ */ new Date());
|
|
6040
6083
|
const entries = await readAuditEntriesAsync();
|
|
6041
6084
|
void ensurePricingLoaded();
|
|
@@ -7070,7 +7113,7 @@ function Cost({ audit }) {
|
|
|
7070
7113
|
flexGrow: 1,
|
|
7071
7114
|
flexBasis: 0,
|
|
7072
7115
|
children: [
|
|
7073
|
-
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "COST" }),
|
|
7116
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, children: "COST \xB7 API value" }),
|
|
7074
7117
|
audit === null ? /* @__PURE__ */ jsx3(Text3, { dimColor: true, children: "loading\u2026" }) : /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
7075
7118
|
/* @__PURE__ */ jsxs3(Box3, { height: 1, children: [
|
|
7076
7119
|
/* @__PURE__ */ jsx3(Box3, { width: LABEL_W2, children: /* @__PURE__ */ jsx3(Text3, { children: "Total" }) }),
|
|
@@ -7116,8 +7159,8 @@ import { Fragment as Fragment3, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-run
|
|
|
7116
7159
|
function TopToolsProjects({ audit }) {
|
|
7117
7160
|
const data = audit?.data;
|
|
7118
7161
|
const tools = data ? [...data.toolMap.entries()].sort(([, a], [, b]) => b.calls - a.calls).slice(0, ROW_LIMIT) : [];
|
|
7119
|
-
const projects = data ? [...data.cost.byProject.entries()].map(([
|
|
7120
|
-
name: basenameOf(
|
|
7162
|
+
const projects = data ? [...data.cost.byProject.entries()].map(([path13, r]) => ({
|
|
7163
|
+
name: basenameOf(path13),
|
|
7121
7164
|
cost: r.cost,
|
|
7122
7165
|
tokens: r.inputTokens + r.outputTokens
|
|
7123
7166
|
})).sort((a, b) => b.cost - a.cost).slice(0, ROW_LIMIT) : [];
|
|
@@ -7554,8 +7597,8 @@ function pickTopLoopFile(loops) {
|
|
|
7554
7597
|
map.set(k, (map.get(k) ?? 0) + (l.count ?? 0));
|
|
7555
7598
|
}
|
|
7556
7599
|
if (map.size === 0) return void 0;
|
|
7557
|
-
const [
|
|
7558
|
-
return { path:
|
|
7600
|
+
const [path13, count] = [...map.entries()].sort((a, b) => b[1] - a[1])[0];
|
|
7601
|
+
return { path: path13, count };
|
|
7559
7602
|
}
|
|
7560
7603
|
var EMPTY_FILTERED_SCAN;
|
|
7561
7604
|
var init_derive = __esm({
|