nairon-bench 0.0.28 → 0.0.30

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 +157 -8
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14665,13 +14665,14 @@ init_client();
14665
14665
  import { existsSync as existsSync7, readdirSync as readdirSync3, readFileSync as readFileSync6, statSync as statSync2 } from "node:fs";
14666
14666
  import { homedir as homedir5 } from "node:os";
14667
14667
  import { join as join7, basename as basename2 } from "node:path";
14668
- async function collectReportData(projectDir, since, until = new Date) {
14668
+ async function collectReportData(projectDir, since, until = new Date, harness) {
14669
14669
  const projectName = basename2(projectDir);
14670
- const [commits, sessions, mcpConfigs] = await Promise.all([
14670
+ const [commits, allSessions, mcpConfigs] = await Promise.all([
14671
14671
  collectGitCommits(projectDir, since, until),
14672
14672
  collectAllSessions(since, until, projectDir),
14673
14673
  collectMCPConfigs()
14674
14674
  ]);
14675
+ const sessions = harness && harness !== "all" ? allSessions.filter((s2) => s2.agent === harness) : allSessions;
14675
14676
  const allPrompts = sessions.flatMap((s2) => s2.prompts);
14676
14677
  const toolUsage = buildToolUsageMap(sessions);
14677
14678
  const stats = calculateStats(sessions, allPrompts);
@@ -14893,7 +14894,128 @@ function parseClaudeTranscript(filePath, fileName) {
14893
14894
  };
14894
14895
  }
14895
14896
  function collectOpenCodeSessions2(openCodeDir, since, until) {
14896
- return [];
14897
+ const sessions = [];
14898
+ const sessionDir = join7(openCodeDir, "storage", "session");
14899
+ const messageDir = join7(openCodeDir, "storage", "message");
14900
+ const partDir = join7(openCodeDir, "storage", "part");
14901
+ if (!existsSync7(sessionDir))
14902
+ return sessions;
14903
+ try {
14904
+ const projectDirs = readdirSync3(sessionDir, { withFileTypes: true }).filter((d2) => d2.isDirectory()).map((d2) => join7(sessionDir, d2.name));
14905
+ for (const projectDir of projectDirs) {
14906
+ const sessionFiles = readdirSync3(projectDir).filter((f3) => f3.endsWith(".json"));
14907
+ for (const sessionFile of sessionFiles) {
14908
+ try {
14909
+ const sessionPath = join7(projectDir, sessionFile);
14910
+ const sessionData = JSON.parse(readFileSync6(sessionPath, "utf-8"));
14911
+ const createdAt = new Date(sessionData.time?.created || 0);
14912
+ const updatedAt = new Date(sessionData.time?.updated || sessionData.time?.created || 0);
14913
+ if (updatedAt < since || createdAt > until)
14914
+ continue;
14915
+ const sessionId = sessionData.id;
14916
+ const sessionMsgDir = join7(messageDir, sessionId);
14917
+ const prompts = [];
14918
+ const responses = [];
14919
+ const toolsUsed = new Set;
14920
+ const filesModified = new Set;
14921
+ let totalTokens = 0;
14922
+ let inputTokens = 0;
14923
+ let outputTokens = 0;
14924
+ let model = "unknown";
14925
+ let startTime = createdAt;
14926
+ let endTime = updatedAt;
14927
+ if (existsSync7(sessionMsgDir)) {
14928
+ const msgFiles = readdirSync3(sessionMsgDir).filter((f3) => f3.endsWith(".json")).sort();
14929
+ for (const msgFile of msgFiles) {
14930
+ try {
14931
+ const msgPath = join7(sessionMsgDir, msgFile);
14932
+ const msgData = JSON.parse(readFileSync6(msgPath, "utf-8"));
14933
+ const msgId = msgData.id;
14934
+ if (msgData.model?.modelID) {
14935
+ model = msgData.model.modelID;
14936
+ }
14937
+ const msgTime = new Date(msgData.time?.created || createdAt);
14938
+ if (msgTime < startTime)
14939
+ startTime = msgTime;
14940
+ if (msgTime > endTime)
14941
+ endTime = msgTime;
14942
+ const msgPartDir = join7(partDir, msgId);
14943
+ let messageText = "";
14944
+ if (existsSync7(msgPartDir)) {
14945
+ const partFiles = readdirSync3(msgPartDir).filter((f3) => f3.endsWith(".json")).sort();
14946
+ for (const partFile of partFiles) {
14947
+ try {
14948
+ const partPath = join7(msgPartDir, partFile);
14949
+ const partData = JSON.parse(readFileSync6(partPath, "utf-8"));
14950
+ if (partData.type === "text" && partData.text && !partData.synthetic) {
14951
+ messageText += partData.text + `
14952
+ `;
14953
+ }
14954
+ if (partData.type === "tool-invocation" || partData.type === "tool-result") {
14955
+ const toolName = partData.toolName || partData.name;
14956
+ if (toolName)
14957
+ toolsUsed.add(toolName);
14958
+ }
14959
+ } catch {}
14960
+ }
14961
+ }
14962
+ if (msgData.role === "user" && messageText.trim()) {
14963
+ const prompt2 = analyzePrompt(messageText, sessionId, prompts.length, msgTime);
14964
+ prompts.push(prompt2);
14965
+ }
14966
+ if (msgData.role === "assistant" && messageText.trim()) {
14967
+ const response = analyzeResponse(messageText, sessionId, responses.length, prompts[prompts.length - 1]?.id ?? "", msgTime);
14968
+ responses.push(response);
14969
+ if (messageText.includes("Write ") || messageText.includes("Created ")) {
14970
+ const fileMatches = messageText.match(/(?:Write|Created|Updated)\s+(\S+\.\w+)/g);
14971
+ if (fileMatches) {
14972
+ fileMatches.forEach((m2) => {
14973
+ const file = m2.split(/\s+/)[1];
14974
+ if (file)
14975
+ filesModified.add(file);
14976
+ });
14977
+ }
14978
+ }
14979
+ }
14980
+ if (msgData.usage) {
14981
+ totalTokens += msgData.usage.totalTokens || 0;
14982
+ inputTokens += msgData.usage.inputTokens || 0;
14983
+ outputTokens += msgData.usage.outputTokens || 0;
14984
+ }
14985
+ } catch {}
14986
+ }
14987
+ }
14988
+ if (prompts.length === 0)
14989
+ continue;
14990
+ const correctionCount = prompts.filter((p) => p.isCorrection).length;
14991
+ const frustrationCount = prompts.filter((p) => p.isFrustrated).length;
14992
+ if (sessionData.summary?.files) {
14993
+ filesModified.add(`${sessionData.summary.files} files changed`);
14994
+ }
14995
+ sessions.push({
14996
+ id: sessionId,
14997
+ agent: "opencode",
14998
+ model,
14999
+ startTime,
15000
+ endTime,
15001
+ durationMinutes: Math.round((endTime.getTime() - startTime.getTime()) / 60000),
15002
+ promptCount: prompts.length,
15003
+ totalTokens,
15004
+ inputTokens,
15005
+ outputTokens,
15006
+ prompts,
15007
+ responses,
15008
+ toolsUsed: Array.from(toolsUsed),
15009
+ filesModified: Array.from(filesModified),
15010
+ hadCompaction: false,
15011
+ correctionCount,
15012
+ frustrationCount
15013
+ });
15014
+ } catch {}
15015
+ }
15016
+ }
15017
+ } catch {}
15018
+ return sessions;
14897
15019
  }
14898
15020
  function analyzePrompt(text, sessionId, index, timestamp) {
14899
15021
  const lower = text.toLowerCase();
@@ -18360,8 +18482,8 @@ function renderGitBlameMarkdown(analysis) {
18360
18482
  }
18361
18483
 
18362
18484
  // src/lib/hackathon-report.ts
18363
- async function generateHackathonReport(projectDir, since, until = new Date) {
18364
- const data = await collectReportData(projectDir, since, until);
18485
+ async function generateHackathonReport(projectDir, since, until = new Date, harness) {
18486
+ const data = await collectReportData(projectDir, since, until, harness);
18365
18487
  const sdlcAnalysis = analyzeSDLC(data);
18366
18488
  const promptAnalysis = analyzePrompts(data);
18367
18489
  const effectivenessProfile = analyzeEffectiveness(data);
@@ -18873,6 +18995,10 @@ var reportCommand = defineCommand2({
18873
18995
  description: "Generate hackathon submission report (last 48 hours)",
18874
18996
  default: false
18875
18997
  },
18998
+ harness: {
18999
+ type: "string",
19000
+ description: "AI harness to analyze: claude-code, opencode, cursor, or all"
19001
+ },
18876
19002
  since: {
18877
19003
  type: "string",
18878
19004
  description: "Time range: 48h, 7d, 30d, or ISO date"
@@ -18933,6 +19059,16 @@ var reportCommand = defineCommand2({
18933
19059
  month: "30d"
18934
19060
  };
18935
19061
  args.since = sinceMap[choice];
19062
+ const harness = await consola.prompt("Which AI harness did you use?", {
19063
+ type: "select",
19064
+ options: [
19065
+ { value: "claude-code", label: "Claude Code" },
19066
+ { value: "opencode", label: "OpenCode" },
19067
+ { value: "cursor", label: "Cursor" },
19068
+ { value: "all", label: "All (combine sessions from all harnesses)" }
19069
+ ]
19070
+ });
19071
+ args.harness = harness;
18936
19072
  const format2 = await consola.prompt("Output format?", {
18937
19073
  type: "select",
18938
19074
  options: [
@@ -18983,12 +19119,25 @@ var reportCommand = defineCommand2({
18983
19119
  });
18984
19120
  async function runHackathonReport(args) {
18985
19121
  const projectDir = process.cwd();
19122
+ let harness = args.harness;
19123
+ if (!harness) {
19124
+ harness = await consola.prompt("Which AI harness did you use?", {
19125
+ type: "select",
19126
+ options: [
19127
+ { value: "claude-code", label: "Claude Code" },
19128
+ { value: "opencode", label: "OpenCode" },
19129
+ { value: "cursor", label: "Cursor" },
19130
+ { value: "all", label: "All (combine sessions from all harnesses)" }
19131
+ ]
19132
+ });
19133
+ }
18986
19134
  const since = parseSince2(args.since || (args.hackathon ? "48h" : "7d"));
18987
19135
  const until = new Date;
18988
19136
  const hoursAgo = Math.round((until.getTime() - since.getTime()) / (1000 * 60 * 60));
18989
- consola.start(`Generating AI-nativeness report for last ${hoursAgo} hours...`);
19137
+ const harnessLabel = harness === "all" ? "all harnesses" : harness;
19138
+ consola.start(`Generating AI-nativeness report for ${harnessLabel} (last ${hoursAgo} hours)...`);
18990
19139
  try {
18991
- const report = await generateHackathonReport(projectDir, since, until);
19140
+ const report = await generateHackathonReport(projectDir, since, until, harness);
18992
19141
  if (args.publish) {
18993
19142
  await publishReport(report);
18994
19143
  return;
@@ -22848,7 +22997,7 @@ var setupCommand = defineCommand2({
22848
22997
  // package.json
22849
22998
  var package_default = {
22850
22999
  name: "nairon-bench",
22851
- version: "0.0.28",
23000
+ version: "0.0.30",
22852
23001
  description: "AI workflow benchmarking CLI",
22853
23002
  type: "module",
22854
23003
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nairon-bench",
3
- "version": "0.0.28",
3
+ "version": "0.0.30",
4
4
  "description": "AI workflow benchmarking CLI",
5
5
  "type": "module",
6
6
  "bin": {