nairon-bench 0.5.0 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +564 -206
- package/package.json +5 -3
- package/postinstall.js +22 -0
package/dist/index.js
CHANGED
|
@@ -4447,8 +4447,8 @@ function defineCommand2(def) {
|
|
|
4447
4447
|
|
|
4448
4448
|
// src/commands/scan.ts
|
|
4449
4449
|
init_dist();
|
|
4450
|
-
import { existsSync as
|
|
4451
|
-
import { join as
|
|
4450
|
+
import { existsSync as existsSync10, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5, readFileSync as readFileSync10 } from "node:fs";
|
|
4451
|
+
import { join as join10 } from "node:path";
|
|
4452
4452
|
|
|
4453
4453
|
// ../../node_modules/simple-git/dist/esm/index.js
|
|
4454
4454
|
var import_file_exists = __toESM(require_dist(), 1);
|
|
@@ -16068,6 +16068,251 @@ function filterAlreadyInstalled(optimizations, status) {
|
|
|
16068
16068
|
});
|
|
16069
16069
|
}
|
|
16070
16070
|
|
|
16071
|
+
// src/lib/first-run.ts
|
|
16072
|
+
init_dist();
|
|
16073
|
+
import { existsSync as existsSync9, readFileSync as readFileSync9, writeFileSync as writeFileSync4, mkdirSync as mkdirSync4 } from "node:fs";
|
|
16074
|
+
import { homedir as homedir8 } from "node:os";
|
|
16075
|
+
import { join as join9 } from "node:path";
|
|
16076
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
16077
|
+
var FIRST_RUN_FLAG = join9(homedir8(), ".nairon-bench", "first-run-complete");
|
|
16078
|
+
var PROJECT_SCAN_MARKER = ".nairon/first-scan-complete";
|
|
16079
|
+
function isFirstScanInProject(projectDir) {
|
|
16080
|
+
return !existsSync9(join9(projectDir, PROJECT_SCAN_MARKER));
|
|
16081
|
+
}
|
|
16082
|
+
function markProjectScanned(projectDir) {
|
|
16083
|
+
const naironDir = join9(projectDir, ".nairon");
|
|
16084
|
+
if (!existsSync9(naironDir)) {
|
|
16085
|
+
mkdirSync4(naironDir, { recursive: true });
|
|
16086
|
+
}
|
|
16087
|
+
writeFileSync4(join9(projectDir, PROJECT_SCAN_MARKER), new Date().toISOString());
|
|
16088
|
+
}
|
|
16089
|
+
var AGENT_CONFIGS = [
|
|
16090
|
+
{
|
|
16091
|
+
id: "claude-code",
|
|
16092
|
+
name: "Claude Code",
|
|
16093
|
+
paths: [".claude"]
|
|
16094
|
+
},
|
|
16095
|
+
{
|
|
16096
|
+
id: "opencode",
|
|
16097
|
+
name: "OpenCode",
|
|
16098
|
+
paths: [".config/opencode", ".local/share/opencode", ".opencode"]
|
|
16099
|
+
},
|
|
16100
|
+
{
|
|
16101
|
+
id: "cursor",
|
|
16102
|
+
name: "Cursor",
|
|
16103
|
+
paths: [".cursor"]
|
|
16104
|
+
},
|
|
16105
|
+
{
|
|
16106
|
+
id: "codex",
|
|
16107
|
+
name: "Codex CLI",
|
|
16108
|
+
paths: [".codex"]
|
|
16109
|
+
},
|
|
16110
|
+
{
|
|
16111
|
+
id: "copilot",
|
|
16112
|
+
name: "GitHub Copilot",
|
|
16113
|
+
paths: [".github-copilot"]
|
|
16114
|
+
},
|
|
16115
|
+
{
|
|
16116
|
+
id: "cody",
|
|
16117
|
+
name: "Sourcegraph Cody",
|
|
16118
|
+
paths: [".cody"]
|
|
16119
|
+
},
|
|
16120
|
+
{
|
|
16121
|
+
id: "aider",
|
|
16122
|
+
name: "Aider",
|
|
16123
|
+
paths: [".aider"]
|
|
16124
|
+
}
|
|
16125
|
+
];
|
|
16126
|
+
function detectAllAgents() {
|
|
16127
|
+
const home = homedir8();
|
|
16128
|
+
const cwd = process.cwd();
|
|
16129
|
+
const detected = [];
|
|
16130
|
+
for (const agent of AGENT_CONFIGS) {
|
|
16131
|
+
for (const relativePath of agent.paths) {
|
|
16132
|
+
const homePath = join9(home, relativePath);
|
|
16133
|
+
if (existsSync9(homePath)) {
|
|
16134
|
+
detected.push({ id: agent.id, name: agent.name, configPath: homePath });
|
|
16135
|
+
break;
|
|
16136
|
+
}
|
|
16137
|
+
const projectPath = join9(cwd, relativePath);
|
|
16138
|
+
if (existsSync9(projectPath)) {
|
|
16139
|
+
detected.push({ id: agent.id, name: agent.name, configPath: projectPath });
|
|
16140
|
+
break;
|
|
16141
|
+
}
|
|
16142
|
+
}
|
|
16143
|
+
}
|
|
16144
|
+
return detected;
|
|
16145
|
+
}
|
|
16146
|
+
function analyzeReadme(projectDir) {
|
|
16147
|
+
const readmePath = join9(projectDir, "README.md");
|
|
16148
|
+
if (!existsSync9(readmePath)) {
|
|
16149
|
+
const alternatives = ["readme.md", "Readme.md", "README.MD", "README"];
|
|
16150
|
+
for (const alt of alternatives) {
|
|
16151
|
+
const altPath = join9(projectDir, alt);
|
|
16152
|
+
if (existsSync9(altPath)) {
|
|
16153
|
+
return parseReadme(readFileSync9(altPath, "utf-8"), projectDir);
|
|
16154
|
+
}
|
|
16155
|
+
}
|
|
16156
|
+
return null;
|
|
16157
|
+
}
|
|
16158
|
+
const content = readFileSync9(readmePath, "utf-8");
|
|
16159
|
+
return parseReadme(content, projectDir);
|
|
16160
|
+
}
|
|
16161
|
+
function parseReadme(content, projectDir) {
|
|
16162
|
+
let name = "Unknown Project";
|
|
16163
|
+
const pkgPath = join9(projectDir, "package.json");
|
|
16164
|
+
if (existsSync9(pkgPath)) {
|
|
16165
|
+
try {
|
|
16166
|
+
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
16167
|
+
if (pkg.name && !pkg.name.startsWith("@") && pkg.name !== "root") {
|
|
16168
|
+
name = pkg.name;
|
|
16169
|
+
}
|
|
16170
|
+
} catch {}
|
|
16171
|
+
}
|
|
16172
|
+
if (name === "Unknown Project") {
|
|
16173
|
+
const headingMatch = content.match(/^#\s+([^<\n]+)$/m);
|
|
16174
|
+
if (headingMatch && headingMatch[1]) {
|
|
16175
|
+
const heading = headingMatch[1].trim();
|
|
16176
|
+
if (!heading.toLowerCase().includes("install") && !heading.toLowerCase().includes("getting started") && heading.length < 50) {
|
|
16177
|
+
name = heading;
|
|
16178
|
+
}
|
|
16179
|
+
}
|
|
16180
|
+
}
|
|
16181
|
+
let description = "";
|
|
16182
|
+
const descMatch = content.match(/^#[^#].*\n\n(.+?)(\n\n|$)/s);
|
|
16183
|
+
if (descMatch && descMatch[1]) {
|
|
16184
|
+
description = descMatch[1].replace(/\n/g, " ").trim().slice(0, 200);
|
|
16185
|
+
}
|
|
16186
|
+
const techStack = [];
|
|
16187
|
+
const techPatterns = {
|
|
16188
|
+
react: /\breact\b/i,
|
|
16189
|
+
"next.js": /\bnext\.?js\b/i,
|
|
16190
|
+
vue: /\bvue\b/i,
|
|
16191
|
+
svelte: /\bsvelte\b/i,
|
|
16192
|
+
typescript: /\btypescript\b/i,
|
|
16193
|
+
python: /\bpython\b/i,
|
|
16194
|
+
rust: /\brust\b/i,
|
|
16195
|
+
go: /\bgolang?\b/i,
|
|
16196
|
+
node: /\bnode\.?js\b/i,
|
|
16197
|
+
bun: /\bbun\b/i,
|
|
16198
|
+
deno: /\bdeno\b/i,
|
|
16199
|
+
tailwind: /\btailwind\b/i,
|
|
16200
|
+
prisma: /\bprisma\b/i,
|
|
16201
|
+
postgres: /\bpostgres\b/i,
|
|
16202
|
+
mongodb: /\bmongo\b/i,
|
|
16203
|
+
redis: /\bredis\b/i,
|
|
16204
|
+
docker: /\bdocker\b/i,
|
|
16205
|
+
kubernetes: /\bkubernetes\b|\bk8s\b/i,
|
|
16206
|
+
aws: /\baws\b/i,
|
|
16207
|
+
vercel: /\bvercel\b/i,
|
|
16208
|
+
cloudflare: /\bcloudflare\b/i,
|
|
16209
|
+
openai: /\bopenai\b/i,
|
|
16210
|
+
anthropic: /\banthropic\b|\bclaude\b/i,
|
|
16211
|
+
langchain: /\blangchain\b/i,
|
|
16212
|
+
convex: /\bconvex\b/i,
|
|
16213
|
+
supabase: /\bsupabase\b/i,
|
|
16214
|
+
firebase: /\bfirebase\b/i,
|
|
16215
|
+
stripe: /\bstripe\b/i,
|
|
16216
|
+
playwright: /\bplaywright\b/i,
|
|
16217
|
+
vitest: /\bvitest\b/i,
|
|
16218
|
+
jest: /\bjest\b/i,
|
|
16219
|
+
remotion: /\bremotion\b/i
|
|
16220
|
+
};
|
|
16221
|
+
for (const [tech, pattern] of Object.entries(techPatterns)) {
|
|
16222
|
+
if (pattern.test(content)) {
|
|
16223
|
+
techStack.push(tech);
|
|
16224
|
+
}
|
|
16225
|
+
}
|
|
16226
|
+
const keywords = [];
|
|
16227
|
+
const keywordPatterns = {
|
|
16228
|
+
api: /\bapi\b|\brest\b|\bgraphql\b/i,
|
|
16229
|
+
cli: /\bcli\b|\bcommand.?line\b/i,
|
|
16230
|
+
web: /\bweb\b|\bwebsite\b|\bfrontend\b/i,
|
|
16231
|
+
mobile: /\bmobile\b|\bios\b|\bandroid\b|\breact.?native\b/i,
|
|
16232
|
+
ai: /\bai\b|\bmachine.?learning\b|\bllm\b|\bgpt\b/i,
|
|
16233
|
+
video: /\bvideo\b|\bstreaming\b|\bmedia\b/i,
|
|
16234
|
+
ecommerce: /\becommerce\b|\bshop\b|\bstore\b|\bpayment\b/i,
|
|
16235
|
+
auth: /\bauth\b|\blogin\b|\bsession\b/i,
|
|
16236
|
+
testing: /\btest\b|\btesting\b|\btdd\b/i,
|
|
16237
|
+
devtools: /\bdevtool\b|\bdeveloper.?tool\b/i
|
|
16238
|
+
};
|
|
16239
|
+
for (const [keyword, pattern] of Object.entries(keywordPatterns)) {
|
|
16240
|
+
if (pattern.test(content)) {
|
|
16241
|
+
keywords.push(keyword);
|
|
16242
|
+
}
|
|
16243
|
+
}
|
|
16244
|
+
return { name, description, techStack, keywords };
|
|
16245
|
+
}
|
|
16246
|
+
function suggestSkills(context) {
|
|
16247
|
+
const suggestions = [];
|
|
16248
|
+
suggestions.push({
|
|
16249
|
+
name: "Find Skills",
|
|
16250
|
+
installCommand: "npx skills add vercel-labs/skills@find-skills --yes",
|
|
16251
|
+
reason: "Discover more skills for your workflow"
|
|
16252
|
+
});
|
|
16253
|
+
if (!context) {
|
|
16254
|
+
suggestions.push({
|
|
16255
|
+
name: "Writing Plans",
|
|
16256
|
+
installCommand: "npx skills add obra/superpowers@writing-plans --yes",
|
|
16257
|
+
reason: "Better planning before implementation"
|
|
16258
|
+
});
|
|
16259
|
+
return suggestions;
|
|
16260
|
+
}
|
|
16261
|
+
if (context.techStack.includes("react") || context.techStack.includes("next.js")) {
|
|
16262
|
+
suggestions.push({
|
|
16263
|
+
name: "React Best Practices",
|
|
16264
|
+
installCommand: "npx skills add vercel-labs/agent-skills@vercel-react-best-practices --yes",
|
|
16265
|
+
reason: `Detected React/Next.js in ${context.name}`
|
|
16266
|
+
});
|
|
16267
|
+
}
|
|
16268
|
+
if (context.techStack.includes("remotion")) {
|
|
16269
|
+
suggestions.push({
|
|
16270
|
+
name: "Remotion",
|
|
16271
|
+
installCommand: "npx skills add remotion-dev/skills@remotion-best-practices --yes",
|
|
16272
|
+
reason: "Detected Remotion video framework"
|
|
16273
|
+
});
|
|
16274
|
+
}
|
|
16275
|
+
if (context.keywords.includes("testing") || context.keywords.includes("tdd")) {
|
|
16276
|
+
suggestions.push({
|
|
16277
|
+
name: "Test-Driven Development",
|
|
16278
|
+
installCommand: "npx skills add obra/superpowers@test-driven-development --yes",
|
|
16279
|
+
reason: "Testing focus detected"
|
|
16280
|
+
});
|
|
16281
|
+
}
|
|
16282
|
+
if (context.keywords.includes("web")) {
|
|
16283
|
+
suggestions.push({
|
|
16284
|
+
name: "Web Design Guidelines",
|
|
16285
|
+
installCommand: "npx skills add vercel-labs/agent-skills@web-design-guidelines --yes",
|
|
16286
|
+
reason: "Web project detected"
|
|
16287
|
+
});
|
|
16288
|
+
}
|
|
16289
|
+
if (!suggestions.some((s2) => s2.name.includes("Plan"))) {
|
|
16290
|
+
suggestions.push({
|
|
16291
|
+
name: "Writing Plans",
|
|
16292
|
+
installCommand: "npx skills add obra/superpowers@writing-plans --yes",
|
|
16293
|
+
reason: "Helps structure work before coding"
|
|
16294
|
+
});
|
|
16295
|
+
}
|
|
16296
|
+
return suggestions.slice(0, 5);
|
|
16297
|
+
}
|
|
16298
|
+
function installSkill2(installCommand) {
|
|
16299
|
+
try {
|
|
16300
|
+
const result = spawnSync2("npx", installCommand.replace("npx ", "").split(" "), {
|
|
16301
|
+
stdio: "pipe",
|
|
16302
|
+
timeout: 60000,
|
|
16303
|
+
shell: true
|
|
16304
|
+
});
|
|
16305
|
+
if (result.status === 0) {
|
|
16306
|
+
return { success: true, message: "Installed successfully" };
|
|
16307
|
+
} else {
|
|
16308
|
+
const stderr = result.stderr?.toString() || "";
|
|
16309
|
+
return { success: false, message: stderr.slice(0, 100) || "Installation failed" };
|
|
16310
|
+
}
|
|
16311
|
+
} catch (error2) {
|
|
16312
|
+
return { success: false, message: error2 instanceof Error ? error2.message : "Unknown error" };
|
|
16313
|
+
}
|
|
16314
|
+
}
|
|
16315
|
+
|
|
16071
16316
|
// src/commands/scan.ts
|
|
16072
16317
|
var scanCommand = defineCommand2({
|
|
16073
16318
|
meta: {
|
|
@@ -16109,6 +16354,10 @@ var scanCommand = defineCommand2({
|
|
|
16109
16354
|
]
|
|
16110
16355
|
});
|
|
16111
16356
|
since = parseSince(period);
|
|
16357
|
+
if (isFirstScanInProject(projectDir)) {
|
|
16358
|
+
await showFirstScanWelcome(projectDir);
|
|
16359
|
+
markProjectScanned(projectDir);
|
|
16360
|
+
}
|
|
16112
16361
|
}
|
|
16113
16362
|
const useCache = true;
|
|
16114
16363
|
const watchMode = false;
|
|
@@ -16245,7 +16494,7 @@ var scanCommand = defineCommand2({
|
|
|
16245
16494
|
console.log(` Projected monthly: ${colors2.primary(`$${scanCost.projectedMonthlyCostUsd.toFixed(2)}`)}`);
|
|
16246
16495
|
console.log(colors2.dim(" " + "═".repeat(45)));
|
|
16247
16496
|
console.log();
|
|
16248
|
-
const reportDir =
|
|
16497
|
+
const reportDir = join10(projectDir, ".nairon/reports");
|
|
16249
16498
|
const reportPath = generateReport(reportDir, score, git, agents, tests, "7d", sdlcAnalysis, scanCost, analysis);
|
|
16250
16499
|
console.log(` ${icons.success} Report saved: ${colors2.dim(reportPath)}`);
|
|
16251
16500
|
if (agents && agents.sessions.length > 0) {
|
|
@@ -16461,12 +16710,12 @@ var scanCommand = defineCommand2({
|
|
|
16461
16710
|
}
|
|
16462
16711
|
});
|
|
16463
16712
|
function loadProjectContext(projectDir) {
|
|
16464
|
-
const contextPath =
|
|
16465
|
-
if (!
|
|
16713
|
+
const contextPath = join10(projectDir, ".nairon", "context.json");
|
|
16714
|
+
if (!existsSync10(contextPath)) {
|
|
16466
16715
|
return null;
|
|
16467
16716
|
}
|
|
16468
16717
|
try {
|
|
16469
|
-
const raw =
|
|
16718
|
+
const raw = readFileSync10(contextPath, "utf-8");
|
|
16470
16719
|
const data = JSON.parse(raw);
|
|
16471
16720
|
const context = {
|
|
16472
16721
|
painPoints: data.painPoints || [],
|
|
@@ -16519,12 +16768,12 @@ function parseSince(since) {
|
|
|
16519
16768
|
return new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
|
|
16520
16769
|
}
|
|
16521
16770
|
function generateReport(reportDir, score, git, agents, tests, since, sdlcAnalysis, scanCost, analysis) {
|
|
16522
|
-
if (!
|
|
16523
|
-
|
|
16771
|
+
if (!existsSync10(reportDir)) {
|
|
16772
|
+
mkdirSync5(reportDir, { recursive: true });
|
|
16524
16773
|
}
|
|
16525
16774
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
16526
16775
|
const filename = `scan-${timestamp}.md`;
|
|
16527
|
-
const filepath =
|
|
16776
|
+
const filepath = join10(reportDir, filename);
|
|
16528
16777
|
const lines = [];
|
|
16529
16778
|
lines.push(`# NaironAI Scan Report`);
|
|
16530
16779
|
lines.push("");
|
|
@@ -16640,7 +16889,7 @@ function generateReport(reportDir, score, git, agents, tests, since, sdlcAnalysi
|
|
|
16640
16889
|
lines.push("---");
|
|
16641
16890
|
lines.push("");
|
|
16642
16891
|
lines.push("*Generated by [nairon-bench](https://github.com/ObaidUr-Rahmaan/nairon-bench)*");
|
|
16643
|
-
|
|
16892
|
+
writeFileSync5(filepath, lines.join(`
|
|
16644
16893
|
`));
|
|
16645
16894
|
return filepath;
|
|
16646
16895
|
}
|
|
@@ -16659,15 +16908,87 @@ function formatTokensPlain(tokens) {
|
|
|
16659
16908
|
return `${Math.round(tokens / 1000)}K`;
|
|
16660
16909
|
return tokens.toString();
|
|
16661
16910
|
}
|
|
16911
|
+
async function showFirstScanWelcome(projectDir) {
|
|
16912
|
+
console.log();
|
|
16913
|
+
console.log(colors2.dim(" " + "═".repeat(50)));
|
|
16914
|
+
console.log(` ${colors2.primary("✨")} ${colors2.bold("First scan in this project!")}`);
|
|
16915
|
+
console.log(colors2.dim(" " + "═".repeat(50)));
|
|
16916
|
+
console.log();
|
|
16917
|
+
const detectedAgents = detectAllAgents();
|
|
16918
|
+
let selectedAgent = null;
|
|
16919
|
+
if (detectedAgents.length === 0) {
|
|
16920
|
+
console.log(` ${icons.info} No AI coding agents detected`);
|
|
16921
|
+
console.log(` ${colors2.dim(" Install Claude Code, Cursor, or OpenCode to get started")}`);
|
|
16922
|
+
} else if (detectedAgents.length === 1) {
|
|
16923
|
+
selectedAgent = detectedAgents[0];
|
|
16924
|
+
console.log(` ${icons.info} Detected agent: ${colors2.bold(selectedAgent.name)}`);
|
|
16925
|
+
} else {
|
|
16926
|
+
console.log(` ${icons.info} Found ${colors2.bold(detectedAgents.length.toString())} AI coding agents:`);
|
|
16927
|
+
console.log();
|
|
16928
|
+
const agentChoice = await consola.prompt("Which agent are you using for this project?", {
|
|
16929
|
+
type: "select",
|
|
16930
|
+
options: detectedAgents.map((a2) => ({
|
|
16931
|
+
value: a2.id,
|
|
16932
|
+
label: a2.name
|
|
16933
|
+
}))
|
|
16934
|
+
});
|
|
16935
|
+
selectedAgent = detectedAgents.find((a2) => a2.id === agentChoice) || detectedAgents[0];
|
|
16936
|
+
console.log();
|
|
16937
|
+
console.log(` ${icons.success} Selected: ${colors2.bold(selectedAgent.name)}`);
|
|
16938
|
+
}
|
|
16939
|
+
const context = analyzeReadme(projectDir);
|
|
16940
|
+
if (context) {
|
|
16941
|
+
console.log(` ${icons.info} Project: ${colors2.bold(context.name)}`);
|
|
16942
|
+
if (context.techStack.length > 0) {
|
|
16943
|
+
console.log(` ${colors2.dim(" Tech: " + context.techStack.slice(0, 4).join(", "))}`);
|
|
16944
|
+
}
|
|
16945
|
+
}
|
|
16946
|
+
console.log();
|
|
16947
|
+
const suggestions = suggestSkills(context);
|
|
16948
|
+
if (suggestions.length > 0) {
|
|
16949
|
+
console.log(` ${colors2.bold("Recommended skills for this project:")}`);
|
|
16950
|
+
console.log();
|
|
16951
|
+
for (let i3 = 0;i3 < Math.min(3, suggestions.length); i3++) {
|
|
16952
|
+
const s2 = suggestions[i3];
|
|
16953
|
+
console.log(` ${colors2.primary((i3 + 1).toString())}. ${colors2.bold(s2.name)}`);
|
|
16954
|
+
console.log(` ${colors2.dim(s2.reason)}`);
|
|
16955
|
+
}
|
|
16956
|
+
console.log();
|
|
16957
|
+
const installChoice = await consola.prompt("Install recommended skills?", {
|
|
16958
|
+
type: "select",
|
|
16959
|
+
options: [
|
|
16960
|
+
{ value: "find-skills", label: "Just find-skills (discover more skills later)" },
|
|
16961
|
+
{ value: "all", label: "All recommended skills" },
|
|
16962
|
+
{ value: "skip", label: "Skip - continue to scan" }
|
|
16963
|
+
]
|
|
16964
|
+
});
|
|
16965
|
+
if (installChoice === "find-skills" || installChoice === "all") {
|
|
16966
|
+
console.log();
|
|
16967
|
+
const toInstall = installChoice === "all" ? suggestions.slice(0, 3) : suggestions.slice(0, 1);
|
|
16968
|
+
for (const skill of toInstall) {
|
|
16969
|
+
process.stdout.write(` Installing ${skill.name}...`);
|
|
16970
|
+
const result = installSkill2(skill.installCommand);
|
|
16971
|
+
if (result.success) {
|
|
16972
|
+
console.log(` ${colors2.success("✓")}`);
|
|
16973
|
+
} else {
|
|
16974
|
+
console.log(` ${colors2.warning("⚠")} ${colors2.dim(`(${result.message.slice(0, 50)})`)}`);
|
|
16975
|
+
}
|
|
16976
|
+
}
|
|
16977
|
+
console.log();
|
|
16978
|
+
}
|
|
16979
|
+
}
|
|
16980
|
+
console.log(colors2.dim(" " + "═".repeat(50)));
|
|
16981
|
+
console.log();
|
|
16982
|
+
}
|
|
16662
16983
|
|
|
16663
16984
|
// src/commands/report.ts
|
|
16664
16985
|
init_dist();
|
|
16665
16986
|
init_client();
|
|
16666
16987
|
|
|
16667
16988
|
// src/collectors/report-data.ts
|
|
16668
|
-
import { existsSync as
|
|
16669
|
-
import { homedir as
|
|
16670
|
-
import { join as
|
|
16989
|
+
import { existsSync as existsSync11, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync2 } from "node:fs";
|
|
16990
|
+
import { homedir as homedir9 } from "node:os";
|
|
16991
|
+
import { join as join11, basename as basename3 } from "node:path";
|
|
16671
16992
|
async function collectReportData(projectDir, since, until = new Date, harness) {
|
|
16672
16993
|
const projectName = basename3(projectDir);
|
|
16673
16994
|
const [commits, allSessions, mcpConfigs] = await Promise.all([
|
|
@@ -16750,12 +17071,12 @@ function detectAIAssistedCommit(message) {
|
|
|
16750
17071
|
}
|
|
16751
17072
|
async function collectAllSessions(since, until, projectDir) {
|
|
16752
17073
|
const sessions = [];
|
|
16753
|
-
const claudeDir =
|
|
16754
|
-
if (
|
|
17074
|
+
const claudeDir = join11(homedir9(), ".claude");
|
|
17075
|
+
if (existsSync11(claudeDir)) {
|
|
16755
17076
|
sessions.push(...collectClaudeCodeSessions(claudeDir, since, until, projectDir));
|
|
16756
17077
|
}
|
|
16757
|
-
const openCodeDir =
|
|
16758
|
-
if (
|
|
17078
|
+
const openCodeDir = join11(homedir9(), ".local", "share", "opencode");
|
|
17079
|
+
if (existsSync11(openCodeDir)) {
|
|
16759
17080
|
sessions.push(...collectOpenCodeSessions2(openCodeDir, since, until));
|
|
16760
17081
|
}
|
|
16761
17082
|
sessions.sort((a2, b2) => a2.startTime.getTime() - b2.startTime.getTime());
|
|
@@ -16763,15 +17084,15 @@ async function collectAllSessions(since, until, projectDir) {
|
|
|
16763
17084
|
}
|
|
16764
17085
|
function collectClaudeCodeSessions(claudeDir, since, until, projectDir) {
|
|
16765
17086
|
const sessions = [];
|
|
16766
|
-
const transcriptsDir =
|
|
16767
|
-
if (!
|
|
17087
|
+
const transcriptsDir = join11(claudeDir, "transcripts");
|
|
17088
|
+
if (!existsSync11(transcriptsDir))
|
|
16768
17089
|
return sessions;
|
|
16769
17090
|
const projectHash = projectDir ? hashPath(projectDir) : null;
|
|
16770
|
-
const projectsDir =
|
|
17091
|
+
const projectsDir = join11(claudeDir, "projects");
|
|
16771
17092
|
try {
|
|
16772
17093
|
const transcriptFiles = readdirSync5(transcriptsDir).filter((f3) => f3.endsWith(".jsonl"));
|
|
16773
17094
|
for (const file of transcriptFiles) {
|
|
16774
|
-
const filePath =
|
|
17095
|
+
const filePath = join11(transcriptsDir, file);
|
|
16775
17096
|
const stat = statSync2(filePath);
|
|
16776
17097
|
if (stat.mtime < since || stat.mtime > until)
|
|
16777
17098
|
continue;
|
|
@@ -16782,12 +17103,12 @@ function collectClaudeCodeSessions(claudeDir, since, until, projectDir) {
|
|
|
16782
17103
|
}
|
|
16783
17104
|
} catch {}
|
|
16784
17105
|
}
|
|
16785
|
-
if (projectHash &&
|
|
16786
|
-
const projectSessionDir =
|
|
16787
|
-
if (
|
|
17106
|
+
if (projectHash && existsSync11(projectsDir)) {
|
|
17107
|
+
const projectSessionDir = join11(projectsDir, projectHash);
|
|
17108
|
+
if (existsSync11(projectSessionDir)) {
|
|
16788
17109
|
const projectFiles = readdirSync5(projectSessionDir).filter((f3) => f3.endsWith(".jsonl"));
|
|
16789
17110
|
for (const file of projectFiles) {
|
|
16790
|
-
const filePath =
|
|
17111
|
+
const filePath = join11(projectSessionDir, file);
|
|
16791
17112
|
const stat = statSync2(filePath);
|
|
16792
17113
|
if (stat.mtime < since || stat.mtime > until)
|
|
16793
17114
|
continue;
|
|
@@ -16806,7 +17127,7 @@ function collectClaudeCodeSessions(claudeDir, since, until, projectDir) {
|
|
|
16806
17127
|
return sessions;
|
|
16807
17128
|
}
|
|
16808
17129
|
function parseClaudeTranscript(filePath, fileName) {
|
|
16809
|
-
const content =
|
|
17130
|
+
const content = readFileSync11(filePath, "utf-8");
|
|
16810
17131
|
const lines = content.trim().split(`
|
|
16811
17132
|
`).filter((l2) => l2.trim());
|
|
16812
17133
|
if (lines.length === 0)
|
|
@@ -16896,25 +17217,25 @@ function parseClaudeTranscript(filePath, fileName) {
|
|
|
16896
17217
|
}
|
|
16897
17218
|
function collectOpenCodeSessions2(openCodeDir, since, until) {
|
|
16898
17219
|
const sessions = [];
|
|
16899
|
-
const sessionDir =
|
|
16900
|
-
const messageDir =
|
|
16901
|
-
const partDir =
|
|
16902
|
-
if (!
|
|
17220
|
+
const sessionDir = join11(openCodeDir, "storage", "session");
|
|
17221
|
+
const messageDir = join11(openCodeDir, "storage", "message");
|
|
17222
|
+
const partDir = join11(openCodeDir, "storage", "part");
|
|
17223
|
+
if (!existsSync11(sessionDir))
|
|
16903
17224
|
return sessions;
|
|
16904
17225
|
try {
|
|
16905
|
-
const projectDirs = readdirSync5(sessionDir, { withFileTypes: true }).filter((d2) => d2.isDirectory()).map((d2) =>
|
|
17226
|
+
const projectDirs = readdirSync5(sessionDir, { withFileTypes: true }).filter((d2) => d2.isDirectory()).map((d2) => join11(sessionDir, d2.name));
|
|
16906
17227
|
for (const projectDir of projectDirs) {
|
|
16907
17228
|
const sessionFiles = readdirSync5(projectDir).filter((f3) => f3.endsWith(".json"));
|
|
16908
17229
|
for (const sessionFile of sessionFiles) {
|
|
16909
17230
|
try {
|
|
16910
|
-
const sessionPath =
|
|
16911
|
-
const sessionData = JSON.parse(
|
|
17231
|
+
const sessionPath = join11(projectDir, sessionFile);
|
|
17232
|
+
const sessionData = JSON.parse(readFileSync11(sessionPath, "utf-8"));
|
|
16912
17233
|
const createdAt = new Date(sessionData.time?.created || 0);
|
|
16913
17234
|
const updatedAt = new Date(sessionData.time?.updated || sessionData.time?.created || 0);
|
|
16914
17235
|
if (updatedAt < since || createdAt > until)
|
|
16915
17236
|
continue;
|
|
16916
17237
|
const sessionId = sessionData.id;
|
|
16917
|
-
const sessionMsgDir =
|
|
17238
|
+
const sessionMsgDir = join11(messageDir, sessionId);
|
|
16918
17239
|
const prompts = [];
|
|
16919
17240
|
const responses = [];
|
|
16920
17241
|
const toolsUsed = new Set;
|
|
@@ -16925,12 +17246,12 @@ function collectOpenCodeSessions2(openCodeDir, since, until) {
|
|
|
16925
17246
|
let model = "unknown";
|
|
16926
17247
|
let startTime = createdAt;
|
|
16927
17248
|
let endTime = updatedAt;
|
|
16928
|
-
if (
|
|
17249
|
+
if (existsSync11(sessionMsgDir)) {
|
|
16929
17250
|
const msgFiles = readdirSync5(sessionMsgDir).filter((f3) => f3.endsWith(".json")).sort();
|
|
16930
17251
|
for (const msgFile of msgFiles) {
|
|
16931
17252
|
try {
|
|
16932
|
-
const msgPath =
|
|
16933
|
-
const msgData = JSON.parse(
|
|
17253
|
+
const msgPath = join11(sessionMsgDir, msgFile);
|
|
17254
|
+
const msgData = JSON.parse(readFileSync11(msgPath, "utf-8"));
|
|
16934
17255
|
const msgId = msgData.id;
|
|
16935
17256
|
if (msgData.model?.modelID) {
|
|
16936
17257
|
model = msgData.model.modelID;
|
|
@@ -16940,14 +17261,14 @@ function collectOpenCodeSessions2(openCodeDir, since, until) {
|
|
|
16940
17261
|
startTime = msgTime;
|
|
16941
17262
|
if (msgTime > endTime)
|
|
16942
17263
|
endTime = msgTime;
|
|
16943
|
-
const msgPartDir =
|
|
17264
|
+
const msgPartDir = join11(partDir, msgId);
|
|
16944
17265
|
let messageText = "";
|
|
16945
|
-
if (
|
|
17266
|
+
if (existsSync11(msgPartDir)) {
|
|
16946
17267
|
const partFiles = readdirSync5(msgPartDir).filter((f3) => f3.endsWith(".json")).sort();
|
|
16947
17268
|
for (const partFile of partFiles) {
|
|
16948
17269
|
try {
|
|
16949
|
-
const partPath =
|
|
16950
|
-
const partData = JSON.parse(
|
|
17270
|
+
const partPath = join11(msgPartDir, partFile);
|
|
17271
|
+
const partData = JSON.parse(readFileSync11(partPath, "utf-8"));
|
|
16951
17272
|
if (partData.type === "text" && partData.text && !partData.synthetic) {
|
|
16952
17273
|
messageText += partData.text + `
|
|
16953
17274
|
`;
|
|
@@ -17121,10 +17442,10 @@ function analyzeResponse(text, sessionId, index, promptId, timestamp) {
|
|
|
17121
17442
|
}
|
|
17122
17443
|
function collectMCPConfigs() {
|
|
17123
17444
|
const configs = [];
|
|
17124
|
-
const claudeConfig =
|
|
17125
|
-
if (
|
|
17445
|
+
const claudeConfig = join11(homedir9(), ".claude.json");
|
|
17446
|
+
if (existsSync11(claudeConfig)) {
|
|
17126
17447
|
try {
|
|
17127
|
-
const data = JSON.parse(
|
|
17448
|
+
const data = JSON.parse(readFileSync11(claudeConfig, "utf-8"));
|
|
17128
17449
|
const mcpServers = data.mcpServers || {};
|
|
17129
17450
|
for (const [name, config] of Object.entries(mcpServers)) {
|
|
17130
17451
|
configs.push({
|
|
@@ -17137,13 +17458,13 @@ function collectMCPConfigs() {
|
|
|
17137
17458
|
} catch {}
|
|
17138
17459
|
}
|
|
17139
17460
|
const openCodeConfigs = [
|
|
17140
|
-
|
|
17141
|
-
|
|
17461
|
+
join11(homedir9(), ".opencode.json"),
|
|
17462
|
+
join11(homedir9(), ".config", "opencode", "opencode.json")
|
|
17142
17463
|
];
|
|
17143
17464
|
for (const configPath of openCodeConfigs) {
|
|
17144
|
-
if (
|
|
17465
|
+
if (existsSync11(configPath)) {
|
|
17145
17466
|
try {
|
|
17146
|
-
const data = JSON.parse(
|
|
17467
|
+
const data = JSON.parse(readFileSync11(configPath, "utf-8"));
|
|
17147
17468
|
const mcpServers = data.mcp || {};
|
|
17148
17469
|
for (const [name, config] of Object.entries(mcpServers)) {
|
|
17149
17470
|
if (!configs.find((c3) => c3.name === name)) {
|
|
@@ -17158,10 +17479,10 @@ function collectMCPConfigs() {
|
|
|
17158
17479
|
} catch {}
|
|
17159
17480
|
}
|
|
17160
17481
|
}
|
|
17161
|
-
const cursorConfig =
|
|
17162
|
-
if (
|
|
17482
|
+
const cursorConfig = join11(homedir9(), ".cursor", "mcp.json");
|
|
17483
|
+
if (existsSync11(cursorConfig)) {
|
|
17163
17484
|
try {
|
|
17164
|
-
const data = JSON.parse(
|
|
17485
|
+
const data = JSON.parse(readFileSync11(cursorConfig, "utf-8"));
|
|
17165
17486
|
const mcpServers = data.mcpServers || {};
|
|
17166
17487
|
for (const [name, config] of Object.entries(mcpServers)) {
|
|
17167
17488
|
if (!configs.find((c3) => c3.name === name)) {
|
|
@@ -19362,9 +19683,9 @@ function getSeverityEmoji(severity) {
|
|
|
19362
19683
|
}
|
|
19363
19684
|
|
|
19364
19685
|
// src/lib/tool-analyzer.ts
|
|
19365
|
-
import { existsSync as
|
|
19366
|
-
import { homedir as
|
|
19367
|
-
import { join as
|
|
19686
|
+
import { existsSync as existsSync12, readdirSync as readdirSync6 } from "node:fs";
|
|
19687
|
+
import { homedir as homedir10 } from "node:os";
|
|
19688
|
+
import { join as join12 } from "node:path";
|
|
19368
19689
|
function analyzeToolUtilization(data) {
|
|
19369
19690
|
const mcpServers = analyzeMCPServers(data);
|
|
19370
19691
|
const mcpSummary = buildMCPSummary(mcpServers);
|
|
@@ -19514,24 +19835,24 @@ function categorizeTools(tools) {
|
|
|
19514
19835
|
}
|
|
19515
19836
|
function analyzeSkills() {
|
|
19516
19837
|
const skills = [];
|
|
19517
|
-
const home =
|
|
19838
|
+
const home = homedir10();
|
|
19518
19839
|
const skillsDirs = [
|
|
19519
|
-
|
|
19520
|
-
|
|
19521
|
-
|
|
19840
|
+
join12(home, ".claude", "skills"),
|
|
19841
|
+
join12(home, ".agents", "skills"),
|
|
19842
|
+
join12(home, ".config", "claude", "skills")
|
|
19522
19843
|
];
|
|
19523
19844
|
const projectSkillsDirs = [
|
|
19524
|
-
|
|
19525
|
-
|
|
19845
|
+
join12(process.cwd(), ".claude", "skills"),
|
|
19846
|
+
join12(process.cwd(), ".agents", "skills")
|
|
19526
19847
|
];
|
|
19527
19848
|
const openCodeSkillDirs = [
|
|
19528
|
-
|
|
19529
|
-
|
|
19849
|
+
join12(home, ".config", "opencode", "skills"),
|
|
19850
|
+
join12(home, ".local", "share", "opencode", "skills")
|
|
19530
19851
|
];
|
|
19531
19852
|
const allSkillDirs = [...skillsDirs, ...projectSkillsDirs, ...openCodeSkillDirs];
|
|
19532
19853
|
const seenSkills = new Set;
|
|
19533
19854
|
for (const skillsDir of allSkillDirs) {
|
|
19534
|
-
if (
|
|
19855
|
+
if (existsSync12(skillsDir)) {
|
|
19535
19856
|
try {
|
|
19536
19857
|
const entries = readdirSync6(skillsDir, { withFileTypes: true });
|
|
19537
19858
|
for (const entry of entries) {
|
|
@@ -19542,7 +19863,7 @@ function analyzeSkills() {
|
|
|
19542
19863
|
if (entry.isDirectory() || entry.isSymbolicLink() || entry.name.endsWith(".md")) {
|
|
19543
19864
|
skills.push({
|
|
19544
19865
|
name: skillName,
|
|
19545
|
-
path:
|
|
19866
|
+
path: join12(skillsDir, entry.name),
|
|
19546
19867
|
used: false,
|
|
19547
19868
|
usageCount: 0
|
|
19548
19869
|
});
|
|
@@ -19839,22 +20160,22 @@ function renderToolUtilizationMarkdown(analysis) {
|
|
|
19839
20160
|
}
|
|
19840
20161
|
|
|
19841
20162
|
// src/lib/coverage-parser.ts
|
|
19842
|
-
import { existsSync as
|
|
19843
|
-
import { join as
|
|
20163
|
+
import { existsSync as existsSync13, readFileSync as readFileSync13 } from "node:fs";
|
|
20164
|
+
import { join as join13 } from "node:path";
|
|
19844
20165
|
function parseCoverageReport(projectDir) {
|
|
19845
20166
|
const coveragePaths = [
|
|
19846
|
-
{ path:
|
|
19847
|
-
{ path:
|
|
19848
|
-
{ path:
|
|
19849
|
-
{ path:
|
|
19850
|
-
{ path:
|
|
19851
|
-
{ path:
|
|
19852
|
-
{ path:
|
|
20167
|
+
{ path: join13(projectDir, "coverage", "lcov.info"), parser: parseLcov },
|
|
20168
|
+
{ path: join13(projectDir, "coverage", "coverage-summary.json"), parser: parseIstanbulSummary },
|
|
20169
|
+
{ path: join13(projectDir, "coverage", "coverage-final.json"), parser: parseIstanbulFinal },
|
|
20170
|
+
{ path: join13(projectDir, "coverage", "cobertura-coverage.xml"), parser: parseCobertura },
|
|
20171
|
+
{ path: join13(projectDir, "coverage", "clover.xml"), parser: parseClover },
|
|
20172
|
+
{ path: join13(projectDir, "lcov.info"), parser: parseLcov },
|
|
20173
|
+
{ path: join13(projectDir, ".nyc_output", "coverage-summary.json"), parser: parseIstanbulSummary }
|
|
19853
20174
|
];
|
|
19854
20175
|
for (const { path, parser: parser4 } of coveragePaths) {
|
|
19855
|
-
if (
|
|
20176
|
+
if (existsSync13(path)) {
|
|
19856
20177
|
try {
|
|
19857
|
-
const content =
|
|
20178
|
+
const content = readFileSync13(path, "utf-8");
|
|
19858
20179
|
return parser4(content, path);
|
|
19859
20180
|
} catch {}
|
|
19860
20181
|
}
|
|
@@ -21566,7 +21887,7 @@ function formatReportAsJSON(report) {
|
|
|
21566
21887
|
}
|
|
21567
21888
|
|
|
21568
21889
|
// src/commands/report.ts
|
|
21569
|
-
import { writeFileSync as
|
|
21890
|
+
import { writeFileSync as writeFileSync6 } from "node:fs";
|
|
21570
21891
|
import { resolve } from "node:path";
|
|
21571
21892
|
var reportCommand = defineCommand2({
|
|
21572
21893
|
meta: {
|
|
@@ -21778,7 +22099,7 @@ async function runHackathonReport(args) {
|
|
|
21778
22099
|
}
|
|
21779
22100
|
if (args.output) {
|
|
21780
22101
|
const filepath = resolve(projectDir, args.output);
|
|
21781
|
-
|
|
22102
|
+
writeFileSync6(filepath, output);
|
|
21782
22103
|
consola.success(`Report saved to ${filepath}`);
|
|
21783
22104
|
}
|
|
21784
22105
|
console.log(output);
|
|
@@ -21947,7 +22268,7 @@ async function runLeadershipReport(args) {
|
|
|
21947
22268
|
}
|
|
21948
22269
|
if (args.output) {
|
|
21949
22270
|
const filepath = resolve(projectDir, args.output);
|
|
21950
|
-
|
|
22271
|
+
writeFileSync6(filepath, output);
|
|
21951
22272
|
consola.success(`Report saved to ${filepath}`);
|
|
21952
22273
|
}
|
|
21953
22274
|
console.log(output);
|
|
@@ -22109,9 +22430,9 @@ function renderBar4(value, width) {
|
|
|
22109
22430
|
}
|
|
22110
22431
|
|
|
22111
22432
|
// src/commands/doctor.ts
|
|
22112
|
-
import { existsSync as
|
|
22113
|
-
import { homedir as
|
|
22114
|
-
import { join as
|
|
22433
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
22434
|
+
import { homedir as homedir11 } from "node:os";
|
|
22435
|
+
import { join as join14 } from "node:path";
|
|
22115
22436
|
init_client();
|
|
22116
22437
|
|
|
22117
22438
|
// src/lib/recommendations-db.ts
|
|
@@ -22237,6 +22558,18 @@ var PLUGINS = [
|
|
|
22237
22558
|
}
|
|
22238
22559
|
];
|
|
22239
22560
|
var SKILLS = [
|
|
22561
|
+
{
|
|
22562
|
+
id: "find-skills",
|
|
22563
|
+
name: "Find Skills",
|
|
22564
|
+
type: "skill",
|
|
22565
|
+
description: "Discover and install skills from the open agent skills ecosystem - essential for any AI workflow",
|
|
22566
|
+
installCommand: "npx skills add vercel-labs/skills@find-skills --yes",
|
|
22567
|
+
phases: ["requirements", "planning", "implementation", "review"],
|
|
22568
|
+
impact: "high",
|
|
22569
|
+
detectionKey: "find-skills",
|
|
22570
|
+
website: "https://skills.sh/vercel-labs/skills/find-skills",
|
|
22571
|
+
badge: "Essential"
|
|
22572
|
+
},
|
|
22240
22573
|
{
|
|
22241
22574
|
id: "tdd-skill",
|
|
22242
22575
|
name: "Test-Driven Development",
|
|
@@ -22760,16 +23093,16 @@ var doctorCommand = defineCommand2({
|
|
|
22760
23093
|
results.push({ label: "OS", status: "info", value: `${process.platform} ${process.arch}` });
|
|
22761
23094
|
results.push({ label: "Bun", status: "info", value: typeof Bun !== "undefined" ? Bun.version : "N/A" });
|
|
22762
23095
|
results.push({ label: "Node", status: "info", value: process.version });
|
|
22763
|
-
results.push({ label: "Home", status: "info", value:
|
|
22764
|
-
const gitDir =
|
|
22765
|
-
if (
|
|
23096
|
+
results.push({ label: "Home", status: "info", value: homedir11() });
|
|
23097
|
+
const gitDir = join14(process.cwd(), ".git");
|
|
23098
|
+
if (existsSync14(gitDir)) {
|
|
22766
23099
|
results.push({ label: "Git", status: "success", value: "Repository detected" });
|
|
22767
23100
|
} else {
|
|
22768
23101
|
results.push({ label: "Git", status: "warn", value: "No repository in current directory" });
|
|
22769
23102
|
}
|
|
22770
23103
|
for (const [agent, pathTemplate] of Object.entries(AGENT_LOG_PATHS)) {
|
|
22771
|
-
const resolvedPath = pathTemplate.replace("~",
|
|
22772
|
-
if (
|
|
23104
|
+
const resolvedPath = pathTemplate.replace("~", homedir11());
|
|
23105
|
+
if (existsSync14(resolvedPath)) {
|
|
22773
23106
|
results.push({ label: agent, status: "success", value: `found at ${resolvedPath}` });
|
|
22774
23107
|
}
|
|
22775
23108
|
}
|
|
@@ -22823,10 +23156,10 @@ var doctorCommand = defineCommand2({
|
|
|
22823
23156
|
});
|
|
22824
23157
|
|
|
22825
23158
|
// src/commands/setup.ts
|
|
22826
|
-
import { existsSync as
|
|
22827
|
-
import { join as
|
|
22828
|
-
import { homedir as
|
|
22829
|
-
import { execSync as
|
|
23159
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, copyFileSync } from "node:fs";
|
|
23160
|
+
import { join as join15, dirname as dirname2 } from "node:path";
|
|
23161
|
+
import { homedir as homedir12, platform as platform2 } from "node:os";
|
|
23162
|
+
import { execSync as execSync4 } from "node:child_process";
|
|
22830
23163
|
import { createInterface } from "node:readline";
|
|
22831
23164
|
var CONVEX_SITE_URL = "https://steady-bass-841.convex.site";
|
|
22832
23165
|
async function fetchSetupData() {
|
|
@@ -22844,7 +23177,7 @@ var FALLBACK_HARNESSES = [
|
|
|
22844
23177
|
id: "claude-code",
|
|
22845
23178
|
name: "Claude Code",
|
|
22846
23179
|
configPaths: [
|
|
22847
|
-
|
|
23180
|
+
join15(homedir12(), ".claude.json")
|
|
22848
23181
|
],
|
|
22849
23182
|
mcpConfigKey: "mcpServers",
|
|
22850
23183
|
detected: false
|
|
@@ -22853,8 +23186,8 @@ var FALLBACK_HARNESSES = [
|
|
|
22853
23186
|
id: "opencode",
|
|
22854
23187
|
name: "OpenCode",
|
|
22855
23188
|
configPaths: [
|
|
22856
|
-
|
|
22857
|
-
|
|
23189
|
+
join15(homedir12(), ".opencode.json"),
|
|
23190
|
+
join15(homedir12(), ".config", "opencode", "opencode.json")
|
|
22858
23191
|
],
|
|
22859
23192
|
mcpConfigKey: "mcp",
|
|
22860
23193
|
detected: false
|
|
@@ -22863,8 +23196,8 @@ var FALLBACK_HARNESSES = [
|
|
|
22863
23196
|
id: "cursor",
|
|
22864
23197
|
name: "Cursor",
|
|
22865
23198
|
configPaths: [
|
|
22866
|
-
|
|
22867
|
-
|
|
23199
|
+
join15(homedir12(), ".cursor", "mcp.json"),
|
|
23200
|
+
join15(homedir12(), "Library", "Application Support", "Cursor", "User", "globalStorage", "mcp.json")
|
|
22868
23201
|
],
|
|
22869
23202
|
mcpConfigKey: "mcpServers",
|
|
22870
23203
|
detected: false
|
|
@@ -22881,7 +23214,7 @@ function getConfigPathsForPlatform(harness) {
|
|
|
22881
23214
|
} else {
|
|
22882
23215
|
paths = pathMap.linux;
|
|
22883
23216
|
}
|
|
22884
|
-
return paths.map((p) => p.replace(/^~/,
|
|
23217
|
+
return paths.map((p) => p.replace(/^~/, homedir12()).replace(/%USERPROFILE%/gi, homedir12()).replace(/%APPDATA%/gi, join15(homedir12(), "AppData", "Roaming")));
|
|
22885
23218
|
}
|
|
22886
23219
|
function convertAPIHarnessToConfig(harness) {
|
|
22887
23220
|
return {
|
|
@@ -22896,7 +23229,7 @@ function detectHarnesses(harnesses) {
|
|
|
22896
23229
|
const detected = [];
|
|
22897
23230
|
for (const harness of harnesses) {
|
|
22898
23231
|
for (const configPath of harness.configPaths) {
|
|
22899
|
-
if (
|
|
23232
|
+
if (existsSync15(configPath)) {
|
|
22900
23233
|
detected.push({
|
|
22901
23234
|
...harness,
|
|
22902
23235
|
detected: true,
|
|
@@ -22909,19 +23242,19 @@ function detectHarnesses(harnesses) {
|
|
|
22909
23242
|
return detected;
|
|
22910
23243
|
}
|
|
22911
23244
|
function backupConfig(configPath) {
|
|
22912
|
-
const backupDir =
|
|
22913
|
-
if (!
|
|
22914
|
-
|
|
23245
|
+
const backupDir = join15(homedir12(), ".nairon", "backups");
|
|
23246
|
+
if (!existsSync15(backupDir)) {
|
|
23247
|
+
mkdirSync6(backupDir, { recursive: true });
|
|
22915
23248
|
}
|
|
22916
23249
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
22917
23250
|
const filename = configPath.replace(/[/\\]/g, "_").replace(/^_/, "");
|
|
22918
|
-
const backupPath =
|
|
23251
|
+
const backupPath = join15(backupDir, `${timestamp}_${filename}`);
|
|
22919
23252
|
copyFileSync(configPath, backupPath);
|
|
22920
23253
|
return backupPath;
|
|
22921
23254
|
}
|
|
22922
23255
|
function readJsonConfig(configPath) {
|
|
22923
23256
|
try {
|
|
22924
|
-
const content =
|
|
23257
|
+
const content = readFileSync14(configPath, "utf-8");
|
|
22925
23258
|
return JSON.parse(content);
|
|
22926
23259
|
} catch {
|
|
22927
23260
|
return {};
|
|
@@ -22929,10 +23262,10 @@ function readJsonConfig(configPath) {
|
|
|
22929
23262
|
}
|
|
22930
23263
|
function writeJsonConfig(configPath, config) {
|
|
22931
23264
|
const dir = dirname2(configPath);
|
|
22932
|
-
if (!
|
|
22933
|
-
|
|
23265
|
+
if (!existsSync15(dir)) {
|
|
23266
|
+
mkdirSync6(dir, { recursive: true });
|
|
22934
23267
|
}
|
|
22935
|
-
|
|
23268
|
+
writeFileSync7(configPath, JSON.stringify(config, null, 2));
|
|
22936
23269
|
}
|
|
22937
23270
|
async function prompt2(question) {
|
|
22938
23271
|
const rl = createInterface({
|
|
@@ -22973,7 +23306,7 @@ function getInstalledMCPs(harnesses) {
|
|
|
22973
23306
|
const installed = new Set;
|
|
22974
23307
|
for (const harness of harnesses) {
|
|
22975
23308
|
for (const configPath of harness.configPaths) {
|
|
22976
|
-
if (!
|
|
23309
|
+
if (!existsSync15(configPath))
|
|
22977
23310
|
continue;
|
|
22978
23311
|
const config = readJsonConfig(configPath);
|
|
22979
23312
|
const mcpServers = config[harness.mcpConfigKey];
|
|
@@ -22997,7 +23330,7 @@ async function installMCPServer(serverName, instruction, harness) {
|
|
|
22997
23330
|
if (!harness.configPath || !instruction.mcpServerConfig)
|
|
22998
23331
|
return false;
|
|
22999
23332
|
try {
|
|
23000
|
-
if (
|
|
23333
|
+
if (existsSync15(harness.configPath)) {
|
|
23001
23334
|
backupConfig(harness.configPath);
|
|
23002
23335
|
}
|
|
23003
23336
|
const config = readJsonConfig(harness.configPath);
|
|
@@ -23025,16 +23358,16 @@ async function installMCPServer(serverName, instruction, harness) {
|
|
|
23025
23358
|
async function installBeads(projectDir) {
|
|
23026
23359
|
try {
|
|
23027
23360
|
try {
|
|
23028
|
-
|
|
23361
|
+
execSync4("bd --version", { stdio: "ignore" });
|
|
23029
23362
|
} catch {
|
|
23030
23363
|
const spinner = createSpinner("Installing Beads globally...");
|
|
23031
23364
|
spinner.start();
|
|
23032
23365
|
try {
|
|
23033
|
-
|
|
23366
|
+
execSync4("bun add -g beads", { stdio: "ignore" });
|
|
23034
23367
|
spinner.succeed("Beads installed globally");
|
|
23035
23368
|
} catch {
|
|
23036
23369
|
try {
|
|
23037
|
-
|
|
23370
|
+
execSync4("npm install -g beads", { stdio: "ignore" });
|
|
23038
23371
|
spinner.succeed("Beads installed globally (via npm)");
|
|
23039
23372
|
} catch {
|
|
23040
23373
|
spinner.fail("Failed to install Beads globally");
|
|
@@ -23042,13 +23375,13 @@ async function installBeads(projectDir) {
|
|
|
23042
23375
|
}
|
|
23043
23376
|
}
|
|
23044
23377
|
}
|
|
23045
|
-
const beadsDir =
|
|
23046
|
-
if (!
|
|
23378
|
+
const beadsDir = join15(projectDir, ".beads");
|
|
23379
|
+
if (!existsSync15(beadsDir)) {
|
|
23047
23380
|
const projectName = projectDir.split(/[/\\]/).pop() ?? "project";
|
|
23048
23381
|
const initSpinner = createSpinner(`Initializing Beads in ${projectName}...`);
|
|
23049
23382
|
initSpinner.start();
|
|
23050
23383
|
try {
|
|
23051
|
-
|
|
23384
|
+
execSync4(`bd init ${projectName}`, { cwd: projectDir, stdio: "ignore" });
|
|
23052
23385
|
initSpinner.succeed(`Beads initialized in ${projectName}`);
|
|
23053
23386
|
} catch {
|
|
23054
23387
|
initSpinner.fail("Failed to initialize Beads in project");
|
|
@@ -23062,9 +23395,9 @@ async function installBeads(projectDir) {
|
|
|
23062
23395
|
}
|
|
23063
23396
|
}
|
|
23064
23397
|
async function createClaudeRules(projectDir) {
|
|
23065
|
-
const claudeMdPath =
|
|
23066
|
-
const agentsMdPath =
|
|
23067
|
-
if (
|
|
23398
|
+
const claudeMdPath = join15(projectDir, "CLAUDE.md");
|
|
23399
|
+
const agentsMdPath = join15(projectDir, "AGENTS.md");
|
|
23400
|
+
if (existsSync15(claudeMdPath) || existsSync15(agentsMdPath)) {
|
|
23068
23401
|
console.log(` ${icons.info} CLAUDE.md or AGENTS.md already exists`);
|
|
23069
23402
|
return true;
|
|
23070
23403
|
}
|
|
@@ -23098,7 +23431,7 @@ bun run build
|
|
|
23098
23431
|
Use conventional commits: feat:, fix:, docs:, refactor:, test:, chore:
|
|
23099
23432
|
`;
|
|
23100
23433
|
try {
|
|
23101
|
-
|
|
23434
|
+
writeFileSync7(claudeMdPath, content);
|
|
23102
23435
|
return true;
|
|
23103
23436
|
} catch {
|
|
23104
23437
|
return false;
|
|
@@ -23378,7 +23711,7 @@ var setupCommand = defineCommand2({
|
|
|
23378
23711
|
});
|
|
23379
23712
|
|
|
23380
23713
|
// src/commands/upgrade.ts
|
|
23381
|
-
import { execSync as
|
|
23714
|
+
import { execSync as execSync5 } from "node:child_process";
|
|
23382
23715
|
var CYAN = "\x1B[36m";
|
|
23383
23716
|
var GREEN = "\x1B[32m";
|
|
23384
23717
|
var YELLOW = "\x1B[33m";
|
|
@@ -23387,6 +23720,27 @@ var BOLD = "\x1B[1m";
|
|
|
23387
23720
|
var RESET = "\x1B[0m";
|
|
23388
23721
|
var MAGENTA = "\x1B[35m";
|
|
23389
23722
|
var CHANGELOG = [
|
|
23723
|
+
{
|
|
23724
|
+
version: "0.5.2",
|
|
23725
|
+
date: "2026-02-14",
|
|
23726
|
+
title: "Multi-Agent Detection",
|
|
23727
|
+
highlights: [
|
|
23728
|
+
"Detects ALL installed AI agents (Claude Code, Cursor, OpenCode, Codex, etc.)",
|
|
23729
|
+
"Choose which agent you're using if multiple are found",
|
|
23730
|
+
"Expanded agent support: Copilot, Cody, Aider"
|
|
23731
|
+
]
|
|
23732
|
+
},
|
|
23733
|
+
{
|
|
23734
|
+
version: "0.5.1",
|
|
23735
|
+
date: "2026-02-14",
|
|
23736
|
+
title: "Smart Project Onboarding",
|
|
23737
|
+
highlights: [
|
|
23738
|
+
"First scan detects your project and suggests relevant skills",
|
|
23739
|
+
"Auto-installs find-skills to discover more tools later",
|
|
23740
|
+
"Analyzes README to recommend skills for your tech stack",
|
|
23741
|
+
"Detects your AI agent (Claude Code, OpenCode, Cursor)"
|
|
23742
|
+
]
|
|
23743
|
+
},
|
|
23390
23744
|
{
|
|
23391
23745
|
version: "0.5.0",
|
|
23392
23746
|
date: "2026-02-14",
|
|
@@ -23703,7 +24057,7 @@ var upgradeCommand = defineCommand2({
|
|
|
23703
24057
|
console.log(`${DIM} Checking for updates...${RESET}`);
|
|
23704
24058
|
let latestVersion;
|
|
23705
24059
|
try {
|
|
23706
|
-
latestVersion =
|
|
24060
|
+
latestVersion = execSync5("npm view nairon-bench version", { encoding: "utf-8" }).trim();
|
|
23707
24061
|
} catch {
|
|
23708
24062
|
console.log(` ${YELLOW}⚠${RESET} Could not check npm registry`);
|
|
23709
24063
|
console.log(` ${DIM}Run 'bun add -g nairon-bench@latest' manually${RESET}`);
|
|
@@ -23730,7 +24084,7 @@ var upgradeCommand = defineCommand2({
|
|
|
23730
24084
|
console.log(` ${CYAN}↓${RESET} Upgrading to ${GREEN}v${latestVersion}${RESET}...`);
|
|
23731
24085
|
console.log();
|
|
23732
24086
|
try {
|
|
23733
|
-
|
|
24087
|
+
execSync5("npm install -g nairon-bench@latest", {
|
|
23734
24088
|
stdio: "inherit",
|
|
23735
24089
|
env: { ...process.env, npm_config_fund: "false" }
|
|
23736
24090
|
});
|
|
@@ -23748,7 +24102,7 @@ var upgradeCommand = defineCommand2({
|
|
|
23748
24102
|
});
|
|
23749
24103
|
function getCurrentVersion() {
|
|
23750
24104
|
try {
|
|
23751
|
-
const output =
|
|
24105
|
+
const output = execSync5("nb --version 2>/dev/null || nairon-bench --version 2>/dev/null", {
|
|
23752
24106
|
encoding: "utf-8",
|
|
23753
24107
|
stdio: ["pipe", "pipe", "pipe"]
|
|
23754
24108
|
});
|
|
@@ -23837,7 +24191,7 @@ function showFullChangelog() {
|
|
|
23837
24191
|
// package.json
|
|
23838
24192
|
var package_default = {
|
|
23839
24193
|
name: "nairon-bench",
|
|
23840
|
-
version: "0.5.
|
|
24194
|
+
version: "0.5.2",
|
|
23841
24195
|
description: "AI workflow benchmarking CLI",
|
|
23842
24196
|
type: "module",
|
|
23843
24197
|
bin: {
|
|
@@ -23845,7 +24199,8 @@ var package_default = {
|
|
|
23845
24199
|
nb: "./dist/index.js"
|
|
23846
24200
|
},
|
|
23847
24201
|
files: [
|
|
23848
|
-
"dist"
|
|
24202
|
+
"dist",
|
|
24203
|
+
"postinstall.js"
|
|
23849
24204
|
],
|
|
23850
24205
|
repository: {
|
|
23851
24206
|
type: "git",
|
|
@@ -23873,7 +24228,8 @@ var package_default = {
|
|
|
23873
24228
|
"test:e2e": "vitest run tests/e2e/",
|
|
23874
24229
|
"test:watch": "vitest",
|
|
23875
24230
|
clean: "rm -rf dist",
|
|
23876
|
-
prepublishOnly: "bun run build"
|
|
24231
|
+
prepublishOnly: "bun run build",
|
|
24232
|
+
postinstall: "node postinstall.js || true"
|
|
23877
24233
|
},
|
|
23878
24234
|
dependencies: {
|
|
23879
24235
|
"cli-boxes": "^4.0.1",
|
|
@@ -23896,9 +24252,9 @@ var versionCommand = defineCommand2({
|
|
|
23896
24252
|
|
|
23897
24253
|
// src/commands/init.ts
|
|
23898
24254
|
init_dist();
|
|
23899
|
-
import { existsSync as
|
|
23900
|
-
import { homedir as
|
|
23901
|
-
import { join as
|
|
24255
|
+
import { existsSync as existsSync16 } from "node:fs";
|
|
24256
|
+
import { homedir as homedir13, platform as platform3, arch } from "node:os";
|
|
24257
|
+
import { join as join16 } from "node:path";
|
|
23902
24258
|
init_client();
|
|
23903
24259
|
|
|
23904
24260
|
// src/lib/github-auth.ts
|
|
@@ -24068,8 +24424,8 @@ var initCommand = defineCommand2({
|
|
|
24068
24424
|
consola.start("Step 2/6: Detecting AI agents...");
|
|
24069
24425
|
const detectedAgents = [];
|
|
24070
24426
|
for (const [agent, pathTemplate] of Object.entries(AGENT_LOG_PATHS)) {
|
|
24071
|
-
const resolvedPath = pathTemplate.replace("~",
|
|
24072
|
-
if (
|
|
24427
|
+
const resolvedPath = pathTemplate.replace("~", homedir13());
|
|
24428
|
+
if (existsSync16(resolvedPath)) {
|
|
24073
24429
|
detectedAgents.push(agent);
|
|
24074
24430
|
consola.success(` Found: ${agent}`);
|
|
24075
24431
|
}
|
|
@@ -24172,7 +24528,7 @@ var initCommand = defineCommand2({
|
|
|
24172
24528
|
{ name: "playwright", configs: ["playwright.config.ts", "playwright.config.js"] }
|
|
24173
24529
|
];
|
|
24174
24530
|
for (const fw of testFrameworks) {
|
|
24175
|
-
if (fw.configs.some((c3) =>
|
|
24531
|
+
if (fw.configs.some((c3) => existsSync16(join16(process.cwd(), c3)))) {
|
|
24176
24532
|
toolStack.testing.push(fw.name);
|
|
24177
24533
|
}
|
|
24178
24534
|
}
|
|
@@ -24241,13 +24597,13 @@ var initCommand = defineCommand2({
|
|
|
24241
24597
|
});
|
|
24242
24598
|
function detectPackageManager() {
|
|
24243
24599
|
const cwd = process.cwd();
|
|
24244
|
-
if (
|
|
24600
|
+
if (existsSync16(join16(cwd, "bun.lock")) || existsSync16(join16(cwd, "bun.lockb")))
|
|
24245
24601
|
return "bun";
|
|
24246
|
-
if (
|
|
24602
|
+
if (existsSync16(join16(cwd, "pnpm-lock.yaml")))
|
|
24247
24603
|
return "pnpm";
|
|
24248
|
-
if (
|
|
24604
|
+
if (existsSync16(join16(cwd, "yarn.lock")))
|
|
24249
24605
|
return "yarn";
|
|
24250
|
-
if (
|
|
24606
|
+
if (existsSync16(join16(cwd, "package-lock.json")))
|
|
24251
24607
|
return "npm";
|
|
24252
24608
|
return;
|
|
24253
24609
|
}
|
|
@@ -24262,15 +24618,15 @@ var CLAUDE_CODE_SKILLS = [
|
|
|
24262
24618
|
];
|
|
24263
24619
|
function detectEasyWins(detectedAgents) {
|
|
24264
24620
|
const wins = [];
|
|
24265
|
-
const home =
|
|
24621
|
+
const home = homedir13();
|
|
24266
24622
|
const hasClaudeCode = detectedAgents.some((a2) => a2.toLowerCase().includes("claude") || a2.toLowerCase().includes("opencode"));
|
|
24267
|
-
const claudeConfigDir =
|
|
24268
|
-
const hasClaudeConfig =
|
|
24623
|
+
const claudeConfigDir = join16(home, ".claude");
|
|
24624
|
+
const hasClaudeConfig = existsSync16(claudeConfigDir);
|
|
24269
24625
|
if (hasClaudeCode || hasClaudeConfig) {
|
|
24270
|
-
const skillsDir =
|
|
24626
|
+
const skillsDir = join16(home, ".claude", "skills");
|
|
24271
24627
|
for (const skill of CLAUDE_CODE_SKILLS) {
|
|
24272
|
-
const skillPath =
|
|
24273
|
-
const isInstalled =
|
|
24628
|
+
const skillPath = join16(skillsDir, skill.id);
|
|
24629
|
+
const isInstalled = existsSync16(skillPath);
|
|
24274
24630
|
if (!isInstalled) {
|
|
24275
24631
|
wins.push({
|
|
24276
24632
|
icon: skill.icon,
|
|
@@ -24286,12 +24642,12 @@ function detectEasyWins(detectedAgents) {
|
|
|
24286
24642
|
// src/commands/onboard.ts
|
|
24287
24643
|
init_dist();
|
|
24288
24644
|
init_client();
|
|
24289
|
-
import { existsSync as
|
|
24290
|
-
import { join as
|
|
24645
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync7, readFileSync as readFileSync16, writeFileSync as writeFileSync8, readdirSync as readdirSync9 } from "node:fs";
|
|
24646
|
+
import { join as join18 } from "node:path";
|
|
24291
24647
|
|
|
24292
24648
|
// src/lib/project-context-detector.ts
|
|
24293
|
-
import { existsSync as
|
|
24294
|
-
import { join as
|
|
24649
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15, readdirSync as readdirSync8 } from "node:fs";
|
|
24650
|
+
import { join as join17, basename as basename4 } from "node:path";
|
|
24295
24651
|
function detectProjectContext(projectDir) {
|
|
24296
24652
|
const projectName = basename4(projectDir);
|
|
24297
24653
|
const projectId = generateProjectId(projectDir);
|
|
@@ -24327,11 +24683,11 @@ function detectTechStack(projectDir) {
|
|
|
24327
24683
|
};
|
|
24328
24684
|
}
|
|
24329
24685
|
function readPackageJson(projectDir) {
|
|
24330
|
-
const pkgPath =
|
|
24331
|
-
if (!
|
|
24686
|
+
const pkgPath = join17(projectDir, "package.json");
|
|
24687
|
+
if (!existsSync17(pkgPath))
|
|
24332
24688
|
return {};
|
|
24333
24689
|
try {
|
|
24334
|
-
return JSON.parse(
|
|
24690
|
+
return JSON.parse(readFileSync15(pkgPath, "utf-8"));
|
|
24335
24691
|
} catch {
|
|
24336
24692
|
return {};
|
|
24337
24693
|
}
|
|
@@ -24352,34 +24708,34 @@ function detectFramework(deps) {
|
|
|
24352
24708
|
return null;
|
|
24353
24709
|
}
|
|
24354
24710
|
function detectMetaFramework(deps, projectDir) {
|
|
24355
|
-
if (deps.next ||
|
|
24711
|
+
if (deps.next || existsSync17(join17(projectDir, "next.config.js")) || existsSync17(join17(projectDir, "next.config.mjs")))
|
|
24356
24712
|
return "next";
|
|
24357
|
-
if (deps.nuxt ||
|
|
24713
|
+
if (deps.nuxt || existsSync17(join17(projectDir, "nuxt.config.ts")))
|
|
24358
24714
|
return "nuxt";
|
|
24359
24715
|
if (deps["@sveltejs/kit"])
|
|
24360
24716
|
return "sveltekit";
|
|
24361
|
-
if (deps.astro ||
|
|
24717
|
+
if (deps.astro || existsSync17(join17(projectDir, "astro.config.mjs")))
|
|
24362
24718
|
return "astro";
|
|
24363
24719
|
if (deps["@remix-run/react"])
|
|
24364
24720
|
return "remix";
|
|
24365
24721
|
if (deps.gatsby)
|
|
24366
24722
|
return "gatsby";
|
|
24367
|
-
if (deps.vite ||
|
|
24723
|
+
if (deps.vite || existsSync17(join17(projectDir, "vite.config.ts")))
|
|
24368
24724
|
return "vite";
|
|
24369
24725
|
return null;
|
|
24370
24726
|
}
|
|
24371
24727
|
function detectRuntime(projectDir) {
|
|
24372
|
-
if (
|
|
24728
|
+
if (existsSync17(join17(projectDir, "bun.lockb")) || existsSync17(join17(projectDir, "bun.lock")))
|
|
24373
24729
|
return "bun";
|
|
24374
|
-
if (
|
|
24730
|
+
if (existsSync17(join17(projectDir, "deno.json")) || existsSync17(join17(projectDir, "deno.lock")))
|
|
24375
24731
|
return "deno";
|
|
24376
24732
|
return "node";
|
|
24377
24733
|
}
|
|
24378
24734
|
function detectLanguage(projectDir) {
|
|
24379
|
-
if (
|
|
24735
|
+
if (existsSync17(join17(projectDir, "tsconfig.json")))
|
|
24380
24736
|
return "typescript";
|
|
24381
|
-
const srcDir =
|
|
24382
|
-
if (
|
|
24737
|
+
const srcDir = join17(projectDir, "src");
|
|
24738
|
+
if (existsSync17(srcDir)) {
|
|
24383
24739
|
try {
|
|
24384
24740
|
const files = readdirSync8(srcDir);
|
|
24385
24741
|
if (files.some((f3) => f3.endsWith(".ts") || f3.endsWith(".tsx")))
|
|
@@ -24390,7 +24746,7 @@ function detectLanguage(projectDir) {
|
|
|
24390
24746
|
}
|
|
24391
24747
|
function detectStyling(deps, projectDir) {
|
|
24392
24748
|
const tools = [];
|
|
24393
|
-
if (deps.tailwindcss ||
|
|
24749
|
+
if (deps.tailwindcss || existsSync17(join17(projectDir, "tailwind.config.js")) || existsSync17(join17(projectDir, "tailwind.config.ts")))
|
|
24394
24750
|
tools.push("tailwind");
|
|
24395
24751
|
if (deps["styled-components"])
|
|
24396
24752
|
tools.push("styled-components");
|
|
@@ -24435,13 +24791,13 @@ function detectORM(deps) {
|
|
|
24435
24791
|
}
|
|
24436
24792
|
function detectTesting(deps, projectDir) {
|
|
24437
24793
|
const tools = [];
|
|
24438
|
-
if (deps.vitest ||
|
|
24794
|
+
if (deps.vitest || existsSync17(join17(projectDir, "vitest.config.ts")))
|
|
24439
24795
|
tools.push("vitest");
|
|
24440
|
-
if (deps.jest ||
|
|
24796
|
+
if (deps.jest || existsSync17(join17(projectDir, "jest.config.js")))
|
|
24441
24797
|
tools.push("jest");
|
|
24442
|
-
if (deps["@playwright/test"] ||
|
|
24798
|
+
if (deps["@playwright/test"] || existsSync17(join17(projectDir, "playwright.config.ts")))
|
|
24443
24799
|
tools.push("playwright");
|
|
24444
|
-
if (deps.cypress ||
|
|
24800
|
+
if (deps.cypress || existsSync17(join17(projectDir, "cypress.config.ts")))
|
|
24445
24801
|
tools.push("cypress");
|
|
24446
24802
|
if (deps["@testing-library/react"] || deps["@testing-library/vue"])
|
|
24447
24803
|
tools.push("testing-library");
|
|
@@ -24473,7 +24829,7 @@ function detectBuildTools(deps, projectDir) {
|
|
|
24473
24829
|
tools.push("esbuild");
|
|
24474
24830
|
if (deps.webpack)
|
|
24475
24831
|
tools.push("webpack");
|
|
24476
|
-
if (deps.turbo ||
|
|
24832
|
+
if (deps.turbo || existsSync17(join17(projectDir, "turbo.json")))
|
|
24477
24833
|
tools.push("turborepo");
|
|
24478
24834
|
if (deps.tsup)
|
|
24479
24835
|
tools.push("tsup");
|
|
@@ -24483,17 +24839,17 @@ function detectBuildTools(deps, projectDir) {
|
|
|
24483
24839
|
}
|
|
24484
24840
|
function detectDeployment(projectDir) {
|
|
24485
24841
|
const tools = [];
|
|
24486
|
-
if (
|
|
24842
|
+
if (existsSync17(join17(projectDir, "vercel.json")) || existsSync17(join17(projectDir, ".vercel")))
|
|
24487
24843
|
tools.push("vercel");
|
|
24488
|
-
if (
|
|
24844
|
+
if (existsSync17(join17(projectDir, "netlify.toml")))
|
|
24489
24845
|
tools.push("netlify");
|
|
24490
|
-
if (
|
|
24846
|
+
if (existsSync17(join17(projectDir, "fly.toml")))
|
|
24491
24847
|
tools.push("fly");
|
|
24492
|
-
if (
|
|
24848
|
+
if (existsSync17(join17(projectDir, "railway.json")))
|
|
24493
24849
|
tools.push("railway");
|
|
24494
|
-
if (
|
|
24850
|
+
if (existsSync17(join17(projectDir, "Dockerfile")))
|
|
24495
24851
|
tools.push("docker");
|
|
24496
|
-
if (
|
|
24852
|
+
if (existsSync17(join17(projectDir, ".github", "workflows")))
|
|
24497
24853
|
tools.push("github-actions");
|
|
24498
24854
|
return tools;
|
|
24499
24855
|
}
|
|
@@ -24516,20 +24872,20 @@ function detectAIML(deps) {
|
|
|
24516
24872
|
return tools;
|
|
24517
24873
|
}
|
|
24518
24874
|
function inferProjectType(projectDir, techStack) {
|
|
24519
|
-
if (
|
|
24875
|
+
if (existsSync17(join17(projectDir, "packages")) || existsSync17(join17(projectDir, "apps"))) {
|
|
24520
24876
|
return "monorepo";
|
|
24521
24877
|
}
|
|
24522
24878
|
const pkg = readPackageJson(projectDir);
|
|
24523
|
-
if (pkg.bin ||
|
|
24879
|
+
if (pkg.bin || existsSync17(join17(projectDir, "src", "cli.ts")) || existsSync17(join17(projectDir, "src", "index.ts"))) {
|
|
24524
24880
|
const hasBin = !!pkg.bin;
|
|
24525
|
-
const hasCommands =
|
|
24881
|
+
const hasCommands = existsSync17(join17(projectDir, "src", "commands"));
|
|
24526
24882
|
if (hasBin || hasCommands)
|
|
24527
24883
|
return "cli";
|
|
24528
24884
|
}
|
|
24529
24885
|
if (!techStack.framework && !techStack.metaFramework && pkg.main) {
|
|
24530
24886
|
return "library";
|
|
24531
24887
|
}
|
|
24532
|
-
if (
|
|
24888
|
+
if (existsSync17(join17(projectDir, "app.json")) || existsSync17(join17(projectDir, "expo"))) {
|
|
24533
24889
|
return "mobile";
|
|
24534
24890
|
}
|
|
24535
24891
|
if (techStack.database.length > 0 && !techStack.framework) {
|
|
@@ -24546,10 +24902,10 @@ function extractDescription(projectDir) {
|
|
|
24546
24902
|
return pkg.description;
|
|
24547
24903
|
const readmePaths = ["README.md", "readme.md", "Readme.md"];
|
|
24548
24904
|
for (const readme of readmePaths) {
|
|
24549
|
-
const path =
|
|
24550
|
-
if (
|
|
24905
|
+
const path = join17(projectDir, readme);
|
|
24906
|
+
if (existsSync17(path)) {
|
|
24551
24907
|
try {
|
|
24552
|
-
const content =
|
|
24908
|
+
const content = readFileSync15(path, "utf-8");
|
|
24553
24909
|
const lines = content.split(`
|
|
24554
24910
|
`);
|
|
24555
24911
|
let foundTitle = false;
|
|
@@ -25967,9 +26323,9 @@ var onboardCommand = defineCommand2({
|
|
|
25967
26323
|
},
|
|
25968
26324
|
async run({ args }) {
|
|
25969
26325
|
const projectPath = process.cwd();
|
|
25970
|
-
const contextPath =
|
|
25971
|
-
if (
|
|
25972
|
-
const existing = JSON.parse(
|
|
26326
|
+
const contextPath = join18(projectPath, ".nairon", "context.json");
|
|
26327
|
+
if (existsSync18(contextPath) && !args.force) {
|
|
26328
|
+
const existing = JSON.parse(readFileSync16(contextPath, "utf-8"));
|
|
25973
26329
|
consola.info("Project already onboarded. Use --force to re-run.");
|
|
25974
26330
|
consola.info(`Business: ${existing.businessContext?.domain || existing.businessContext?.slice?.(0, 50) || "Not set"}...`);
|
|
25975
26331
|
consola.info(`Stack: ${formatTechStackSummary(existing)}`);
|
|
@@ -26117,11 +26473,11 @@ var onboardCommand = defineCommand2({
|
|
|
26117
26473
|
createdAt: new Date().toISOString(),
|
|
26118
26474
|
updatedAt: new Date().toISOString()
|
|
26119
26475
|
};
|
|
26120
|
-
const naironDir =
|
|
26121
|
-
if (!
|
|
26122
|
-
|
|
26476
|
+
const naironDir = join18(projectPath, ".nairon");
|
|
26477
|
+
if (!existsSync18(naironDir)) {
|
|
26478
|
+
mkdirSync7(naironDir, { recursive: true });
|
|
26123
26479
|
}
|
|
26124
|
-
|
|
26480
|
+
writeFileSync8(contextPath, JSON.stringify(fullContext, null, 2));
|
|
26125
26481
|
consola.success(`Saved to ${contextPath}`);
|
|
26126
26482
|
if (isSupermemoryConfigured()) {
|
|
26127
26483
|
consola.start("Storing in Supermemory...");
|
|
@@ -26209,51 +26565,51 @@ function formatTechStackSummary(context) {
|
|
|
26209
26565
|
function detectInstalledTools(projectPath) {
|
|
26210
26566
|
const tools = [];
|
|
26211
26567
|
const home = process.env.HOME || "";
|
|
26212
|
-
const userClaudeJson =
|
|
26213
|
-
if (
|
|
26568
|
+
const userClaudeJson = join18(home, ".claude.json");
|
|
26569
|
+
if (existsSync18(userClaudeJson)) {
|
|
26214
26570
|
try {
|
|
26215
|
-
const config = JSON.parse(
|
|
26571
|
+
const config = JSON.parse(readFileSync16(userClaudeJson, "utf-8"));
|
|
26216
26572
|
if (config.mcpServers) {
|
|
26217
26573
|
tools.push(...Object.keys(config.mcpServers));
|
|
26218
26574
|
}
|
|
26219
26575
|
} catch {}
|
|
26220
26576
|
}
|
|
26221
|
-
const claudeDesktopConfig =
|
|
26222
|
-
if (
|
|
26577
|
+
const claudeDesktopConfig = join18(home, ".claude", "claude_desktop_config.json");
|
|
26578
|
+
if (existsSync18(claudeDesktopConfig)) {
|
|
26223
26579
|
try {
|
|
26224
|
-
const config = JSON.parse(
|
|
26580
|
+
const config = JSON.parse(readFileSync16(claudeDesktopConfig, "utf-8"));
|
|
26225
26581
|
if (config.mcpServers) {
|
|
26226
26582
|
tools.push(...Object.keys(config.mcpServers));
|
|
26227
26583
|
}
|
|
26228
26584
|
} catch {}
|
|
26229
26585
|
}
|
|
26230
|
-
const projectMcpJson =
|
|
26231
|
-
if (
|
|
26586
|
+
const projectMcpJson = join18(projectPath, ".mcp.json");
|
|
26587
|
+
if (existsSync18(projectMcpJson)) {
|
|
26232
26588
|
try {
|
|
26233
|
-
const config = JSON.parse(
|
|
26589
|
+
const config = JSON.parse(readFileSync16(projectMcpJson, "utf-8"));
|
|
26234
26590
|
if (config.mcpServers) {
|
|
26235
26591
|
tools.push(...Object.keys(config.mcpServers));
|
|
26236
26592
|
}
|
|
26237
26593
|
} catch {}
|
|
26238
26594
|
}
|
|
26239
|
-
const projectClaudeConfig =
|
|
26240
|
-
if (
|
|
26595
|
+
const projectClaudeConfig = join18(projectPath, ".claude", "settings.json");
|
|
26596
|
+
if (existsSync18(projectClaudeConfig)) {
|
|
26241
26597
|
try {
|
|
26242
|
-
const config = JSON.parse(
|
|
26598
|
+
const config = JSON.parse(readFileSync16(projectClaudeConfig, "utf-8"));
|
|
26243
26599
|
if (config.mcpServers) {
|
|
26244
26600
|
tools.push(...Object.keys(config.mcpServers));
|
|
26245
26601
|
}
|
|
26246
26602
|
} catch {}
|
|
26247
26603
|
}
|
|
26248
|
-
const skillsDir =
|
|
26249
|
-
if (
|
|
26604
|
+
const skillsDir = join18(home, ".config", "opencode", "skills");
|
|
26605
|
+
if (existsSync18(skillsDir)) {
|
|
26250
26606
|
try {
|
|
26251
26607
|
const skills = readdirSync9(skillsDir);
|
|
26252
26608
|
tools.push(...skills.filter((s2) => !s2.startsWith(".")));
|
|
26253
26609
|
} catch {}
|
|
26254
26610
|
}
|
|
26255
|
-
const agentsSkillsDir =
|
|
26256
|
-
if (
|
|
26611
|
+
const agentsSkillsDir = join18(home, ".agents", "skills");
|
|
26612
|
+
if (existsSync18(agentsSkillsDir)) {
|
|
26257
26613
|
try {
|
|
26258
26614
|
const skills = readdirSync9(agentsSkillsDir);
|
|
26259
26615
|
tools.push(...skills.filter((s2) => !s2.startsWith(".")));
|
|
@@ -26263,11 +26619,11 @@ function detectInstalledTools(projectPath) {
|
|
|
26263
26619
|
}
|
|
26264
26620
|
function detectPrimaryAgent() {
|
|
26265
26621
|
const home = process.env.HOME || "";
|
|
26266
|
-
if (
|
|
26622
|
+
if (existsSync18(join18(home, ".claude")))
|
|
26267
26623
|
return "claude-code";
|
|
26268
|
-
if (
|
|
26624
|
+
if (existsSync18(join18(home, ".cursor")))
|
|
26269
26625
|
return "cursor";
|
|
26270
|
-
if (
|
|
26626
|
+
if (existsSync18(join18(home, ".config", "opencode")))
|
|
26271
26627
|
return "opencode";
|
|
26272
26628
|
return;
|
|
26273
26629
|
}
|
|
@@ -26362,7 +26718,7 @@ function formatBytes(bytes) {
|
|
|
26362
26718
|
// package.json
|
|
26363
26719
|
var package_default2 = {
|
|
26364
26720
|
name: "nairon-bench",
|
|
26365
|
-
version: "0.5.
|
|
26721
|
+
version: "0.5.2",
|
|
26366
26722
|
description: "AI workflow benchmarking CLI",
|
|
26367
26723
|
type: "module",
|
|
26368
26724
|
bin: {
|
|
@@ -26370,7 +26726,8 @@ var package_default2 = {
|
|
|
26370
26726
|
nb: "./dist/index.js"
|
|
26371
26727
|
},
|
|
26372
26728
|
files: [
|
|
26373
|
-
"dist"
|
|
26729
|
+
"dist",
|
|
26730
|
+
"postinstall.js"
|
|
26374
26731
|
],
|
|
26375
26732
|
repository: {
|
|
26376
26733
|
type: "git",
|
|
@@ -26398,7 +26755,8 @@ var package_default2 = {
|
|
|
26398
26755
|
"test:e2e": "vitest run tests/e2e/",
|
|
26399
26756
|
"test:watch": "vitest",
|
|
26400
26757
|
clean: "rm -rf dist",
|
|
26401
|
-
prepublishOnly: "bun run build"
|
|
26758
|
+
prepublishOnly: "bun run build",
|
|
26759
|
+
postinstall: "node postinstall.js || true"
|
|
26402
26760
|
},
|
|
26403
26761
|
dependencies: {
|
|
26404
26762
|
"cli-boxes": "^4.0.1",
|
|
@@ -26463,7 +26821,7 @@ var hasVersion = args.includes("--version");
|
|
|
26463
26821
|
if (!hasSubcommand && !hasHelp && !hasVersion && args.length === 0) {
|
|
26464
26822
|
showBanner();
|
|
26465
26823
|
} else {
|
|
26466
|
-
const
|
|
26824
|
+
const cmd = defineCommand({
|
|
26467
26825
|
meta: {
|
|
26468
26826
|
name: "nairon-bench",
|
|
26469
26827
|
version: VERSION2,
|
|
@@ -26481,5 +26839,5 @@ if (!hasSubcommand && !hasHelp && !hasVersion && args.length === 0) {
|
|
|
26481
26839
|
cache: cacheCommand
|
|
26482
26840
|
}
|
|
26483
26841
|
});
|
|
26484
|
-
runMain(
|
|
26842
|
+
runMain(cmd);
|
|
26485
26843
|
}
|