nairon-bench 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +733 -608
- 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);
|
|
@@ -16067,159 +16067,261 @@ function filterAlreadyInstalled(optimizations, status) {
|
|
|
16067
16067
|
return true;
|
|
16068
16068
|
});
|
|
16069
16069
|
}
|
|
16070
|
-
var QUICK_INSTALL_PRESETS = {
|
|
16071
|
-
essential: [
|
|
16072
|
-
{
|
|
16073
|
-
id: "context7",
|
|
16074
|
-
name: "Context7 MCP",
|
|
16075
|
-
type: "mcp",
|
|
16076
|
-
description: "Up-to-date library documentation",
|
|
16077
|
-
installCommand: "claude mcp add context7 https://mcp.context7.com/mcp --transport http",
|
|
16078
|
-
selected: true
|
|
16079
|
-
},
|
|
16080
|
-
{
|
|
16081
|
-
id: "supermemory",
|
|
16082
|
-
name: "Supermemory MCP",
|
|
16083
|
-
type: "mcp",
|
|
16084
|
-
description: "Persistent memory across sessions",
|
|
16085
|
-
installCommand: "claude mcp add supermemory -- npx -y @supermemory/mcp@latest",
|
|
16086
|
-
selected: true
|
|
16087
|
-
},
|
|
16088
|
-
{
|
|
16089
|
-
id: "beads",
|
|
16090
|
-
name: "Beads Task Manager",
|
|
16091
|
-
type: "mcp",
|
|
16092
|
-
description: "Persistent task tracking",
|
|
16093
|
-
installCommand: "bun add -g beads && bd init",
|
|
16094
|
-
selected: true
|
|
16095
|
-
}
|
|
16096
|
-
],
|
|
16097
|
-
productivity: [
|
|
16098
|
-
{
|
|
16099
|
-
id: "claude-md",
|
|
16100
|
-
name: "CLAUDE.md",
|
|
16101
|
-
type: "config",
|
|
16102
|
-
description: "Project context file",
|
|
16103
|
-
configPath: "CLAUDE.md",
|
|
16104
|
-
configContent: `# Project Instructions
|
|
16105
|
-
|
|
16106
|
-
## Build & Test Commands
|
|
16107
|
-
\`\`\`bash
|
|
16108
|
-
bun test # Run tests
|
|
16109
|
-
bun run build # Build project
|
|
16110
|
-
bun run lint # Run linter
|
|
16111
|
-
\`\`\`
|
|
16112
|
-
|
|
16113
|
-
## Architecture
|
|
16114
|
-
Describe your project structure here.
|
|
16115
16070
|
|
|
16116
|
-
|
|
16117
|
-
|
|
16118
|
-
|
|
16119
|
-
|
|
16120
|
-
|
|
16121
|
-
|
|
16122
|
-
|
|
16123
|
-
|
|
16124
|
-
|
|
16125
|
-
|
|
16126
|
-
|
|
16127
|
-
|
|
16128
|
-
|
|
16129
|
-
|
|
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
|
+
function detectAgent() {
|
|
16090
|
+
const home = homedir8();
|
|
16091
|
+
const claudeConfig = join9(home, ".claude");
|
|
16092
|
+
const hasClaudeCode = existsSync9(claudeConfig);
|
|
16093
|
+
const opencodeConfig = join9(home, ".config", "opencode");
|
|
16094
|
+
const opencodeData = join9(home, ".local", "share", "opencode");
|
|
16095
|
+
const hasOpenCode = existsSync9(opencodeConfig) || existsSync9(opencodeData);
|
|
16096
|
+
const cursorConfig = join9(home, ".cursor");
|
|
16097
|
+
const hasCursor = existsSync9(cursorConfig);
|
|
16098
|
+
if (hasClaudeCode)
|
|
16099
|
+
return "claude-code";
|
|
16100
|
+
if (hasOpenCode)
|
|
16101
|
+
return "opencode";
|
|
16102
|
+
if (hasCursor)
|
|
16103
|
+
return "cursor";
|
|
16104
|
+
return "unknown";
|
|
16105
|
+
}
|
|
16106
|
+
function analyzeReadme(projectDir) {
|
|
16107
|
+
const readmePath = join9(projectDir, "README.md");
|
|
16108
|
+
if (!existsSync9(readmePath)) {
|
|
16109
|
+
const alternatives = ["readme.md", "Readme.md", "README.MD", "README"];
|
|
16110
|
+
for (const alt of alternatives) {
|
|
16111
|
+
const altPath = join9(projectDir, alt);
|
|
16112
|
+
if (existsSync9(altPath)) {
|
|
16113
|
+
return parseReadme(readFileSync9(altPath, "utf-8"), projectDir);
|
|
16114
|
+
}
|
|
16130
16115
|
}
|
|
16131
|
-
|
|
16132
|
-
}
|
|
16116
|
+
return null;
|
|
16117
|
+
}
|
|
16118
|
+
const content = readFileSync9(readmePath, "utf-8");
|
|
16119
|
+
return parseReadme(content, projectDir);
|
|
16120
|
+
}
|
|
16121
|
+
function parseReadme(content, projectDir) {
|
|
16122
|
+
let name = "Unknown Project";
|
|
16123
|
+
const pkgPath = join9(projectDir, "package.json");
|
|
16124
|
+
if (existsSync9(pkgPath)) {
|
|
16125
|
+
try {
|
|
16126
|
+
const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
|
|
16127
|
+
if (pkg.name && !pkg.name.startsWith("@") && pkg.name !== "root") {
|
|
16128
|
+
name = pkg.name;
|
|
16129
|
+
}
|
|
16130
|
+
} catch {}
|
|
16131
|
+
}
|
|
16132
|
+
if (name === "Unknown Project") {
|
|
16133
|
+
const headingMatch = content.match(/^#\s+([^<\n]+)$/m);
|
|
16134
|
+
if (headingMatch && headingMatch[1]) {
|
|
16135
|
+
const heading = headingMatch[1].trim();
|
|
16136
|
+
if (!heading.toLowerCase().includes("install") && !heading.toLowerCase().includes("getting started") && heading.length < 50) {
|
|
16137
|
+
name = heading;
|
|
16138
|
+
}
|
|
16139
|
+
}
|
|
16140
|
+
}
|
|
16141
|
+
let description = "";
|
|
16142
|
+
const descMatch = content.match(/^#[^#].*\n\n(.+?)(\n\n|$)/s);
|
|
16143
|
+
if (descMatch && descMatch[1]) {
|
|
16144
|
+
description = descMatch[1].replace(/\n/g, " ").trim().slice(0, 200);
|
|
16145
|
+
}
|
|
16146
|
+
const techStack = [];
|
|
16147
|
+
const techPatterns = {
|
|
16148
|
+
react: /\breact\b/i,
|
|
16149
|
+
"next.js": /\bnext\.?js\b/i,
|
|
16150
|
+
vue: /\bvue\b/i,
|
|
16151
|
+
svelte: /\bsvelte\b/i,
|
|
16152
|
+
typescript: /\btypescript\b/i,
|
|
16153
|
+
python: /\bpython\b/i,
|
|
16154
|
+
rust: /\brust\b/i,
|
|
16155
|
+
go: /\bgolang?\b/i,
|
|
16156
|
+
node: /\bnode\.?js\b/i,
|
|
16157
|
+
bun: /\bbun\b/i,
|
|
16158
|
+
deno: /\bdeno\b/i,
|
|
16159
|
+
tailwind: /\btailwind\b/i,
|
|
16160
|
+
prisma: /\bprisma\b/i,
|
|
16161
|
+
postgres: /\bpostgres\b/i,
|
|
16162
|
+
mongodb: /\bmongo\b/i,
|
|
16163
|
+
redis: /\bredis\b/i,
|
|
16164
|
+
docker: /\bdocker\b/i,
|
|
16165
|
+
kubernetes: /\bkubernetes\b|\bk8s\b/i,
|
|
16166
|
+
aws: /\baws\b/i,
|
|
16167
|
+
vercel: /\bvercel\b/i,
|
|
16168
|
+
cloudflare: /\bcloudflare\b/i,
|
|
16169
|
+
openai: /\bopenai\b/i,
|
|
16170
|
+
anthropic: /\banthropic\b|\bclaude\b/i,
|
|
16171
|
+
langchain: /\blangchain\b/i,
|
|
16172
|
+
convex: /\bconvex\b/i,
|
|
16173
|
+
supabase: /\bsupabase\b/i,
|
|
16174
|
+
firebase: /\bfirebase\b/i,
|
|
16175
|
+
stripe: /\bstripe\b/i,
|
|
16176
|
+
playwright: /\bplaywright\b/i,
|
|
16177
|
+
vitest: /\bvitest\b/i,
|
|
16178
|
+
jest: /\bjest\b/i,
|
|
16179
|
+
remotion: /\bremotion\b/i
|
|
16180
|
+
};
|
|
16181
|
+
for (const [tech, pattern] of Object.entries(techPatterns)) {
|
|
16182
|
+
if (pattern.test(content)) {
|
|
16183
|
+
techStack.push(tech);
|
|
16184
|
+
}
|
|
16185
|
+
}
|
|
16186
|
+
const keywords = [];
|
|
16187
|
+
const keywordPatterns = {
|
|
16188
|
+
api: /\bapi\b|\brest\b|\bgraphql\b/i,
|
|
16189
|
+
cli: /\bcli\b|\bcommand.?line\b/i,
|
|
16190
|
+
web: /\bweb\b|\bwebsite\b|\bfrontend\b/i,
|
|
16191
|
+
mobile: /\bmobile\b|\bios\b|\bandroid\b|\breact.?native\b/i,
|
|
16192
|
+
ai: /\bai\b|\bmachine.?learning\b|\bllm\b|\bgpt\b/i,
|
|
16193
|
+
video: /\bvideo\b|\bstreaming\b|\bmedia\b/i,
|
|
16194
|
+
ecommerce: /\becommerce\b|\bshop\b|\bstore\b|\bpayment\b/i,
|
|
16195
|
+
auth: /\bauth\b|\blogin\b|\bsession\b/i,
|
|
16196
|
+
testing: /\btest\b|\btesting\b|\btdd\b/i,
|
|
16197
|
+
devtools: /\bdevtool\b|\bdeveloper.?tool\b/i
|
|
16198
|
+
};
|
|
16199
|
+
for (const [keyword, pattern] of Object.entries(keywordPatterns)) {
|
|
16200
|
+
if (pattern.test(content)) {
|
|
16201
|
+
keywords.push(keyword);
|
|
16202
|
+
}
|
|
16203
|
+
}
|
|
16204
|
+
return { name, description, techStack, keywords };
|
|
16205
|
+
}
|
|
16206
|
+
function suggestSkills(context) {
|
|
16207
|
+
const suggestions = [];
|
|
16208
|
+
suggestions.push({
|
|
16209
|
+
name: "Find Skills",
|
|
16210
|
+
installCommand: "npx skills add vercel-labs/skills@find-skills --yes",
|
|
16211
|
+
reason: "Discover more skills for your workflow"
|
|
16212
|
+
});
|
|
16213
|
+
if (!context) {
|
|
16214
|
+
suggestions.push({
|
|
16215
|
+
name: "Writing Plans",
|
|
16216
|
+
installCommand: "npx skills add obra/superpowers@writing-plans --yes",
|
|
16217
|
+
reason: "Better planning before implementation"
|
|
16218
|
+
});
|
|
16219
|
+
return suggestions;
|
|
16220
|
+
}
|
|
16221
|
+
if (context.techStack.includes("react") || context.techStack.includes("next.js")) {
|
|
16222
|
+
suggestions.push({
|
|
16223
|
+
name: "React Best Practices",
|
|
16224
|
+
installCommand: "npx skills add vercel-labs/agent-skills@vercel-react-best-practices --yes",
|
|
16225
|
+
reason: `Detected React/Next.js in ${context.name}`
|
|
16226
|
+
});
|
|
16227
|
+
}
|
|
16228
|
+
if (context.techStack.includes("remotion")) {
|
|
16229
|
+
suggestions.push({
|
|
16230
|
+
name: "Remotion",
|
|
16231
|
+
installCommand: "npx skills add remotion-dev/skills@remotion-best-practices --yes",
|
|
16232
|
+
reason: "Detected Remotion video framework"
|
|
16233
|
+
});
|
|
16234
|
+
}
|
|
16235
|
+
if (context.keywords.includes("testing") || context.keywords.includes("tdd")) {
|
|
16236
|
+
suggestions.push({
|
|
16237
|
+
name: "Test-Driven Development",
|
|
16238
|
+
installCommand: "npx skills add obra/superpowers@test-driven-development --yes",
|
|
16239
|
+
reason: "Testing focus detected"
|
|
16240
|
+
});
|
|
16241
|
+
}
|
|
16242
|
+
if (context.keywords.includes("web")) {
|
|
16243
|
+
suggestions.push({
|
|
16244
|
+
name: "Web Design Guidelines",
|
|
16245
|
+
installCommand: "npx skills add vercel-labs/agent-skills@web-design-guidelines --yes",
|
|
16246
|
+
reason: "Web project detected"
|
|
16247
|
+
});
|
|
16248
|
+
}
|
|
16249
|
+
if (!suggestions.some((s2) => s2.name.includes("Plan"))) {
|
|
16250
|
+
suggestions.push({
|
|
16251
|
+
name: "Writing Plans",
|
|
16252
|
+
installCommand: "npx skills add obra/superpowers@writing-plans --yes",
|
|
16253
|
+
reason: "Helps structure work before coding"
|
|
16254
|
+
});
|
|
16255
|
+
}
|
|
16256
|
+
return suggestions.slice(0, 5);
|
|
16257
|
+
}
|
|
16258
|
+
function installSkill2(installCommand) {
|
|
16259
|
+
try {
|
|
16260
|
+
const result = spawnSync2("npx", installCommand.replace("npx ", "").split(" "), {
|
|
16261
|
+
stdio: "pipe",
|
|
16262
|
+
timeout: 60000,
|
|
16263
|
+
shell: true
|
|
16264
|
+
});
|
|
16265
|
+
if (result.status === 0) {
|
|
16266
|
+
return { success: true, message: "Installed successfully" };
|
|
16267
|
+
} else {
|
|
16268
|
+
const stderr = result.stderr?.toString() || "";
|
|
16269
|
+
return { success: false, message: stderr.slice(0, 100) || "Installation failed" };
|
|
16270
|
+
}
|
|
16271
|
+
} catch (error2) {
|
|
16272
|
+
return { success: false, message: error2 instanceof Error ? error2.message : "Unknown error" };
|
|
16273
|
+
}
|
|
16274
|
+
}
|
|
16133
16275
|
|
|
16134
16276
|
// src/commands/scan.ts
|
|
16135
16277
|
var scanCommand = defineCommand2({
|
|
16136
16278
|
meta: {
|
|
16137
16279
|
name: "scan",
|
|
16138
|
-
description: "
|
|
16280
|
+
description: "Scan your AI workflow and get optimization recommendations (interactive)"
|
|
16139
16281
|
},
|
|
16140
16282
|
args: {
|
|
16141
|
-
since: {
|
|
16142
|
-
type: "string",
|
|
16143
|
-
description: 'Time range: 6h, 24h, 7d, 30d, or "7 days"',
|
|
16144
|
-
default: "7d"
|
|
16145
|
-
},
|
|
16146
|
-
project: {
|
|
16147
|
-
type: "string",
|
|
16148
|
-
description: "Project directory to scan (defaults to cwd)"
|
|
16149
|
-
},
|
|
16150
|
-
install: {
|
|
16151
|
-
type: "boolean",
|
|
16152
|
-
alias: "i",
|
|
16153
|
-
description: "Install recommended optimizations (interactive)",
|
|
16154
|
-
default: false
|
|
16155
|
-
},
|
|
16156
|
-
"install-all": {
|
|
16157
|
-
type: "boolean",
|
|
16158
|
-
description: "Install all recommended optimizations (non-interactive)",
|
|
16159
|
-
default: false
|
|
16160
|
-
},
|
|
16161
|
-
"install-essentials": {
|
|
16162
|
-
type: "boolean",
|
|
16163
|
-
description: "Install essential tools: Context7, Supermemory, Beads",
|
|
16164
|
-
default: false
|
|
16165
|
-
},
|
|
16166
|
-
offline: {
|
|
16167
|
-
type: "boolean",
|
|
16168
|
-
description: "Skip uploading results to Convex",
|
|
16169
|
-
default: false
|
|
16170
|
-
},
|
|
16171
|
-
"no-report": {
|
|
16172
|
-
type: "boolean",
|
|
16173
|
-
description: "Skip generating markdown report",
|
|
16174
|
-
default: false
|
|
16175
|
-
},
|
|
16176
|
-
"report-dir": {
|
|
16177
|
-
type: "string",
|
|
16178
|
-
description: "Directory for reports (defaults to .nairon/reports)",
|
|
16179
|
-
default: ".nairon/reports"
|
|
16180
|
-
},
|
|
16181
|
-
brief: {
|
|
16182
|
-
type: "boolean",
|
|
16183
|
-
description: "Show brief output (skip detailed analysis)",
|
|
16184
|
-
default: false
|
|
16185
|
-
},
|
|
16186
16283
|
json: {
|
|
16187
16284
|
type: "boolean",
|
|
16188
|
-
description: "Output
|
|
16285
|
+
description: "Output as JSON (for CI/scripts)",
|
|
16189
16286
|
default: false
|
|
16190
16287
|
},
|
|
16191
16288
|
quiet: {
|
|
16192
16289
|
type: "boolean",
|
|
16193
16290
|
alias: "q",
|
|
16194
|
-
description: "
|
|
16195
|
-
default: false
|
|
16196
|
-
},
|
|
16197
|
-
"no-cache": {
|
|
16198
|
-
type: "boolean",
|
|
16199
|
-
description: "Disable session caching (slower but ensures fresh data)",
|
|
16200
|
-
default: false
|
|
16201
|
-
},
|
|
16202
|
-
watch: {
|
|
16203
|
-
type: "boolean",
|
|
16204
|
-
alias: "w",
|
|
16205
|
-
description: "Watch mode - re-scan on file changes",
|
|
16291
|
+
description: "Only output score number",
|
|
16206
16292
|
default: false
|
|
16207
|
-
},
|
|
16208
|
-
"watch-interval": {
|
|
16209
|
-
type: "string",
|
|
16210
|
-
description: "Watch interval in seconds (default: 30)",
|
|
16211
|
-
default: "30"
|
|
16212
16293
|
}
|
|
16213
16294
|
},
|
|
16214
16295
|
async run({ args }) {
|
|
16215
|
-
const projectDir =
|
|
16216
|
-
const since = parseSince(args.since);
|
|
16296
|
+
const projectDir = process.cwd();
|
|
16217
16297
|
const jsonOutput = args.json;
|
|
16218
16298
|
const quietMode = args.quiet;
|
|
16219
|
-
const useCache = !args["no-cache"];
|
|
16220
|
-
const watchMode = args.watch;
|
|
16221
|
-
const watchInterval = parseInt(args["watch-interval"] || "30", 10) * 1000;
|
|
16222
16299
|
const silent = jsonOutput || quietMode;
|
|
16300
|
+
let since;
|
|
16301
|
+
if (silent) {
|
|
16302
|
+
since = parseSince("7d");
|
|
16303
|
+
} else {
|
|
16304
|
+
console.log();
|
|
16305
|
+
console.log(" \uD83D\uDD0D " + "\x1B[1mNaironAI Workflow Scanner\x1B[0m");
|
|
16306
|
+
console.log(" " + "\x1B[2m" + "─".repeat(35) + "\x1B[0m");
|
|
16307
|
+
console.log();
|
|
16308
|
+
const period = await consola.prompt("Time period to analyze?", {
|
|
16309
|
+
type: "select",
|
|
16310
|
+
options: [
|
|
16311
|
+
{ value: "7d", label: "Last 7 days (recommended)" },
|
|
16312
|
+
{ value: "24h", label: "Last 24 hours" },
|
|
16313
|
+
{ value: "30d", label: "Last 30 days" }
|
|
16314
|
+
]
|
|
16315
|
+
});
|
|
16316
|
+
since = parseSince(period);
|
|
16317
|
+
if (isFirstScanInProject(projectDir)) {
|
|
16318
|
+
await showFirstScanWelcome(projectDir);
|
|
16319
|
+
markProjectScanned(projectDir);
|
|
16320
|
+
}
|
|
16321
|
+
}
|
|
16322
|
+
const useCache = true;
|
|
16323
|
+
const watchMode = false;
|
|
16324
|
+
const watchInterval = 30000;
|
|
16223
16325
|
if (watchMode) {
|
|
16224
16326
|
console.log();
|
|
16225
16327
|
console.log(colors2.bold(colors2.primary(" NaironAI Watch Mode")));
|
|
@@ -16352,19 +16454,17 @@ var scanCommand = defineCommand2({
|
|
|
16352
16454
|
console.log(` Projected monthly: ${colors2.primary(`$${scanCost.projectedMonthlyCostUsd.toFixed(2)}`)}`);
|
|
16353
16455
|
console.log(colors2.dim(" " + "═".repeat(45)));
|
|
16354
16456
|
console.log();
|
|
16355
|
-
|
|
16356
|
-
|
|
16357
|
-
|
|
16358
|
-
|
|
16359
|
-
}
|
|
16360
|
-
if (agents && agents.sessions.length > 0 && !args.brief) {
|
|
16457
|
+
const reportDir = join10(projectDir, ".nairon/reports");
|
|
16458
|
+
const reportPath = generateReport(reportDir, score, git, agents, tests, "7d", sdlcAnalysis, scanCost, analysis);
|
|
16459
|
+
console.log(` ${icons.success} Report saved: ${colors2.dim(reportPath)}`);
|
|
16460
|
+
if (agents && agents.sessions.length > 0) {
|
|
16361
16461
|
const effortBreakdown = analyzeEffort(agents.sessions, git);
|
|
16362
16462
|
const effortLines = formatEffortBreakdown(effortBreakdown);
|
|
16363
16463
|
for (const line of effortLines) {
|
|
16364
16464
|
console.log(line);
|
|
16365
16465
|
}
|
|
16366
16466
|
}
|
|
16367
|
-
if (agents && agents.sessions.length > 0
|
|
16467
|
+
if (agents && agents.sessions.length > 0) {
|
|
16368
16468
|
const frustrationSummary = detectFrustrations(agents.sessions);
|
|
16369
16469
|
if (frustrationSummary.totalFrustrations > 0) {
|
|
16370
16470
|
const frustrationLines = formatFrustrationSummary(frustrationSummary);
|
|
@@ -16373,68 +16473,71 @@ var scanCommand = defineCommand2({
|
|
|
16373
16473
|
}
|
|
16374
16474
|
}
|
|
16375
16475
|
}
|
|
16376
|
-
|
|
16377
|
-
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
16383
|
-
|
|
16384
|
-
|
|
16385
|
-
|
|
16386
|
-
|
|
16387
|
-
|
|
16388
|
-
|
|
16389
|
-
|
|
16390
|
-
|
|
16391
|
-
|
|
16392
|
-
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16398
|
-
|
|
16399
|
-
|
|
16400
|
-
|
|
16401
|
-
|
|
16402
|
-
|
|
16403
|
-
|
|
16404
|
-
tool.installed = true;
|
|
16405
|
-
}
|
|
16476
|
+
const installedStatus = checkInstalledStatus(projectDir);
|
|
16477
|
+
const projectContext = loadProjectContext(projectDir);
|
|
16478
|
+
if (projectContext) {
|
|
16479
|
+
console.log(` ${colors2.dim("Using project context from onboarding for personalized recommendations")}`);
|
|
16480
|
+
}
|
|
16481
|
+
const sdlc = analyzeSDLC(agents, git, tests, projectDir, analysis, projectContext);
|
|
16482
|
+
for (const phase of [sdlc.requirements, sdlc.planning, sdlc.implementation, sdlc.review]) {
|
|
16483
|
+
phase.recommendations = phase.recommendations.filter((rec) => {
|
|
16484
|
+
const id = rec.title.toLowerCase().replace(/\s+/g, "-");
|
|
16485
|
+
if (id.includes("context7") && installedStatus.context7)
|
|
16486
|
+
return false;
|
|
16487
|
+
if (id.includes("supermemory") && installedStatus.supermemory)
|
|
16488
|
+
return false;
|
|
16489
|
+
if (id.includes("nia") && installedStatus.nia)
|
|
16490
|
+
return false;
|
|
16491
|
+
if (id.includes("beads") && installedStatus.beads)
|
|
16492
|
+
return false;
|
|
16493
|
+
return true;
|
|
16494
|
+
});
|
|
16495
|
+
for (const tool of phase.tools) {
|
|
16496
|
+
if (tool.name.toLowerCase().includes("context7") && installedStatus.context7) {
|
|
16497
|
+
tool.installed = true;
|
|
16498
|
+
}
|
|
16499
|
+
if (tool.name.toLowerCase().includes("supermemory") && installedStatus.supermemory) {
|
|
16500
|
+
tool.installed = true;
|
|
16501
|
+
}
|
|
16502
|
+
if (tool.name.toLowerCase().includes("nia") && installedStatus.nia) {
|
|
16503
|
+
tool.installed = true;
|
|
16406
16504
|
}
|
|
16407
16505
|
}
|
|
16408
|
-
|
|
16409
|
-
|
|
16410
|
-
|
|
16411
|
-
|
|
16412
|
-
|
|
16413
|
-
|
|
16414
|
-
|
|
16415
|
-
|
|
16416
|
-
|
|
16417
|
-
|
|
16418
|
-
|
|
16419
|
-
|
|
16420
|
-
|
|
16421
|
-
|
|
16422
|
-
|
|
16423
|
-
|
|
16506
|
+
}
|
|
16507
|
+
const totalRecs = [sdlc.requirements, sdlc.planning, sdlc.implementation, sdlc.review].reduce((a2, p) => a2 + p.recommendations.length, 0);
|
|
16508
|
+
if (totalRecs > 0) {
|
|
16509
|
+
sdlc.overall.summary = sdlc.overall.summary.replace(/\d+ optimizations available\./, `${totalRecs} optimizations available.`);
|
|
16510
|
+
} else if (sdlc.overall.summary.includes("optimizations available")) {
|
|
16511
|
+
sdlc.overall.summary = sdlc.overall.summary.replace(/\d+ optimizations available\./, "All recommended tools installed.");
|
|
16512
|
+
}
|
|
16513
|
+
const sdlcLines = formatSDLCForTerminal(sdlc);
|
|
16514
|
+
for (const line of sdlcLines) {
|
|
16515
|
+
console.log(line);
|
|
16516
|
+
}
|
|
16517
|
+
let allRecs = [];
|
|
16518
|
+
for (const phase of [sdlc.requirements, sdlc.planning, sdlc.implementation, sdlc.review]) {
|
|
16519
|
+
for (const rec of phase.recommendations) {
|
|
16520
|
+
if (rec.installCommand) {
|
|
16521
|
+
allRecs.push(phaseRecToInstallable(rec));
|
|
16424
16522
|
}
|
|
16425
16523
|
}
|
|
16426
|
-
|
|
16427
|
-
|
|
16428
|
-
|
|
16429
|
-
|
|
16430
|
-
|
|
16431
|
-
|
|
16432
|
-
|
|
16433
|
-
|
|
16434
|
-
|
|
16524
|
+
}
|
|
16525
|
+
allRecs = filterAlreadyInstalled(allRecs, installedStatus);
|
|
16526
|
+
if (allRecs.length > 0) {
|
|
16527
|
+
console.log();
|
|
16528
|
+
const optionLabels = allRecs.map((rec) => `${rec.name} - ${rec.description}`);
|
|
16529
|
+
const selected = await consola.prompt(`${allRecs.length} optimizations available. Select to install (space to select, enter to confirm):`, {
|
|
16530
|
+
type: "multiselect",
|
|
16531
|
+
options: optionLabels,
|
|
16532
|
+
required: false
|
|
16533
|
+
});
|
|
16534
|
+
if (selected && typeof selected !== "symbol" && Array.isArray(selected) && selected.length > 0) {
|
|
16535
|
+
const toInstall = allRecs.filter((rec) => selected.some((s2) => s2.startsWith(rec.name))).map((r3) => ({ ...r3, selected: true }));
|
|
16536
|
+
if (toInstall.length > 0) {
|
|
16435
16537
|
console.log();
|
|
16436
|
-
|
|
16437
|
-
|
|
16538
|
+
console.log(` ${colors2.bold("Installing...")}${colors2.dim("")}`);
|
|
16539
|
+
console.log();
|
|
16540
|
+
const results = await installOptimizations(toInstall, projectDir, {});
|
|
16438
16541
|
for (const result of results) {
|
|
16439
16542
|
if (result.success) {
|
|
16440
16543
|
console.log(` ${colors2.success("✓")} ${result.name}: ${result.message}`);
|
|
@@ -16444,82 +16547,15 @@ var scanCommand = defineCommand2({
|
|
|
16444
16547
|
}
|
|
16445
16548
|
console.log();
|
|
16446
16549
|
}
|
|
16447
|
-
} else
|
|
16448
|
-
console.log();
|
|
16449
|
-
console.log(` ${colors2.bold(colors2.primary("Installing All Optimizations"))}`);
|
|
16450
|
-
console.log(colors2.dim(" " + "─".repeat(40)));
|
|
16451
|
-
console.log();
|
|
16452
|
-
const results = await installOptimizations(allRecs.map((r3) => ({ ...r3, selected: true })), projectDir, {});
|
|
16453
|
-
for (const result of results) {
|
|
16454
|
-
if (result.success) {
|
|
16455
|
-
console.log(` ${colors2.success("✓")} ${result.name}: ${result.message}`);
|
|
16456
|
-
} else {
|
|
16457
|
-
console.log(` ${colors2.error("✗")} ${result.name}: ${result.error || result.message}`);
|
|
16458
|
-
}
|
|
16459
|
-
}
|
|
16460
|
-
console.log();
|
|
16461
|
-
} else if (allRecs.length > 0 && !args["install-essentials"] && !args["install-all"]) {
|
|
16550
|
+
} else {
|
|
16551
|
+
console.log(` ${colors2.dim("Skipped.")}`);
|
|
16462
16552
|
console.log();
|
|
16463
|
-
const optionLabels = allRecs.map((rec) => `${rec.name} - ${rec.description}`);
|
|
16464
|
-
const selected = await consola.prompt(`${allRecs.length} optimizations available. Select to install (space to select, enter to confirm):`, {
|
|
16465
|
-
type: "multiselect",
|
|
16466
|
-
options: optionLabels,
|
|
16467
|
-
required: false
|
|
16468
|
-
});
|
|
16469
|
-
if (selected && typeof selected !== "symbol" && Array.isArray(selected) && selected.length > 0) {
|
|
16470
|
-
const toInstall = allRecs.filter((rec) => selected.some((s2) => s2.startsWith(rec.name))).map((r3) => ({ ...r3, selected: true }));
|
|
16471
|
-
if (toInstall.length > 0) {
|
|
16472
|
-
console.log();
|
|
16473
|
-
console.log(` ${colors2.bold("Installing...")}${colors2.dim("")}`);
|
|
16474
|
-
console.log();
|
|
16475
|
-
const results = await installOptimizations(toInstall, projectDir, {});
|
|
16476
|
-
for (const result of results) {
|
|
16477
|
-
if (result.success) {
|
|
16478
|
-
console.log(` ${colors2.success("✓")} ${result.name}: ${result.message}`);
|
|
16479
|
-
} else {
|
|
16480
|
-
console.log(` ${colors2.error("✗")} ${result.name}: ${result.error || result.message}`);
|
|
16481
|
-
}
|
|
16482
|
-
}
|
|
16483
|
-
console.log();
|
|
16484
|
-
}
|
|
16485
|
-
} else {
|
|
16486
|
-
console.log(` ${colors2.dim("Skipped. Run")} ${colors2.primary("nb scan --install-essentials")} ${colors2.dim("anytime to quick-install.")}`);
|
|
16487
|
-
console.log();
|
|
16488
|
-
}
|
|
16489
16553
|
}
|
|
16490
16554
|
}
|
|
16491
16555
|
}
|
|
16492
|
-
if (args.offline) {
|
|
16493
|
-
if (!silent) {
|
|
16494
|
-
console.log(` ${icons.info} Offline mode - skipping cloud sync`);
|
|
16495
|
-
console.log();
|
|
16496
|
-
}
|
|
16497
|
-
if (jsonOutput) {
|
|
16498
|
-
const output = {
|
|
16499
|
-
score: score.overall,
|
|
16500
|
-
tier: score.tier,
|
|
16501
|
-
baseScore: score.baseScore,
|
|
16502
|
-
tokenEfficiency: score.tokenEfficiency,
|
|
16503
|
-
phases: score.phases,
|
|
16504
|
-
cost: scanCost,
|
|
16505
|
-
git: git ? { commitCount: git.commitCount, authors: git.authors.length } : null,
|
|
16506
|
-
agents: agents ? { sessions: agents.totalSessions, tokens: agents.totalTokens } : null,
|
|
16507
|
-
tests: tests ? { total: tests.totalTests, passRate: tests.passRate } : null,
|
|
16508
|
-
scannedAt: score.scannedAt
|
|
16509
|
-
};
|
|
16510
|
-
console.log(JSON.stringify(output, null, 2));
|
|
16511
|
-
} else if (quietMode) {
|
|
16512
|
-
console.log(score.overall);
|
|
16513
|
-
}
|
|
16514
|
-
return;
|
|
16515
|
-
}
|
|
16516
16556
|
const client = getClient();
|
|
16517
16557
|
const clerkId = getClerkId();
|
|
16518
16558
|
if (!client || !clerkId) {
|
|
16519
|
-
if (!silent) {
|
|
16520
|
-
console.log(` ${icons.info} Run ${colors2.primary("nb init")} to enable cloud sync`);
|
|
16521
|
-
console.log();
|
|
16522
|
-
}
|
|
16523
16559
|
if (jsonOutput) {
|
|
16524
16560
|
const output = {
|
|
16525
16561
|
score: score.overall,
|
|
@@ -16634,12 +16670,12 @@ var scanCommand = defineCommand2({
|
|
|
16634
16670
|
}
|
|
16635
16671
|
});
|
|
16636
16672
|
function loadProjectContext(projectDir) {
|
|
16637
|
-
const contextPath =
|
|
16638
|
-
if (!
|
|
16673
|
+
const contextPath = join10(projectDir, ".nairon", "context.json");
|
|
16674
|
+
if (!existsSync10(contextPath)) {
|
|
16639
16675
|
return null;
|
|
16640
16676
|
}
|
|
16641
16677
|
try {
|
|
16642
|
-
const raw =
|
|
16678
|
+
const raw = readFileSync10(contextPath, "utf-8");
|
|
16643
16679
|
const data = JSON.parse(raw);
|
|
16644
16680
|
const context = {
|
|
16645
16681
|
painPoints: data.painPoints || [],
|
|
@@ -16692,12 +16728,12 @@ function parseSince(since) {
|
|
|
16692
16728
|
return new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
|
|
16693
16729
|
}
|
|
16694
16730
|
function generateReport(reportDir, score, git, agents, tests, since, sdlcAnalysis, scanCost, analysis) {
|
|
16695
|
-
if (!
|
|
16696
|
-
|
|
16731
|
+
if (!existsSync10(reportDir)) {
|
|
16732
|
+
mkdirSync5(reportDir, { recursive: true });
|
|
16697
16733
|
}
|
|
16698
16734
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
16699
16735
|
const filename = `scan-${timestamp}.md`;
|
|
16700
|
-
const filepath =
|
|
16736
|
+
const filepath = join10(reportDir, filename);
|
|
16701
16737
|
const lines = [];
|
|
16702
16738
|
lines.push(`# NaironAI Scan Report`);
|
|
16703
16739
|
lines.push("");
|
|
@@ -16813,7 +16849,7 @@ function generateReport(reportDir, score, git, agents, tests, since, sdlcAnalysi
|
|
|
16813
16849
|
lines.push("---");
|
|
16814
16850
|
lines.push("");
|
|
16815
16851
|
lines.push("*Generated by [nairon-bench](https://github.com/ObaidUr-Rahmaan/nairon-bench)*");
|
|
16816
|
-
|
|
16852
|
+
writeFileSync5(filepath, lines.join(`
|
|
16817
16853
|
`));
|
|
16818
16854
|
return filepath;
|
|
16819
16855
|
}
|
|
@@ -16832,15 +16868,73 @@ function formatTokensPlain(tokens) {
|
|
|
16832
16868
|
return `${Math.round(tokens / 1000)}K`;
|
|
16833
16869
|
return tokens.toString();
|
|
16834
16870
|
}
|
|
16871
|
+
async function showFirstScanWelcome(projectDir) {
|
|
16872
|
+
console.log();
|
|
16873
|
+
console.log(colors2.dim(" " + "═".repeat(50)));
|
|
16874
|
+
console.log(` ${colors2.primary("✨")} ${colors2.bold("First scan in this project!")}`);
|
|
16875
|
+
console.log(colors2.dim(" " + "═".repeat(50)));
|
|
16876
|
+
console.log();
|
|
16877
|
+
const agent = detectAgent();
|
|
16878
|
+
const agentNames = {
|
|
16879
|
+
"claude-code": "Claude Code",
|
|
16880
|
+
opencode: "OpenCode",
|
|
16881
|
+
cursor: "Cursor",
|
|
16882
|
+
unknown: "Unknown"
|
|
16883
|
+
};
|
|
16884
|
+
console.log(` ${icons.info} Detected agent: ${colors2.bold(agentNames[agent])}`);
|
|
16885
|
+
const context = analyzeReadme(projectDir);
|
|
16886
|
+
if (context) {
|
|
16887
|
+
console.log(` ${icons.info} Project: ${colors2.bold(context.name)}`);
|
|
16888
|
+
if (context.techStack.length > 0) {
|
|
16889
|
+
console.log(` ${colors2.dim(" Tech: " + context.techStack.slice(0, 4).join(", "))}`);
|
|
16890
|
+
}
|
|
16891
|
+
}
|
|
16892
|
+
console.log();
|
|
16893
|
+
const suggestions = suggestSkills(context);
|
|
16894
|
+
if (suggestions.length > 0) {
|
|
16895
|
+
console.log(` ${colors2.bold("Recommended skills for this project:")}`);
|
|
16896
|
+
console.log();
|
|
16897
|
+
for (let i3 = 0;i3 < Math.min(3, suggestions.length); i3++) {
|
|
16898
|
+
const s2 = suggestions[i3];
|
|
16899
|
+
console.log(` ${colors2.primary((i3 + 1).toString())}. ${colors2.bold(s2.name)}`);
|
|
16900
|
+
console.log(` ${colors2.dim(s2.reason)}`);
|
|
16901
|
+
}
|
|
16902
|
+
console.log();
|
|
16903
|
+
const installChoice = await consola.prompt("Install recommended skills?", {
|
|
16904
|
+
type: "select",
|
|
16905
|
+
options: [
|
|
16906
|
+
{ value: "find-skills", label: "Just find-skills (discover more skills later)" },
|
|
16907
|
+
{ value: "all", label: "All recommended skills" },
|
|
16908
|
+
{ value: "skip", label: "Skip - continue to scan" }
|
|
16909
|
+
]
|
|
16910
|
+
});
|
|
16911
|
+
if (installChoice === "find-skills" || installChoice === "all") {
|
|
16912
|
+
console.log();
|
|
16913
|
+
const toInstall = installChoice === "all" ? suggestions.slice(0, 3) : suggestions.slice(0, 1);
|
|
16914
|
+
for (const skill of toInstall) {
|
|
16915
|
+
process.stdout.write(` Installing ${skill.name}...`);
|
|
16916
|
+
const result = installSkill2(skill.installCommand);
|
|
16917
|
+
if (result.success) {
|
|
16918
|
+
console.log(` ${colors2.success("✓")}`);
|
|
16919
|
+
} else {
|
|
16920
|
+
console.log(` ${colors2.warning("⚠")} ${colors2.dim(`(${result.message.slice(0, 50)})`)}`);
|
|
16921
|
+
}
|
|
16922
|
+
}
|
|
16923
|
+
console.log();
|
|
16924
|
+
}
|
|
16925
|
+
}
|
|
16926
|
+
console.log(colors2.dim(" " + "═".repeat(50)));
|
|
16927
|
+
console.log();
|
|
16928
|
+
}
|
|
16835
16929
|
|
|
16836
16930
|
// src/commands/report.ts
|
|
16837
16931
|
init_dist();
|
|
16838
16932
|
init_client();
|
|
16839
16933
|
|
|
16840
16934
|
// src/collectors/report-data.ts
|
|
16841
|
-
import { existsSync as
|
|
16842
|
-
import { homedir as
|
|
16843
|
-
import { join as
|
|
16935
|
+
import { existsSync as existsSync11, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync2 } from "node:fs";
|
|
16936
|
+
import { homedir as homedir9 } from "node:os";
|
|
16937
|
+
import { join as join11, basename as basename3 } from "node:path";
|
|
16844
16938
|
async function collectReportData(projectDir, since, until = new Date, harness) {
|
|
16845
16939
|
const projectName = basename3(projectDir);
|
|
16846
16940
|
const [commits, allSessions, mcpConfigs] = await Promise.all([
|
|
@@ -16923,12 +17017,12 @@ function detectAIAssistedCommit(message) {
|
|
|
16923
17017
|
}
|
|
16924
17018
|
async function collectAllSessions(since, until, projectDir) {
|
|
16925
17019
|
const sessions = [];
|
|
16926
|
-
const claudeDir =
|
|
16927
|
-
if (
|
|
17020
|
+
const claudeDir = join11(homedir9(), ".claude");
|
|
17021
|
+
if (existsSync11(claudeDir)) {
|
|
16928
17022
|
sessions.push(...collectClaudeCodeSessions(claudeDir, since, until, projectDir));
|
|
16929
17023
|
}
|
|
16930
|
-
const openCodeDir =
|
|
16931
|
-
if (
|
|
17024
|
+
const openCodeDir = join11(homedir9(), ".local", "share", "opencode");
|
|
17025
|
+
if (existsSync11(openCodeDir)) {
|
|
16932
17026
|
sessions.push(...collectOpenCodeSessions2(openCodeDir, since, until));
|
|
16933
17027
|
}
|
|
16934
17028
|
sessions.sort((a2, b2) => a2.startTime.getTime() - b2.startTime.getTime());
|
|
@@ -16936,15 +17030,15 @@ async function collectAllSessions(since, until, projectDir) {
|
|
|
16936
17030
|
}
|
|
16937
17031
|
function collectClaudeCodeSessions(claudeDir, since, until, projectDir) {
|
|
16938
17032
|
const sessions = [];
|
|
16939
|
-
const transcriptsDir =
|
|
16940
|
-
if (!
|
|
17033
|
+
const transcriptsDir = join11(claudeDir, "transcripts");
|
|
17034
|
+
if (!existsSync11(transcriptsDir))
|
|
16941
17035
|
return sessions;
|
|
16942
17036
|
const projectHash = projectDir ? hashPath(projectDir) : null;
|
|
16943
|
-
const projectsDir =
|
|
17037
|
+
const projectsDir = join11(claudeDir, "projects");
|
|
16944
17038
|
try {
|
|
16945
17039
|
const transcriptFiles = readdirSync5(transcriptsDir).filter((f3) => f3.endsWith(".jsonl"));
|
|
16946
17040
|
for (const file of transcriptFiles) {
|
|
16947
|
-
const filePath =
|
|
17041
|
+
const filePath = join11(transcriptsDir, file);
|
|
16948
17042
|
const stat = statSync2(filePath);
|
|
16949
17043
|
if (stat.mtime < since || stat.mtime > until)
|
|
16950
17044
|
continue;
|
|
@@ -16955,12 +17049,12 @@ function collectClaudeCodeSessions(claudeDir, since, until, projectDir) {
|
|
|
16955
17049
|
}
|
|
16956
17050
|
} catch {}
|
|
16957
17051
|
}
|
|
16958
|
-
if (projectHash &&
|
|
16959
|
-
const projectSessionDir =
|
|
16960
|
-
if (
|
|
17052
|
+
if (projectHash && existsSync11(projectsDir)) {
|
|
17053
|
+
const projectSessionDir = join11(projectsDir, projectHash);
|
|
17054
|
+
if (existsSync11(projectSessionDir)) {
|
|
16961
17055
|
const projectFiles = readdirSync5(projectSessionDir).filter((f3) => f3.endsWith(".jsonl"));
|
|
16962
17056
|
for (const file of projectFiles) {
|
|
16963
|
-
const filePath =
|
|
17057
|
+
const filePath = join11(projectSessionDir, file);
|
|
16964
17058
|
const stat = statSync2(filePath);
|
|
16965
17059
|
if (stat.mtime < since || stat.mtime > until)
|
|
16966
17060
|
continue;
|
|
@@ -16979,7 +17073,7 @@ function collectClaudeCodeSessions(claudeDir, since, until, projectDir) {
|
|
|
16979
17073
|
return sessions;
|
|
16980
17074
|
}
|
|
16981
17075
|
function parseClaudeTranscript(filePath, fileName) {
|
|
16982
|
-
const content =
|
|
17076
|
+
const content = readFileSync11(filePath, "utf-8");
|
|
16983
17077
|
const lines = content.trim().split(`
|
|
16984
17078
|
`).filter((l2) => l2.trim());
|
|
16985
17079
|
if (lines.length === 0)
|
|
@@ -17069,25 +17163,25 @@ function parseClaudeTranscript(filePath, fileName) {
|
|
|
17069
17163
|
}
|
|
17070
17164
|
function collectOpenCodeSessions2(openCodeDir, since, until) {
|
|
17071
17165
|
const sessions = [];
|
|
17072
|
-
const sessionDir =
|
|
17073
|
-
const messageDir =
|
|
17074
|
-
const partDir =
|
|
17075
|
-
if (!
|
|
17166
|
+
const sessionDir = join11(openCodeDir, "storage", "session");
|
|
17167
|
+
const messageDir = join11(openCodeDir, "storage", "message");
|
|
17168
|
+
const partDir = join11(openCodeDir, "storage", "part");
|
|
17169
|
+
if (!existsSync11(sessionDir))
|
|
17076
17170
|
return sessions;
|
|
17077
17171
|
try {
|
|
17078
|
-
const projectDirs = readdirSync5(sessionDir, { withFileTypes: true }).filter((d2) => d2.isDirectory()).map((d2) =>
|
|
17172
|
+
const projectDirs = readdirSync5(sessionDir, { withFileTypes: true }).filter((d2) => d2.isDirectory()).map((d2) => join11(sessionDir, d2.name));
|
|
17079
17173
|
for (const projectDir of projectDirs) {
|
|
17080
17174
|
const sessionFiles = readdirSync5(projectDir).filter((f3) => f3.endsWith(".json"));
|
|
17081
17175
|
for (const sessionFile of sessionFiles) {
|
|
17082
17176
|
try {
|
|
17083
|
-
const sessionPath =
|
|
17084
|
-
const sessionData = JSON.parse(
|
|
17177
|
+
const sessionPath = join11(projectDir, sessionFile);
|
|
17178
|
+
const sessionData = JSON.parse(readFileSync11(sessionPath, "utf-8"));
|
|
17085
17179
|
const createdAt = new Date(sessionData.time?.created || 0);
|
|
17086
17180
|
const updatedAt = new Date(sessionData.time?.updated || sessionData.time?.created || 0);
|
|
17087
17181
|
if (updatedAt < since || createdAt > until)
|
|
17088
17182
|
continue;
|
|
17089
17183
|
const sessionId = sessionData.id;
|
|
17090
|
-
const sessionMsgDir =
|
|
17184
|
+
const sessionMsgDir = join11(messageDir, sessionId);
|
|
17091
17185
|
const prompts = [];
|
|
17092
17186
|
const responses = [];
|
|
17093
17187
|
const toolsUsed = new Set;
|
|
@@ -17098,12 +17192,12 @@ function collectOpenCodeSessions2(openCodeDir, since, until) {
|
|
|
17098
17192
|
let model = "unknown";
|
|
17099
17193
|
let startTime = createdAt;
|
|
17100
17194
|
let endTime = updatedAt;
|
|
17101
|
-
if (
|
|
17195
|
+
if (existsSync11(sessionMsgDir)) {
|
|
17102
17196
|
const msgFiles = readdirSync5(sessionMsgDir).filter((f3) => f3.endsWith(".json")).sort();
|
|
17103
17197
|
for (const msgFile of msgFiles) {
|
|
17104
17198
|
try {
|
|
17105
|
-
const msgPath =
|
|
17106
|
-
const msgData = JSON.parse(
|
|
17199
|
+
const msgPath = join11(sessionMsgDir, msgFile);
|
|
17200
|
+
const msgData = JSON.parse(readFileSync11(msgPath, "utf-8"));
|
|
17107
17201
|
const msgId = msgData.id;
|
|
17108
17202
|
if (msgData.model?.modelID) {
|
|
17109
17203
|
model = msgData.model.modelID;
|
|
@@ -17113,14 +17207,14 @@ function collectOpenCodeSessions2(openCodeDir, since, until) {
|
|
|
17113
17207
|
startTime = msgTime;
|
|
17114
17208
|
if (msgTime > endTime)
|
|
17115
17209
|
endTime = msgTime;
|
|
17116
|
-
const msgPartDir =
|
|
17210
|
+
const msgPartDir = join11(partDir, msgId);
|
|
17117
17211
|
let messageText = "";
|
|
17118
|
-
if (
|
|
17212
|
+
if (existsSync11(msgPartDir)) {
|
|
17119
17213
|
const partFiles = readdirSync5(msgPartDir).filter((f3) => f3.endsWith(".json")).sort();
|
|
17120
17214
|
for (const partFile of partFiles) {
|
|
17121
17215
|
try {
|
|
17122
|
-
const partPath =
|
|
17123
|
-
const partData = JSON.parse(
|
|
17216
|
+
const partPath = join11(msgPartDir, partFile);
|
|
17217
|
+
const partData = JSON.parse(readFileSync11(partPath, "utf-8"));
|
|
17124
17218
|
if (partData.type === "text" && partData.text && !partData.synthetic) {
|
|
17125
17219
|
messageText += partData.text + `
|
|
17126
17220
|
`;
|
|
@@ -17294,10 +17388,10 @@ function analyzeResponse(text, sessionId, index, promptId, timestamp) {
|
|
|
17294
17388
|
}
|
|
17295
17389
|
function collectMCPConfigs() {
|
|
17296
17390
|
const configs = [];
|
|
17297
|
-
const claudeConfig =
|
|
17298
|
-
if (
|
|
17391
|
+
const claudeConfig = join11(homedir9(), ".claude.json");
|
|
17392
|
+
if (existsSync11(claudeConfig)) {
|
|
17299
17393
|
try {
|
|
17300
|
-
const data = JSON.parse(
|
|
17394
|
+
const data = JSON.parse(readFileSync11(claudeConfig, "utf-8"));
|
|
17301
17395
|
const mcpServers = data.mcpServers || {};
|
|
17302
17396
|
for (const [name, config] of Object.entries(mcpServers)) {
|
|
17303
17397
|
configs.push({
|
|
@@ -17310,13 +17404,13 @@ function collectMCPConfigs() {
|
|
|
17310
17404
|
} catch {}
|
|
17311
17405
|
}
|
|
17312
17406
|
const openCodeConfigs = [
|
|
17313
|
-
|
|
17314
|
-
|
|
17407
|
+
join11(homedir9(), ".opencode.json"),
|
|
17408
|
+
join11(homedir9(), ".config", "opencode", "opencode.json")
|
|
17315
17409
|
];
|
|
17316
17410
|
for (const configPath of openCodeConfigs) {
|
|
17317
|
-
if (
|
|
17411
|
+
if (existsSync11(configPath)) {
|
|
17318
17412
|
try {
|
|
17319
|
-
const data = JSON.parse(
|
|
17413
|
+
const data = JSON.parse(readFileSync11(configPath, "utf-8"));
|
|
17320
17414
|
const mcpServers = data.mcp || {};
|
|
17321
17415
|
for (const [name, config] of Object.entries(mcpServers)) {
|
|
17322
17416
|
if (!configs.find((c3) => c3.name === name)) {
|
|
@@ -17331,10 +17425,10 @@ function collectMCPConfigs() {
|
|
|
17331
17425
|
} catch {}
|
|
17332
17426
|
}
|
|
17333
17427
|
}
|
|
17334
|
-
const cursorConfig =
|
|
17335
|
-
if (
|
|
17428
|
+
const cursorConfig = join11(homedir9(), ".cursor", "mcp.json");
|
|
17429
|
+
if (existsSync11(cursorConfig)) {
|
|
17336
17430
|
try {
|
|
17337
|
-
const data = JSON.parse(
|
|
17431
|
+
const data = JSON.parse(readFileSync11(cursorConfig, "utf-8"));
|
|
17338
17432
|
const mcpServers = data.mcpServers || {};
|
|
17339
17433
|
for (const [name, config] of Object.entries(mcpServers)) {
|
|
17340
17434
|
if (!configs.find((c3) => c3.name === name)) {
|
|
@@ -19535,9 +19629,9 @@ function getSeverityEmoji(severity) {
|
|
|
19535
19629
|
}
|
|
19536
19630
|
|
|
19537
19631
|
// src/lib/tool-analyzer.ts
|
|
19538
|
-
import { existsSync as
|
|
19539
|
-
import { homedir as
|
|
19540
|
-
import { join as
|
|
19632
|
+
import { existsSync as existsSync12, readdirSync as readdirSync6 } from "node:fs";
|
|
19633
|
+
import { homedir as homedir10 } from "node:os";
|
|
19634
|
+
import { join as join12 } from "node:path";
|
|
19541
19635
|
function analyzeToolUtilization(data) {
|
|
19542
19636
|
const mcpServers = analyzeMCPServers(data);
|
|
19543
19637
|
const mcpSummary = buildMCPSummary(mcpServers);
|
|
@@ -19687,24 +19781,24 @@ function categorizeTools(tools) {
|
|
|
19687
19781
|
}
|
|
19688
19782
|
function analyzeSkills() {
|
|
19689
19783
|
const skills = [];
|
|
19690
|
-
const home =
|
|
19784
|
+
const home = homedir10();
|
|
19691
19785
|
const skillsDirs = [
|
|
19692
|
-
|
|
19693
|
-
|
|
19694
|
-
|
|
19786
|
+
join12(home, ".claude", "skills"),
|
|
19787
|
+
join12(home, ".agents", "skills"),
|
|
19788
|
+
join12(home, ".config", "claude", "skills")
|
|
19695
19789
|
];
|
|
19696
19790
|
const projectSkillsDirs = [
|
|
19697
|
-
|
|
19698
|
-
|
|
19791
|
+
join12(process.cwd(), ".claude", "skills"),
|
|
19792
|
+
join12(process.cwd(), ".agents", "skills")
|
|
19699
19793
|
];
|
|
19700
19794
|
const openCodeSkillDirs = [
|
|
19701
|
-
|
|
19702
|
-
|
|
19795
|
+
join12(home, ".config", "opencode", "skills"),
|
|
19796
|
+
join12(home, ".local", "share", "opencode", "skills")
|
|
19703
19797
|
];
|
|
19704
19798
|
const allSkillDirs = [...skillsDirs, ...projectSkillsDirs, ...openCodeSkillDirs];
|
|
19705
19799
|
const seenSkills = new Set;
|
|
19706
19800
|
for (const skillsDir of allSkillDirs) {
|
|
19707
|
-
if (
|
|
19801
|
+
if (existsSync12(skillsDir)) {
|
|
19708
19802
|
try {
|
|
19709
19803
|
const entries = readdirSync6(skillsDir, { withFileTypes: true });
|
|
19710
19804
|
for (const entry of entries) {
|
|
@@ -19715,7 +19809,7 @@ function analyzeSkills() {
|
|
|
19715
19809
|
if (entry.isDirectory() || entry.isSymbolicLink() || entry.name.endsWith(".md")) {
|
|
19716
19810
|
skills.push({
|
|
19717
19811
|
name: skillName,
|
|
19718
|
-
path:
|
|
19812
|
+
path: join12(skillsDir, entry.name),
|
|
19719
19813
|
used: false,
|
|
19720
19814
|
usageCount: 0
|
|
19721
19815
|
});
|
|
@@ -20012,22 +20106,22 @@ function renderToolUtilizationMarkdown(analysis) {
|
|
|
20012
20106
|
}
|
|
20013
20107
|
|
|
20014
20108
|
// src/lib/coverage-parser.ts
|
|
20015
|
-
import { existsSync as
|
|
20016
|
-
import { join as
|
|
20109
|
+
import { existsSync as existsSync13, readFileSync as readFileSync13 } from "node:fs";
|
|
20110
|
+
import { join as join13 } from "node:path";
|
|
20017
20111
|
function parseCoverageReport(projectDir) {
|
|
20018
20112
|
const coveragePaths = [
|
|
20019
|
-
{ path:
|
|
20020
|
-
{ path:
|
|
20021
|
-
{ path:
|
|
20022
|
-
{ path:
|
|
20023
|
-
{ path:
|
|
20024
|
-
{ path:
|
|
20025
|
-
{ path:
|
|
20113
|
+
{ path: join13(projectDir, "coverage", "lcov.info"), parser: parseLcov },
|
|
20114
|
+
{ path: join13(projectDir, "coverage", "coverage-summary.json"), parser: parseIstanbulSummary },
|
|
20115
|
+
{ path: join13(projectDir, "coverage", "coverage-final.json"), parser: parseIstanbulFinal },
|
|
20116
|
+
{ path: join13(projectDir, "coverage", "cobertura-coverage.xml"), parser: parseCobertura },
|
|
20117
|
+
{ path: join13(projectDir, "coverage", "clover.xml"), parser: parseClover },
|
|
20118
|
+
{ path: join13(projectDir, "lcov.info"), parser: parseLcov },
|
|
20119
|
+
{ path: join13(projectDir, ".nyc_output", "coverage-summary.json"), parser: parseIstanbulSummary }
|
|
20026
20120
|
];
|
|
20027
20121
|
for (const { path, parser: parser4 } of coveragePaths) {
|
|
20028
|
-
if (
|
|
20122
|
+
if (existsSync13(path)) {
|
|
20029
20123
|
try {
|
|
20030
|
-
const content =
|
|
20124
|
+
const content = readFileSync13(path, "utf-8");
|
|
20031
20125
|
return parser4(content, path);
|
|
20032
20126
|
} catch {}
|
|
20033
20127
|
}
|
|
@@ -21739,150 +21833,151 @@ function formatReportAsJSON(report) {
|
|
|
21739
21833
|
}
|
|
21740
21834
|
|
|
21741
21835
|
// src/commands/report.ts
|
|
21742
|
-
import { writeFileSync as
|
|
21836
|
+
import { writeFileSync as writeFileSync6 } from "node:fs";
|
|
21743
21837
|
import { resolve } from "node:path";
|
|
21744
21838
|
var reportCommand = defineCommand2({
|
|
21745
21839
|
meta: {
|
|
21746
21840
|
name: "report",
|
|
21747
|
-
description: "Generate AI-nativeness reports
|
|
21841
|
+
description: "Generate AI-nativeness reports (interactive)"
|
|
21748
21842
|
},
|
|
21749
21843
|
args: {
|
|
21750
|
-
|
|
21751
|
-
type: "boolean",
|
|
21752
|
-
description: "Generate hackathon submission report (last 48 hours)",
|
|
21753
|
-
default: false
|
|
21754
|
-
},
|
|
21755
|
-
harness: {
|
|
21756
|
-
type: "string",
|
|
21757
|
-
description: "AI harness to analyze: claude-code, opencode, cursor, or all"
|
|
21758
|
-
},
|
|
21759
|
-
since: {
|
|
21760
|
-
type: "string",
|
|
21761
|
-
description: "Time range: 48h, 7d, 30d, or ISO date"
|
|
21762
|
-
},
|
|
21763
|
-
output: {
|
|
21764
|
-
type: "string",
|
|
21765
|
-
description: "Save report to file (e.g., report.md)"
|
|
21766
|
-
},
|
|
21767
|
-
publish: {
|
|
21768
|
-
type: "boolean",
|
|
21769
|
-
description: "Publish report and get a shareable public link",
|
|
21770
|
-
default: false
|
|
21771
|
-
},
|
|
21772
|
-
phase: {
|
|
21773
|
-
type: "string",
|
|
21774
|
-
description: "Drill into a specific phase (requirements, planning, implementation, testing, review)"
|
|
21775
|
-
},
|
|
21776
|
-
weekly: {
|
|
21777
|
-
type: "boolean",
|
|
21778
|
-
description: "Show latest scheduled weekly improvement report",
|
|
21779
|
-
default: false
|
|
21780
|
-
},
|
|
21781
|
-
history: {
|
|
21782
|
-
type: "boolean",
|
|
21783
|
-
description: "Show score trend over time",
|
|
21784
|
-
default: false
|
|
21785
|
-
},
|
|
21786
|
-
limit: {
|
|
21787
|
-
type: "string",
|
|
21788
|
-
description: "Number of historical scans to show",
|
|
21789
|
-
default: "10"
|
|
21790
|
-
},
|
|
21791
|
-
format: {
|
|
21792
|
-
type: "string",
|
|
21793
|
-
description: "Output format: terminal, md, json, or text (legacy)",
|
|
21794
|
-
default: "terminal"
|
|
21795
|
-
},
|
|
21796
|
-
leadership: {
|
|
21844
|
+
json: {
|
|
21797
21845
|
type: "boolean",
|
|
21798
|
-
description: "
|
|
21846
|
+
description: "Output as JSON (for CI/scripts)",
|
|
21799
21847
|
default: false
|
|
21800
21848
|
}
|
|
21801
21849
|
},
|
|
21802
21850
|
async run({ args }) {
|
|
21803
|
-
if (args.
|
|
21804
|
-
|
|
21851
|
+
if (args.json) {
|
|
21852
|
+
const projectDir = process.cwd();
|
|
21853
|
+
const since = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
|
|
21854
|
+
const report = await generateHackathonReport(projectDir, since, new Date, "all");
|
|
21855
|
+
console.log(formatReportAsJSON(report));
|
|
21805
21856
|
return;
|
|
21806
21857
|
}
|
|
21807
|
-
|
|
21808
|
-
|
|
21809
|
-
|
|
21810
|
-
|
|
21811
|
-
|
|
21812
|
-
|
|
21813
|
-
|
|
21814
|
-
|
|
21815
|
-
|
|
21816
|
-
|
|
21817
|
-
|
|
21818
|
-
|
|
21819
|
-
|
|
21820
|
-
|
|
21821
|
-
if (choice === "hackathon" || choice === "week" || choice === "month") {
|
|
21822
|
-
const sinceMap = {
|
|
21823
|
-
hackathon: "48h",
|
|
21824
|
-
week: "7d",
|
|
21825
|
-
month: "30d"
|
|
21826
|
-
};
|
|
21827
|
-
args.since = sinceMap[choice];
|
|
21828
|
-
const harness = await consola.prompt("Which AI harness did you use?", {
|
|
21829
|
-
type: "select",
|
|
21830
|
-
options: [
|
|
21831
|
-
{ value: "claude-code", label: "Claude Code" },
|
|
21832
|
-
{ value: "opencode", label: "OpenCode" },
|
|
21833
|
-
{ value: "cursor", label: "Cursor" },
|
|
21834
|
-
{ value: "all", label: "All (combine sessions from all harnesses)" }
|
|
21835
|
-
]
|
|
21836
|
-
});
|
|
21837
|
-
args.harness = harness;
|
|
21838
|
-
const format2 = await consola.prompt("Output format?", {
|
|
21839
|
-
type: "select",
|
|
21840
|
-
options: [
|
|
21841
|
-
{ value: "terminal", label: "Terminal (view now)" },
|
|
21842
|
-
{ value: "md", label: "Markdown (for submission)" },
|
|
21843
|
-
{ value: "publish", label: "Public link (shareable URL)" },
|
|
21844
|
-
{ value: "json", label: "JSON (programmatic)" }
|
|
21845
|
-
]
|
|
21846
|
-
});
|
|
21847
|
-
if (format2 === "publish") {
|
|
21848
|
-
args.publish = true;
|
|
21849
|
-
args.format = "terminal";
|
|
21850
|
-
} else {
|
|
21851
|
-
args.format = format2;
|
|
21852
|
-
}
|
|
21853
|
-
if (format2 === "md") {
|
|
21854
|
-
const filename = await consola.prompt("Save to file?", {
|
|
21855
|
-
type: "text",
|
|
21856
|
-
default: "ai-nativeness-report.md",
|
|
21857
|
-
placeholder: "report.md"
|
|
21858
|
-
});
|
|
21859
|
-
if (filename && typeof filename === "string") {
|
|
21860
|
-
args.output = filename;
|
|
21861
|
-
}
|
|
21862
|
-
}
|
|
21863
|
-
await runHackathonReport(args);
|
|
21864
|
-
return;
|
|
21865
|
-
}
|
|
21866
|
-
args.format = "text";
|
|
21867
|
-
}
|
|
21868
|
-
const client = getClient();
|
|
21869
|
-
const clerkId = getClerkId();
|
|
21870
|
-
if (!client || !clerkId) {
|
|
21871
|
-
consola.error("Not connected to Convex. Run `nb init` to set up your profile.");
|
|
21872
|
-
consola.info("Use `nb report --hackathon` for local AI-nativeness report.");
|
|
21858
|
+
console.log();
|
|
21859
|
+
console.log(" \uD83D\uDCCA " + "\x1B[1mNaironAI Report Generator\x1B[0m");
|
|
21860
|
+
console.log(" " + "\x1B[2m" + "─".repeat(35) + "\x1B[0m");
|
|
21861
|
+
console.log();
|
|
21862
|
+
const reportType = await consola.prompt("What kind of report?", {
|
|
21863
|
+
type: "select",
|
|
21864
|
+
options: [
|
|
21865
|
+
{ value: "ai-nativeness", label: "AI-Nativeness Report (recommended)" },
|
|
21866
|
+
{ value: "leadership", label: "Leadership Report (effort visibility)" },
|
|
21867
|
+
{ value: "cloud", label: "Cloud Benchmark (requires nb init)" }
|
|
21868
|
+
]
|
|
21869
|
+
});
|
|
21870
|
+
if (reportType === "leadership") {
|
|
21871
|
+
await runLeadershipReportInteractive();
|
|
21873
21872
|
return;
|
|
21874
21873
|
}
|
|
21875
|
-
if (
|
|
21876
|
-
await
|
|
21874
|
+
if (reportType === "cloud") {
|
|
21875
|
+
await runCloudReport();
|
|
21877
21876
|
return;
|
|
21878
21877
|
}
|
|
21879
|
-
|
|
21880
|
-
|
|
21881
|
-
|
|
21878
|
+
const period = await consola.prompt("Time period?", {
|
|
21879
|
+
type: "select",
|
|
21880
|
+
options: [
|
|
21881
|
+
{ value: "48h", label: "Last 48 hours (hackathon)" },
|
|
21882
|
+
{ value: "7d", label: "Last 7 days" },
|
|
21883
|
+
{ value: "30d", label: "Last 30 days" }
|
|
21884
|
+
]
|
|
21885
|
+
});
|
|
21886
|
+
const harness = await consola.prompt("Which AI tool?", {
|
|
21887
|
+
type: "select",
|
|
21888
|
+
options: [
|
|
21889
|
+
{ value: "all", label: "All tools (recommended)" },
|
|
21890
|
+
{ value: "claude-code", label: "Claude Code" },
|
|
21891
|
+
{ value: "opencode", label: "OpenCode" },
|
|
21892
|
+
{ value: "cursor", label: "Cursor" }
|
|
21893
|
+
]
|
|
21894
|
+
});
|
|
21895
|
+
const format2 = await consola.prompt("Output format?", {
|
|
21896
|
+
type: "select",
|
|
21897
|
+
options: [
|
|
21898
|
+
{ value: "publish", label: "Public link (shareable URL)" },
|
|
21899
|
+
{ value: "terminal", label: "Terminal (view now)" },
|
|
21900
|
+
{ value: "md", label: "Markdown file" },
|
|
21901
|
+
{ value: "json", label: "JSON" }
|
|
21902
|
+
]
|
|
21903
|
+
});
|
|
21904
|
+
const reportArgs = {
|
|
21905
|
+
since: period,
|
|
21906
|
+
harness,
|
|
21907
|
+
format: format2 === "publish" ? "terminal" : format2,
|
|
21908
|
+
publish: format2 === "publish"
|
|
21909
|
+
};
|
|
21910
|
+
if (format2 === "md") {
|
|
21911
|
+
const filename = await consola.prompt("Save to file?", {
|
|
21912
|
+
type: "text",
|
|
21913
|
+
default: "ai-nativeness-report.md",
|
|
21914
|
+
placeholder: "report.md"
|
|
21915
|
+
});
|
|
21916
|
+
if (filename && typeof filename === "string") {
|
|
21917
|
+
reportArgs.output = filename;
|
|
21918
|
+
}
|
|
21882
21919
|
}
|
|
21883
|
-
await
|
|
21920
|
+
await runHackathonReport(reportArgs);
|
|
21884
21921
|
}
|
|
21885
21922
|
});
|
|
21923
|
+
async function runLeadershipReportInteractive() {
|
|
21924
|
+
const period = await consola.prompt("Time period?", {
|
|
21925
|
+
type: "select",
|
|
21926
|
+
options: [
|
|
21927
|
+
{ value: "7d", label: "Last 7 days" },
|
|
21928
|
+
{ value: "30d", label: "Last 30 days" },
|
|
21929
|
+
{ value: "48h", label: "Last 48 hours" }
|
|
21930
|
+
]
|
|
21931
|
+
});
|
|
21932
|
+
const format2 = await consola.prompt("Output format?", {
|
|
21933
|
+
type: "select",
|
|
21934
|
+
options: [
|
|
21935
|
+
{ value: "terminal", label: "Terminal (view now)" },
|
|
21936
|
+
{ value: "md", label: "Markdown file" }
|
|
21937
|
+
]
|
|
21938
|
+
});
|
|
21939
|
+
let output;
|
|
21940
|
+
if (format2 === "md") {
|
|
21941
|
+
const filename = await consola.prompt("Save to file?", {
|
|
21942
|
+
type: "text",
|
|
21943
|
+
default: "leadership-report.md"
|
|
21944
|
+
});
|
|
21945
|
+
if (filename && typeof filename === "string") {
|
|
21946
|
+
output = filename;
|
|
21947
|
+
}
|
|
21948
|
+
}
|
|
21949
|
+
await runLeadershipReport({
|
|
21950
|
+
since: period,
|
|
21951
|
+
format: format2,
|
|
21952
|
+
output
|
|
21953
|
+
});
|
|
21954
|
+
}
|
|
21955
|
+
async function runCloudReport() {
|
|
21956
|
+
const client = getClient();
|
|
21957
|
+
const clerkId = getClerkId();
|
|
21958
|
+
if (!client || !clerkId) {
|
|
21959
|
+
consola.error("Not connected to Convex. Run `nb init` to set up your profile.");
|
|
21960
|
+
consola.info("Try the AI-Nativeness Report instead - it works locally.");
|
|
21961
|
+
return;
|
|
21962
|
+
}
|
|
21963
|
+
const cloudOption = await consola.prompt("What would you like to see?", {
|
|
21964
|
+
type: "select",
|
|
21965
|
+
options: [
|
|
21966
|
+
{ value: "latest", label: "Latest scan results" },
|
|
21967
|
+
{ value: "history", label: "Score history (trend)" },
|
|
21968
|
+
{ value: "weekly", label: "Weekly improvement report" }
|
|
21969
|
+
]
|
|
21970
|
+
});
|
|
21971
|
+
if (cloudOption === "weekly") {
|
|
21972
|
+
await showWeeklyReport(client, clerkId, "text");
|
|
21973
|
+
return;
|
|
21974
|
+
}
|
|
21975
|
+
if (cloudOption === "history") {
|
|
21976
|
+
await showHistory(client, clerkId, 10, "text");
|
|
21977
|
+
return;
|
|
21978
|
+
}
|
|
21979
|
+
await showLatestScan(client, clerkId, undefined, "text");
|
|
21980
|
+
}
|
|
21886
21981
|
async function runHackathonReport(args) {
|
|
21887
21982
|
const projectDir = process.cwd();
|
|
21888
21983
|
let harness = args.harness;
|
|
@@ -21950,7 +22045,7 @@ async function runHackathonReport(args) {
|
|
|
21950
22045
|
}
|
|
21951
22046
|
if (args.output) {
|
|
21952
22047
|
const filepath = resolve(projectDir, args.output);
|
|
21953
|
-
|
|
22048
|
+
writeFileSync6(filepath, output);
|
|
21954
22049
|
consola.success(`Report saved to ${filepath}`);
|
|
21955
22050
|
}
|
|
21956
22051
|
console.log(output);
|
|
@@ -22119,7 +22214,7 @@ async function runLeadershipReport(args) {
|
|
|
22119
22214
|
}
|
|
22120
22215
|
if (args.output) {
|
|
22121
22216
|
const filepath = resolve(projectDir, args.output);
|
|
22122
|
-
|
|
22217
|
+
writeFileSync6(filepath, output);
|
|
22123
22218
|
consola.success(`Report saved to ${filepath}`);
|
|
22124
22219
|
}
|
|
22125
22220
|
console.log(output);
|
|
@@ -22281,9 +22376,9 @@ function renderBar4(value, width) {
|
|
|
22281
22376
|
}
|
|
22282
22377
|
|
|
22283
22378
|
// src/commands/doctor.ts
|
|
22284
|
-
import { existsSync as
|
|
22285
|
-
import { homedir as
|
|
22286
|
-
import { join as
|
|
22379
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
22380
|
+
import { homedir as homedir11 } from "node:os";
|
|
22381
|
+
import { join as join14 } from "node:path";
|
|
22287
22382
|
init_client();
|
|
22288
22383
|
|
|
22289
22384
|
// src/lib/recommendations-db.ts
|
|
@@ -22409,6 +22504,18 @@ var PLUGINS = [
|
|
|
22409
22504
|
}
|
|
22410
22505
|
];
|
|
22411
22506
|
var SKILLS = [
|
|
22507
|
+
{
|
|
22508
|
+
id: "find-skills",
|
|
22509
|
+
name: "Find Skills",
|
|
22510
|
+
type: "skill",
|
|
22511
|
+
description: "Discover and install skills from the open agent skills ecosystem - essential for any AI workflow",
|
|
22512
|
+
installCommand: "npx skills add vercel-labs/skills@find-skills --yes",
|
|
22513
|
+
phases: ["requirements", "planning", "implementation", "review"],
|
|
22514
|
+
impact: "high",
|
|
22515
|
+
detectionKey: "find-skills",
|
|
22516
|
+
website: "https://skills.sh/vercel-labs/skills/find-skills",
|
|
22517
|
+
badge: "Essential"
|
|
22518
|
+
},
|
|
22412
22519
|
{
|
|
22413
22520
|
id: "tdd-skill",
|
|
22414
22521
|
name: "Test-Driven Development",
|
|
@@ -22880,25 +22987,17 @@ function printVerificationResults(summary, verbose = false) {
|
|
|
22880
22987
|
var doctorCommand = defineCommand2({
|
|
22881
22988
|
meta: {
|
|
22882
22989
|
name: "doctor",
|
|
22883
|
-
description: "Check
|
|
22990
|
+
description: "Check system health and diagnose issues"
|
|
22884
22991
|
},
|
|
22885
22992
|
args: {
|
|
22886
22993
|
"verify-recommendations": {
|
|
22887
22994
|
type: "boolean",
|
|
22888
|
-
description: "
|
|
22889
|
-
alias: "verify",
|
|
22995
|
+
description: "",
|
|
22890
22996
|
default: false
|
|
22891
22997
|
},
|
|
22892
22998
|
thorough: {
|
|
22893
22999
|
type: "boolean",
|
|
22894
|
-
description: "
|
|
22895
|
-
alias: "t",
|
|
22896
|
-
default: false
|
|
22897
|
-
},
|
|
22898
|
-
verbose: {
|
|
22899
|
-
type: "boolean",
|
|
22900
|
-
description: "Show all results including valid recommendations",
|
|
22901
|
-
alias: "v",
|
|
23000
|
+
description: "",
|
|
22902
23001
|
default: false
|
|
22903
23002
|
}
|
|
22904
23003
|
},
|
|
@@ -22924,32 +23023,32 @@ var doctorCommand = defineCommand2({
|
|
|
22924
23023
|
} else {
|
|
22925
23024
|
spinner2.succeed("All recommendations verified");
|
|
22926
23025
|
}
|
|
22927
|
-
printVerificationResults(summary,
|
|
23026
|
+
printVerificationResults(summary, true);
|
|
22928
23027
|
if (summary.invalid > 0) {
|
|
22929
23028
|
process.exit(1);
|
|
22930
23029
|
}
|
|
22931
23030
|
return;
|
|
22932
23031
|
}
|
|
22933
23032
|
console.log();
|
|
22934
|
-
console.log(
|
|
22935
|
-
console.log(
|
|
22936
|
-
|
|
23033
|
+
console.log(" \uD83E\uDE7A " + "\x1B[1mNaironAI Doctor\x1B[0m");
|
|
23034
|
+
console.log(" " + "\x1B[2m" + "─".repeat(35) + "\x1B[0m");
|
|
23035
|
+
console.log();
|
|
22937
23036
|
const spinner = createSpinner("Running diagnostics...");
|
|
22938
23037
|
spinner.start();
|
|
22939
23038
|
const results = [];
|
|
22940
23039
|
results.push({ label: "OS", status: "info", value: `${process.platform} ${process.arch}` });
|
|
22941
23040
|
results.push({ label: "Bun", status: "info", value: typeof Bun !== "undefined" ? Bun.version : "N/A" });
|
|
22942
23041
|
results.push({ label: "Node", status: "info", value: process.version });
|
|
22943
|
-
results.push({ label: "Home", status: "info", value:
|
|
22944
|
-
const gitDir =
|
|
22945
|
-
if (
|
|
23042
|
+
results.push({ label: "Home", status: "info", value: homedir11() });
|
|
23043
|
+
const gitDir = join14(process.cwd(), ".git");
|
|
23044
|
+
if (existsSync14(gitDir)) {
|
|
22946
23045
|
results.push({ label: "Git", status: "success", value: "Repository detected" });
|
|
22947
23046
|
} else {
|
|
22948
23047
|
results.push({ label: "Git", status: "warn", value: "No repository in current directory" });
|
|
22949
23048
|
}
|
|
22950
23049
|
for (const [agent, pathTemplate] of Object.entries(AGENT_LOG_PATHS)) {
|
|
22951
|
-
const resolvedPath = pathTemplate.replace("~",
|
|
22952
|
-
if (
|
|
23050
|
+
const resolvedPath = pathTemplate.replace("~", homedir11());
|
|
23051
|
+
if (existsSync14(resolvedPath)) {
|
|
22953
23052
|
results.push({ label: agent, status: "success", value: `found at ${resolvedPath}` });
|
|
22954
23053
|
}
|
|
22955
23054
|
}
|
|
@@ -23003,10 +23102,10 @@ var doctorCommand = defineCommand2({
|
|
|
23003
23102
|
});
|
|
23004
23103
|
|
|
23005
23104
|
// src/commands/setup.ts
|
|
23006
|
-
import { existsSync as
|
|
23007
|
-
import { join as
|
|
23008
|
-
import { homedir as
|
|
23009
|
-
import { execSync as
|
|
23105
|
+
import { existsSync as existsSync15, readFileSync as readFileSync14, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, copyFileSync } from "node:fs";
|
|
23106
|
+
import { join as join15, dirname as dirname2 } from "node:path";
|
|
23107
|
+
import { homedir as homedir12, platform as platform2 } from "node:os";
|
|
23108
|
+
import { execSync as execSync4 } from "node:child_process";
|
|
23010
23109
|
import { createInterface } from "node:readline";
|
|
23011
23110
|
var CONVEX_SITE_URL = "https://steady-bass-841.convex.site";
|
|
23012
23111
|
async function fetchSetupData() {
|
|
@@ -23024,7 +23123,7 @@ var FALLBACK_HARNESSES = [
|
|
|
23024
23123
|
id: "claude-code",
|
|
23025
23124
|
name: "Claude Code",
|
|
23026
23125
|
configPaths: [
|
|
23027
|
-
|
|
23126
|
+
join15(homedir12(), ".claude.json")
|
|
23028
23127
|
],
|
|
23029
23128
|
mcpConfigKey: "mcpServers",
|
|
23030
23129
|
detected: false
|
|
@@ -23033,8 +23132,8 @@ var FALLBACK_HARNESSES = [
|
|
|
23033
23132
|
id: "opencode",
|
|
23034
23133
|
name: "OpenCode",
|
|
23035
23134
|
configPaths: [
|
|
23036
|
-
|
|
23037
|
-
|
|
23135
|
+
join15(homedir12(), ".opencode.json"),
|
|
23136
|
+
join15(homedir12(), ".config", "opencode", "opencode.json")
|
|
23038
23137
|
],
|
|
23039
23138
|
mcpConfigKey: "mcp",
|
|
23040
23139
|
detected: false
|
|
@@ -23043,8 +23142,8 @@ var FALLBACK_HARNESSES = [
|
|
|
23043
23142
|
id: "cursor",
|
|
23044
23143
|
name: "Cursor",
|
|
23045
23144
|
configPaths: [
|
|
23046
|
-
|
|
23047
|
-
|
|
23145
|
+
join15(homedir12(), ".cursor", "mcp.json"),
|
|
23146
|
+
join15(homedir12(), "Library", "Application Support", "Cursor", "User", "globalStorage", "mcp.json")
|
|
23048
23147
|
],
|
|
23049
23148
|
mcpConfigKey: "mcpServers",
|
|
23050
23149
|
detected: false
|
|
@@ -23061,7 +23160,7 @@ function getConfigPathsForPlatform(harness) {
|
|
|
23061
23160
|
} else {
|
|
23062
23161
|
paths = pathMap.linux;
|
|
23063
23162
|
}
|
|
23064
|
-
return paths.map((p) => p.replace(/^~/,
|
|
23163
|
+
return paths.map((p) => p.replace(/^~/, homedir12()).replace(/%USERPROFILE%/gi, homedir12()).replace(/%APPDATA%/gi, join15(homedir12(), "AppData", "Roaming")));
|
|
23065
23164
|
}
|
|
23066
23165
|
function convertAPIHarnessToConfig(harness) {
|
|
23067
23166
|
return {
|
|
@@ -23076,7 +23175,7 @@ function detectHarnesses(harnesses) {
|
|
|
23076
23175
|
const detected = [];
|
|
23077
23176
|
for (const harness of harnesses) {
|
|
23078
23177
|
for (const configPath of harness.configPaths) {
|
|
23079
|
-
if (
|
|
23178
|
+
if (existsSync15(configPath)) {
|
|
23080
23179
|
detected.push({
|
|
23081
23180
|
...harness,
|
|
23082
23181
|
detected: true,
|
|
@@ -23089,19 +23188,19 @@ function detectHarnesses(harnesses) {
|
|
|
23089
23188
|
return detected;
|
|
23090
23189
|
}
|
|
23091
23190
|
function backupConfig(configPath) {
|
|
23092
|
-
const backupDir =
|
|
23093
|
-
if (!
|
|
23094
|
-
|
|
23191
|
+
const backupDir = join15(homedir12(), ".nairon", "backups");
|
|
23192
|
+
if (!existsSync15(backupDir)) {
|
|
23193
|
+
mkdirSync6(backupDir, { recursive: true });
|
|
23095
23194
|
}
|
|
23096
23195
|
const timestamp = new Date().toISOString().replace(/[:.]/g, "-").slice(0, 19);
|
|
23097
23196
|
const filename = configPath.replace(/[/\\]/g, "_").replace(/^_/, "");
|
|
23098
|
-
const backupPath =
|
|
23197
|
+
const backupPath = join15(backupDir, `${timestamp}_${filename}`);
|
|
23099
23198
|
copyFileSync(configPath, backupPath);
|
|
23100
23199
|
return backupPath;
|
|
23101
23200
|
}
|
|
23102
23201
|
function readJsonConfig(configPath) {
|
|
23103
23202
|
try {
|
|
23104
|
-
const content =
|
|
23203
|
+
const content = readFileSync14(configPath, "utf-8");
|
|
23105
23204
|
return JSON.parse(content);
|
|
23106
23205
|
} catch {
|
|
23107
23206
|
return {};
|
|
@@ -23109,10 +23208,10 @@ function readJsonConfig(configPath) {
|
|
|
23109
23208
|
}
|
|
23110
23209
|
function writeJsonConfig(configPath, config) {
|
|
23111
23210
|
const dir = dirname2(configPath);
|
|
23112
|
-
if (!
|
|
23113
|
-
|
|
23211
|
+
if (!existsSync15(dir)) {
|
|
23212
|
+
mkdirSync6(dir, { recursive: true });
|
|
23114
23213
|
}
|
|
23115
|
-
|
|
23214
|
+
writeFileSync7(configPath, JSON.stringify(config, null, 2));
|
|
23116
23215
|
}
|
|
23117
23216
|
async function prompt2(question) {
|
|
23118
23217
|
const rl = createInterface({
|
|
@@ -23153,7 +23252,7 @@ function getInstalledMCPs(harnesses) {
|
|
|
23153
23252
|
const installed = new Set;
|
|
23154
23253
|
for (const harness of harnesses) {
|
|
23155
23254
|
for (const configPath of harness.configPaths) {
|
|
23156
|
-
if (!
|
|
23255
|
+
if (!existsSync15(configPath))
|
|
23157
23256
|
continue;
|
|
23158
23257
|
const config = readJsonConfig(configPath);
|
|
23159
23258
|
const mcpServers = config[harness.mcpConfigKey];
|
|
@@ -23177,7 +23276,7 @@ async function installMCPServer(serverName, instruction, harness) {
|
|
|
23177
23276
|
if (!harness.configPath || !instruction.mcpServerConfig)
|
|
23178
23277
|
return false;
|
|
23179
23278
|
try {
|
|
23180
|
-
if (
|
|
23279
|
+
if (existsSync15(harness.configPath)) {
|
|
23181
23280
|
backupConfig(harness.configPath);
|
|
23182
23281
|
}
|
|
23183
23282
|
const config = readJsonConfig(harness.configPath);
|
|
@@ -23205,16 +23304,16 @@ async function installMCPServer(serverName, instruction, harness) {
|
|
|
23205
23304
|
async function installBeads(projectDir) {
|
|
23206
23305
|
try {
|
|
23207
23306
|
try {
|
|
23208
|
-
|
|
23307
|
+
execSync4("bd --version", { stdio: "ignore" });
|
|
23209
23308
|
} catch {
|
|
23210
23309
|
const spinner = createSpinner("Installing Beads globally...");
|
|
23211
23310
|
spinner.start();
|
|
23212
23311
|
try {
|
|
23213
|
-
|
|
23312
|
+
execSync4("bun add -g beads", { stdio: "ignore" });
|
|
23214
23313
|
spinner.succeed("Beads installed globally");
|
|
23215
23314
|
} catch {
|
|
23216
23315
|
try {
|
|
23217
|
-
|
|
23316
|
+
execSync4("npm install -g beads", { stdio: "ignore" });
|
|
23218
23317
|
spinner.succeed("Beads installed globally (via npm)");
|
|
23219
23318
|
} catch {
|
|
23220
23319
|
spinner.fail("Failed to install Beads globally");
|
|
@@ -23222,13 +23321,13 @@ async function installBeads(projectDir) {
|
|
|
23222
23321
|
}
|
|
23223
23322
|
}
|
|
23224
23323
|
}
|
|
23225
|
-
const beadsDir =
|
|
23226
|
-
if (!
|
|
23324
|
+
const beadsDir = join15(projectDir, ".beads");
|
|
23325
|
+
if (!existsSync15(beadsDir)) {
|
|
23227
23326
|
const projectName = projectDir.split(/[/\\]/).pop() ?? "project";
|
|
23228
23327
|
const initSpinner = createSpinner(`Initializing Beads in ${projectName}...`);
|
|
23229
23328
|
initSpinner.start();
|
|
23230
23329
|
try {
|
|
23231
|
-
|
|
23330
|
+
execSync4(`bd init ${projectName}`, { cwd: projectDir, stdio: "ignore" });
|
|
23232
23331
|
initSpinner.succeed(`Beads initialized in ${projectName}`);
|
|
23233
23332
|
} catch {
|
|
23234
23333
|
initSpinner.fail("Failed to initialize Beads in project");
|
|
@@ -23242,9 +23341,9 @@ async function installBeads(projectDir) {
|
|
|
23242
23341
|
}
|
|
23243
23342
|
}
|
|
23244
23343
|
async function createClaudeRules(projectDir) {
|
|
23245
|
-
const claudeMdPath =
|
|
23246
|
-
const agentsMdPath =
|
|
23247
|
-
if (
|
|
23344
|
+
const claudeMdPath = join15(projectDir, "CLAUDE.md");
|
|
23345
|
+
const agentsMdPath = join15(projectDir, "AGENTS.md");
|
|
23346
|
+
if (existsSync15(claudeMdPath) || existsSync15(agentsMdPath)) {
|
|
23248
23347
|
console.log(` ${icons.info} CLAUDE.md or AGENTS.md already exists`);
|
|
23249
23348
|
return true;
|
|
23250
23349
|
}
|
|
@@ -23278,7 +23377,7 @@ bun run build
|
|
|
23278
23377
|
Use conventional commits: feat:, fix:, docs:, refactor:, test:, chore:
|
|
23279
23378
|
`;
|
|
23280
23379
|
try {
|
|
23281
|
-
|
|
23380
|
+
writeFileSync7(claudeMdPath, content);
|
|
23282
23381
|
return true;
|
|
23283
23382
|
} catch {
|
|
23284
23383
|
return false;
|
|
@@ -23558,7 +23657,7 @@ var setupCommand = defineCommand2({
|
|
|
23558
23657
|
});
|
|
23559
23658
|
|
|
23560
23659
|
// src/commands/upgrade.ts
|
|
23561
|
-
import { execSync as
|
|
23660
|
+
import { execSync as execSync5 } from "node:child_process";
|
|
23562
23661
|
var CYAN = "\x1B[36m";
|
|
23563
23662
|
var GREEN = "\x1B[32m";
|
|
23564
23663
|
var YELLOW = "\x1B[33m";
|
|
@@ -23568,8 +23667,30 @@ var RESET = "\x1B[0m";
|
|
|
23568
23667
|
var MAGENTA = "\x1B[35m";
|
|
23569
23668
|
var CHANGELOG = [
|
|
23570
23669
|
{
|
|
23571
|
-
version: "0.
|
|
23670
|
+
version: "0.5.1",
|
|
23671
|
+
date: "2026-02-14",
|
|
23672
|
+
title: "Smart Project Onboarding",
|
|
23673
|
+
highlights: [
|
|
23674
|
+
"First scan detects your project and suggests relevant skills",
|
|
23675
|
+
"Auto-installs find-skills to discover more tools later",
|
|
23676
|
+
"Analyzes README to recommend skills for your tech stack",
|
|
23677
|
+
"Detects your AI agent (Claude Code, OpenCode, Cursor)"
|
|
23678
|
+
]
|
|
23679
|
+
},
|
|
23680
|
+
{
|
|
23681
|
+
version: "0.5.0",
|
|
23572
23682
|
date: "2026-02-14",
|
|
23683
|
+
title: "Interactive-First CLI",
|
|
23684
|
+
highlights: [
|
|
23685
|
+
"No more flags to remember - commands guide you through options",
|
|
23686
|
+
"Just run nb scan or nb report and follow the prompts",
|
|
23687
|
+
"Public link is now the first option for report sharing",
|
|
23688
|
+
"CI/scripts still supported via --json flag"
|
|
23689
|
+
]
|
|
23690
|
+
},
|
|
23691
|
+
{
|
|
23692
|
+
version: "0.4.0",
|
|
23693
|
+
date: "2026-02-13",
|
|
23573
23694
|
title: "AI Work Visibility",
|
|
23574
23695
|
highlights: [
|
|
23575
23696
|
"New: Effort breakdown shows generation/review/correction/integration time",
|
|
@@ -23604,7 +23725,7 @@ var CHANGELOG = [
|
|
|
23604
23725
|
title: "Reliable Recommendations",
|
|
23605
23726
|
highlights: [
|
|
23606
23727
|
"Fixed skills.sh format - skills now install correctly",
|
|
23607
|
-
"
|
|
23728
|
+
"Improved recommendation validation before release"
|
|
23608
23729
|
]
|
|
23609
23730
|
},
|
|
23610
23731
|
{
|
|
@@ -23872,7 +23993,7 @@ var upgradeCommand = defineCommand2({
|
|
|
23872
23993
|
console.log(`${DIM} Checking for updates...${RESET}`);
|
|
23873
23994
|
let latestVersion;
|
|
23874
23995
|
try {
|
|
23875
|
-
latestVersion =
|
|
23996
|
+
latestVersion = execSync5("npm view nairon-bench version", { encoding: "utf-8" }).trim();
|
|
23876
23997
|
} catch {
|
|
23877
23998
|
console.log(` ${YELLOW}⚠${RESET} Could not check npm registry`);
|
|
23878
23999
|
console.log(` ${DIM}Run 'bun add -g nairon-bench@latest' manually${RESET}`);
|
|
@@ -23899,7 +24020,7 @@ var upgradeCommand = defineCommand2({
|
|
|
23899
24020
|
console.log(` ${CYAN}↓${RESET} Upgrading to ${GREEN}v${latestVersion}${RESET}...`);
|
|
23900
24021
|
console.log();
|
|
23901
24022
|
try {
|
|
23902
|
-
|
|
24023
|
+
execSync5("npm install -g nairon-bench@latest", {
|
|
23903
24024
|
stdio: "inherit",
|
|
23904
24025
|
env: { ...process.env, npm_config_fund: "false" }
|
|
23905
24026
|
});
|
|
@@ -23917,7 +24038,7 @@ var upgradeCommand = defineCommand2({
|
|
|
23917
24038
|
});
|
|
23918
24039
|
function getCurrentVersion() {
|
|
23919
24040
|
try {
|
|
23920
|
-
const output =
|
|
24041
|
+
const output = execSync5("nb --version 2>/dev/null || nairon-bench --version 2>/dev/null", {
|
|
23921
24042
|
encoding: "utf-8",
|
|
23922
24043
|
stdio: ["pipe", "pipe", "pipe"]
|
|
23923
24044
|
});
|
|
@@ -24006,7 +24127,7 @@ function showFullChangelog() {
|
|
|
24006
24127
|
// package.json
|
|
24007
24128
|
var package_default = {
|
|
24008
24129
|
name: "nairon-bench",
|
|
24009
|
-
version: "0.
|
|
24130
|
+
version: "0.5.1",
|
|
24010
24131
|
description: "AI workflow benchmarking CLI",
|
|
24011
24132
|
type: "module",
|
|
24012
24133
|
bin: {
|
|
@@ -24014,7 +24135,8 @@ var package_default = {
|
|
|
24014
24135
|
nb: "./dist/index.js"
|
|
24015
24136
|
},
|
|
24016
24137
|
files: [
|
|
24017
|
-
"dist"
|
|
24138
|
+
"dist",
|
|
24139
|
+
"postinstall.js"
|
|
24018
24140
|
],
|
|
24019
24141
|
repository: {
|
|
24020
24142
|
type: "git",
|
|
@@ -24042,7 +24164,8 @@ var package_default = {
|
|
|
24042
24164
|
"test:e2e": "vitest run tests/e2e/",
|
|
24043
24165
|
"test:watch": "vitest",
|
|
24044
24166
|
clean: "rm -rf dist",
|
|
24045
|
-
prepublishOnly: "bun run build"
|
|
24167
|
+
prepublishOnly: "bun run build",
|
|
24168
|
+
postinstall: "node postinstall.js || true"
|
|
24046
24169
|
},
|
|
24047
24170
|
dependencies: {
|
|
24048
24171
|
"cli-boxes": "^4.0.1",
|
|
@@ -24065,9 +24188,9 @@ var versionCommand = defineCommand2({
|
|
|
24065
24188
|
|
|
24066
24189
|
// src/commands/init.ts
|
|
24067
24190
|
init_dist();
|
|
24068
|
-
import { existsSync as
|
|
24069
|
-
import { homedir as
|
|
24070
|
-
import { join as
|
|
24191
|
+
import { existsSync as existsSync16 } from "node:fs";
|
|
24192
|
+
import { homedir as homedir13, platform as platform3, arch } from "node:os";
|
|
24193
|
+
import { join as join16 } from "node:path";
|
|
24071
24194
|
init_client();
|
|
24072
24195
|
|
|
24073
24196
|
// src/lib/github-auth.ts
|
|
@@ -24237,8 +24360,8 @@ var initCommand = defineCommand2({
|
|
|
24237
24360
|
consola.start("Step 2/6: Detecting AI agents...");
|
|
24238
24361
|
const detectedAgents = [];
|
|
24239
24362
|
for (const [agent, pathTemplate] of Object.entries(AGENT_LOG_PATHS)) {
|
|
24240
|
-
const resolvedPath = pathTemplate.replace("~",
|
|
24241
|
-
if (
|
|
24363
|
+
const resolvedPath = pathTemplate.replace("~", homedir13());
|
|
24364
|
+
if (existsSync16(resolvedPath)) {
|
|
24242
24365
|
detectedAgents.push(agent);
|
|
24243
24366
|
consola.success(` Found: ${agent}`);
|
|
24244
24367
|
}
|
|
@@ -24341,7 +24464,7 @@ var initCommand = defineCommand2({
|
|
|
24341
24464
|
{ name: "playwright", configs: ["playwright.config.ts", "playwright.config.js"] }
|
|
24342
24465
|
];
|
|
24343
24466
|
for (const fw of testFrameworks) {
|
|
24344
|
-
if (fw.configs.some((c3) =>
|
|
24467
|
+
if (fw.configs.some((c3) => existsSync16(join16(process.cwd(), c3)))) {
|
|
24345
24468
|
toolStack.testing.push(fw.name);
|
|
24346
24469
|
}
|
|
24347
24470
|
}
|
|
@@ -24410,13 +24533,13 @@ var initCommand = defineCommand2({
|
|
|
24410
24533
|
});
|
|
24411
24534
|
function detectPackageManager() {
|
|
24412
24535
|
const cwd = process.cwd();
|
|
24413
|
-
if (
|
|
24536
|
+
if (existsSync16(join16(cwd, "bun.lock")) || existsSync16(join16(cwd, "bun.lockb")))
|
|
24414
24537
|
return "bun";
|
|
24415
|
-
if (
|
|
24538
|
+
if (existsSync16(join16(cwd, "pnpm-lock.yaml")))
|
|
24416
24539
|
return "pnpm";
|
|
24417
|
-
if (
|
|
24540
|
+
if (existsSync16(join16(cwd, "yarn.lock")))
|
|
24418
24541
|
return "yarn";
|
|
24419
|
-
if (
|
|
24542
|
+
if (existsSync16(join16(cwd, "package-lock.json")))
|
|
24420
24543
|
return "npm";
|
|
24421
24544
|
return;
|
|
24422
24545
|
}
|
|
@@ -24431,15 +24554,15 @@ var CLAUDE_CODE_SKILLS = [
|
|
|
24431
24554
|
];
|
|
24432
24555
|
function detectEasyWins(detectedAgents) {
|
|
24433
24556
|
const wins = [];
|
|
24434
|
-
const home =
|
|
24557
|
+
const home = homedir13();
|
|
24435
24558
|
const hasClaudeCode = detectedAgents.some((a2) => a2.toLowerCase().includes("claude") || a2.toLowerCase().includes("opencode"));
|
|
24436
|
-
const claudeConfigDir =
|
|
24437
|
-
const hasClaudeConfig =
|
|
24559
|
+
const claudeConfigDir = join16(home, ".claude");
|
|
24560
|
+
const hasClaudeConfig = existsSync16(claudeConfigDir);
|
|
24438
24561
|
if (hasClaudeCode || hasClaudeConfig) {
|
|
24439
|
-
const skillsDir =
|
|
24562
|
+
const skillsDir = join16(home, ".claude", "skills");
|
|
24440
24563
|
for (const skill of CLAUDE_CODE_SKILLS) {
|
|
24441
|
-
const skillPath =
|
|
24442
|
-
const isInstalled =
|
|
24564
|
+
const skillPath = join16(skillsDir, skill.id);
|
|
24565
|
+
const isInstalled = existsSync16(skillPath);
|
|
24443
24566
|
if (!isInstalled) {
|
|
24444
24567
|
wins.push({
|
|
24445
24568
|
icon: skill.icon,
|
|
@@ -24455,12 +24578,12 @@ function detectEasyWins(detectedAgents) {
|
|
|
24455
24578
|
// src/commands/onboard.ts
|
|
24456
24579
|
init_dist();
|
|
24457
24580
|
init_client();
|
|
24458
|
-
import { existsSync as
|
|
24459
|
-
import { join as
|
|
24581
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync7, readFileSync as readFileSync16, writeFileSync as writeFileSync8, readdirSync as readdirSync9 } from "node:fs";
|
|
24582
|
+
import { join as join18 } from "node:path";
|
|
24460
24583
|
|
|
24461
24584
|
// src/lib/project-context-detector.ts
|
|
24462
|
-
import { existsSync as
|
|
24463
|
-
import { join as
|
|
24585
|
+
import { existsSync as existsSync17, readFileSync as readFileSync15, readdirSync as readdirSync8 } from "node:fs";
|
|
24586
|
+
import { join as join17, basename as basename4 } from "node:path";
|
|
24464
24587
|
function detectProjectContext(projectDir) {
|
|
24465
24588
|
const projectName = basename4(projectDir);
|
|
24466
24589
|
const projectId = generateProjectId(projectDir);
|
|
@@ -24496,11 +24619,11 @@ function detectTechStack(projectDir) {
|
|
|
24496
24619
|
};
|
|
24497
24620
|
}
|
|
24498
24621
|
function readPackageJson(projectDir) {
|
|
24499
|
-
const pkgPath =
|
|
24500
|
-
if (!
|
|
24622
|
+
const pkgPath = join17(projectDir, "package.json");
|
|
24623
|
+
if (!existsSync17(pkgPath))
|
|
24501
24624
|
return {};
|
|
24502
24625
|
try {
|
|
24503
|
-
return JSON.parse(
|
|
24626
|
+
return JSON.parse(readFileSync15(pkgPath, "utf-8"));
|
|
24504
24627
|
} catch {
|
|
24505
24628
|
return {};
|
|
24506
24629
|
}
|
|
@@ -24521,34 +24644,34 @@ function detectFramework(deps) {
|
|
|
24521
24644
|
return null;
|
|
24522
24645
|
}
|
|
24523
24646
|
function detectMetaFramework(deps, projectDir) {
|
|
24524
|
-
if (deps.next ||
|
|
24647
|
+
if (deps.next || existsSync17(join17(projectDir, "next.config.js")) || existsSync17(join17(projectDir, "next.config.mjs")))
|
|
24525
24648
|
return "next";
|
|
24526
|
-
if (deps.nuxt ||
|
|
24649
|
+
if (deps.nuxt || existsSync17(join17(projectDir, "nuxt.config.ts")))
|
|
24527
24650
|
return "nuxt";
|
|
24528
24651
|
if (deps["@sveltejs/kit"])
|
|
24529
24652
|
return "sveltekit";
|
|
24530
|
-
if (deps.astro ||
|
|
24653
|
+
if (deps.astro || existsSync17(join17(projectDir, "astro.config.mjs")))
|
|
24531
24654
|
return "astro";
|
|
24532
24655
|
if (deps["@remix-run/react"])
|
|
24533
24656
|
return "remix";
|
|
24534
24657
|
if (deps.gatsby)
|
|
24535
24658
|
return "gatsby";
|
|
24536
|
-
if (deps.vite ||
|
|
24659
|
+
if (deps.vite || existsSync17(join17(projectDir, "vite.config.ts")))
|
|
24537
24660
|
return "vite";
|
|
24538
24661
|
return null;
|
|
24539
24662
|
}
|
|
24540
24663
|
function detectRuntime(projectDir) {
|
|
24541
|
-
if (
|
|
24664
|
+
if (existsSync17(join17(projectDir, "bun.lockb")) || existsSync17(join17(projectDir, "bun.lock")))
|
|
24542
24665
|
return "bun";
|
|
24543
|
-
if (
|
|
24666
|
+
if (existsSync17(join17(projectDir, "deno.json")) || existsSync17(join17(projectDir, "deno.lock")))
|
|
24544
24667
|
return "deno";
|
|
24545
24668
|
return "node";
|
|
24546
24669
|
}
|
|
24547
24670
|
function detectLanguage(projectDir) {
|
|
24548
|
-
if (
|
|
24671
|
+
if (existsSync17(join17(projectDir, "tsconfig.json")))
|
|
24549
24672
|
return "typescript";
|
|
24550
|
-
const srcDir =
|
|
24551
|
-
if (
|
|
24673
|
+
const srcDir = join17(projectDir, "src");
|
|
24674
|
+
if (existsSync17(srcDir)) {
|
|
24552
24675
|
try {
|
|
24553
24676
|
const files = readdirSync8(srcDir);
|
|
24554
24677
|
if (files.some((f3) => f3.endsWith(".ts") || f3.endsWith(".tsx")))
|
|
@@ -24559,7 +24682,7 @@ function detectLanguage(projectDir) {
|
|
|
24559
24682
|
}
|
|
24560
24683
|
function detectStyling(deps, projectDir) {
|
|
24561
24684
|
const tools = [];
|
|
24562
|
-
if (deps.tailwindcss ||
|
|
24685
|
+
if (deps.tailwindcss || existsSync17(join17(projectDir, "tailwind.config.js")) || existsSync17(join17(projectDir, "tailwind.config.ts")))
|
|
24563
24686
|
tools.push("tailwind");
|
|
24564
24687
|
if (deps["styled-components"])
|
|
24565
24688
|
tools.push("styled-components");
|
|
@@ -24604,13 +24727,13 @@ function detectORM(deps) {
|
|
|
24604
24727
|
}
|
|
24605
24728
|
function detectTesting(deps, projectDir) {
|
|
24606
24729
|
const tools = [];
|
|
24607
|
-
if (deps.vitest ||
|
|
24730
|
+
if (deps.vitest || existsSync17(join17(projectDir, "vitest.config.ts")))
|
|
24608
24731
|
tools.push("vitest");
|
|
24609
|
-
if (deps.jest ||
|
|
24732
|
+
if (deps.jest || existsSync17(join17(projectDir, "jest.config.js")))
|
|
24610
24733
|
tools.push("jest");
|
|
24611
|
-
if (deps["@playwright/test"] ||
|
|
24734
|
+
if (deps["@playwright/test"] || existsSync17(join17(projectDir, "playwright.config.ts")))
|
|
24612
24735
|
tools.push("playwright");
|
|
24613
|
-
if (deps.cypress ||
|
|
24736
|
+
if (deps.cypress || existsSync17(join17(projectDir, "cypress.config.ts")))
|
|
24614
24737
|
tools.push("cypress");
|
|
24615
24738
|
if (deps["@testing-library/react"] || deps["@testing-library/vue"])
|
|
24616
24739
|
tools.push("testing-library");
|
|
@@ -24642,7 +24765,7 @@ function detectBuildTools(deps, projectDir) {
|
|
|
24642
24765
|
tools.push("esbuild");
|
|
24643
24766
|
if (deps.webpack)
|
|
24644
24767
|
tools.push("webpack");
|
|
24645
|
-
if (deps.turbo ||
|
|
24768
|
+
if (deps.turbo || existsSync17(join17(projectDir, "turbo.json")))
|
|
24646
24769
|
tools.push("turborepo");
|
|
24647
24770
|
if (deps.tsup)
|
|
24648
24771
|
tools.push("tsup");
|
|
@@ -24652,17 +24775,17 @@ function detectBuildTools(deps, projectDir) {
|
|
|
24652
24775
|
}
|
|
24653
24776
|
function detectDeployment(projectDir) {
|
|
24654
24777
|
const tools = [];
|
|
24655
|
-
if (
|
|
24778
|
+
if (existsSync17(join17(projectDir, "vercel.json")) || existsSync17(join17(projectDir, ".vercel")))
|
|
24656
24779
|
tools.push("vercel");
|
|
24657
|
-
if (
|
|
24780
|
+
if (existsSync17(join17(projectDir, "netlify.toml")))
|
|
24658
24781
|
tools.push("netlify");
|
|
24659
|
-
if (
|
|
24782
|
+
if (existsSync17(join17(projectDir, "fly.toml")))
|
|
24660
24783
|
tools.push("fly");
|
|
24661
|
-
if (
|
|
24784
|
+
if (existsSync17(join17(projectDir, "railway.json")))
|
|
24662
24785
|
tools.push("railway");
|
|
24663
|
-
if (
|
|
24786
|
+
if (existsSync17(join17(projectDir, "Dockerfile")))
|
|
24664
24787
|
tools.push("docker");
|
|
24665
|
-
if (
|
|
24788
|
+
if (existsSync17(join17(projectDir, ".github", "workflows")))
|
|
24666
24789
|
tools.push("github-actions");
|
|
24667
24790
|
return tools;
|
|
24668
24791
|
}
|
|
@@ -24685,20 +24808,20 @@ function detectAIML(deps) {
|
|
|
24685
24808
|
return tools;
|
|
24686
24809
|
}
|
|
24687
24810
|
function inferProjectType(projectDir, techStack) {
|
|
24688
|
-
if (
|
|
24811
|
+
if (existsSync17(join17(projectDir, "packages")) || existsSync17(join17(projectDir, "apps"))) {
|
|
24689
24812
|
return "monorepo";
|
|
24690
24813
|
}
|
|
24691
24814
|
const pkg = readPackageJson(projectDir);
|
|
24692
|
-
if (pkg.bin ||
|
|
24815
|
+
if (pkg.bin || existsSync17(join17(projectDir, "src", "cli.ts")) || existsSync17(join17(projectDir, "src", "index.ts"))) {
|
|
24693
24816
|
const hasBin = !!pkg.bin;
|
|
24694
|
-
const hasCommands =
|
|
24817
|
+
const hasCommands = existsSync17(join17(projectDir, "src", "commands"));
|
|
24695
24818
|
if (hasBin || hasCommands)
|
|
24696
24819
|
return "cli";
|
|
24697
24820
|
}
|
|
24698
24821
|
if (!techStack.framework && !techStack.metaFramework && pkg.main) {
|
|
24699
24822
|
return "library";
|
|
24700
24823
|
}
|
|
24701
|
-
if (
|
|
24824
|
+
if (existsSync17(join17(projectDir, "app.json")) || existsSync17(join17(projectDir, "expo"))) {
|
|
24702
24825
|
return "mobile";
|
|
24703
24826
|
}
|
|
24704
24827
|
if (techStack.database.length > 0 && !techStack.framework) {
|
|
@@ -24715,10 +24838,10 @@ function extractDescription(projectDir) {
|
|
|
24715
24838
|
return pkg.description;
|
|
24716
24839
|
const readmePaths = ["README.md", "readme.md", "Readme.md"];
|
|
24717
24840
|
for (const readme of readmePaths) {
|
|
24718
|
-
const path =
|
|
24719
|
-
if (
|
|
24841
|
+
const path = join17(projectDir, readme);
|
|
24842
|
+
if (existsSync17(path)) {
|
|
24720
24843
|
try {
|
|
24721
|
-
const content =
|
|
24844
|
+
const content = readFileSync15(path, "utf-8");
|
|
24722
24845
|
const lines = content.split(`
|
|
24723
24846
|
`);
|
|
24724
24847
|
let foundTitle = false;
|
|
@@ -26136,9 +26259,9 @@ var onboardCommand = defineCommand2({
|
|
|
26136
26259
|
},
|
|
26137
26260
|
async run({ args }) {
|
|
26138
26261
|
const projectPath = process.cwd();
|
|
26139
|
-
const contextPath =
|
|
26140
|
-
if (
|
|
26141
|
-
const existing = JSON.parse(
|
|
26262
|
+
const contextPath = join18(projectPath, ".nairon", "context.json");
|
|
26263
|
+
if (existsSync18(contextPath) && !args.force) {
|
|
26264
|
+
const existing = JSON.parse(readFileSync16(contextPath, "utf-8"));
|
|
26142
26265
|
consola.info("Project already onboarded. Use --force to re-run.");
|
|
26143
26266
|
consola.info(`Business: ${existing.businessContext?.domain || existing.businessContext?.slice?.(0, 50) || "Not set"}...`);
|
|
26144
26267
|
consola.info(`Stack: ${formatTechStackSummary(existing)}`);
|
|
@@ -26286,11 +26409,11 @@ var onboardCommand = defineCommand2({
|
|
|
26286
26409
|
createdAt: new Date().toISOString(),
|
|
26287
26410
|
updatedAt: new Date().toISOString()
|
|
26288
26411
|
};
|
|
26289
|
-
const naironDir =
|
|
26290
|
-
if (!
|
|
26291
|
-
|
|
26412
|
+
const naironDir = join18(projectPath, ".nairon");
|
|
26413
|
+
if (!existsSync18(naironDir)) {
|
|
26414
|
+
mkdirSync7(naironDir, { recursive: true });
|
|
26292
26415
|
}
|
|
26293
|
-
|
|
26416
|
+
writeFileSync8(contextPath, JSON.stringify(fullContext, null, 2));
|
|
26294
26417
|
consola.success(`Saved to ${contextPath}`);
|
|
26295
26418
|
if (isSupermemoryConfigured()) {
|
|
26296
26419
|
consola.start("Storing in Supermemory...");
|
|
@@ -26378,51 +26501,51 @@ function formatTechStackSummary(context) {
|
|
|
26378
26501
|
function detectInstalledTools(projectPath) {
|
|
26379
26502
|
const tools = [];
|
|
26380
26503
|
const home = process.env.HOME || "";
|
|
26381
|
-
const userClaudeJson =
|
|
26382
|
-
if (
|
|
26504
|
+
const userClaudeJson = join18(home, ".claude.json");
|
|
26505
|
+
if (existsSync18(userClaudeJson)) {
|
|
26383
26506
|
try {
|
|
26384
|
-
const config = JSON.parse(
|
|
26507
|
+
const config = JSON.parse(readFileSync16(userClaudeJson, "utf-8"));
|
|
26385
26508
|
if (config.mcpServers) {
|
|
26386
26509
|
tools.push(...Object.keys(config.mcpServers));
|
|
26387
26510
|
}
|
|
26388
26511
|
} catch {}
|
|
26389
26512
|
}
|
|
26390
|
-
const claudeDesktopConfig =
|
|
26391
|
-
if (
|
|
26513
|
+
const claudeDesktopConfig = join18(home, ".claude", "claude_desktop_config.json");
|
|
26514
|
+
if (existsSync18(claudeDesktopConfig)) {
|
|
26392
26515
|
try {
|
|
26393
|
-
const config = JSON.parse(
|
|
26516
|
+
const config = JSON.parse(readFileSync16(claudeDesktopConfig, "utf-8"));
|
|
26394
26517
|
if (config.mcpServers) {
|
|
26395
26518
|
tools.push(...Object.keys(config.mcpServers));
|
|
26396
26519
|
}
|
|
26397
26520
|
} catch {}
|
|
26398
26521
|
}
|
|
26399
|
-
const projectMcpJson =
|
|
26400
|
-
if (
|
|
26522
|
+
const projectMcpJson = join18(projectPath, ".mcp.json");
|
|
26523
|
+
if (existsSync18(projectMcpJson)) {
|
|
26401
26524
|
try {
|
|
26402
|
-
const config = JSON.parse(
|
|
26525
|
+
const config = JSON.parse(readFileSync16(projectMcpJson, "utf-8"));
|
|
26403
26526
|
if (config.mcpServers) {
|
|
26404
26527
|
tools.push(...Object.keys(config.mcpServers));
|
|
26405
26528
|
}
|
|
26406
26529
|
} catch {}
|
|
26407
26530
|
}
|
|
26408
|
-
const projectClaudeConfig =
|
|
26409
|
-
if (
|
|
26531
|
+
const projectClaudeConfig = join18(projectPath, ".claude", "settings.json");
|
|
26532
|
+
if (existsSync18(projectClaudeConfig)) {
|
|
26410
26533
|
try {
|
|
26411
|
-
const config = JSON.parse(
|
|
26534
|
+
const config = JSON.parse(readFileSync16(projectClaudeConfig, "utf-8"));
|
|
26412
26535
|
if (config.mcpServers) {
|
|
26413
26536
|
tools.push(...Object.keys(config.mcpServers));
|
|
26414
26537
|
}
|
|
26415
26538
|
} catch {}
|
|
26416
26539
|
}
|
|
26417
|
-
const skillsDir =
|
|
26418
|
-
if (
|
|
26540
|
+
const skillsDir = join18(home, ".config", "opencode", "skills");
|
|
26541
|
+
if (existsSync18(skillsDir)) {
|
|
26419
26542
|
try {
|
|
26420
26543
|
const skills = readdirSync9(skillsDir);
|
|
26421
26544
|
tools.push(...skills.filter((s2) => !s2.startsWith(".")));
|
|
26422
26545
|
} catch {}
|
|
26423
26546
|
}
|
|
26424
|
-
const agentsSkillsDir =
|
|
26425
|
-
if (
|
|
26547
|
+
const agentsSkillsDir = join18(home, ".agents", "skills");
|
|
26548
|
+
if (existsSync18(agentsSkillsDir)) {
|
|
26426
26549
|
try {
|
|
26427
26550
|
const skills = readdirSync9(agentsSkillsDir);
|
|
26428
26551
|
tools.push(...skills.filter((s2) => !s2.startsWith(".")));
|
|
@@ -26432,11 +26555,11 @@ function detectInstalledTools(projectPath) {
|
|
|
26432
26555
|
}
|
|
26433
26556
|
function detectPrimaryAgent() {
|
|
26434
26557
|
const home = process.env.HOME || "";
|
|
26435
|
-
if (
|
|
26558
|
+
if (existsSync18(join18(home, ".claude")))
|
|
26436
26559
|
return "claude-code";
|
|
26437
|
-
if (
|
|
26560
|
+
if (existsSync18(join18(home, ".cursor")))
|
|
26438
26561
|
return "cursor";
|
|
26439
|
-
if (
|
|
26562
|
+
if (existsSync18(join18(home, ".config", "opencode")))
|
|
26440
26563
|
return "opencode";
|
|
26441
26564
|
return;
|
|
26442
26565
|
}
|
|
@@ -26531,7 +26654,7 @@ function formatBytes(bytes) {
|
|
|
26531
26654
|
// package.json
|
|
26532
26655
|
var package_default2 = {
|
|
26533
26656
|
name: "nairon-bench",
|
|
26534
|
-
version: "0.
|
|
26657
|
+
version: "0.5.1",
|
|
26535
26658
|
description: "AI workflow benchmarking CLI",
|
|
26536
26659
|
type: "module",
|
|
26537
26660
|
bin: {
|
|
@@ -26539,7 +26662,8 @@ var package_default2 = {
|
|
|
26539
26662
|
nb: "./dist/index.js"
|
|
26540
26663
|
},
|
|
26541
26664
|
files: [
|
|
26542
|
-
"dist"
|
|
26665
|
+
"dist",
|
|
26666
|
+
"postinstall.js"
|
|
26543
26667
|
],
|
|
26544
26668
|
repository: {
|
|
26545
26669
|
type: "git",
|
|
@@ -26567,7 +26691,8 @@ var package_default2 = {
|
|
|
26567
26691
|
"test:e2e": "vitest run tests/e2e/",
|
|
26568
26692
|
"test:watch": "vitest",
|
|
26569
26693
|
clean: "rm -rf dist",
|
|
26570
|
-
prepublishOnly: "bun run build"
|
|
26694
|
+
prepublishOnly: "bun run build",
|
|
26695
|
+
postinstall: "node postinstall.js || true"
|
|
26571
26696
|
},
|
|
26572
26697
|
dependencies: {
|
|
26573
26698
|
"cli-boxes": "^4.0.1",
|
|
@@ -26632,7 +26757,7 @@ var hasVersion = args.includes("--version");
|
|
|
26632
26757
|
if (!hasSubcommand && !hasHelp && !hasVersion && args.length === 0) {
|
|
26633
26758
|
showBanner();
|
|
26634
26759
|
} else {
|
|
26635
|
-
const
|
|
26760
|
+
const cmd = defineCommand({
|
|
26636
26761
|
meta: {
|
|
26637
26762
|
name: "nairon-bench",
|
|
26638
26763
|
version: VERSION2,
|
|
@@ -26650,5 +26775,5 @@ if (!hasSubcommand && !hasHelp && !hasVersion && args.length === 0) {
|
|
|
26650
26775
|
cache: cacheCommand
|
|
26651
26776
|
}
|
|
26652
26777
|
});
|
|
26653
|
-
runMain(
|
|
26778
|
+
runMain(cmd);
|
|
26654
26779
|
}
|