nairon-bench 0.5.2 → 0.5.3

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 +137 -42
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -3661,10 +3661,10 @@ class ConvexHttpClient {
3661
3661
  }
3662
3662
  this.isProcessingQueue = true;
3663
3663
  while (this.mutationQueue.length > 0) {
3664
- const { mutation, args, resolve, reject } = this.mutationQueue.shift();
3664
+ const { mutation, args, resolve: resolve2, reject } = this.mutationQueue.shift();
3665
3665
  try {
3666
3666
  const result = await this.mutationInner(mutation, args);
3667
- resolve(result);
3667
+ resolve2(result);
3668
3668
  } catch (error) {
3669
3669
  reject(error);
3670
3670
  }
@@ -3672,8 +3672,8 @@ class ConvexHttpClient {
3672
3672
  this.isProcessingQueue = false;
3673
3673
  }
3674
3674
  enqueueMutation(mutation, args) {
3675
- return new Promise((resolve, reject) => {
3676
- this.mutationQueue.push({ mutation, args, resolve, reject });
3675
+ return new Promise((resolve2, reject) => {
3676
+ this.mutationQueue.push({ mutation, args, resolve: resolve2, reject });
3677
3677
  this.processMutationQueue();
3678
3678
  });
3679
3679
  }
@@ -8518,7 +8518,7 @@ async function collectGit(projectDir, since) {
8518
8518
  // src/collectors/agents.ts
8519
8519
  import { existsSync as existsSync2, readdirSync, readFileSync as readFileSync2 } from "node:fs";
8520
8520
  import { homedir as homedir2 } from "node:os";
8521
- import { join as join2, basename } from "node:path";
8521
+ import { join as join2, basename, resolve } from "node:path";
8522
8522
  // ../shared/src/constants.ts
8523
8523
  var PHASE_WEIGHTS = {
8524
8524
  requirements: 0.2,
@@ -8921,17 +8921,18 @@ function getCacheInfo() {
8921
8921
 
8922
8922
  // src/collectors/agents.ts
8923
8923
  var sessionCache = null;
8924
- async function collectAgentSessions(since, useCache = true) {
8924
+ async function collectAgentSessions(since, useCache = true, projectDir) {
8925
8925
  sessionCache = useCache ? new SessionCache : null;
8926
+ const targetProjectDir = projectDir ? resolve(projectDir) : process.cwd();
8926
8927
  const sessions = [];
8927
8928
  const claudeProjectsDir = join2(homedir2(), ".claude", "projects");
8928
8929
  if (existsSync2(claudeProjectsDir)) {
8929
- const claudeSessions = collectClaudeSessions(claudeProjectsDir, since);
8930
+ const claudeSessions = collectClaudeSessions(claudeProjectsDir, since, targetProjectDir);
8930
8931
  sessions.push(...claudeSessions);
8931
8932
  }
8932
8933
  const openCodeDir = join2(homedir2(), ".local", "share", "opencode");
8933
8934
  if (existsSync2(openCodeDir)) {
8934
- const openCodeSessions = collectOpenCodeSessions(openCodeDir, since);
8935
+ const openCodeSessions = collectOpenCodeSessions(openCodeDir, since, targetProjectDir);
8935
8936
  sessions.push(...openCodeSessions);
8936
8937
  }
8937
8938
  const cursorDirs = [
@@ -9011,11 +9012,29 @@ async function collectAgentSessions(since, useCache = true) {
9011
9012
  costByModel
9012
9013
  };
9013
9014
  }
9014
- function collectClaudeSessions(projectsDir, since) {
9015
+ function collectClaudeSessions(projectsDir, since, targetProjectDir) {
9015
9016
  const sessions = [];
9016
9017
  try {
9017
9018
  const projectDirs = readdirSync(projectsDir, { withFileTypes: true }).filter((d2) => d2.isDirectory()).map((d2) => join2(projectsDir, d2.name));
9019
+ let matchingProjectDir = null;
9018
9020
  for (const projectDir of projectDirs) {
9021
+ const projectMetaFile = join2(projectDir, ".project.json");
9022
+ if (existsSync2(projectMetaFile)) {
9023
+ try {
9024
+ const meta = JSON.parse(readFileSync2(projectMetaFile, "utf-8"));
9025
+ if (meta.directory) {
9026
+ const metaDir = resolve(meta.directory);
9027
+ const isMatch = metaDir === targetProjectDir || targetProjectDir.startsWith(metaDir + "/") || metaDir.startsWith(targetProjectDir + "/");
9028
+ if (isMatch) {
9029
+ matchingProjectDir = projectDir;
9030
+ break;
9031
+ }
9032
+ }
9033
+ } catch {}
9034
+ }
9035
+ }
9036
+ const dirsToScan = matchingProjectDir ? [matchingProjectDir] : projectDirs;
9037
+ for (const projectDir of dirsToScan) {
9019
9038
  const files = readdirSync(projectDir).filter((f3) => f3.endsWith(".jsonl")).map((f3) => join2(projectDir, f3));
9020
9039
  for (const file of files) {
9021
9040
  const session = parseClaudeSessionFile(file, since);
@@ -9289,7 +9308,7 @@ function similarity(a2, b2) {
9289
9308
  const union = new Set([...wordsA, ...wordsB]);
9290
9309
  return union.size > 0 ? intersection.size / union.size : 0;
9291
9310
  }
9292
- function collectOpenCodeSessions(baseDir, since) {
9311
+ function collectOpenCodeSessions(baseDir, since, targetProjectDir) {
9293
9312
  const sessions = [];
9294
9313
  const sessionStorageDir = join2(baseDir, "storage", "session");
9295
9314
  const messageStorageDir = join2(baseDir, "storage", "message");
@@ -9301,7 +9320,7 @@ function collectOpenCodeSessions(baseDir, since) {
9301
9320
  for (const projectDir of projectDirs) {
9302
9321
  const sessionFiles = readdirSync(projectDir).filter((f3) => f3.startsWith("ses_") && f3.endsWith(".json")).map((f3) => join2(projectDir, f3));
9303
9322
  for (const sessionFile of sessionFiles) {
9304
- const session = parseOpenCodeSession(sessionFile, messageStorageDir, partStorageDir, since);
9323
+ const session = parseOpenCodeSession(sessionFile, messageStorageDir, partStorageDir, since, targetProjectDir);
9305
9324
  if (session) {
9306
9325
  sessions.push(session);
9307
9326
  }
@@ -9310,7 +9329,7 @@ function collectOpenCodeSessions(baseDir, since) {
9310
9329
  } catch {}
9311
9330
  return sessions;
9312
9331
  }
9313
- function parseOpenCodeSession(sessionFile, messageStorageDir, partStorageDir, since) {
9332
+ function parseOpenCodeSession(sessionFile, messageStorageDir, partStorageDir, since, targetProjectDir) {
9314
9333
  try {
9315
9334
  const cached = sessionCache?.get(sessionFile);
9316
9335
  if (cached) {
@@ -9322,6 +9341,13 @@ function parseOpenCodeSession(sessionFile, messageStorageDir, partStorageDir, si
9322
9341
  }
9323
9342
  const sessionContent = readFileSync2(sessionFile, "utf-8");
9324
9343
  const session = JSON.parse(sessionContent);
9344
+ if (session.directory) {
9345
+ const sessionDir = resolve(session.directory);
9346
+ const isMatch = sessionDir === targetProjectDir || targetProjectDir.startsWith(sessionDir + "/") || sessionDir.startsWith(targetProjectDir + "/");
9347
+ if (!isMatch) {
9348
+ return null;
9349
+ }
9350
+ }
9325
9351
  const sessionStart = new Date(session.time.created);
9326
9352
  const sessionEnd = session.time.updated ? new Date(session.time.updated) : sessionStart;
9327
9353
  if (sessionEnd < since)
@@ -14763,7 +14789,7 @@ var icons = {
14763
14789
  brain: "\uD83E\uDDE0",
14764
14790
  target: "\uD83C\uDFAF"
14765
14791
  };
14766
- var sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
14792
+ var sleep = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
14767
14793
  function clearLine2() {
14768
14794
  readline.clearLine(process.stdout, 0);
14769
14795
  readline.cursorTo(process.stdout, 0);
@@ -15110,8 +15136,12 @@ function extractFrustrationPrompts(sessionPath, patterns) {
15110
15136
  }
15111
15137
  }
15112
15138
  } else if (sessionPath.endsWith(".json")) {
15113
- for (const _3 of patterns) {
15114
- prompts.push("");
15139
+ const sessionData = JSON.parse(content);
15140
+ const sessionId = sessionData.id;
15141
+ const userPrompts = extractOpenCodePrompts(sessionId);
15142
+ for (const pattern of patterns) {
15143
+ const frustrationMsg = findFrustrationMessage(userPrompts);
15144
+ prompts.push(frustrationMsg || userPrompts[0] || "");
15115
15145
  }
15116
15146
  }
15117
15147
  return prompts;
@@ -15119,6 +15149,45 @@ function extractFrustrationPrompts(sessionPath, patterns) {
15119
15149
  return [];
15120
15150
  }
15121
15151
  }
15152
+ function extractOpenCodePrompts(sessionId) {
15153
+ const home = homedir6();
15154
+ const messageDir = join7(home, ".local", "share", "opencode", "storage", "message", sessionId);
15155
+ const partBaseDir = join7(home, ".local", "share", "opencode", "storage", "part");
15156
+ if (!existsSync7(messageDir))
15157
+ return [];
15158
+ const prompts = [];
15159
+ try {
15160
+ const messageFiles = fsReaddirSync(messageDir).filter((f3) => f3.endsWith(".json")).sort();
15161
+ for (const msgFile of messageFiles) {
15162
+ try {
15163
+ const msgPath = join7(messageDir, msgFile);
15164
+ const msgData = JSON.parse(readFileSync7(msgPath, "utf-8"));
15165
+ if (msgData.role !== "user")
15166
+ continue;
15167
+ const messageId = msgData.id;
15168
+ const timestamp = msgData.time?.created;
15169
+ const partDir = join7(partBaseDir, messageId);
15170
+ if (!existsSync7(partDir))
15171
+ continue;
15172
+ const partFiles = fsReaddirSync(partDir).filter((f3) => f3.endsWith(".json"));
15173
+ let messageText = "";
15174
+ for (const partFile of partFiles) {
15175
+ try {
15176
+ const partData = JSON.parse(readFileSync7(join7(partDir, partFile), "utf-8"));
15177
+ if (partData.type === "text" && partData.text) {
15178
+ messageText += partData.text + " ";
15179
+ }
15180
+ } catch {}
15181
+ }
15182
+ if (messageText.trim()) {
15183
+ const timeStr = timestamp ? new Date(timestamp).toLocaleTimeString() : "";
15184
+ prompts.push(`[${timeStr}] ${messageText.trim()}`);
15185
+ }
15186
+ } catch {}
15187
+ }
15188
+ } catch {}
15189
+ return prompts;
15190
+ }
15122
15191
  function extractMessageText(msg) {
15123
15192
  if (typeof msg.content === "string")
15124
15193
  return msg.content;
@@ -15313,25 +15382,40 @@ function formatFrustrationSummary(summary) {
15313
15382
  }
15314
15383
  function formatFrustrationEvent(f3, index) {
15315
15384
  const lines = [];
15316
- lines.push(` ${colors2.warning(`${index}.`)} ${colors2.bold(f3.patternDescription)} ${colors2.dim(`(${f3.agent})`)}`);
15317
- lines.push(` ${colors2.dim("Session:")} ${f3.sessionId.slice(0, 12)}...`);
15318
- lines.push(` ${colors2.dim("Time wasted:")} ~${f3.estimatedTimeWastedMinutes} min`);
15319
- lines.push(` ${colors2.dim("Cause:")} ${formatCauseLabel(f3.rootCause.category)}`);
15385
+ lines.push(` ${colors2.error(`${index}.`)} ${formatCauseLabel(f3.rootCause.category)}`);
15386
+ lines.push(` ${colors2.dim("Session:")} ${f3.sessionId.slice(0, 16)}... ${colors2.dim(`(${f3.agent})`)}`);
15387
+ if (f3.timestamp) {
15388
+ const date = new Date(f3.timestamp);
15389
+ lines.push(` ${colors2.dim("When:")} ${date.toLocaleDateString()} ${date.toLocaleTimeString()}`);
15390
+ }
15391
+ lines.push(` ${colors2.dim("Time wasted:")} ${colors2.warning(`~${f3.estimatedTimeWastedMinutes} min`)}`);
15320
15392
  if (f3.exactPrompt && f3.exactPrompt.length > 0 && !f3.exactPrompt.startsWith("(Unable")) {
15321
15393
  lines.push("");
15322
- lines.push(` ${colors2.dim("┌" + "─".repeat(40))}`);
15323
- const promptLines = wrapText(f3.exactPrompt, 38);
15324
- for (const line of promptLines.slice(0, 4)) {
15325
- lines.push(` ${colors2.dim("")} ${line}`);
15394
+ lines.push(` ${colors2.bold("Your prompt:")}`);
15395
+ lines.push(` ${colors2.dim("┌" + "─".repeat(50))}`);
15396
+ let promptText = f3.exactPrompt;
15397
+ if (promptText.startsWith("[")) {
15398
+ const closeBracket = promptText.indexOf("]");
15399
+ if (closeBracket > 0 && closeBracket < 15) {
15400
+ promptText = promptText.slice(closeBracket + 2);
15401
+ }
15402
+ }
15403
+ const promptLines = wrapText(promptText, 48);
15404
+ for (const line of promptLines.slice(0, 6)) {
15405
+ lines.push(` ${colors2.dim("│")} ${colors2.primary(line)}`);
15326
15406
  }
15327
- if (promptLines.length > 4) {
15328
- lines.push(` ${colors2.dim("│")} ${colors2.dim("...")}`);
15407
+ if (promptLines.length > 6) {
15408
+ lines.push(` ${colors2.dim("│")} ${colors2.dim(`... (${promptLines.length - 6} more lines)`)}`);
15329
15409
  }
15330
- lines.push(` ${colors2.dim("└" + "─".repeat(40))}`);
15410
+ lines.push(` ${colors2.dim("└" + "─".repeat(50))}`);
15411
+ } else {
15412
+ lines.push("");
15413
+ lines.push(` ${colors2.dim("(Prompt not captured - " + f3.patternDescription + ")")}`);
15331
15414
  }
15332
15415
  lines.push("");
15333
- lines.push(` ${colors2.success("Fix:")} ${f3.recommendedFix.tool}`);
15334
- lines.push(` ${colors2.dim("$")} ${colors2.primary(f3.recommendedFix.installCommand)}`);
15416
+ lines.push(` ${colors2.success("Fix with:")} ${colors2.bold(f3.recommendedFix.tool)}`);
15417
+ lines.push(` ${colors2.dim(f3.recommendedFix.description)}`);
15418
+ lines.push(` ${colors2.dim("$")} ${colors2.primary(f3.recommendedFix.installCommand)}`);
15335
15419
  return lines;
15336
15420
  }
15337
15421
  function formatCauseLabel(cause) {
@@ -16376,7 +16460,7 @@ var scanCommand = defineCommand2({
16376
16460
  const timestamp = new Date().toLocaleTimeString();
16377
16461
  try {
16378
16462
  const git2 = await collectGit(projectDir, since);
16379
- const agents2 = await collectAgentSessions(since, useCache);
16463
+ const agents2 = await collectAgentSessions(since, useCache, projectDir);
16380
16464
  const tests2 = await collectTestResults(projectDir);
16381
16465
  const score2 = computeNaironScore(git2 ?? undefined, agents2 ?? undefined, tests2 ?? undefined);
16382
16466
  const delta = scanCount > 1 ? score2.overall - lastScore : 0;
@@ -16421,7 +16505,7 @@ var scanCommand = defineCommand2({
16421
16505
  }
16422
16506
  if (!silent)
16423
16507
  await thinkingStep("Scanning AI session logs...", 600);
16424
- const agents = await collectAgentSessions(since, useCache);
16508
+ const agents = await collectAgentSessions(since, useCache, projectDir);
16425
16509
  if (agents && !silent) {
16426
16510
  await revealDiscovery(icons.success, `Sessions: ${colors2.primary(agents.totalSessions.toString())} sessions loaded`, 200);
16427
16511
  }
@@ -21888,7 +21972,7 @@ function formatReportAsJSON(report) {
21888
21972
 
21889
21973
  // src/commands/report.ts
21890
21974
  import { writeFileSync as writeFileSync6 } from "node:fs";
21891
- import { resolve } from "node:path";
21975
+ import { resolve as resolve2 } from "node:path";
21892
21976
  var reportCommand = defineCommand2({
21893
21977
  meta: {
21894
21978
  name: "report",
@@ -22098,7 +22182,7 @@ async function runHackathonReport(args) {
22098
22182
  break;
22099
22183
  }
22100
22184
  if (args.output) {
22101
- const filepath = resolve(projectDir, args.output);
22185
+ const filepath = resolve2(projectDir, args.output);
22102
22186
  writeFileSync6(filepath, output);
22103
22187
  consola.success(`Report saved to ${filepath}`);
22104
22188
  }
@@ -22250,7 +22334,7 @@ async function runLeadershipReport(args) {
22250
22334
  const since = parseSince2(args.since || "7d");
22251
22335
  const periodLabel = args.since === "30d" ? "Last 30 days" : args.since === "48h" ? "Last 48 hours" : "Last 7 days";
22252
22336
  consola.start(`Generating leadership report (${periodLabel})...`);
22253
- const agents = await collectAgentSessions(since);
22337
+ const agents = await collectAgentSessions(since, true, projectDir);
22254
22338
  if (!agents || agents.sessions.length === 0) {
22255
22339
  consola.warn("No AI sessions found in the specified time range.");
22256
22340
  consola.info("Try running with --since 30d for a longer time range.");
@@ -22267,7 +22351,7 @@ async function runLeadershipReport(args) {
22267
22351
  `);
22268
22352
  }
22269
22353
  if (args.output) {
22270
- const filepath = resolve(projectDir, args.output);
22354
+ const filepath = resolve2(projectDir, args.output);
22271
22355
  writeFileSync6(filepath, output);
22272
22356
  consola.success(`Report saved to ${filepath}`);
22273
22357
  }
@@ -23272,10 +23356,10 @@ async function prompt2(question) {
23272
23356
  input: process.stdin,
23273
23357
  output: process.stdout
23274
23358
  });
23275
- return new Promise((resolve2) => {
23359
+ return new Promise((resolve3) => {
23276
23360
  rl.question(question, (answer) => {
23277
23361
  rl.close();
23278
- resolve2(answer.trim());
23362
+ resolve3(answer.trim());
23279
23363
  });
23280
23364
  });
23281
23365
  }
@@ -23720,6 +23804,17 @@ var BOLD = "\x1B[1m";
23720
23804
  var RESET = "\x1B[0m";
23721
23805
  var MAGENTA = "\x1B[35m";
23722
23806
  var CHANGELOG = [
23807
+ {
23808
+ version: "0.5.3",
23809
+ date: "2026-02-14",
23810
+ title: "Project-Scoped Analysis",
23811
+ highlights: [
23812
+ "CRITICAL FIX: Sessions now filtered to current project only",
23813
+ "No more mixing data from different projects in reports",
23814
+ "Improved frustration display with exact prompts and timestamps",
23815
+ "Better OpenCode prompt extraction for frustration analysis"
23816
+ ]
23817
+ },
23723
23818
  {
23724
23819
  version: "0.5.2",
23725
23820
  date: "2026-02-14",
@@ -24191,7 +24286,7 @@ function showFullChangelog() {
24191
24286
  // package.json
24192
24287
  var package_default = {
24193
24288
  name: "nairon-bench",
24194
- version: "0.5.2",
24289
+ version: "0.5.3",
24195
24290
  description: "AI workflow benchmarking CLI",
24196
24291
  type: "module",
24197
24292
  bin: {
@@ -24380,7 +24475,7 @@ async function fetchGitHubUser(accessToken) {
24380
24475
  return await response.json();
24381
24476
  }
24382
24477
  function sleep2(ms) {
24383
- return new Promise((resolve2) => setTimeout(resolve2, ms));
24478
+ return new Promise((resolve3) => setTimeout(resolve3, ms));
24384
24479
  }
24385
24480
 
24386
24481
  // src/commands/init.ts
@@ -25169,7 +25264,7 @@ var safeJSON = (text) => {
25169
25264
  };
25170
25265
 
25171
25266
  // ../../node_modules/supermemory/internal/utils/sleep.mjs
25172
- var sleep3 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
25267
+ var sleep3 = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms));
25173
25268
 
25174
25269
  // ../../node_modules/supermemory/version.mjs
25175
25270
  var VERSION = "4.11.1";
@@ -25811,8 +25906,8 @@ var _APIPromise_client;
25811
25906
 
25812
25907
  class APIPromise extends Promise {
25813
25908
  constructor(client, responsePromise, parseResponse = defaultParseResponse) {
25814
- super((resolve2) => {
25815
- resolve2(null);
25909
+ super((resolve3) => {
25910
+ resolve3(null);
25816
25911
  });
25817
25912
  this.responsePromise = responsePromise;
25818
25913
  this.parseResponse = parseResponse;
@@ -26718,7 +26813,7 @@ function formatBytes(bytes) {
26718
26813
  // package.json
26719
26814
  var package_default2 = {
26720
26815
  name: "nairon-bench",
26721
- version: "0.5.2",
26816
+ version: "0.5.3",
26722
26817
  description: "AI workflow benchmarking CLI",
26723
26818
  type: "module",
26724
26819
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nairon-bench",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "AI workflow benchmarking CLI",
5
5
  "type": "module",
6
6
  "bin": {