nairon-bench 0.0.20 → 0.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +386 -177
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3868,15 +3868,15 @@ __export(exports_client, {
3868
3868
  getClerkId: () => getClerkId,
3869
3869
  api: () => api
3870
3870
  });
3871
- import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync, mkdirSync } from "node:fs";
3872
- import { join as join3 } from "node:path";
3873
- import { homedir as homedir2 } from "node:os";
3871
+ import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
3872
+ import { join as join4 } from "node:path";
3873
+ import { homedir as homedir3 } from "node:os";
3874
3874
  function loadConfig() {
3875
- if (!existsSync3(CONFIG_FILE)) {
3875
+ if (!existsSync4(CONFIG_FILE)) {
3876
3876
  return { github: undefined };
3877
3877
  }
3878
3878
  try {
3879
- return JSON.parse(readFileSync3(CONFIG_FILE, "utf-8"));
3879
+ return JSON.parse(readFileSync4(CONFIG_FILE, "utf-8"));
3880
3880
  } catch {
3881
3881
  return { github: undefined };
3882
3882
  }
@@ -3884,8 +3884,8 @@ function loadConfig() {
3884
3884
  function saveConfig(config) {
3885
3885
  const existing = loadConfig();
3886
3886
  const merged = { ...existing, ...config };
3887
- mkdirSync(CONFIG_DIR, { recursive: true });
3888
- writeFileSync(CONFIG_FILE, JSON.stringify(merged, null, 2));
3887
+ mkdirSync2(CONFIG_DIR, { recursive: true });
3888
+ writeFileSync2(CONFIG_FILE, JSON.stringify(merged, null, 2));
3889
3889
  }
3890
3890
  function getConfig() {
3891
3891
  return loadConfig();
@@ -3929,8 +3929,8 @@ var init_client = __esm(() => {
3929
3929
  init_index_node();
3930
3930
  init_api2();
3931
3931
  init_dist();
3932
- CONFIG_DIR = join3(homedir2(), ".nairon-bench");
3933
- CONFIG_FILE = join3(CONFIG_DIR, "config.json");
3932
+ CONFIG_DIR = join4(homedir3(), ".nairon-bench");
3933
+ CONFIG_FILE = join4(CONFIG_DIR, "config.json");
3934
3934
  getClerkId = getGitHub;
3935
3935
  requireClerkId = requireGitHub;
3936
3936
  });
@@ -4446,8 +4446,8 @@ function defineCommand2(def) {
4446
4446
  }
4447
4447
 
4448
4448
  // src/commands/scan.ts
4449
- import { existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2 } from "node:fs";
4450
- import { join as join5 } from "node:path";
4449
+ import { existsSync as existsSync6, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "node:fs";
4450
+ import { join as join6 } from "node:path";
4451
4451
 
4452
4452
  // ../../node_modules/simple-git/dist/esm/index.js
4453
4453
  var import_file_exists = __toESM(require_dist(), 1);
@@ -8515,9 +8515,9 @@ async function collectGit(projectDir, since) {
8515
8515
  }
8516
8516
 
8517
8517
  // src/collectors/agents.ts
8518
- import { existsSync, readdirSync, readFileSync } from "node:fs";
8519
- import { homedir } from "node:os";
8520
- import { join, basename } from "node:path";
8518
+ import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "node:fs";
8519
+ import { homedir as homedir2 } from "node:os";
8520
+ import { join as join2, basename } from "node:path";
8521
8521
  // ../shared/src/constants.ts
8522
8522
  var PHASE_WEIGHTS = {
8523
8523
  requirements: 0.2,
@@ -8800,57 +8800,179 @@ function computeNaironScore(git, agents, tests) {
8800
8800
  function clamp(value, min, max) {
8801
8801
  return Math.min(Math.max(value, min), max);
8802
8802
  }
8803
+ // src/lib/cache.ts
8804
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, statSync } from "node:fs";
8805
+ import { join } from "node:path";
8806
+ import { homedir } from "node:os";
8807
+ var CACHE_VERSION = 1;
8808
+ var CACHE_DIR = join(homedir(), ".nairon", "cache");
8809
+ var SESSION_CACHE_FILE = join(CACHE_DIR, "sessions.json");
8810
+ function ensureCacheDir() {
8811
+ if (!existsSync(CACHE_DIR)) {
8812
+ mkdirSync(CACHE_DIR, { recursive: true });
8813
+ }
8814
+ }
8815
+ function loadCache() {
8816
+ try {
8817
+ if (existsSync(SESSION_CACHE_FILE)) {
8818
+ const content = readFileSync(SESSION_CACHE_FILE, "utf-8");
8819
+ const data = JSON.parse(content);
8820
+ if (data.version === CACHE_VERSION) {
8821
+ return data;
8822
+ }
8823
+ }
8824
+ } catch {}
8825
+ return { version: CACHE_VERSION, entries: {} };
8826
+ }
8827
+ function saveCache(data) {
8828
+ ensureCacheDir();
8829
+ writeFileSync(SESSION_CACHE_FILE, JSON.stringify(data));
8830
+ }
8831
+ function isCacheValid(filePath, cache2) {
8832
+ const entry = cache2.entries[filePath];
8833
+ if (!entry)
8834
+ return false;
8835
+ try {
8836
+ const stat = statSync(filePath);
8837
+ return entry.mtime === stat.mtimeMs && entry.size === stat.size;
8838
+ } catch {
8839
+ return false;
8840
+ }
8841
+ }
8842
+ function getFileStats(filePath) {
8843
+ try {
8844
+ const stat = statSync(filePath);
8845
+ return { mtime: stat.mtimeMs, size: stat.size };
8846
+ } catch {
8847
+ return null;
8848
+ }
8849
+ }
8850
+ class SessionCache {
8851
+ cache;
8852
+ dirty = false;
8853
+ constructor() {
8854
+ this.cache = loadCache();
8855
+ }
8856
+ isValid(filePath) {
8857
+ return isCacheValid(filePath, this.cache);
8858
+ }
8859
+ get(filePath) {
8860
+ if (this.isValid(filePath)) {
8861
+ return this.cache.entries[filePath].session;
8862
+ }
8863
+ return null;
8864
+ }
8865
+ set(filePath, session) {
8866
+ const stats = getFileStats(filePath);
8867
+ if (!stats)
8868
+ return;
8869
+ this.cache.entries[filePath] = {
8870
+ mtime: stats.mtime,
8871
+ size: stats.size,
8872
+ session
8873
+ };
8874
+ this.dirty = true;
8875
+ }
8876
+ save() {
8877
+ if (this.dirty) {
8878
+ saveCache(this.cache);
8879
+ this.dirty = false;
8880
+ }
8881
+ }
8882
+ getStats() {
8883
+ return {
8884
+ total: Object.keys(this.cache.entries).length,
8885
+ hits: 0,
8886
+ misses: 0
8887
+ };
8888
+ }
8889
+ prune() {
8890
+ const before = Object.keys(this.cache.entries).length;
8891
+ for (const filePath of Object.keys(this.cache.entries)) {
8892
+ if (!existsSync(filePath)) {
8893
+ delete this.cache.entries[filePath];
8894
+ this.dirty = true;
8895
+ }
8896
+ }
8897
+ return before - Object.keys(this.cache.entries).length;
8898
+ }
8899
+ }
8900
+ function clearCache() {
8901
+ try {
8902
+ if (existsSync(SESSION_CACHE_FILE)) {
8903
+ writeFileSync(SESSION_CACHE_FILE, JSON.stringify({ version: CACHE_VERSION, entries: {} }));
8904
+ }
8905
+ } catch {}
8906
+ }
8907
+ function getCacheInfo() {
8908
+ try {
8909
+ if (existsSync(SESSION_CACHE_FILE)) {
8910
+ const stat = statSync(SESSION_CACHE_FILE);
8911
+ const cache2 = loadCache();
8912
+ return {
8913
+ entries: Object.keys(cache2.entries).length,
8914
+ sizeBytes: stat.size
8915
+ };
8916
+ }
8917
+ } catch {}
8918
+ return { entries: 0, sizeBytes: 0 };
8919
+ }
8920
+
8803
8921
  // src/collectors/agents.ts
8804
- async function collectAgentSessions(since) {
8922
+ var sessionCache = null;
8923
+ async function collectAgentSessions(since, useCache = true) {
8924
+ sessionCache = useCache ? new SessionCache : null;
8805
8925
  const sessions = [];
8806
- const claudeProjectsDir = join(homedir(), ".claude", "projects");
8807
- if (existsSync(claudeProjectsDir)) {
8926
+ const claudeProjectsDir = join2(homedir2(), ".claude", "projects");
8927
+ if (existsSync2(claudeProjectsDir)) {
8808
8928
  const claudeSessions = collectClaudeSessions(claudeProjectsDir, since);
8809
8929
  sessions.push(...claudeSessions);
8810
8930
  }
8811
- const openCodeDir = join(homedir(), ".local", "share", "opencode");
8812
- if (existsSync(openCodeDir)) {
8931
+ const openCodeDir = join2(homedir2(), ".local", "share", "opencode");
8932
+ if (existsSync2(openCodeDir)) {
8813
8933
  const openCodeSessions = collectOpenCodeSessions(openCodeDir, since);
8814
8934
  sessions.push(...openCodeSessions);
8815
8935
  }
8816
8936
  const cursorDirs = [
8817
- join(homedir(), ".cursor", "sessions"),
8818
- join(homedir(), "Library", "Application Support", "Cursor", "sessions"),
8819
- join(homedir(), ".config", "cursor", "sessions")
8937
+ join2(homedir2(), ".cursor", "sessions"),
8938
+ join2(homedir2(), "Library", "Application Support", "Cursor", "sessions"),
8939
+ join2(homedir2(), ".config", "cursor", "sessions")
8820
8940
  ];
8821
8941
  for (const cursorDir of cursorDirs) {
8822
- if (existsSync(cursorDir)) {
8942
+ if (existsSync2(cursorDir)) {
8823
8943
  const cursorSessions = collectCursorSessions(cursorDir, since);
8824
8944
  sessions.push(...cursorSessions);
8825
8945
  break;
8826
8946
  }
8827
8947
  }
8828
8948
  const windsurfDirs = [
8829
- join(homedir(), ".codeium", "chat_history"),
8830
- join(homedir(), ".windsurf", "sessions"),
8831
- join(homedir(), "Library", "Application Support", "Windsurf", "sessions")
8949
+ join2(homedir2(), ".codeium", "chat_history"),
8950
+ join2(homedir2(), ".windsurf", "sessions"),
8951
+ join2(homedir2(), "Library", "Application Support", "Windsurf", "sessions")
8832
8952
  ];
8833
8953
  for (const windsurfDir of windsurfDirs) {
8834
- if (existsSync(windsurfDir)) {
8954
+ if (existsSync2(windsurfDir)) {
8835
8955
  const windsurfSessions = collectWindsurfSessions(windsurfDir, since);
8836
8956
  sessions.push(...windsurfSessions);
8837
8957
  break;
8838
8958
  }
8839
8959
  }
8840
8960
  const copilotDirs = [
8841
- join(homedir(), ".config", "github-copilot"),
8842
- join(homedir(), "Library", "Application Support", "Code", "User", "globalStorage", "github.copilot"),
8843
- join(homedir(), ".vscode", "extensions")
8961
+ join2(homedir2(), ".config", "github-copilot"),
8962
+ join2(homedir2(), "Library", "Application Support", "Code", "User", "globalStorage", "github.copilot"),
8963
+ join2(homedir2(), ".vscode", "extensions")
8844
8964
  ];
8845
8965
  for (const copilotDir of copilotDirs) {
8846
- if (existsSync(copilotDir)) {
8966
+ if (existsSync2(copilotDir)) {
8847
8967
  const copilotSessions = collectCopilotSessions(copilotDir, since);
8848
8968
  sessions.push(...copilotSessions);
8849
8969
  break;
8850
8970
  }
8851
8971
  }
8852
- if (sessions.length === 0)
8972
+ if (sessions.length === 0) {
8973
+ sessionCache?.save();
8853
8974
  return null;
8975
+ }
8854
8976
  let totalTokens = 0;
8855
8977
  let totalInputTokens = 0;
8856
8978
  let totalOutputTokens = 0;
@@ -8873,6 +8995,7 @@ async function collectAgentSessions(since) {
8873
8995
  costByModel[session.model] = (costByModel[session.model] ?? 0) + session.costUsd;
8874
8996
  }
8875
8997
  }
8998
+ sessionCache?.save();
8876
8999
  return {
8877
9000
  sessions,
8878
9001
  totalSessions: sessions.length,
@@ -8890,9 +9013,9 @@ async function collectAgentSessions(since) {
8890
9013
  function collectClaudeSessions(projectsDir, since) {
8891
9014
  const sessions = [];
8892
9015
  try {
8893
- const projectDirs = readdirSync(projectsDir, { withFileTypes: true }).filter((d2) => d2.isDirectory()).map((d2) => join(projectsDir, d2.name));
9016
+ const projectDirs = readdirSync(projectsDir, { withFileTypes: true }).filter((d2) => d2.isDirectory()).map((d2) => join2(projectsDir, d2.name));
8894
9017
  for (const projectDir of projectDirs) {
8895
- const files = readdirSync(projectDir).filter((f3) => f3.endsWith(".jsonl")).map((f3) => join(projectDir, f3));
9018
+ const files = readdirSync(projectDir).filter((f3) => f3.endsWith(".jsonl")).map((f3) => join2(projectDir, f3));
8896
9019
  for (const file of files) {
8897
9020
  const session = parseClaudeSessionFile(file, since);
8898
9021
  if (session) {
@@ -8905,7 +9028,15 @@ function collectClaudeSessions(projectsDir, since) {
8905
9028
  }
8906
9029
  function parseClaudeSessionFile(filePath, since) {
8907
9030
  try {
8908
- const content = readFileSync(filePath, "utf-8");
9031
+ const cached = sessionCache?.get(filePath);
9032
+ if (cached) {
9033
+ const cachedEndedAt = cached.endedAt ? new Date(cached.endedAt) : null;
9034
+ if (cachedEndedAt && cachedEndedAt >= since) {
9035
+ return cached;
9036
+ }
9037
+ return null;
9038
+ }
9039
+ const content = readFileSync2(filePath, "utf-8");
8909
9040
  const lines = content.trim().split(`
8910
9041
  `).filter(Boolean);
8911
9042
  if (lines.length === 0)
@@ -8970,7 +9101,7 @@ function parseClaudeSessionFile(filePath, since) {
8970
9101
  const durationMinutes = Math.round((endedAt.getTime() - startedAt.getTime()) / 60000);
8971
9102
  const costUsd = calculateTokenCost(model, inputTokens, outputTokens, cachedTokens);
8972
9103
  const patterns = detectPatterns(messages);
8973
- return {
9104
+ const session = {
8974
9105
  agent: "claude",
8975
9106
  sessionId: basename(filePath, ".jsonl"),
8976
9107
  startedAt: startedAt.toISOString(),
@@ -8987,6 +9118,8 @@ function parseClaudeSessionFile(filePath, since) {
8987
9118
  toolNames: Array.from(toolNamesSet),
8988
9119
  patterns
8989
9120
  };
9121
+ sessionCache?.set(filePath, session);
9122
+ return session;
8990
9123
  } catch {
8991
9124
  return null;
8992
9125
  }
@@ -9157,15 +9290,15 @@ function similarity(a2, b2) {
9157
9290
  }
9158
9291
  function collectOpenCodeSessions(baseDir, since) {
9159
9292
  const sessions = [];
9160
- const sessionStorageDir = join(baseDir, "storage", "session");
9161
- const messageStorageDir = join(baseDir, "storage", "message");
9162
- const partStorageDir = join(baseDir, "storage", "part");
9163
- if (!existsSync(sessionStorageDir))
9293
+ const sessionStorageDir = join2(baseDir, "storage", "session");
9294
+ const messageStorageDir = join2(baseDir, "storage", "message");
9295
+ const partStorageDir = join2(baseDir, "storage", "part");
9296
+ if (!existsSync2(sessionStorageDir))
9164
9297
  return sessions;
9165
9298
  try {
9166
- const projectDirs = readdirSync(sessionStorageDir, { withFileTypes: true }).filter((d2) => d2.isDirectory()).map((d2) => join(sessionStorageDir, d2.name));
9299
+ const projectDirs = readdirSync(sessionStorageDir, { withFileTypes: true }).filter((d2) => d2.isDirectory()).map((d2) => join2(sessionStorageDir, d2.name));
9167
9300
  for (const projectDir of projectDirs) {
9168
- const sessionFiles = readdirSync(projectDir).filter((f3) => f3.startsWith("ses_") && f3.endsWith(".json")).map((f3) => join(projectDir, f3));
9301
+ const sessionFiles = readdirSync(projectDir).filter((f3) => f3.startsWith("ses_") && f3.endsWith(".json")).map((f3) => join2(projectDir, f3));
9169
9302
  for (const sessionFile of sessionFiles) {
9170
9303
  const session = parseOpenCodeSession(sessionFile, messageStorageDir, partStorageDir, since);
9171
9304
  if (session) {
@@ -9178,20 +9311,28 @@ function collectOpenCodeSessions(baseDir, since) {
9178
9311
  }
9179
9312
  function parseOpenCodeSession(sessionFile, messageStorageDir, partStorageDir, since) {
9180
9313
  try {
9181
- const sessionContent = readFileSync(sessionFile, "utf-8");
9314
+ const cached = sessionCache?.get(sessionFile);
9315
+ if (cached) {
9316
+ const cachedEndedAt = cached.endedAt ? new Date(cached.endedAt) : null;
9317
+ if (cachedEndedAt && cachedEndedAt >= since) {
9318
+ return cached;
9319
+ }
9320
+ return null;
9321
+ }
9322
+ const sessionContent = readFileSync2(sessionFile, "utf-8");
9182
9323
  const session = JSON.parse(sessionContent);
9183
9324
  const sessionStart = new Date(session.time.created);
9184
9325
  const sessionEnd = session.time.updated ? new Date(session.time.updated) : sessionStart;
9185
9326
  if (sessionEnd < since)
9186
9327
  return null;
9187
- const messagesDir = join(messageStorageDir, session.id);
9188
- if (!existsSync(messagesDir))
9328
+ const messagesDir = join2(messageStorageDir, session.id);
9329
+ if (!existsSync2(messagesDir))
9189
9330
  return null;
9190
- const messageFiles = readdirSync(messagesDir).filter((f3) => f3.startsWith("msg_") && f3.endsWith(".json")).map((f3) => join(messagesDir, f3));
9331
+ const messageFiles = readdirSync(messagesDir).filter((f3) => f3.startsWith("msg_") && f3.endsWith(".json")).map((f3) => join2(messagesDir, f3));
9191
9332
  const messages = [];
9192
9333
  for (const msgFile of messageFiles) {
9193
9334
  try {
9194
- const msgContent = readFileSync(msgFile, "utf-8");
9335
+ const msgContent = readFileSync2(msgFile, "utf-8");
9195
9336
  messages.push(JSON.parse(msgContent));
9196
9337
  } catch {}
9197
9338
  }
@@ -9223,7 +9364,7 @@ function parseOpenCodeSession(sessionFile, messageStorageDir, partStorageDir, si
9223
9364
  const durationMinutes = Math.round((sessionEnd.getTime() - sessionStart.getTime()) / 60000);
9224
9365
  const costUsd = calculateTokenCost(model, inputTokens, outputTokens, cachedTokens);
9225
9366
  const patterns = detectOpenCodePatterns(messages, partStorageDir);
9226
- return {
9367
+ const agentSession = {
9227
9368
  agent: "opencode",
9228
9369
  sessionId: session.id,
9229
9370
  startedAt: sessionStart.toISOString(),
@@ -9240,6 +9381,8 @@ function parseOpenCodeSession(sessionFile, messageStorageDir, partStorageDir, si
9240
9381
  toolNames: [],
9241
9382
  patterns
9242
9383
  };
9384
+ sessionCache?.set(sessionFile, agentSession);
9385
+ return agentSession;
9243
9386
  } catch {
9244
9387
  return null;
9245
9388
  }
@@ -9251,14 +9394,14 @@ function detectOpenCodePatterns(messages, partStorageDir) {
9251
9394
  const msg = messages[i2];
9252
9395
  if (msg.role !== "user")
9253
9396
  continue;
9254
- const partDir = join(partStorageDir, msg.id);
9255
- if (!existsSync(partDir))
9397
+ const partDir = join2(partStorageDir, msg.id);
9398
+ if (!existsSync2(partDir))
9256
9399
  continue;
9257
9400
  try {
9258
9401
  const partFiles = readdirSync(partDir).filter((f3) => f3.endsWith(".json"));
9259
9402
  let text = "";
9260
9403
  for (const partFile of partFiles) {
9261
- const partContent = readFileSync(join(partDir, partFile), "utf-8");
9404
+ const partContent = readFileSync2(join2(partDir, partFile), "utf-8");
9262
9405
  const part = JSON.parse(partContent);
9263
9406
  if (part.type === "text" && part.text) {
9264
9407
  text += part.text + " ";
@@ -9384,9 +9527,9 @@ function collectCursorSessions(sessionsDir, since) {
9384
9527
  try {
9385
9528
  const files = readdirSync(sessionsDir).filter((f3) => f3.endsWith(".json") || f3.endsWith(".jsonl"));
9386
9529
  for (const file of files) {
9387
- const filePath = join(sessionsDir, file);
9530
+ const filePath = join2(sessionsDir, file);
9388
9531
  try {
9389
- const content = readFileSync(filePath, "utf-8");
9532
+ const content = readFileSync2(filePath, "utf-8");
9390
9533
  let data;
9391
9534
  if (content.startsWith("[")) {
9392
9535
  data = JSON.parse(content);
@@ -9431,7 +9574,7 @@ function collectCursorSessions(sessionsDir, since) {
9431
9574
  outputTokens,
9432
9575
  cachedTokens: 0,
9433
9576
  totalTokens,
9434
- costUsd: calculateTokenCost(inputTokens, outputTokens, "gpt-4"),
9577
+ costUsd: calculateTokenCost(firstEntry?.model || "gpt-4", inputTokens, outputTokens),
9435
9578
  model: firstEntry?.model || "gpt-4",
9436
9579
  toolCalls: 0,
9437
9580
  messageCount,
@@ -9448,9 +9591,9 @@ function collectWindsurfSessions(sessionsDir, since) {
9448
9591
  try {
9449
9592
  const files = readdirSync(sessionsDir).filter((f3) => f3.endsWith(".json") || f3.endsWith(".jsonl"));
9450
9593
  for (const file of files) {
9451
- const filePath = join(sessionsDir, file);
9594
+ const filePath = join2(sessionsDir, file);
9452
9595
  try {
9453
- const content = readFileSync(filePath, "utf-8");
9596
+ const content = readFileSync2(filePath, "utf-8");
9454
9597
  let data;
9455
9598
  if (content.startsWith("[")) {
9456
9599
  data = JSON.parse(content);
@@ -9494,7 +9637,7 @@ function collectWindsurfSessions(sessionsDir, since) {
9494
9637
  outputTokens,
9495
9638
  cachedTokens: 0,
9496
9639
  totalTokens,
9497
- costUsd: calculateTokenCost(inputTokens, outputTokens, "gpt-4"),
9640
+ costUsd: calculateTokenCost(firstEntry?.model || "codeium", inputTokens, outputTokens),
9498
9641
  model: firstEntry?.model || "codeium",
9499
9642
  toolCalls: 0,
9500
9643
  messageCount,
@@ -9510,19 +9653,19 @@ function collectCopilotSessions(copilotDir, since) {
9510
9653
  const sessions = [];
9511
9654
  try {
9512
9655
  const searchPaths = [
9513
- join(copilotDir, "usage"),
9514
- join(copilotDir, "telemetry"),
9515
- join(copilotDir, "chat"),
9656
+ join2(copilotDir, "usage"),
9657
+ join2(copilotDir, "telemetry"),
9658
+ join2(copilotDir, "chat"),
9516
9659
  copilotDir
9517
9660
  ];
9518
9661
  for (const searchPath of searchPaths) {
9519
- if (!existsSync(searchPath))
9662
+ if (!existsSync2(searchPath))
9520
9663
  continue;
9521
9664
  const files = readdirSync(searchPath).filter((f3) => f3.endsWith(".json") || f3.endsWith(".jsonl") || f3.endsWith(".log"));
9522
9665
  for (const file of files) {
9523
- const filePath = join(searchPath, file);
9666
+ const filePath = join2(searchPath, file);
9524
9667
  try {
9525
- const content = readFileSync(filePath, "utf-8");
9668
+ const content = readFileSync2(filePath, "utf-8");
9526
9669
  let entries = [];
9527
9670
  try {
9528
9671
  if (content.startsWith("[")) {
@@ -9584,8 +9727,8 @@ function collectCopilotSessions(copilotDir, since) {
9584
9727
  }
9585
9728
 
9586
9729
  // src/collectors/tests.ts
9587
- import { existsSync as existsSync2, readFileSync as readFileSync2 } from "node:fs";
9588
- import { join as join2 } from "node:path";
9730
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "node:fs";
9731
+ import { join as join3 } from "node:path";
9589
9732
  async function collectTestResults(projectDir) {
9590
9733
  const vitestResult = tryVitestReport(projectDir);
9591
9734
  if (vitestResult)
@@ -9600,16 +9743,16 @@ async function collectTestResults(projectDir) {
9600
9743
  }
9601
9744
  function tryVitestReport(projectDir) {
9602
9745
  const paths = [
9603
- join2(projectDir, "test-results", "vitest-results.json"),
9604
- join2(projectDir, "coverage", "coverage-summary.json")
9746
+ join3(projectDir, "test-results", "vitest-results.json"),
9747
+ join3(projectDir, "coverage", "coverage-summary.json")
9605
9748
  ];
9606
- const hasVitest = ["vitest.config.ts", "vitest.config.js", "vitest.config.mts"].some((f3) => existsSync2(join2(projectDir, f3)));
9749
+ const hasVitest = ["vitest.config.ts", "vitest.config.js", "vitest.config.mts"].some((f3) => existsSync3(join3(projectDir, f3)));
9607
9750
  if (!hasVitest)
9608
9751
  return null;
9609
9752
  for (const p of paths) {
9610
- if (existsSync2(p)) {
9753
+ if (existsSync3(p)) {
9611
9754
  try {
9612
- const data = JSON.parse(readFileSync2(p, "utf-8"));
9755
+ const data = JSON.parse(readFileSync3(p, "utf-8"));
9613
9756
  return parseVitestJson(data);
9614
9757
  } catch {}
9615
9758
  }
@@ -9645,16 +9788,16 @@ function parseVitestJson(data) {
9645
9788
  }
9646
9789
  function tryJestReport(projectDir) {
9647
9790
  const paths = [
9648
- join2(projectDir, "test-results", "jest-results.json"),
9649
- join2(projectDir, "jest-results.json")
9791
+ join3(projectDir, "test-results", "jest-results.json"),
9792
+ join3(projectDir, "jest-results.json")
9650
9793
  ];
9651
- const hasJest = ["jest.config.ts", "jest.config.js", "jest.config.mjs"].some((f3) => existsSync2(join2(projectDir, f3)));
9794
+ const hasJest = ["jest.config.ts", "jest.config.js", "jest.config.mjs"].some((f3) => existsSync3(join3(projectDir, f3)));
9652
9795
  if (!hasJest)
9653
9796
  return null;
9654
9797
  for (const p of paths) {
9655
- if (existsSync2(p)) {
9798
+ if (existsSync3(p)) {
9656
9799
  try {
9657
- const data = JSON.parse(readFileSync2(p, "utf-8"));
9800
+ const data = JSON.parse(readFileSync3(p, "utf-8"));
9658
9801
  return {
9659
9802
  framework: "jest",
9660
9803
  totalTests: data.numTotalTests ?? 0,
@@ -9675,13 +9818,13 @@ function tryPlaywrightReport(projectDir) {
9675
9818
  const hasPlaywright = [
9676
9819
  "playwright.config.ts",
9677
9820
  "playwright.config.js"
9678
- ].some((f3) => existsSync2(join2(projectDir, f3)));
9821
+ ].some((f3) => existsSync3(join3(projectDir, f3)));
9679
9822
  if (!hasPlaywright)
9680
9823
  return null;
9681
- const reportPath = join2(projectDir, "test-results", "results.json");
9682
- if (existsSync2(reportPath)) {
9824
+ const reportPath = join3(projectDir, "test-results", "results.json");
9825
+ if (existsSync3(reportPath)) {
9683
9826
  try {
9684
- const data = JSON.parse(readFileSync2(reportPath, "utf-8"));
9827
+ const data = JSON.parse(readFileSync3(reportPath, "utf-8"));
9685
9828
  const suites = data.suites ?? [];
9686
9829
  let passed = 0;
9687
9830
  let failed = 0;
@@ -9722,9 +9865,9 @@ function tryPlaywrightReport(projectDir) {
9722
9865
  init_client();
9723
9866
 
9724
9867
  // src/lib/analyzer.ts
9725
- import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync4 } from "node:fs";
9726
- import { homedir as homedir3 } from "node:os";
9727
- import { join as join4 } from "node:path";
9868
+ import { existsSync as existsSync5, readdirSync as readdirSync2, readFileSync as readFileSync5 } from "node:fs";
9869
+ import { homedir as homedir4 } from "node:os";
9870
+ import { join as join5 } from "node:path";
9728
9871
  import { execSync } from "node:child_process";
9729
9872
  function analyzeWorkflow(agents, projectDir) {
9730
9873
  const sessionPatterns = analyzeSessionPatterns(agents);
@@ -9829,10 +9972,10 @@ function analyzeEfficiency(agents) {
9829
9972
  };
9830
9973
  }
9831
9974
  function detectEnvironment(projectDir, agents) {
9832
- const home = homedir3();
9833
- const claudeConfigDir = join4(home, ".claude");
9834
- const hasClaudeRules = existsSync4(join4(projectDir, "CLAUDE.md")) || existsSync4(join4(projectDir, ".claude", "settings.local.json")) || existsSync4(join4(projectDir, ".cursorrules")) || existsSync4(join4(projectDir, ".clauderules"));
9835
- const hasAgentsmd = existsSync4(join4(projectDir, "AGENTS.md"));
9975
+ const home = homedir4();
9976
+ const claudeConfigDir = join5(home, ".claude");
9977
+ const hasClaudeRules = existsSync5(join5(projectDir, "CLAUDE.md")) || existsSync5(join5(projectDir, ".claude", "settings.local.json")) || existsSync5(join5(projectDir, ".cursorrules")) || existsSync5(join5(projectDir, ".clauderules"));
9978
+ const hasAgentsmd = existsSync5(join5(projectDir, "AGENTS.md"));
9836
9979
  let hasSupermemory = false;
9837
9980
  let hasContext7 = false;
9838
9981
  let hasNia = false;
@@ -9886,13 +10029,13 @@ function detectEnvironment(projectDir, agents) {
9886
10029
  }
9887
10030
  }
9888
10031
  }
9889
- const transcriptsDir = join4(home, ".claude", "transcripts");
9890
- if (!hasSupermemory && existsSync4(transcriptsDir)) {
10032
+ const transcriptsDir = join5(home, ".claude", "transcripts");
10033
+ if (!hasSupermemory && existsSync5(transcriptsDir)) {
9891
10034
  try {
9892
10035
  const transcriptFiles = readdirSync2(transcriptsDir).filter((f3) => f3.endsWith(".jsonl")).slice(-20);
9893
10036
  for (const file of transcriptFiles) {
9894
10037
  try {
9895
- const content = readFileSync4(join4(transcriptsDir, file), "utf-8");
10038
+ const content = readFileSync5(join5(transcriptsDir, file), "utf-8");
9896
10039
  if (content.includes('"tool_name":"supermemory"') || content.includes('"name":"supermemory"') || content.includes("supermemory")) {
9897
10040
  hasSupermemory = true;
9898
10041
  if (!detectedMcps.includes("supermemory")) {
@@ -9905,18 +10048,18 @@ function detectEnvironment(projectDir, agents) {
9905
10048
  }
9906
10049
  } catch {}
9907
10050
  }
9908
- const claudeSettingsLocal = join4(home, ".claude", "settings.local.json");
9909
- const claudeProjectSettings = join4(projectDir, ".claude", "settings.local.json");
10051
+ const claudeSettingsLocal = join5(home, ".claude", "settings.local.json");
10052
+ const claudeProjectSettings = join5(projectDir, ".claude", "settings.local.json");
9910
10053
  const mcpConfigPaths = [
9911
- join4(home, ".claude", "claude_desktop_config.json"),
9912
- join4(home, ".claude", "settings.json"),
10054
+ join5(home, ".claude", "claude_desktop_config.json"),
10055
+ join5(home, ".claude", "settings.json"),
9913
10056
  claudeSettingsLocal,
9914
10057
  claudeProjectSettings
9915
10058
  ];
9916
10059
  for (const configPath of mcpConfigPaths) {
9917
- if (existsSync4(configPath)) {
10060
+ if (existsSync5(configPath)) {
9918
10061
  try {
9919
- const config = JSON.parse(readFileSync4(configPath, "utf-8"));
10062
+ const config = JSON.parse(readFileSync5(configPath, "utf-8"));
9920
10063
  const mcpServers = config.mcpServers || config.mcp_servers || {};
9921
10064
  for (const [name, _3] of Object.entries(mcpServers)) {
9922
10065
  const mcpName = name.toLowerCase();
@@ -9940,12 +10083,12 @@ function detectEnvironment(projectDir, agents) {
9940
10083
  } catch {}
9941
10084
  }
9942
10085
  }
9943
- const agentsMdPath = join4(projectDir, "AGENTS.md");
9944
- const globalAgentsMdPath = join4(home, ".config", "Claude", "AGENTS.md");
10086
+ const agentsMdPath = join5(projectDir, "AGENTS.md");
10087
+ const globalAgentsMdPath = join5(home, ".config", "Claude", "AGENTS.md");
9945
10088
  for (const agentsMd of [agentsMdPath, globalAgentsMdPath]) {
9946
- if (existsSync4(agentsMd)) {
10089
+ if (existsSync5(agentsMd)) {
9947
10090
  try {
9948
- const content = readFileSync4(agentsMd, "utf-8").toLowerCase();
10091
+ const content = readFileSync5(agentsMd, "utf-8").toLowerCase();
9949
10092
  if (content.includes("context7") || content.includes("context-7")) {
9950
10093
  hasContext7 = true;
9951
10094
  if (!detectedMcps.includes("context7")) {
@@ -10003,16 +10146,16 @@ function detectEnvironment(projectDir, agents) {
10003
10146
  } catch {}
10004
10147
  }
10005
10148
  if (!hasBeads) {
10006
- hasBeads = existsSync4(join4(projectDir, ".beads"));
10149
+ hasBeads = existsSync5(join5(projectDir, ".beads"));
10007
10150
  }
10008
10151
  let hasSkills = false;
10009
10152
  let skillCount = 0;
10010
10153
  const skillsDirs = [
10011
- join4(claudeConfigDir, "skills"),
10012
- join4(home, ".agents", "skills")
10154
+ join5(claudeConfigDir, "skills"),
10155
+ join5(home, ".agents", "skills")
10013
10156
  ];
10014
10157
  for (const skillsDir of skillsDirs) {
10015
- if (existsSync4(skillsDir)) {
10158
+ if (existsSync5(skillsDir)) {
10016
10159
  try {
10017
10160
  const skills = readdirSync2(skillsDir, { withFileTypes: true }).filter((d2) => d2.isDirectory() || d2.isSymbolicLink());
10018
10161
  skillCount += skills.length;
@@ -10223,7 +10366,7 @@ function analyzeRequirements(agents, git, projectDir) {
10223
10366
  recommendations.push("Spend more time understanding the problem before implementing");
10224
10367
  }
10225
10368
  }
10226
- const hasRequirementsDocs = existsSync4(join4(projectDir, "CLAUDE.md")) || existsSync4(join4(projectDir, "docs", "requirements.md")) || existsSync4(join4(projectDir, "PRD.md"));
10369
+ const hasRequirementsDocs = existsSync5(join5(projectDir, "CLAUDE.md")) || existsSync5(join5(projectDir, "docs", "requirements.md")) || existsSync5(join5(projectDir, "PRD.md"));
10227
10370
  if (hasRequirementsDocs) {
10228
10371
  score += 10;
10229
10372
  } else {
@@ -10250,18 +10393,18 @@ function analyzePlanning(agents, git, projectDir) {
10250
10393
  const issues = [];
10251
10394
  const recommendations = [];
10252
10395
  let score = 50;
10253
- const usesTaskTracking = existsSync4(join4(projectDir, ".beads"));
10396
+ const usesTaskTracking = existsSync5(join5(projectDir, ".beads"));
10254
10397
  if (usesTaskTracking) {
10255
10398
  score += 20;
10256
10399
  } else {
10257
10400
  issues.push("No task tracking system detected");
10258
10401
  recommendations.push("Install Beads for persistent task tracking: bun add -g beads && bd init");
10259
10402
  }
10260
- const usesDesignDocs = existsSync4(join4(projectDir, "docs", "design.md")) || existsSync4(join4(projectDir, "ARCHITECTURE.md")) || existsSync4(join4(projectDir, "docs", "spec.md"));
10403
+ const usesDesignDocs = existsSync5(join5(projectDir, "docs", "design.md")) || existsSync5(join5(projectDir, "ARCHITECTURE.md")) || existsSync5(join5(projectDir, "docs", "spec.md"));
10261
10404
  if (usesDesignDocs) {
10262
10405
  score += 15;
10263
10406
  }
10264
- const hasSystemDesign = existsSync4(join4(projectDir, "CLAUDE.md")) || existsSync4(join4(projectDir, "AGENTS.md")) || existsSync4(join4(projectDir, ".claude", "settings.local.json"));
10407
+ const hasSystemDesign = existsSync5(join5(projectDir, "CLAUDE.md")) || existsSync5(join5(projectDir, "AGENTS.md")) || existsSync5(join5(projectDir, ".claude", "settings.local.json"));
10265
10408
  if (hasSystemDesign) {
10266
10409
  score += 15;
10267
10410
  } else {
@@ -10363,7 +10506,7 @@ function analyzeTestingPhase(agents, tests, projectDir) {
10363
10506
  const issues = [];
10364
10507
  const recommendations = [];
10365
10508
  let score = 40;
10366
- const hasTestFramework = tests !== null || existsSync4(join4(projectDir, "vitest.config.ts")) || existsSync4(join4(projectDir, "jest.config.js")) || existsSync4(join4(projectDir, "playwright.config.ts"));
10509
+ const hasTestFramework = tests !== null || existsSync5(join5(projectDir, "vitest.config.ts")) || existsSync5(join5(projectDir, "jest.config.js")) || existsSync5(join5(projectDir, "playwright.config.ts"));
10367
10510
  if (hasTestFramework) {
10368
10511
  score += 15;
10369
10512
  } else {
@@ -14023,6 +14166,11 @@ var scanCommand = defineCommand2({
14023
14166
  alias: "q",
14024
14167
  description: "Quiet mode - only output the score number",
14025
14168
  default: false
14169
+ },
14170
+ "no-cache": {
14171
+ type: "boolean",
14172
+ description: "Disable session caching (slower but ensures fresh data)",
14173
+ default: false
14026
14174
  }
14027
14175
  },
14028
14176
  async run({ args }) {
@@ -14030,6 +14178,7 @@ var scanCommand = defineCommand2({
14030
14178
  const since = parseSince(args.since);
14031
14179
  const jsonOutput = args.json;
14032
14180
  const quietMode = args.quiet;
14181
+ const useCache = !args["no-cache"];
14033
14182
  const silent = jsonOutput || quietMode;
14034
14183
  if (!silent) {
14035
14184
  console.log();
@@ -14047,7 +14196,7 @@ var scanCommand = defineCommand2({
14047
14196
  }
14048
14197
  if (!silent)
14049
14198
  await thinkingStep("Scanning AI session logs...", 600);
14050
- const agents = await collectAgentSessions(since);
14199
+ const agents = await collectAgentSessions(since, useCache);
14051
14200
  if (agents && !silent) {
14052
14201
  await revealDiscovery(icons.success, `Sessions: ${colors2.primary(agents.totalSessions.toString())} sessions loaded`, 200);
14053
14202
  }
@@ -14142,7 +14291,7 @@ var scanCommand = defineCommand2({
14142
14291
  console.log(colors2.dim(" " + "═".repeat(45)));
14143
14292
  console.log();
14144
14293
  if (!args["no-report"]) {
14145
- const reportDir = join5(projectDir, args["report-dir"]);
14294
+ const reportDir = join6(projectDir, args["report-dir"]);
14146
14295
  const reportPath = generateReport(reportDir, score, git, agents, tests, args.since, sdlcAnalysis, scanCost, analysis);
14147
14296
  console.log(` ${icons.success} Report saved: ${colors2.dim(reportPath)}`);
14148
14297
  }
@@ -14302,12 +14451,12 @@ function parseSince(since) {
14302
14451
  return new Date(Date.now() - ms);
14303
14452
  }
14304
14453
  function generateReport(reportDir, score, git, agents, tests, since, sdlcAnalysis, scanCost, analysis) {
14305
- if (!existsSync5(reportDir)) {
14306
- mkdirSync2(reportDir, { recursive: true });
14454
+ if (!existsSync6(reportDir)) {
14455
+ mkdirSync3(reportDir, { recursive: true });
14307
14456
  }
14308
14457
  const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
14309
14458
  const filename = `scan-${timestamp}.md`;
14310
- const filepath = join5(reportDir, filename);
14459
+ const filepath = join6(reportDir, filename);
14311
14460
  const lines = [];
14312
14461
  lines.push(`# NaironAI Scan Report`);
14313
14462
  lines.push("");
@@ -14423,7 +14572,7 @@ function generateReport(reportDir, score, git, agents, tests, since, sdlcAnalysi
14423
14572
  lines.push("---");
14424
14573
  lines.push("");
14425
14574
  lines.push("*Generated by [nairon-bench](https://github.com/ObaidUr-Rahmaan/nairon-bench)*");
14426
- writeFileSync2(filepath, lines.join(`
14575
+ writeFileSync3(filepath, lines.join(`
14427
14576
  `));
14428
14577
  return filepath;
14429
14578
  }
@@ -14622,9 +14771,9 @@ function renderBar(value, width) {
14622
14771
  }
14623
14772
 
14624
14773
  // src/commands/doctor.ts
14625
- import { existsSync as existsSync6 } from "node:fs";
14626
- import { homedir as homedir4 } from "node:os";
14627
- import { join as join6 } from "node:path";
14774
+ import { existsSync as existsSync7 } from "node:fs";
14775
+ import { homedir as homedir5 } from "node:os";
14776
+ import { join as join7 } from "node:path";
14628
14777
  init_client();
14629
14778
  var doctorCommand = defineCommand2({
14630
14779
  meta: {
@@ -14642,16 +14791,16 @@ var doctorCommand = defineCommand2({
14642
14791
  results.push({ label: "OS", status: "info", value: `${process.platform} ${process.arch}` });
14643
14792
  results.push({ label: "Bun", status: "info", value: typeof Bun !== "undefined" ? Bun.version : "N/A" });
14644
14793
  results.push({ label: "Node", status: "info", value: process.version });
14645
- results.push({ label: "Home", status: "info", value: homedir4() });
14646
- const gitDir = join6(process.cwd(), ".git");
14647
- if (existsSync6(gitDir)) {
14794
+ results.push({ label: "Home", status: "info", value: homedir5() });
14795
+ const gitDir = join7(process.cwd(), ".git");
14796
+ if (existsSync7(gitDir)) {
14648
14797
  results.push({ label: "Git", status: "success", value: "Repository detected" });
14649
14798
  } else {
14650
14799
  results.push({ label: "Git", status: "warn", value: "No repository in current directory" });
14651
14800
  }
14652
14801
  for (const [agent, pathTemplate] of Object.entries(AGENT_LOG_PATHS)) {
14653
- const resolvedPath = pathTemplate.replace("~", homedir4());
14654
- if (existsSync6(resolvedPath)) {
14802
+ const resolvedPath = pathTemplate.replace("~", homedir5());
14803
+ if (existsSync7(resolvedPath)) {
14655
14804
  results.push({ label: agent, status: "success", value: `found at ${resolvedPath}` });
14656
14805
  }
14657
14806
  }
@@ -14706,9 +14855,9 @@ var doctorCommand = defineCommand2({
14706
14855
 
14707
14856
  // src/commands/init.ts
14708
14857
  init_dist();
14709
- import { existsSync as existsSync7 } from "node:fs";
14710
- import { homedir as homedir5, platform as platform2, arch } from "node:os";
14711
- import { join as join7 } from "node:path";
14858
+ import { existsSync as existsSync8 } from "node:fs";
14859
+ import { homedir as homedir6, platform as platform2, arch } from "node:os";
14860
+ import { join as join8 } from "node:path";
14712
14861
  init_client();
14713
14862
 
14714
14863
  // src/lib/github-auth.ts
@@ -14878,8 +15027,8 @@ var initCommand = defineCommand2({
14878
15027
  consola.start("Step 2/6: Detecting AI agents...");
14879
15028
  const detectedAgents = [];
14880
15029
  for (const [agent, pathTemplate] of Object.entries(AGENT_LOG_PATHS)) {
14881
- const resolvedPath = pathTemplate.replace("~", homedir5());
14882
- if (existsSync7(resolvedPath)) {
15030
+ const resolvedPath = pathTemplate.replace("~", homedir6());
15031
+ if (existsSync8(resolvedPath)) {
14883
15032
  detectedAgents.push(agent);
14884
15033
  consola.success(` Found: ${agent}`);
14885
15034
  }
@@ -14982,7 +15131,7 @@ var initCommand = defineCommand2({
14982
15131
  { name: "playwright", configs: ["playwright.config.ts", "playwright.config.js"] }
14983
15132
  ];
14984
15133
  for (const fw of testFrameworks) {
14985
- if (fw.configs.some((c3) => existsSync7(join7(process.cwd(), c3)))) {
15134
+ if (fw.configs.some((c3) => existsSync8(join8(process.cwd(), c3)))) {
14986
15135
  toolStack.testing.push(fw.name);
14987
15136
  }
14988
15137
  }
@@ -15051,13 +15200,13 @@ var initCommand = defineCommand2({
15051
15200
  });
15052
15201
  function detectPackageManager() {
15053
15202
  const cwd = process.cwd();
15054
- if (existsSync7(join7(cwd, "bun.lock")) || existsSync7(join7(cwd, "bun.lockb")))
15203
+ if (existsSync8(join8(cwd, "bun.lock")) || existsSync8(join8(cwd, "bun.lockb")))
15055
15204
  return "bun";
15056
- if (existsSync7(join7(cwd, "pnpm-lock.yaml")))
15205
+ if (existsSync8(join8(cwd, "pnpm-lock.yaml")))
15057
15206
  return "pnpm";
15058
- if (existsSync7(join7(cwd, "yarn.lock")))
15207
+ if (existsSync8(join8(cwd, "yarn.lock")))
15059
15208
  return "yarn";
15060
- if (existsSync7(join7(cwd, "package-lock.json")))
15209
+ if (existsSync8(join8(cwd, "package-lock.json")))
15061
15210
  return "npm";
15062
15211
  return;
15063
15212
  }
@@ -15072,15 +15221,15 @@ var CLAUDE_CODE_SKILLS = [
15072
15221
  ];
15073
15222
  function detectEasyWins(detectedAgents) {
15074
15223
  const wins = [];
15075
- const home = homedir5();
15224
+ const home = homedir6();
15076
15225
  const hasClaudeCode = detectedAgents.some((a2) => a2.toLowerCase().includes("claude") || a2.toLowerCase().includes("opencode"));
15077
- const claudeConfigDir = join7(home, ".claude");
15078
- const hasClaudeConfig = existsSync7(claudeConfigDir);
15226
+ const claudeConfigDir = join8(home, ".claude");
15227
+ const hasClaudeConfig = existsSync8(claudeConfigDir);
15079
15228
  if (hasClaudeCode || hasClaudeConfig) {
15080
- const skillsDir = join7(home, ".claude", "skills");
15229
+ const skillsDir = join8(home, ".claude", "skills");
15081
15230
  for (const skill of CLAUDE_CODE_SKILLS) {
15082
- const skillPath = join7(skillsDir, skill.id);
15083
- const isInstalled = existsSync7(skillPath);
15231
+ const skillPath = join8(skillsDir, skill.id);
15232
+ const isInstalled = existsSync8(skillPath);
15084
15233
  if (!isInstalled) {
15085
15234
  wins.push({
15086
15235
  icon: skill.icon,
@@ -15851,9 +16000,9 @@ function renderBar2(value, width) {
15851
16000
  // src/commands/publish.ts
15852
16001
  init_dist();
15853
16002
  init_client();
15854
- import { existsSync as existsSync8, readdirSync as readdirSync3, readFileSync as readFileSync5 } from "node:fs";
15855
- import { join as join8 } from "node:path";
15856
- import { homedir as homedir6 } from "node:os";
16003
+ import { existsSync as existsSync9, readdirSync as readdirSync3, readFileSync as readFileSync6 } from "node:fs";
16004
+ import { join as join9 } from "node:path";
16005
+ import { homedir as homedir7 } from "node:os";
15857
16006
  var publishCommand = defineCommand2({
15858
16007
  meta: {
15859
16008
  name: "publish",
@@ -15877,7 +16026,7 @@ var publishCommand = defineCommand2({
15877
16026
  },
15878
16027
  async run({ args }) {
15879
16028
  const projectDir = args.project ?? process.cwd();
15880
- const reportDir = join8(projectDir, args["report-dir"]);
16029
+ const reportDir = join9(projectDir, args["report-dir"]);
15881
16030
  consola.start(`Analyzing your AI workflow...
15882
16031
  `);
15883
16032
  consola.info("Reading scan reports...");
@@ -15957,12 +16106,12 @@ var publishCommand = defineCommand2({
15957
16106
  }
15958
16107
  });
15959
16108
  function readReports(reportDir) {
15960
- if (!existsSync8(reportDir)) {
16109
+ if (!existsSync9(reportDir)) {
15961
16110
  return [];
15962
16111
  }
15963
16112
  const files = readdirSync3(reportDir).filter((f3) => f3.endsWith(".md") && f3.startsWith("scan-")).sort();
15964
16113
  return files.map((file) => {
15965
- const content = readFileSync5(join8(reportDir, file), "utf-8");
16114
+ const content = readFileSync6(join9(reportDir, file), "utf-8");
15966
16115
  return parseReport(content, file);
15967
16116
  });
15968
16117
  }
@@ -15991,13 +16140,13 @@ function parseReport(content, filename) {
15991
16140
  return { date, overall, tier, tokenEfficiency, tokenWaste, phases, models };
15992
16141
  }
15993
16142
  function detectConcepts(projectDir) {
15994
- const home = homedir6();
16143
+ const home = homedir7();
15995
16144
  return {
15996
- skills: existsSync8(join8(home, ".claude", "settings.json")) && readFileSync5(join8(home, ".claude", "settings.json"), "utf-8").includes("skill"),
15997
- mcpServers: existsSync8(join8(home, ".config", "opencode", "config.json")) || existsSync8(join8(home, ".claude", "claude_desktop_config.json")) || existsSync8(join8(home, ".claude", "settings.json")) && readFileSync5(join8(home, ".claude", "settings.json"), "utf-8").includes("mcpServers"),
15998
- customCommands: existsSync8(join8(home, ".claude", "commands")) || existsSync8(join8(projectDir, ".claude", "commands")),
15999
- agentConfig: existsSync8(join8(projectDir, "AGENTS.md")) || existsSync8(join8(projectDir, ".cursorrules")) || existsSync8(join8(projectDir, ".github", "copilot-instructions.md")),
16000
- contextManagement: existsSync8(join8(projectDir, "MEMORY.md")) || existsSync8(join8(projectDir, ".context")) || existsSync8(join8(projectDir, "docs", "architecture.md")) || existsSync8(join8(projectDir, ".beads"))
16145
+ skills: existsSync9(join9(home, ".claude", "settings.json")) && readFileSync6(join9(home, ".claude", "settings.json"), "utf-8").includes("skill"),
16146
+ mcpServers: existsSync9(join9(home, ".config", "opencode", "config.json")) || existsSync9(join9(home, ".claude", "claude_desktop_config.json")) || existsSync9(join9(home, ".claude", "settings.json")) && readFileSync6(join9(home, ".claude", "settings.json"), "utf-8").includes("mcpServers"),
16147
+ customCommands: existsSync9(join9(home, ".claude", "commands")) || existsSync9(join9(projectDir, ".claude", "commands")),
16148
+ agentConfig: existsSync9(join9(projectDir, "AGENTS.md")) || existsSync9(join9(projectDir, ".cursorrules")) || existsSync9(join9(projectDir, ".github", "copilot-instructions.md")),
16149
+ contextManagement: existsSync9(join9(projectDir, "MEMORY.md")) || existsSync9(join9(projectDir, ".context")) || existsSync9(join9(projectDir, "docs", "architecture.md")) || existsSync9(join9(projectDir, ".beads"))
16001
16150
  };
16002
16151
  }
16003
16152
  function computeConceptsScore(concepts) {
@@ -16018,18 +16167,18 @@ function computeConceptsScore(concepts) {
16018
16167
  }
16019
16168
  function detectTools(projectDir) {
16020
16169
  const tools = [];
16021
- const home = homedir6();
16170
+ const home = homedir7();
16022
16171
  const toolChecks = [
16023
- { name: "Claude Code", check: () => existsSync8(join8(home, ".claude")) },
16024
- { name: "Cursor", check: () => existsSync8(join8(projectDir, ".cursorrules")) },
16025
- { name: "GitHub Copilot", check: () => existsSync8(join8(projectDir, ".github", "copilot-instructions.md")) },
16026
- { name: "OpenCode", check: () => existsSync8(join8(home, ".config", "opencode")) },
16027
- { name: "Windsurf", check: () => existsSync8(join8(home, ".windsurf")) },
16028
- { name: "Aider", check: () => existsSync8(join8(projectDir, ".aider.conf.yml")) },
16029
- { name: "Codeium", check: () => existsSync8(join8(home, ".codeium")) },
16030
- { name: "Beads", check: () => existsSync8(join8(projectDir, ".beads")) },
16031
- { name: "Convex", check: () => existsSync8(join8(projectDir, "convex")) },
16032
- { name: "Supabase", check: () => existsSync8(join8(projectDir, "supabase")) }
16172
+ { name: "Claude Code", check: () => existsSync9(join9(home, ".claude")) },
16173
+ { name: "Cursor", check: () => existsSync9(join9(projectDir, ".cursorrules")) },
16174
+ { name: "GitHub Copilot", check: () => existsSync9(join9(projectDir, ".github", "copilot-instructions.md")) },
16175
+ { name: "OpenCode", check: () => existsSync9(join9(home, ".config", "opencode")) },
16176
+ { name: "Windsurf", check: () => existsSync9(join9(home, ".windsurf")) },
16177
+ { name: "Aider", check: () => existsSync9(join9(projectDir, ".aider.conf.yml")) },
16178
+ { name: "Codeium", check: () => existsSync9(join9(home, ".codeium")) },
16179
+ { name: "Beads", check: () => existsSync9(join9(projectDir, ".beads")) },
16180
+ { name: "Convex", check: () => existsSync9(join9(projectDir, "convex")) },
16181
+ { name: "Supabase", check: () => existsSync9(join9(projectDir, "supabase")) }
16033
16182
  ];
16034
16183
  for (const { name, check } of toolChecks) {
16035
16184
  try {
@@ -16439,9 +16588,9 @@ function formatTokens3(tokens) {
16439
16588
  }
16440
16589
 
16441
16590
  // src/commands/session.ts
16442
- import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync6, statSync } from "node:fs";
16443
- import { homedir as homedir7 } from "node:os";
16444
- import { join as join9, basename as basename2 } from "node:path";
16591
+ import { existsSync as existsSync10, readdirSync as readdirSync4, readFileSync as readFileSync7, statSync as statSync2 } from "node:fs";
16592
+ import { homedir as homedir8 } from "node:os";
16593
+ import { join as join10, basename as basename2 } from "node:path";
16445
16594
  var sessionCommand = defineCommand2({
16446
16595
  meta: {
16447
16596
  name: "session",
@@ -16600,23 +16749,23 @@ var sessionCommand = defineCommand2({
16600
16749
  });
16601
16750
  async function collectSessionList() {
16602
16751
  const sessions = [];
16603
- const claudeProjectsDir = join9(homedir7(), ".claude", "projects");
16604
- if (!existsSync9(claudeProjectsDir)) {
16752
+ const claudeProjectsDir = join10(homedir8(), ".claude", "projects");
16753
+ if (!existsSync10(claudeProjectsDir)) {
16605
16754
  return sessions;
16606
16755
  }
16607
16756
  const projectDirs = readdirSync4(claudeProjectsDir);
16608
16757
  for (const projectDir of projectDirs) {
16609
- const projectPath = join9(claudeProjectsDir, projectDir);
16610
- const stat = statSync(projectPath);
16758
+ const projectPath = join10(claudeProjectsDir, projectDir);
16759
+ const stat = statSync2(projectPath);
16611
16760
  if (!stat.isDirectory())
16612
16761
  continue;
16613
16762
  const projectName = decodeProjectName(projectDir);
16614
16763
  const files = readdirSync4(projectPath).filter((f3) => f3.endsWith(".jsonl"));
16615
16764
  for (const file of files) {
16616
- const filePath = join9(projectPath, file);
16765
+ const filePath = join10(projectPath, file);
16617
16766
  const sessionId = basename2(file, ".jsonl").slice(0, 8);
16618
16767
  try {
16619
- const content = readFileSync6(filePath, "utf-8");
16768
+ const content = readFileSync7(filePath, "utf-8");
16620
16769
  const lines = content.trim().split(`
16621
16770
  `).filter(Boolean);
16622
16771
  if (lines.length === 0)
@@ -16658,7 +16807,7 @@ async function collectSessionList() {
16658
16807
  if (cost === 0 && totalTokens > 0) {
16659
16808
  cost = totalTokens / 1e6 * 3;
16660
16809
  }
16661
- const fileStat = statSync(filePath);
16810
+ const fileStat = statSync2(filePath);
16662
16811
  const duration = Math.round((fileStat.mtimeMs - startedAt.getTime()) / 60000);
16663
16812
  sessions.push({
16664
16813
  id: sessionId,
@@ -16690,7 +16839,7 @@ async function parseSessionDetails(filePath) {
16690
16839
  patterns: []
16691
16840
  };
16692
16841
  try {
16693
- const content = readFileSync6(filePath, "utf-8");
16842
+ const content = readFileSync7(filePath, "utf-8");
16694
16843
  const lines = content.trim().split(`
16695
16844
  `).filter(Boolean);
16696
16845
  const filesSet = new Set;
@@ -16772,7 +16921,7 @@ function decodeProjectName(encoded) {
16772
16921
  }
16773
16922
 
16774
16923
  // src/commands/export.ts
16775
- import { writeFileSync as writeFileSync3 } from "node:fs";
16924
+ import { writeFileSync as writeFileSync4 } from "node:fs";
16776
16925
  var exportCommand = defineCommand2({
16777
16926
  meta: {
16778
16927
  name: "export",
@@ -16890,12 +17039,12 @@ var exportCommand = defineCommand2({
16890
17039
  for (const fmt of formats) {
16891
17040
  if (fmt === "json") {
16892
17041
  const jsonPath = `${basePath}.json`;
16893
- writeFileSync3(jsonPath, JSON.stringify(exportData, null, 2));
17042
+ writeFileSync4(jsonPath, JSON.stringify(exportData, null, 2));
16894
17043
  console.log(` ${icons.success} Exported: ${colors2.primary(jsonPath)}`);
16895
17044
  } else if (fmt === "csv") {
16896
17045
  const csvPath = `${basePath}.csv`;
16897
17046
  const csv = generateCSV(exportData);
16898
- writeFileSync3(csvPath, csv);
17047
+ writeFileSync4(csvPath, csv);
16899
17048
  console.log(` ${icons.success} Exported: ${colors2.primary(csvPath)}`);
16900
17049
  }
16901
17050
  }
@@ -17424,6 +17573,65 @@ var badgesCommand = defineCommand2({
17424
17573
  }
17425
17574
  });
17426
17575
 
17576
+ // src/commands/cache.ts
17577
+ var cacheCommand = defineCommand2({
17578
+ meta: {
17579
+ name: "cache",
17580
+ description: "Manage the session cache for faster scans"
17581
+ },
17582
+ args: {
17583
+ clear: {
17584
+ type: "boolean",
17585
+ description: "Clear the session cache",
17586
+ default: false
17587
+ },
17588
+ info: {
17589
+ type: "boolean",
17590
+ description: "Show cache statistics",
17591
+ default: false
17592
+ }
17593
+ },
17594
+ async run({ args }) {
17595
+ console.log();
17596
+ console.log(colors2.bold(colors2.primary(" Session Cache")));
17597
+ console.log(colors2.dim(" " + "─".repeat(40)));
17598
+ console.log();
17599
+ if (args.clear) {
17600
+ const spinner = createSpinner("Clearing cache...");
17601
+ spinner.start();
17602
+ try {
17603
+ clearCache();
17604
+ spinner.succeed("Cache cleared");
17605
+ } catch (err) {
17606
+ spinner.fail("Failed to clear cache");
17607
+ console.log(` ${colors2.dim(err instanceof Error ? err.message : String(err))}`);
17608
+ }
17609
+ console.log();
17610
+ return;
17611
+ }
17612
+ const info2 = getCacheInfo();
17613
+ console.log(` ${icons.info} Cache Status`);
17614
+ console.log();
17615
+ console.log(` ${colors2.dim("Cached sessions:")} ${colors2.primary(info2.entries.toString())}`);
17616
+ console.log(` ${colors2.dim("Cache size:")} ${colors2.primary(formatBytes(info2.sizeBytes))}`);
17617
+ console.log();
17618
+ if (info2.entries > 0) {
17619
+ console.log(` ${colors2.dim("Run")} ${colors2.primary("nb cache --clear")} ${colors2.dim("to clear the cache")}`);
17620
+ } else {
17621
+ console.log(` ${colors2.dim("Cache is empty. Run")} ${colors2.primary("nb scan")} ${colors2.dim("to populate it.")}`);
17622
+ }
17623
+ console.log();
17624
+ }
17625
+ });
17626
+ function formatBytes(bytes) {
17627
+ if (bytes === 0)
17628
+ return "0 B";
17629
+ const k2 = 1024;
17630
+ const sizes = ["B", "KB", "MB", "GB"];
17631
+ const i3 = Math.floor(Math.log(bytes) / Math.log(k2));
17632
+ return `${parseFloat((bytes / Math.pow(k2, i3)).toFixed(1))} ${sizes[i3]}`;
17633
+ }
17634
+
17427
17635
  // src/index.ts
17428
17636
  var VERSION = "0.0.13";
17429
17637
  var CYAN = "\x1B[36m";
@@ -17454,7 +17662,7 @@ function showBanner() {
17454
17662
  log("");
17455
17663
  }
17456
17664
  var args = process.argv.slice(2);
17457
- var subcommands = ["init", "scan", "report", "dashboard", "insights", "tools", "doctor", "publish", "history", "cost", "session", "export", "pr", "badges"];
17665
+ var subcommands = ["init", "scan", "report", "dashboard", "insights", "tools", "doctor", "publish", "history", "cost", "session", "export", "pr", "badges", "cache"];
17458
17666
  var hasSubcommand = args.some((arg) => subcommands.includes(arg));
17459
17667
  var hasHelp = args.includes("--help") || args.includes("-h");
17460
17668
  var hasVersion = args.includes("--version");
@@ -17481,7 +17689,8 @@ if (!hasSubcommand && !hasHelp && !hasVersion && args.length === 0) {
17481
17689
  session: sessionCommand,
17482
17690
  export: exportCommand,
17483
17691
  pr: prCommand,
17484
- badges: badgesCommand
17692
+ badges: badgesCommand,
17693
+ cache: cacheCommand
17485
17694
  }
17486
17695
  });
17487
17696
  runMain(main);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nairon-bench",
3
- "version": "0.0.20",
3
+ "version": "0.0.21",
4
4
  "description": "AI workflow benchmarking CLI",
5
5
  "type": "module",
6
6
  "bin": {