nairon-bench 0.0.39 → 0.1.0
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 +1068 -29
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -14181,6 +14181,11 @@ var scanCommand = defineCommand2({
|
|
|
14181
14181
|
description: "Disable session caching (slower but ensures fresh data)",
|
|
14182
14182
|
default: false
|
|
14183
14183
|
},
|
|
14184
|
+
"no-recommend": {
|
|
14185
|
+
type: "boolean",
|
|
14186
|
+
description: "Skip showing recommendations after scan",
|
|
14187
|
+
default: false
|
|
14188
|
+
},
|
|
14184
14189
|
watch: {
|
|
14185
14190
|
type: "boolean",
|
|
14186
14191
|
alias: "w",
|
|
@@ -14360,6 +14365,9 @@ var scanCommand = defineCommand2({
|
|
|
14360
14365
|
const reportPath = generateReport(reportDir, score, git, agents, tests, args.since, sdlcAnalysis, scanCost, analysis);
|
|
14361
14366
|
console.log(` ${icons.success} Report saved: ${colors2.dim(reportPath)}`);
|
|
14362
14367
|
}
|
|
14368
|
+
if (!args["no-recommend"]) {
|
|
14369
|
+
await showQuickRecommendations(analysis, agents, tests, projectDir);
|
|
14370
|
+
}
|
|
14363
14371
|
}
|
|
14364
14372
|
if (args.offline) {
|
|
14365
14373
|
if (!silent) {
|
|
@@ -14656,6 +14664,67 @@ function formatTokensPlain(tokens) {
|
|
|
14656
14664
|
return `${Math.round(tokens / 1000)}K`;
|
|
14657
14665
|
return tokens.toString();
|
|
14658
14666
|
}
|
|
14667
|
+
async function showQuickRecommendations(analysis, agents, tests, projectDir) {
|
|
14668
|
+
const suggestions = [];
|
|
14669
|
+
if (analysis.sessionPatterns.memoryLossCount > 2 || analysis.sessionPatterns.contextCompactions > 3) {
|
|
14670
|
+
suggestions.push({
|
|
14671
|
+
icon: "\uD83E\uDDE0",
|
|
14672
|
+
text: "Frequent context loss detected",
|
|
14673
|
+
tool: "Supermemory"
|
|
14674
|
+
});
|
|
14675
|
+
}
|
|
14676
|
+
if (!analysis.environment.hasContext7 && analysis.sessionPatterns.toolFailures > 2) {
|
|
14677
|
+
suggestions.push({
|
|
14678
|
+
icon: "\uD83D\uDCDA",
|
|
14679
|
+
text: "API hallucinations likely",
|
|
14680
|
+
tool: "Context7"
|
|
14681
|
+
});
|
|
14682
|
+
}
|
|
14683
|
+
if (!tests || tests.totalTests === 0) {
|
|
14684
|
+
suggestions.push({
|
|
14685
|
+
icon: "\uD83E\uDDEA",
|
|
14686
|
+
text: "No tests detected",
|
|
14687
|
+
tool: "Agentic TDD workflow"
|
|
14688
|
+
});
|
|
14689
|
+
}
|
|
14690
|
+
if (analysis.sessionPatterns.longBackForth > 2) {
|
|
14691
|
+
suggestions.push({
|
|
14692
|
+
icon: "\uD83D\uDCAC",
|
|
14693
|
+
text: "Excessive back-and-forth in sessions",
|
|
14694
|
+
tool: "Skills/structured prompts"
|
|
14695
|
+
});
|
|
14696
|
+
}
|
|
14697
|
+
if (!analysis.environment.hasBeads && agents && agents.totalSessions > 5) {
|
|
14698
|
+
suggestions.push({
|
|
14699
|
+
icon: "\uD83D\uDCCB",
|
|
14700
|
+
text: "No persistent task tracking",
|
|
14701
|
+
tool: "Beads"
|
|
14702
|
+
});
|
|
14703
|
+
}
|
|
14704
|
+
if (analysis.efficiency.tokensWastedWeekly > 50000) {
|
|
14705
|
+
suggestions.push({
|
|
14706
|
+
icon: "\uD83D\uDCB0",
|
|
14707
|
+
text: `~${formatTokensPlain(analysis.efficiency.tokensWastedWeekly)} tokens wasted/week`,
|
|
14708
|
+
tool: "Token optimization"
|
|
14709
|
+
});
|
|
14710
|
+
}
|
|
14711
|
+
if (suggestions.length === 0) {
|
|
14712
|
+
return;
|
|
14713
|
+
}
|
|
14714
|
+
const toShow = suggestions.slice(0, 3);
|
|
14715
|
+
console.log();
|
|
14716
|
+
console.log(` ${colors2.bold(colors2.primary("Quick Recommendations"))}`);
|
|
14717
|
+
console.log(colors2.dim(" " + "─".repeat(40)));
|
|
14718
|
+
console.log();
|
|
14719
|
+
for (const suggestion of toShow) {
|
|
14720
|
+
const toolHint = suggestion.tool ? colors2.success(` → ${suggestion.tool}`) : "";
|
|
14721
|
+
console.log(` ${suggestion.icon} ${suggestion.text}${toolHint}`);
|
|
14722
|
+
await sleep(100);
|
|
14723
|
+
}
|
|
14724
|
+
console.log();
|
|
14725
|
+
console.log(` ${colors2.dim(`Run ${colors2.primary("nb recommend")} for personalized tool suggestions`)}`);
|
|
14726
|
+
console.log(` ${colors2.dim(`Use ${colors2.primary("nb scan --no-recommend")} to skip this`)}`);
|
|
14727
|
+
}
|
|
14659
14728
|
|
|
14660
14729
|
// src/commands/report.ts
|
|
14661
14730
|
init_dist();
|
|
@@ -19719,6 +19788,30 @@ async function runHackathonReport(args) {
|
|
|
19719
19788
|
consola.start(`Generating AI-nativeness report for ${harnessLabel} (last ${hoursAgo} hours)...`);
|
|
19720
19789
|
try {
|
|
19721
19790
|
const report = await generateHackathonReport(projectDir, since, until, harness);
|
|
19791
|
+
if (report.summary.totalSessions === 0 && harness && harness !== "all") {
|
|
19792
|
+
consola.warn(`No sessions found for harness "${harness}".`);
|
|
19793
|
+
consola.info(`Try running with --harness all to include sessions from all AI tools.`);
|
|
19794
|
+
consola.info(`Or check that your AI tool's session logs exist in the expected location.`);
|
|
19795
|
+
const allReport = await generateHackathonReport(projectDir, since, until, "all");
|
|
19796
|
+
if (allReport.summary.totalSessions > 0) {
|
|
19797
|
+
consola.info(`Found ${allReport.summary.totalSessions} sessions from other harnesses.`);
|
|
19798
|
+
const useAll = await consola.prompt("Use all sessions instead?", {
|
|
19799
|
+
type: "confirm",
|
|
19800
|
+
initial: true
|
|
19801
|
+
});
|
|
19802
|
+
if (useAll) {
|
|
19803
|
+
const newReport = allReport;
|
|
19804
|
+
if (args.publish) {
|
|
19805
|
+
await publishReport(newReport);
|
|
19806
|
+
return;
|
|
19807
|
+
}
|
|
19808
|
+
const format3 = args.format || "terminal";
|
|
19809
|
+
const output2 = format3 === "md" || format3 === "markdown" ? formatReportAsMarkdown(newReport) : format3 === "json" ? formatReportAsJSON(newReport) : formatReportAsTerminal(newReport);
|
|
19810
|
+
console.log(output2);
|
|
19811
|
+
return;
|
|
19812
|
+
}
|
|
19813
|
+
}
|
|
19814
|
+
}
|
|
19722
19815
|
if (args.publish) {
|
|
19723
19816
|
await publishReport(report);
|
|
19724
19817
|
return;
|
|
@@ -19764,6 +19857,21 @@ async function publishReport(report) {
|
|
|
19764
19857
|
consola.info("Alternatively, use `nb report --hackathon --format md` for local markdown.");
|
|
19765
19858
|
return;
|
|
19766
19859
|
}
|
|
19860
|
+
if (report.summary.totalSessions === 0) {
|
|
19861
|
+
consola.warn("Publishing report with 0 sessions detected.");
|
|
19862
|
+
consola.info("This may result in incomplete data. Common causes:");
|
|
19863
|
+
consola.info(" - Selected harness doesn't match your AI tool");
|
|
19864
|
+
consola.info(" - Session logs not found in expected location");
|
|
19865
|
+
consola.info(" - Time range doesn't include recent sessions");
|
|
19866
|
+
const proceed = await consola.prompt("Continue publishing anyway?", {
|
|
19867
|
+
type: "confirm",
|
|
19868
|
+
initial: false
|
|
19869
|
+
});
|
|
19870
|
+
if (!proceed) {
|
|
19871
|
+
consola.info("Aborted. Try running with --harness all");
|
|
19872
|
+
return;
|
|
19873
|
+
}
|
|
19874
|
+
}
|
|
19767
19875
|
consola.start("Publishing report...");
|
|
19768
19876
|
const markdownContent = formatReportAsMarkdown(report);
|
|
19769
19877
|
const basePayload = {
|
|
@@ -23590,10 +23698,937 @@ var setupCommand = defineCommand2({
|
|
|
23590
23698
|
}
|
|
23591
23699
|
}
|
|
23592
23700
|
});
|
|
23701
|
+
|
|
23702
|
+
// src/commands/onboard.ts
|
|
23703
|
+
init_dist();
|
|
23704
|
+
init_client();
|
|
23705
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync5, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "node:fs";
|
|
23706
|
+
import { join as join15, basename as basename5 } from "node:path";
|
|
23707
|
+
var TECH_PATTERNS = {
|
|
23708
|
+
typescript: ["tsconfig.json", "*.ts", "*.tsx"],
|
|
23709
|
+
javascript: ["*.js", "*.jsx", "*.mjs"],
|
|
23710
|
+
python: ["*.py", "requirements.txt", "pyproject.toml", "setup.py"],
|
|
23711
|
+
rust: ["Cargo.toml", "*.rs"],
|
|
23712
|
+
go: ["go.mod", "*.go"],
|
|
23713
|
+
nextjs: ["next.config.js", "next.config.ts", "next.config.mjs"],
|
|
23714
|
+
react: ["package.json:react"],
|
|
23715
|
+
vue: ["vue.config.js", "nuxt.config.ts", "package.json:vue"],
|
|
23716
|
+
svelte: ["svelte.config.js", "package.json:svelte"],
|
|
23717
|
+
astro: ["astro.config.mjs", "astro.config.ts"],
|
|
23718
|
+
express: ["package.json:express"],
|
|
23719
|
+
fastify: ["package.json:fastify"],
|
|
23720
|
+
hono: ["package.json:hono"],
|
|
23721
|
+
django: ["manage.py", "settings.py"],
|
|
23722
|
+
flask: ["app.py:Flask"],
|
|
23723
|
+
prisma: ["prisma/schema.prisma"],
|
|
23724
|
+
drizzle: ["drizzle.config.ts"],
|
|
23725
|
+
convex: ["convex/"],
|
|
23726
|
+
supabase: [".supabase/", "supabase/"],
|
|
23727
|
+
vitest: ["vitest.config.ts", "vitest.config.js"],
|
|
23728
|
+
jest: ["jest.config.ts", "jest.config.js"],
|
|
23729
|
+
playwright: ["playwright.config.ts"],
|
|
23730
|
+
langchain: ["package.json:langchain", "requirements.txt:langchain"],
|
|
23731
|
+
openai: ["package.json:openai", "requirements.txt:openai"],
|
|
23732
|
+
anthropic: ["package.json:@anthropic-ai"]
|
|
23733
|
+
};
|
|
23734
|
+
var PROJECT_TYPES = {
|
|
23735
|
+
"Web App": ["nextjs", "react", "vue", "svelte", "astro"],
|
|
23736
|
+
"API/Backend": ["express", "fastify", "hono", "django", "flask"],
|
|
23737
|
+
"CLI Tool": ["citty", "commander", "yargs"],
|
|
23738
|
+
Library: ["tsup", "rollup", "esbuild"],
|
|
23739
|
+
"Mobile App": ["react-native", "expo"],
|
|
23740
|
+
"AI/ML": ["langchain", "openai", "anthropic"]
|
|
23741
|
+
};
|
|
23742
|
+
var onboardCommand = defineCommand2({
|
|
23743
|
+
meta: {
|
|
23744
|
+
name: "onboard",
|
|
23745
|
+
description: "Set up project context for personalized AI workflow recommendations"
|
|
23746
|
+
},
|
|
23747
|
+
args: {
|
|
23748
|
+
force: {
|
|
23749
|
+
type: "boolean",
|
|
23750
|
+
description: "Re-run onboarding even if already configured",
|
|
23751
|
+
default: false
|
|
23752
|
+
}
|
|
23753
|
+
},
|
|
23754
|
+
async run({ args }) {
|
|
23755
|
+
const projectPath = process.cwd();
|
|
23756
|
+
const contextPath = join15(projectPath, ".nairon", "context.json");
|
|
23757
|
+
if (existsSync15(contextPath) && !args.force) {
|
|
23758
|
+
const existing = JSON.parse(readFileSync12(contextPath, "utf-8"));
|
|
23759
|
+
consola.info("Project already onboarded. Use --force to re-run.");
|
|
23760
|
+
consola.info(`Business: ${existing.businessContext?.slice(0, 50)}...`);
|
|
23761
|
+
consola.info(`Stack: ${existing.techStack?.join(", ")}`);
|
|
23762
|
+
return;
|
|
23763
|
+
}
|
|
23764
|
+
consola.log("");
|
|
23765
|
+
consola.box({
|
|
23766
|
+
title: "Project Onboarding",
|
|
23767
|
+
message: [
|
|
23768
|
+
"Let's set up your project context for personalized recommendations.",
|
|
23769
|
+
"",
|
|
23770
|
+
"This helps Nairon Bench suggest tools and workflows",
|
|
23771
|
+
"that are specifically relevant to YOUR project."
|
|
23772
|
+
].join(`
|
|
23773
|
+
`)
|
|
23774
|
+
});
|
|
23775
|
+
consola.log("");
|
|
23776
|
+
consola.start("Step 1/4: Detecting tech stack...");
|
|
23777
|
+
const { techStack, languages } = detectTechStack(projectPath);
|
|
23778
|
+
const projectType = detectProjectType(techStack);
|
|
23779
|
+
consola.success(`Detected: ${techStack.slice(0, 5).join(", ")}${techStack.length > 5 ? ` +${techStack.length - 5} more` : ""}`);
|
|
23780
|
+
consola.info(`Project type: ${projectType}`);
|
|
23781
|
+
const confirmStack = await consola.prompt("Is this correct?", {
|
|
23782
|
+
type: "confirm",
|
|
23783
|
+
initial: true
|
|
23784
|
+
});
|
|
23785
|
+
let finalStack = techStack;
|
|
23786
|
+
if (confirmStack === false) {
|
|
23787
|
+
const stackInput = await consola.prompt("Enter your tech stack (comma-separated):", {
|
|
23788
|
+
type: "text",
|
|
23789
|
+
default: techStack.join(", ")
|
|
23790
|
+
});
|
|
23791
|
+
if (typeof stackInput === "string") {
|
|
23792
|
+
finalStack = stackInput.split(",").map((s2) => s2.trim()).filter(Boolean);
|
|
23793
|
+
}
|
|
23794
|
+
}
|
|
23795
|
+
consola.log("");
|
|
23796
|
+
consola.info("Step 2/4: Tell us about your project");
|
|
23797
|
+
const businessContext = await consola.prompt("What are you building? (e.g., 'B2B SaaS for invoice automation', 'Personal blog with AI features')", {
|
|
23798
|
+
type: "text",
|
|
23799
|
+
placeholder: "Describe your project in 1-2 sentences"
|
|
23800
|
+
});
|
|
23801
|
+
if (typeof businessContext === "symbol" || !businessContext) {
|
|
23802
|
+
consola.warn("Onboarding cancelled.");
|
|
23803
|
+
return;
|
|
23804
|
+
}
|
|
23805
|
+
const targetUsers = await consola.prompt("Who are your target users? (e.g., 'SMB accountants', 'Developers', 'General consumers')", {
|
|
23806
|
+
type: "text",
|
|
23807
|
+
placeholder: "Describe your target audience"
|
|
23808
|
+
});
|
|
23809
|
+
if (typeof targetUsers === "symbol" || !targetUsers) {
|
|
23810
|
+
consola.warn("Onboarding cancelled.");
|
|
23811
|
+
return;
|
|
23812
|
+
}
|
|
23813
|
+
consola.log("");
|
|
23814
|
+
consola.info("Step 3/4: What are your biggest workflow challenges?");
|
|
23815
|
+
const painPointOptions = [
|
|
23816
|
+
{ label: "Finding the right context/docs for AI", value: "context" },
|
|
23817
|
+
{ label: "Long sessions that lose context", value: "session_length" },
|
|
23818
|
+
{ label: "AI hallucinations / wrong code", value: "hallucinations" },
|
|
23819
|
+
{ label: "Testing and debugging AI-generated code", value: "testing" },
|
|
23820
|
+
{ label: "Prompt engineering / getting good outputs", value: "prompting" },
|
|
23821
|
+
{ label: "Managing multiple AI tools", value: "tool_management" },
|
|
23822
|
+
{ label: "Cost management / token efficiency", value: "cost" }
|
|
23823
|
+
];
|
|
23824
|
+
const selectedPainPoints = await consola.prompt("Select your top challenges:", {
|
|
23825
|
+
type: "multiselect",
|
|
23826
|
+
options: painPointOptions
|
|
23827
|
+
});
|
|
23828
|
+
const painPoints = Array.isArray(selectedPainPoints) ? selectedPainPoints.map((p) => typeof p === "string" ? p : p.value) : [];
|
|
23829
|
+
consola.log("");
|
|
23830
|
+
consola.start("Step 4/4: Detecting installed AI tools...");
|
|
23831
|
+
const installedTools = detectInstalledTools(projectPath);
|
|
23832
|
+
consola.success(`Found: ${installedTools.length > 0 ? installedTools.join(", ") : "None detected"}`);
|
|
23833
|
+
const context = {
|
|
23834
|
+
projectPath,
|
|
23835
|
+
projectName: basename5(projectPath),
|
|
23836
|
+
businessContext,
|
|
23837
|
+
targetUsers,
|
|
23838
|
+
techStack: finalStack,
|
|
23839
|
+
detectedLanguages: languages,
|
|
23840
|
+
painPoints,
|
|
23841
|
+
installedTools,
|
|
23842
|
+
primaryAgent: detectPrimaryAgent(),
|
|
23843
|
+
createdAt: new Date().toISOString(),
|
|
23844
|
+
updatedAt: new Date().toISOString()
|
|
23845
|
+
};
|
|
23846
|
+
const naironDir = join15(projectPath, ".nairon");
|
|
23847
|
+
if (!existsSync15(naironDir)) {
|
|
23848
|
+
mkdirSync5(naironDir, { recursive: true });
|
|
23849
|
+
}
|
|
23850
|
+
writeFileSync7(contextPath, JSON.stringify(context, null, 2));
|
|
23851
|
+
consola.success(`Saved to ${contextPath}`);
|
|
23852
|
+
const client = getClient();
|
|
23853
|
+
const config = getConfig();
|
|
23854
|
+
if (client) {
|
|
23855
|
+
consola.start("Syncing to cloud...");
|
|
23856
|
+
try {
|
|
23857
|
+
await client.mutation(api.nightcrawler.saveProjectContext, {
|
|
23858
|
+
projectPath,
|
|
23859
|
+
businessContext: context.businessContext,
|
|
23860
|
+
targetUsers: context.targetUsers,
|
|
23861
|
+
techStack: context.techStack,
|
|
23862
|
+
detectedLanguages: context.detectedLanguages,
|
|
23863
|
+
painPoints: context.painPoints,
|
|
23864
|
+
installedTools: context.installedTools,
|
|
23865
|
+
...context.primaryAgent ? { primaryAgent: context.primaryAgent } : {}
|
|
23866
|
+
});
|
|
23867
|
+
consola.success("Project context synced to cloud");
|
|
23868
|
+
} catch (err) {
|
|
23869
|
+
consola.warn(`Cloud sync failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
23870
|
+
}
|
|
23871
|
+
}
|
|
23872
|
+
const recommendations = getQuickRecommendations(context);
|
|
23873
|
+
consola.log("");
|
|
23874
|
+
consola.box({
|
|
23875
|
+
title: "Onboarding Complete!",
|
|
23876
|
+
message: [
|
|
23877
|
+
`Project: ${context.projectName}`,
|
|
23878
|
+
`Type: ${projectType}`,
|
|
23879
|
+
`Stack: ${finalStack.slice(0, 4).join(", ")}`,
|
|
23880
|
+
`Pain points: ${painPoints.length} identified`,
|
|
23881
|
+
"",
|
|
23882
|
+
"Quick recommendations based on your profile:",
|
|
23883
|
+
...recommendations.map((r3) => ` ${r3.icon} ${r3.title}`),
|
|
23884
|
+
"",
|
|
23885
|
+
"Run 'nb recommend' for detailed suggestions",
|
|
23886
|
+
"Run 'nb trending' to see what's hot in the community"
|
|
23887
|
+
].join(`
|
|
23888
|
+
`)
|
|
23889
|
+
});
|
|
23890
|
+
}
|
|
23891
|
+
});
|
|
23892
|
+
function detectTechStack(projectPath) {
|
|
23893
|
+
const techStack = [];
|
|
23894
|
+
const languages = [];
|
|
23895
|
+
const pkgPath = join15(projectPath, "package.json");
|
|
23896
|
+
let pkgJson = {};
|
|
23897
|
+
if (existsSync15(pkgPath)) {
|
|
23898
|
+
try {
|
|
23899
|
+
pkgJson = JSON.parse(readFileSync12(pkgPath, "utf-8"));
|
|
23900
|
+
} catch {}
|
|
23901
|
+
}
|
|
23902
|
+
const allDeps = {
|
|
23903
|
+
...pkgJson.dependencies,
|
|
23904
|
+
...pkgJson.devDependencies
|
|
23905
|
+
};
|
|
23906
|
+
for (const [tech, patterns] of Object.entries(TECH_PATTERNS)) {
|
|
23907
|
+
for (const pattern of patterns) {
|
|
23908
|
+
if (pattern.startsWith("package.json:")) {
|
|
23909
|
+
const dep = pattern.replace("package.json:", "");
|
|
23910
|
+
if (allDeps[dep]) {
|
|
23911
|
+
techStack.push(tech);
|
|
23912
|
+
break;
|
|
23913
|
+
}
|
|
23914
|
+
} else if (pattern.includes("/")) {
|
|
23915
|
+
if (existsSync15(join15(projectPath, pattern))) {
|
|
23916
|
+
techStack.push(tech);
|
|
23917
|
+
break;
|
|
23918
|
+
}
|
|
23919
|
+
} else if (!pattern.includes("*")) {
|
|
23920
|
+
if (existsSync15(join15(projectPath, pattern))) {
|
|
23921
|
+
techStack.push(tech);
|
|
23922
|
+
break;
|
|
23923
|
+
}
|
|
23924
|
+
}
|
|
23925
|
+
}
|
|
23926
|
+
}
|
|
23927
|
+
if (techStack.includes("typescript") || existsSync15(join15(projectPath, "tsconfig.json"))) {
|
|
23928
|
+
languages.push("TypeScript");
|
|
23929
|
+
}
|
|
23930
|
+
if (techStack.includes("javascript") || pkgJson.name) {
|
|
23931
|
+
languages.push("JavaScript");
|
|
23932
|
+
}
|
|
23933
|
+
if (techStack.includes("python") || existsSync15(join15(projectPath, "requirements.txt"))) {
|
|
23934
|
+
languages.push("Python");
|
|
23935
|
+
}
|
|
23936
|
+
if (techStack.includes("rust"))
|
|
23937
|
+
languages.push("Rust");
|
|
23938
|
+
if (techStack.includes("go"))
|
|
23939
|
+
languages.push("Go");
|
|
23940
|
+
return { techStack, languages };
|
|
23941
|
+
}
|
|
23942
|
+
function detectProjectType(techStack) {
|
|
23943
|
+
for (const [type, techs] of Object.entries(PROJECT_TYPES)) {
|
|
23944
|
+
if (techs.some((t2) => techStack.includes(t2))) {
|
|
23945
|
+
return type;
|
|
23946
|
+
}
|
|
23947
|
+
}
|
|
23948
|
+
return "General";
|
|
23949
|
+
}
|
|
23950
|
+
function detectInstalledTools(projectPath) {
|
|
23951
|
+
const tools = [];
|
|
23952
|
+
const home = process.env.HOME || "";
|
|
23953
|
+
const claudeConfigPath = join15(home, ".claude", "claude_desktop_config.json");
|
|
23954
|
+
if (existsSync15(claudeConfigPath)) {
|
|
23955
|
+
try {
|
|
23956
|
+
const config = JSON.parse(readFileSync12(claudeConfigPath, "utf-8"));
|
|
23957
|
+
if (config.mcpServers) {
|
|
23958
|
+
tools.push(...Object.keys(config.mcpServers));
|
|
23959
|
+
}
|
|
23960
|
+
} catch {}
|
|
23961
|
+
}
|
|
23962
|
+
const projectClaudeConfig = join15(projectPath, ".claude", "settings.json");
|
|
23963
|
+
if (existsSync15(projectClaudeConfig)) {
|
|
23964
|
+
try {
|
|
23965
|
+
const config = JSON.parse(readFileSync12(projectClaudeConfig, "utf-8"));
|
|
23966
|
+
if (config.mcpServers) {
|
|
23967
|
+
tools.push(...Object.keys(config.mcpServers));
|
|
23968
|
+
}
|
|
23969
|
+
} catch {}
|
|
23970
|
+
}
|
|
23971
|
+
const skillsDir = join15(home, ".claude", "skills");
|
|
23972
|
+
if (existsSync15(skillsDir)) {
|
|
23973
|
+
try {
|
|
23974
|
+
const { readdirSync: readdirSync8 } = __require("fs");
|
|
23975
|
+
const skills = readdirSync8(skillsDir);
|
|
23976
|
+
tools.push(...skills.filter((s2) => !s2.startsWith(".")));
|
|
23977
|
+
} catch {}
|
|
23978
|
+
}
|
|
23979
|
+
return [...new Set(tools)];
|
|
23980
|
+
}
|
|
23981
|
+
function detectPrimaryAgent() {
|
|
23982
|
+
const home = process.env.HOME || "";
|
|
23983
|
+
if (existsSync15(join15(home, ".claude")))
|
|
23984
|
+
return "claude-code";
|
|
23985
|
+
if (existsSync15(join15(home, ".cursor")))
|
|
23986
|
+
return "cursor";
|
|
23987
|
+
if (existsSync15(join15(home, ".config", "opencode")))
|
|
23988
|
+
return "opencode";
|
|
23989
|
+
return;
|
|
23990
|
+
}
|
|
23991
|
+
function getQuickRecommendations(context) {
|
|
23992
|
+
const recs = [];
|
|
23993
|
+
if (context.painPoints.includes("context") && !context.installedTools.includes("context7")) {
|
|
23994
|
+
recs.push({ icon: "\uD83D\uDCDA", title: "Context7 MCP - Better library docs in context" });
|
|
23995
|
+
}
|
|
23996
|
+
if (context.painPoints.includes("session_length") && !context.installedTools.includes("supermemory")) {
|
|
23997
|
+
recs.push({ icon: "\uD83E\uDDE0", title: "Supermemory - Persistent memory across sessions" });
|
|
23998
|
+
}
|
|
23999
|
+
if (context.painPoints.includes("testing")) {
|
|
24000
|
+
recs.push({ icon: "\uD83E\uDDEA", title: "Agentic TDD workflow - AI-assisted test-driven dev" });
|
|
24001
|
+
}
|
|
24002
|
+
if (context.painPoints.includes("cost")) {
|
|
24003
|
+
recs.push({ icon: "\uD83D\uDCB0", title: "OpenRouter - Route to cheapest model per task" });
|
|
24004
|
+
}
|
|
24005
|
+
if (context.painPoints.includes("prompting")) {
|
|
24006
|
+
recs.push({ icon: "✨", title: "Structured prompting patterns from community" });
|
|
24007
|
+
}
|
|
24008
|
+
if (recs.length === 0) {
|
|
24009
|
+
recs.push({ icon: "\uD83D\uDD25", title: "Run 'nb trending' to see what's hot" });
|
|
24010
|
+
}
|
|
24011
|
+
return recs.slice(0, 3);
|
|
24012
|
+
}
|
|
24013
|
+
|
|
24014
|
+
// src/commands/trending.ts
|
|
24015
|
+
init_dist();
|
|
24016
|
+
init_client();
|
|
24017
|
+
var CYAN = "\x1B[36m";
|
|
24018
|
+
var YELLOW = "\x1B[33m";
|
|
24019
|
+
var GREEN = "\x1B[32m";
|
|
24020
|
+
var DIM = "\x1B[2m";
|
|
24021
|
+
var BOLD = "\x1B[1m";
|
|
24022
|
+
var RESET = "\x1B[0m";
|
|
24023
|
+
var MAGENTA = "\x1B[35m";
|
|
24024
|
+
var CATEGORY_ICONS = {
|
|
24025
|
+
announcement: "\uD83D\uDCE2",
|
|
24026
|
+
launch: "\uD83D\uDE80",
|
|
24027
|
+
usage_pattern: "\uD83D\uDCA1",
|
|
24028
|
+
tutorial: "\uD83D\uDCFA",
|
|
24029
|
+
tip: "⚡"
|
|
24030
|
+
};
|
|
24031
|
+
var CATEGORY_LABELS = {
|
|
24032
|
+
announcement: "ANNOUNCEMENTS",
|
|
24033
|
+
launch: "LAUNCHES",
|
|
24034
|
+
usage_pattern: "WORKFLOWS",
|
|
24035
|
+
tutorial: "TUTORIALS",
|
|
24036
|
+
tip: "TIPS"
|
|
24037
|
+
};
|
|
24038
|
+
var trendingCommand = defineCommand2({
|
|
24039
|
+
meta: {
|
|
24040
|
+
name: "trending",
|
|
24041
|
+
description: "See what's hot in the AI dev tools community"
|
|
24042
|
+
},
|
|
24043
|
+
args: {
|
|
24044
|
+
days: {
|
|
24045
|
+
type: "string",
|
|
24046
|
+
description: "Time range (1, 7, 30)",
|
|
24047
|
+
default: "7"
|
|
24048
|
+
},
|
|
24049
|
+
category: {
|
|
24050
|
+
type: "string",
|
|
24051
|
+
description: "Filter by category (announcement, launch, usage_pattern, tutorial, tip)"
|
|
24052
|
+
},
|
|
24053
|
+
limit: {
|
|
24054
|
+
type: "string",
|
|
24055
|
+
description: "Max results per category",
|
|
24056
|
+
default: "5"
|
|
24057
|
+
},
|
|
24058
|
+
tools: {
|
|
24059
|
+
type: "boolean",
|
|
24060
|
+
description: "Show top tools only",
|
|
24061
|
+
default: false
|
|
24062
|
+
}
|
|
24063
|
+
},
|
|
24064
|
+
async run({ args }) {
|
|
24065
|
+
const client = getClient();
|
|
24066
|
+
if (!client) {
|
|
24067
|
+
consola.error("Not connected to cloud. Run 'nb doctor' to check connection.");
|
|
24068
|
+
return;
|
|
24069
|
+
}
|
|
24070
|
+
const days = parseInt(args.days) || 7;
|
|
24071
|
+
const limit = parseInt(args.limit) || 5;
|
|
24072
|
+
consola.log("");
|
|
24073
|
+
console.log(`${YELLOW}\uD83D\uDD25 Hot Topics — Last ${days} Day${days > 1 ? "s" : ""}${RESET}`);
|
|
24074
|
+
console.log(`${DIM}${"─".repeat(50)}${RESET}`);
|
|
24075
|
+
try {
|
|
24076
|
+
if (args.tools) {
|
|
24077
|
+
await showTopTools(client, days, limit * 2);
|
|
24078
|
+
return;
|
|
24079
|
+
}
|
|
24080
|
+
const insights = await client.query(api.nightcrawler.getRecentInsights, {
|
|
24081
|
+
limit: 50,
|
|
24082
|
+
maxHypeScore: 70,
|
|
24083
|
+
...args.category ? { category: args.category } : {}
|
|
24084
|
+
});
|
|
24085
|
+
if (insights.length === 0) {
|
|
24086
|
+
consola.log("");
|
|
24087
|
+
consola.warn("No trending insights found. The Nightcrawler may not have run yet.");
|
|
24088
|
+
consola.info("Run the Nightcrawler manually or wait for the scheduled job.");
|
|
24089
|
+
showFallbackMessage();
|
|
24090
|
+
return;
|
|
24091
|
+
}
|
|
24092
|
+
const byCategory = {};
|
|
24093
|
+
for (const insight of insights) {
|
|
24094
|
+
const cat = insight.category;
|
|
24095
|
+
if (!byCategory[cat]) {
|
|
24096
|
+
byCategory[cat] = [];
|
|
24097
|
+
}
|
|
24098
|
+
byCategory[cat].push(insight);
|
|
24099
|
+
}
|
|
24100
|
+
const categoryOrder = ["announcement", "launch", "usage_pattern", "tutorial", "tip"];
|
|
24101
|
+
for (const category of categoryOrder) {
|
|
24102
|
+
const categoryInsights = byCategory[category];
|
|
24103
|
+
if (!categoryInsights || categoryInsights.length === 0)
|
|
24104
|
+
continue;
|
|
24105
|
+
const icon = CATEGORY_ICONS[category] || "\uD83D\uDCCC";
|
|
24106
|
+
const label = CATEGORY_LABELS[category] || category.toUpperCase();
|
|
24107
|
+
consola.log("");
|
|
24108
|
+
console.log(`${BOLD}${icon} ${label}${RESET}`);
|
|
24109
|
+
for (const insight of categoryInsights.slice(0, limit)) {
|
|
24110
|
+
const likes = formatNumber2(insight.engagement.likes);
|
|
24111
|
+
const hasVideo = insight.hasVideo ? `${MAGENTA}▶${RESET} ` : "";
|
|
24112
|
+
const tools = insight.toolsMentioned.length > 0 ? `${DIM}[${insight.toolsMentioned.slice(0, 2).join(", ")}]${RESET}` : "";
|
|
24113
|
+
console.log(`${DIM}├─${RESET} ${hasVideo}${insight.keyInsight.slice(0, 60)}${insight.keyInsight.length > 60 ? "..." : ""}`);
|
|
24114
|
+
console.log(`${DIM}│ ${RESET}${GREEN}${likes}❤${RESET} @${insight.authorHandle} ${tools}`);
|
|
24115
|
+
}
|
|
24116
|
+
console.log(`${DIM}└─${RESET}`);
|
|
24117
|
+
}
|
|
24118
|
+
consola.log("");
|
|
24119
|
+
await showTopTools(client, days, 5);
|
|
24120
|
+
consola.log("");
|
|
24121
|
+
console.log(`${DIM}Run 'nb trending --tools' for detailed tool rankings${RESET}`);
|
|
24122
|
+
console.log(`${DIM}Run 'nb recommend' for personalized suggestions${RESET}`);
|
|
24123
|
+
} catch (err) {
|
|
24124
|
+
consola.error(`Failed to fetch trending: ${err instanceof Error ? err.message : String(err)}`);
|
|
24125
|
+
showFallbackMessage();
|
|
24126
|
+
}
|
|
24127
|
+
}
|
|
24128
|
+
});
|
|
24129
|
+
async function showTopTools(client, days, limit) {
|
|
24130
|
+
try {
|
|
24131
|
+
const trending = await client.query(api.nightcrawler.getTrendingTools, {
|
|
24132
|
+
days,
|
|
24133
|
+
limit
|
|
24134
|
+
});
|
|
24135
|
+
if (trending.length === 0) {
|
|
24136
|
+
console.log(`${DIM}No tool data available yet.${RESET}`);
|
|
24137
|
+
return;
|
|
24138
|
+
}
|
|
24139
|
+
console.log(`${BOLD}\uD83D\uDEE0️ TOP TOOLS${RESET}`);
|
|
24140
|
+
for (let i3 = 0;i3 < trending.length; i3++) {
|
|
24141
|
+
const tool = trending[i3];
|
|
24142
|
+
const rank = i3 + 1;
|
|
24143
|
+
const bar = createBar(tool.mentions, trending[0].mentions);
|
|
24144
|
+
const avgLikes = formatNumber2(tool.avgLikes);
|
|
24145
|
+
console.log(`${DIM}${rank}.${RESET} ${CYAN}${tool.tool}${RESET}`);
|
|
24146
|
+
console.log(` ${bar} ${tool.mentions} mentions · ${avgLikes} avg❤`);
|
|
24147
|
+
}
|
|
24148
|
+
} catch (err) {
|
|
24149
|
+
console.log(`${DIM}Could not fetch tool rankings.${RESET}`);
|
|
24150
|
+
}
|
|
24151
|
+
}
|
|
24152
|
+
function showFallbackMessage() {
|
|
24153
|
+
consola.log("");
|
|
24154
|
+
consola.box({
|
|
24155
|
+
title: "Nightcrawler Not Running",
|
|
24156
|
+
message: [
|
|
24157
|
+
"The trending data comes from the Nightcrawler background job",
|
|
24158
|
+
"which scrapes X/Twitter for high-engagement dev tool posts.",
|
|
24159
|
+
"",
|
|
24160
|
+
"To populate data manually, run:",
|
|
24161
|
+
" cd skills/x-research",
|
|
24162
|
+
' bun run x-search.ts search "MCP server" --quick',
|
|
24163
|
+
"",
|
|
24164
|
+
"Or wait for the scheduled Nightcrawler job."
|
|
24165
|
+
].join(`
|
|
24166
|
+
`)
|
|
24167
|
+
});
|
|
24168
|
+
}
|
|
24169
|
+
function formatNumber2(num) {
|
|
24170
|
+
if (num >= 1e6)
|
|
24171
|
+
return `${(num / 1e6).toFixed(1)}M`;
|
|
24172
|
+
if (num >= 1000)
|
|
24173
|
+
return `${(num / 1000).toFixed(1)}K`;
|
|
24174
|
+
return num.toString();
|
|
24175
|
+
}
|
|
24176
|
+
function createBar(value, max, width = 15) {
|
|
24177
|
+
const filled = Math.round(value / max * width);
|
|
24178
|
+
const empty = width - filled;
|
|
24179
|
+
return `${GREEN}${"█".repeat(filled)}${RESET}${DIM}${"░".repeat(empty)}${RESET}`;
|
|
24180
|
+
}
|
|
24181
|
+
|
|
24182
|
+
// src/commands/recommend.ts
|
|
24183
|
+
init_dist();
|
|
24184
|
+
init_client();
|
|
24185
|
+
import { existsSync as existsSync16, readFileSync as readFileSync13 } from "node:fs";
|
|
24186
|
+
import { join as join16 } from "node:path";
|
|
24187
|
+
var CYAN2 = "\x1B[36m";
|
|
24188
|
+
var YELLOW2 = "\x1B[33m";
|
|
24189
|
+
var GREEN2 = "\x1B[32m";
|
|
24190
|
+
var DIM2 = "\x1B[2m";
|
|
24191
|
+
var BOLD2 = "\x1B[1m";
|
|
24192
|
+
var RESET2 = "\x1B[0m";
|
|
24193
|
+
var MAGENTA2 = "\x1B[35m";
|
|
24194
|
+
var PAIN_POINT_TOOLS = {
|
|
24195
|
+
context: [
|
|
24196
|
+
{ tool: "context7", reason: "Fetches up-to-date library docs directly into AI context", installCmd: "nb tools install context7" },
|
|
24197
|
+
{ tool: "nia", reason: "Index and search external repos, docs, and packages" }
|
|
24198
|
+
],
|
|
24199
|
+
session_length: [
|
|
24200
|
+
{ tool: "supermemory", reason: "Persistent memory across sessions - never lose context", installCmd: "nb tools install supermemory" },
|
|
24201
|
+
{ tool: "beads", reason: "Task tracking that persists between sessions" }
|
|
24202
|
+
],
|
|
24203
|
+
hallucinations: [
|
|
24204
|
+
{ tool: "context7", reason: "Real docs reduce hallucinations by 40%+", installCmd: "nb tools install context7" },
|
|
24205
|
+
{ tool: "repoprompt", reason: "Better context building for accurate code generation" }
|
|
24206
|
+
],
|
|
24207
|
+
testing: [
|
|
24208
|
+
{ tool: "stagehand", reason: "AI-powered E2E testing with Playwright" },
|
|
24209
|
+
{ tool: "agentic-tdd", reason: "Test-driven development workflow for AI coding" }
|
|
24210
|
+
],
|
|
24211
|
+
prompting: [
|
|
24212
|
+
{ tool: "skills", reason: "Pre-built prompt patterns for common tasks" },
|
|
24213
|
+
{ tool: "structured-prompts", reason: "Templates that get better AI outputs" }
|
|
24214
|
+
],
|
|
24215
|
+
tool_management: [
|
|
24216
|
+
{ tool: "oh-my-opencode", reason: "Unified agent harness - one config for all tools" },
|
|
24217
|
+
{ tool: "mcp-installer", reason: "Easy MCP server management" }
|
|
24218
|
+
],
|
|
24219
|
+
cost: [
|
|
24220
|
+
{ tool: "openrouter", reason: "Route to cheapest model per task", installCmd: "nb tools install openrouter" },
|
|
24221
|
+
{ tool: "token-counter", reason: "Track and optimize token usage" }
|
|
24222
|
+
]
|
|
24223
|
+
};
|
|
24224
|
+
var STACK_TOOLS = {
|
|
24225
|
+
nextjs: [{ tool: "vercel-mcp", reason: "Deploy and manage Vercel projects from AI" }],
|
|
24226
|
+
react: [{ tool: "storybook-mcp", reason: "AI-assisted component development" }],
|
|
24227
|
+
typescript: [{ tool: "typescript-mcp", reason: "Better type inference in AI context" }],
|
|
24228
|
+
prisma: [{ tool: "prisma-mcp", reason: "Database schema and queries in AI context" }],
|
|
24229
|
+
convex: [{ tool: "convex-mcp", reason: "Convex functions and schema in AI context" }],
|
|
24230
|
+
python: [{ tool: "python-mcp", reason: "Python environment and packages in AI context" }]
|
|
24231
|
+
};
|
|
24232
|
+
var recommendCommand = defineCommand2({
|
|
24233
|
+
meta: {
|
|
24234
|
+
name: "recommend",
|
|
24235
|
+
description: "Get personalized AI workflow recommendations based on your project"
|
|
24236
|
+
},
|
|
24237
|
+
args: {
|
|
24238
|
+
scan: {
|
|
24239
|
+
type: "boolean",
|
|
24240
|
+
description: "Re-analyze project before recommending",
|
|
24241
|
+
default: false
|
|
24242
|
+
},
|
|
24243
|
+
limit: {
|
|
24244
|
+
type: "string",
|
|
24245
|
+
description: "Max recommendations to show",
|
|
24246
|
+
default: "5"
|
|
24247
|
+
},
|
|
24248
|
+
all: {
|
|
24249
|
+
type: "boolean",
|
|
24250
|
+
description: "Show all recommendations (not just top)",
|
|
24251
|
+
default: false
|
|
24252
|
+
}
|
|
24253
|
+
},
|
|
24254
|
+
async run({ args }) {
|
|
24255
|
+
const projectPath = process.cwd();
|
|
24256
|
+
const contextPath = join16(projectPath, ".nairon", "context.json");
|
|
24257
|
+
const limit = parseInt(args.limit) || 5;
|
|
24258
|
+
consola.log("");
|
|
24259
|
+
console.log(`${YELLOW2}\uD83D\uDCCA Analyzing your project...${RESET2}`);
|
|
24260
|
+
let context = null;
|
|
24261
|
+
if (existsSync16(contextPath)) {
|
|
24262
|
+
try {
|
|
24263
|
+
context = JSON.parse(readFileSync13(contextPath, "utf-8"));
|
|
24264
|
+
console.log(`${DIM2}Loaded context from ${contextPath}${RESET2}`);
|
|
24265
|
+
} catch {}
|
|
24266
|
+
}
|
|
24267
|
+
if (!context) {
|
|
24268
|
+
consola.warn("No project context found. Run 'nb onboard' first for personalized recommendations.");
|
|
24269
|
+
consola.log("");
|
|
24270
|
+
await showGenericRecommendations();
|
|
24271
|
+
return;
|
|
24272
|
+
}
|
|
24273
|
+
const recommendations = [];
|
|
24274
|
+
for (const painPoint of context.painPoints) {
|
|
24275
|
+
const tools = PAIN_POINT_TOOLS[painPoint] || [];
|
|
24276
|
+
for (const tool of tools) {
|
|
24277
|
+
if (!context.installedTools.includes(tool.tool)) {
|
|
24278
|
+
recommendations.push({
|
|
24279
|
+
tool: tool.tool,
|
|
24280
|
+
reason: tool.reason,
|
|
24281
|
+
source: "pain_point",
|
|
24282
|
+
relevanceScore: 0.9,
|
|
24283
|
+
installCmd: tool.installCmd
|
|
24284
|
+
});
|
|
24285
|
+
}
|
|
24286
|
+
}
|
|
24287
|
+
}
|
|
24288
|
+
for (const tech of context.techStack) {
|
|
24289
|
+
const tools = STACK_TOOLS[tech.toLowerCase()] || [];
|
|
24290
|
+
for (const tool of tools) {
|
|
24291
|
+
if (!context.installedTools.includes(tool.tool)) {
|
|
24292
|
+
recommendations.push({
|
|
24293
|
+
tool: tool.tool,
|
|
24294
|
+
reason: tool.reason,
|
|
24295
|
+
source: "stack",
|
|
24296
|
+
relevanceScore: 0.7
|
|
24297
|
+
});
|
|
24298
|
+
}
|
|
24299
|
+
}
|
|
24300
|
+
}
|
|
24301
|
+
const client = getClient();
|
|
24302
|
+
if (client) {
|
|
24303
|
+
try {
|
|
24304
|
+
const trending = await client.query(api.nightcrawler.getRecommendationsForProject, {
|
|
24305
|
+
projectPath,
|
|
24306
|
+
limit: 10
|
|
24307
|
+
});
|
|
24308
|
+
for (const t2 of trending) {
|
|
24309
|
+
if (recommendations.some((r3) => r3.tool === t2.toolSlug))
|
|
24310
|
+
continue;
|
|
24311
|
+
if (context.installedTools.includes(t2.toolSlug))
|
|
24312
|
+
continue;
|
|
24313
|
+
recommendations.push({
|
|
24314
|
+
tool: t2.toolSlug,
|
|
24315
|
+
reason: t2.reason,
|
|
24316
|
+
source: "trending",
|
|
24317
|
+
relevanceScore: t2.relevanceScore,
|
|
24318
|
+
trendingMentions: t2.mentions
|
|
24319
|
+
});
|
|
24320
|
+
}
|
|
24321
|
+
} catch (err) {}
|
|
24322
|
+
}
|
|
24323
|
+
const seen = new Set;
|
|
24324
|
+
const uniqueRecs = recommendations.filter((r3) => {
|
|
24325
|
+
if (seen.has(r3.tool))
|
|
24326
|
+
return false;
|
|
24327
|
+
seen.add(r3.tool);
|
|
24328
|
+
return true;
|
|
24329
|
+
}).sort((a2, b2) => b2.relevanceScore - a2.relevanceScore);
|
|
24330
|
+
consola.log("");
|
|
24331
|
+
console.log(`${BOLD2}${CYAN2}RECOMMENDATIONS FOR ${context.projectName.toUpperCase()}${RESET2}`);
|
|
24332
|
+
console.log(`${DIM2}Based on: ${context.painPoints.length} pain points, ${context.techStack.length} stack items${RESET2}`);
|
|
24333
|
+
console.log(`${DIM2}${"─".repeat(50)}${RESET2}`);
|
|
24334
|
+
const toShow = args.all ? uniqueRecs : uniqueRecs.slice(0, limit);
|
|
24335
|
+
if (toShow.length === 0) {
|
|
24336
|
+
consola.success("Your setup looks great! No new recommendations at this time.");
|
|
24337
|
+
consola.log("");
|
|
24338
|
+
console.log(`${DIM2}Run 'nb trending' to see what's new in the community${RESET2}`);
|
|
24339
|
+
return;
|
|
24340
|
+
}
|
|
24341
|
+
for (let i3 = 0;i3 < toShow.length; i3++) {
|
|
24342
|
+
const rec = toShow[i3];
|
|
24343
|
+
const num = i3 + 1;
|
|
24344
|
+
const sourceIcon = getSourceIcon(rec.source);
|
|
24345
|
+
const trendingBadge = rec.trendingMentions ? `${MAGENTA2}↑${rec.trendingMentions}${RESET2} ` : "";
|
|
24346
|
+
consola.log("");
|
|
24347
|
+
console.log(`${BOLD2}${num}. ${CYAN2}${rec.tool}${RESET2} ${sourceIcon}`);
|
|
24348
|
+
console.log(` ${trendingBadge}${rec.reason}`);
|
|
24349
|
+
if (rec.installCmd) {
|
|
24350
|
+
console.log(` ${DIM2}Install: ${GREEN2}${rec.installCmd}${RESET2}`);
|
|
24351
|
+
}
|
|
24352
|
+
}
|
|
24353
|
+
consola.log("");
|
|
24354
|
+
console.log(`${DIM2}${"─".repeat(50)}${RESET2}`);
|
|
24355
|
+
const painPointRecs = toShow.filter((r3) => r3.source === "pain_point").length;
|
|
24356
|
+
const stackRecs = toShow.filter((r3) => r3.source === "stack").length;
|
|
24357
|
+
const trendingRecs = toShow.filter((r3) => r3.source === "trending").length;
|
|
24358
|
+
console.log(`${DIM2}${painPointRecs} for pain points · ${stackRecs} for your stack · ${trendingRecs} trending${RESET2}`);
|
|
24359
|
+
if (!args.all && uniqueRecs.length > limit) {
|
|
24360
|
+
console.log(`${DIM2}Run 'nb recommend --all' to see ${uniqueRecs.length - limit} more${RESET2}`);
|
|
24361
|
+
}
|
|
24362
|
+
if (context.installedTools.length > 0) {
|
|
24363
|
+
consola.log("");
|
|
24364
|
+
console.log(`${GREEN2}✓ Already installed:${RESET2} ${context.installedTools.slice(0, 5).join(", ")}${context.installedTools.length > 5 ? ` +${context.installedTools.length - 5} more` : ""}`);
|
|
24365
|
+
}
|
|
24366
|
+
}
|
|
24367
|
+
});
|
|
24368
|
+
async function showGenericRecommendations() {
|
|
24369
|
+
console.log(`${BOLD2}${CYAN2}TOP COMMUNITY RECOMMENDATIONS${RESET2}`);
|
|
24370
|
+
console.log(`${DIM2}Run 'nb onboard' for personalized suggestions${RESET2}`);
|
|
24371
|
+
console.log(`${DIM2}${"─".repeat(50)}${RESET2}`);
|
|
24372
|
+
consola.log("");
|
|
24373
|
+
const genericRecs = [
|
|
24374
|
+
{ tool: "context7", reason: "Up-to-date library docs in AI context - reduces hallucinations" },
|
|
24375
|
+
{ tool: "supermemory", reason: "Persistent memory across sessions" },
|
|
24376
|
+
{ tool: "repoprompt", reason: "Better context building for code generation" },
|
|
24377
|
+
{ tool: "beads", reason: "Task tracking that persists between sessions" },
|
|
24378
|
+
{ tool: "stagehand", reason: "AI-powered E2E testing" }
|
|
24379
|
+
];
|
|
24380
|
+
for (let i3 = 0;i3 < genericRecs.length; i3++) {
|
|
24381
|
+
const rec = genericRecs[i3];
|
|
24382
|
+
console.log(`${BOLD2}${i3 + 1}. ${CYAN2}${rec.tool}${RESET2}`);
|
|
24383
|
+
console.log(` ${rec.reason}`);
|
|
24384
|
+
consola.log("");
|
|
24385
|
+
}
|
|
24386
|
+
}
|
|
24387
|
+
function getSourceIcon(source) {
|
|
24388
|
+
switch (source) {
|
|
24389
|
+
case "pain_point":
|
|
24390
|
+
return `${YELLOW2}[pain point]${RESET2}`;
|
|
24391
|
+
case "stack":
|
|
24392
|
+
return `${GREEN2}[your stack]${RESET2}`;
|
|
24393
|
+
case "trending":
|
|
24394
|
+
return `${MAGENTA2}[trending]${RESET2}`;
|
|
24395
|
+
case "community":
|
|
24396
|
+
return `${DIM2}[community]${RESET2}`;
|
|
24397
|
+
default:
|
|
24398
|
+
return "";
|
|
24399
|
+
}
|
|
24400
|
+
}
|
|
24401
|
+
|
|
24402
|
+
// src/commands/upgrade.ts
|
|
24403
|
+
import { execSync as execSync5 } from "node:child_process";
|
|
24404
|
+
var CYAN3 = "\x1B[36m";
|
|
24405
|
+
var GREEN3 = "\x1B[32m";
|
|
24406
|
+
var YELLOW3 = "\x1B[33m";
|
|
24407
|
+
var DIM3 = "\x1B[2m";
|
|
24408
|
+
var BOLD3 = "\x1B[1m";
|
|
24409
|
+
var RESET3 = "\x1B[0m";
|
|
24410
|
+
var MAGENTA3 = "\x1B[35m";
|
|
24411
|
+
var CHANGELOG = [
|
|
24412
|
+
{
|
|
24413
|
+
version: "0.1.0",
|
|
24414
|
+
date: "2026-02-13",
|
|
24415
|
+
title: "Nightcrawler & Recommendations",
|
|
24416
|
+
highlights: [
|
|
24417
|
+
"nb onboard - Set up project context for personalized recommendations",
|
|
24418
|
+
"nb trending - See hot topics in AI dev tools community",
|
|
24419
|
+
"nb recommend - Get personalized tool suggestions",
|
|
24420
|
+
"Auto-recommendations after nb scan",
|
|
24421
|
+
"Background X/Twitter scraper with hype filter",
|
|
24422
|
+
"Cost-optimized scraping (~$35/month)"
|
|
24423
|
+
]
|
|
24424
|
+
},
|
|
24425
|
+
{
|
|
24426
|
+
version: "0.0.40",
|
|
24427
|
+
date: "2026-02-10",
|
|
24428
|
+
title: "Frustration Detection & Smarter Reports",
|
|
24429
|
+
highlights: [
|
|
24430
|
+
"Detect frustration patterns in AI sessions",
|
|
24431
|
+
"Improved report generation",
|
|
24432
|
+
"Better token waste analysis"
|
|
24433
|
+
]
|
|
24434
|
+
},
|
|
24435
|
+
{
|
|
24436
|
+
version: "0.0.34",
|
|
24437
|
+
date: "2026-02-08",
|
|
24438
|
+
title: "Accurate Token & Commit Tracking",
|
|
24439
|
+
highlights: [
|
|
24440
|
+
"Fixed token counting accuracy",
|
|
24441
|
+
"Improved commit attribution",
|
|
24442
|
+
"Better session correlation"
|
|
24443
|
+
]
|
|
24444
|
+
},
|
|
24445
|
+
{
|
|
24446
|
+
version: "0.0.31",
|
|
24447
|
+
date: "2026-02-08",
|
|
24448
|
+
title: "Multi-Agent Support & Report Sharing",
|
|
24449
|
+
highlights: [
|
|
24450
|
+
"Support for multiple AI agents",
|
|
24451
|
+
"Shareable reports with nb publish",
|
|
24452
|
+
"Improved dashboard"
|
|
24453
|
+
]
|
|
24454
|
+
},
|
|
24455
|
+
{
|
|
24456
|
+
version: "0.0.26",
|
|
24457
|
+
date: "2026-02-07",
|
|
24458
|
+
title: "Hackathon Reports & Publish Links",
|
|
24459
|
+
highlights: [
|
|
24460
|
+
"nb report for hackathon submissions",
|
|
24461
|
+
"Publishable report links",
|
|
24462
|
+
"SDLC phase analysis"
|
|
24463
|
+
]
|
|
24464
|
+
},
|
|
24465
|
+
{
|
|
24466
|
+
version: "0.0.22",
|
|
24467
|
+
date: "2026-02-07",
|
|
24468
|
+
title: "Multi-Agent & Team Features",
|
|
24469
|
+
highlights: [
|
|
24470
|
+
"Team workflow support",
|
|
24471
|
+
"Multi-agent session tracking",
|
|
24472
|
+
"Improved cost analysis"
|
|
24473
|
+
]
|
|
24474
|
+
},
|
|
24475
|
+
{
|
|
24476
|
+
version: "0.0.18",
|
|
24477
|
+
date: "2026-02-07",
|
|
24478
|
+
title: "CI/CD & Analytics",
|
|
24479
|
+
highlights: [
|
|
24480
|
+
"CI/CD integration support",
|
|
24481
|
+
"Enhanced analytics dashboard",
|
|
24482
|
+
"Badge system"
|
|
24483
|
+
]
|
|
24484
|
+
}
|
|
24485
|
+
];
|
|
24486
|
+
var upgradeCommand = defineCommand2({
|
|
24487
|
+
meta: {
|
|
24488
|
+
name: "upgrade",
|
|
24489
|
+
description: "Upgrade nairon-bench to the latest version and see what's new"
|
|
24490
|
+
},
|
|
24491
|
+
args: {
|
|
24492
|
+
check: {
|
|
24493
|
+
type: "boolean",
|
|
24494
|
+
description: "Only check for updates without installing",
|
|
24495
|
+
default: false
|
|
24496
|
+
},
|
|
24497
|
+
changelog: {
|
|
24498
|
+
type: "boolean",
|
|
24499
|
+
description: "Show full changelog",
|
|
24500
|
+
default: false
|
|
24501
|
+
}
|
|
24502
|
+
},
|
|
24503
|
+
async run({ args }) {
|
|
24504
|
+
const currentVersion = getCurrentVersion();
|
|
24505
|
+
console.log();
|
|
24506
|
+
console.log(`${BOLD3}${CYAN3} nairon-bench upgrade${RESET3}`);
|
|
24507
|
+
console.log(`${DIM3} ${"─".repeat(40)}${RESET3}`);
|
|
24508
|
+
console.log();
|
|
24509
|
+
if (args.changelog) {
|
|
24510
|
+
showFullChangelog();
|
|
24511
|
+
return;
|
|
24512
|
+
}
|
|
24513
|
+
console.log(`${DIM3} Checking for updates...${RESET3}`);
|
|
24514
|
+
let latestVersion;
|
|
24515
|
+
try {
|
|
24516
|
+
latestVersion = execSync5("npm view nairon-bench version", { encoding: "utf-8" }).trim();
|
|
24517
|
+
} catch {
|
|
24518
|
+
console.log(` ${YELLOW3}⚠${RESET3} Could not check npm registry`);
|
|
24519
|
+
console.log(` ${DIM3}Run 'bun upgrade -g nairon-bench' manually${RESET3}`);
|
|
24520
|
+
return;
|
|
24521
|
+
}
|
|
24522
|
+
console.log();
|
|
24523
|
+
console.log(` ${DIM3}Current:${RESET3} ${currentVersion}`);
|
|
24524
|
+
console.log(` ${DIM3}Latest:${RESET3} ${latestVersion}`);
|
|
24525
|
+
console.log();
|
|
24526
|
+
if (compareVersions(currentVersion, latestVersion) >= 0) {
|
|
24527
|
+
console.log(` ${GREEN3}✓${RESET3} You're on the latest version!`);
|
|
24528
|
+
console.log();
|
|
24529
|
+
console.log(` ${DIM3}Run 'nb upgrade --changelog' to see past releases${RESET3}`);
|
|
24530
|
+
return;
|
|
24531
|
+
}
|
|
24532
|
+
const newReleases = getNewReleases(currentVersion, latestVersion);
|
|
24533
|
+
if (newReleases.length > 0) {
|
|
24534
|
+
showWhatsNew(newReleases);
|
|
24535
|
+
}
|
|
24536
|
+
if (args.check) {
|
|
24537
|
+
console.log();
|
|
24538
|
+
console.log(` ${DIM3}Run 'nb upgrade' to install${RESET3}`);
|
|
24539
|
+
return;
|
|
24540
|
+
}
|
|
24541
|
+
console.log();
|
|
24542
|
+
console.log(`${DIM3} ${"─".repeat(40)}${RESET3}`);
|
|
24543
|
+
console.log(` ${CYAN3}↓${RESET3} Upgrading to ${GREEN3}v${latestVersion}${RESET3}...`);
|
|
24544
|
+
console.log();
|
|
24545
|
+
try {
|
|
24546
|
+
try {
|
|
24547
|
+
execSync5("bun upgrade -g nairon-bench", { stdio: "inherit" });
|
|
24548
|
+
} catch {
|
|
24549
|
+
execSync5("npm install -g nairon-bench@latest", { stdio: "inherit" });
|
|
24550
|
+
}
|
|
24551
|
+
console.log();
|
|
24552
|
+
console.log(` ${GREEN3}✓${RESET3} Upgraded to ${GREEN3}v${latestVersion}${RESET3}`);
|
|
24553
|
+
console.log();
|
|
24554
|
+
console.log(` ${DIM3}Run 'nb doctor' to verify installation${RESET3}`);
|
|
24555
|
+
} catch (err) {
|
|
24556
|
+
console.log();
|
|
24557
|
+
console.log(` ${YELLOW3}⚠${RESET3} Upgrade failed`);
|
|
24558
|
+
console.log(` ${DIM3}Try running manually:${RESET3}`);
|
|
24559
|
+
console.log(` ${CYAN3}bun upgrade -g nairon-bench${RESET3}`);
|
|
24560
|
+
console.log(` ${DIM3}or${RESET3}`);
|
|
24561
|
+
console.log(` ${CYAN3}npm install -g nairon-bench@latest${RESET3}`);
|
|
24562
|
+
}
|
|
24563
|
+
}
|
|
24564
|
+
});
|
|
24565
|
+
function getCurrentVersion() {
|
|
24566
|
+
try {
|
|
24567
|
+
const output = execSync5("nb --version 2>/dev/null || nairon-bench --version 2>/dev/null", {
|
|
24568
|
+
encoding: "utf-8",
|
|
24569
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
24570
|
+
});
|
|
24571
|
+
const match = output.match(/v?(\d+\.\d+\.\d+)/);
|
|
24572
|
+
return match ? match[1] : "0.0.0";
|
|
24573
|
+
} catch {
|
|
24574
|
+
return "0.0.0";
|
|
24575
|
+
}
|
|
24576
|
+
}
|
|
24577
|
+
function compareVersions(a2, b2) {
|
|
24578
|
+
const partsA = a2.split(".").map(Number);
|
|
24579
|
+
const partsB = b2.split(".").map(Number);
|
|
24580
|
+
for (let i3 = 0;i3 < 3; i3++) {
|
|
24581
|
+
const diff = (partsA[i3] || 0) - (partsB[i3] || 0);
|
|
24582
|
+
if (diff !== 0)
|
|
24583
|
+
return diff;
|
|
24584
|
+
}
|
|
24585
|
+
return 0;
|
|
24586
|
+
}
|
|
24587
|
+
function getNewReleases(currentVersion, latestVersion) {
|
|
24588
|
+
return CHANGELOG.filter((entry) => {
|
|
24589
|
+
return compareVersions(entry.version, currentVersion) > 0 && compareVersions(entry.version, latestVersion) <= 0;
|
|
24590
|
+
});
|
|
24591
|
+
}
|
|
24592
|
+
function showWhatsNew(releases) {
|
|
24593
|
+
console.log(` ${BOLD3}${MAGENTA3}What's New${RESET3}`);
|
|
24594
|
+
console.log();
|
|
24595
|
+
for (const release of releases) {
|
|
24596
|
+
const isMajor = release.version.endsWith(".0") && !release.version.startsWith("0.0.");
|
|
24597
|
+
const isMinor = release.version.split(".")[1] !== "0" && release.version.endsWith(".0");
|
|
24598
|
+
const versionColor = isMajor ? GREEN3 : isMinor ? CYAN3 : DIM3;
|
|
24599
|
+
console.log(` ${versionColor}${BOLD3}v${release.version}${RESET3} ${DIM3}(${release.date})${RESET3}`);
|
|
24600
|
+
console.log(` ${release.title}`);
|
|
24601
|
+
console.log();
|
|
24602
|
+
for (const highlight of release.highlights.slice(0, 4)) {
|
|
24603
|
+
console.log(` ${GREEN3}•${RESET3} ${highlight}`);
|
|
24604
|
+
}
|
|
24605
|
+
if (release.highlights.length > 4) {
|
|
24606
|
+
console.log(` ${DIM3}+ ${release.highlights.length - 4} more improvements${RESET3}`);
|
|
24607
|
+
}
|
|
24608
|
+
console.log();
|
|
24609
|
+
}
|
|
24610
|
+
}
|
|
24611
|
+
function showFullChangelog() {
|
|
24612
|
+
console.log(` ${BOLD3}${MAGENTA3}Full Changelog${RESET3}`);
|
|
24613
|
+
console.log();
|
|
24614
|
+
for (const release of CHANGELOG) {
|
|
24615
|
+
console.log(` ${CYAN3}${BOLD3}v${release.version}${RESET3} ${DIM3}(${release.date})${RESET3}`);
|
|
24616
|
+
console.log(` ${release.title}`);
|
|
24617
|
+
console.log();
|
|
24618
|
+
for (const highlight of release.highlights) {
|
|
24619
|
+
console.log(` ${GREEN3}•${RESET3} ${highlight}`);
|
|
24620
|
+
}
|
|
24621
|
+
console.log();
|
|
24622
|
+
console.log(` ${DIM3}${"─".repeat(38)}${RESET3}`);
|
|
24623
|
+
console.log();
|
|
24624
|
+
}
|
|
24625
|
+
console.log(` ${DIM3}See full history at:${RESET3}`);
|
|
24626
|
+
console.log(` ${CYAN3}https://nairon.ai/changelog${RESET3}`);
|
|
24627
|
+
}
|
|
23593
24628
|
// package.json
|
|
23594
24629
|
var package_default = {
|
|
23595
24630
|
name: "nairon-bench",
|
|
23596
|
-
version: "0.0
|
|
24631
|
+
version: "0.1.0",
|
|
23597
24632
|
description: "AI workflow benchmarking CLI",
|
|
23598
24633
|
type: "module",
|
|
23599
24634
|
bin: {
|
|
@@ -23638,52 +24673,52 @@ var package_default = {
|
|
|
23638
24673
|
};
|
|
23639
24674
|
|
|
23640
24675
|
// src/lib/mascot.ts
|
|
23641
|
-
var
|
|
24676
|
+
var CYAN4 = "\x1B[36m";
|
|
23642
24677
|
var WHITE = "\x1B[97m";
|
|
23643
|
-
var
|
|
23644
|
-
var
|
|
23645
|
-
var
|
|
24678
|
+
var DIM4 = "\x1B[2m";
|
|
24679
|
+
var BOLD4 = "\x1B[1m";
|
|
24680
|
+
var RESET4 = "\x1B[0m";
|
|
23646
24681
|
function renderMascot(version2, cwd) {
|
|
23647
24682
|
const projectName = cwd ? cwd.split("/").pop() || cwd : "";
|
|
23648
|
-
const projectLine = projectName ? ` ${
|
|
24683
|
+
const projectLine = projectName ? ` ${DIM4}${projectName}${RESET4}` : "";
|
|
23649
24684
|
return `
|
|
23650
|
-
${WHITE} ▗▄▄▄▄▄▄▄▄▖${
|
|
23651
|
-
${WHITE} ▐${
|
|
23652
|
-
${WHITE} ▐${
|
|
23653
|
-
${WHITE} ▐${
|
|
23654
|
-
${WHITE} ▝▀▀▀▀▀▀▀▀▘${
|
|
24685
|
+
${WHITE} ▗▄▄▄▄▄▄▄▄▖${RESET4}
|
|
24686
|
+
${WHITE} ▐${CYAN4}█▀▀▀▀▀▀█${WHITE}▌${RESET4} ${BOLD4}NBench${RESET4} ${DIM4}v${version2}${RESET4}
|
|
24687
|
+
${WHITE} ▐${CYAN4}█ ${WHITE}▲${CYAN4} █${WHITE}▌${RESET4} ${DIM4}Benchmark AI workflows${RESET4}
|
|
24688
|
+
${WHITE} ▐${CYAN4}█▄▄▄▄▄▄█${WHITE}▌${RESET4}${projectLine}
|
|
24689
|
+
${WHITE} ▝▀▀▀▀▀▀▀▀▘${RESET4}
|
|
23655
24690
|
`;
|
|
23656
24691
|
}
|
|
23657
24692
|
|
|
23658
24693
|
// src/index.ts
|
|
23659
24694
|
var VERSION = package_default.version;
|
|
23660
|
-
var
|
|
23661
|
-
var
|
|
23662
|
-
var
|
|
23663
|
-
var
|
|
24695
|
+
var YELLOW4 = "\x1B[33m";
|
|
24696
|
+
var DIM5 = "\x1B[2m";
|
|
24697
|
+
var BOLD5 = "\x1B[1m";
|
|
24698
|
+
var RESET5 = "\x1B[0m";
|
|
23664
24699
|
function showBanner() {
|
|
23665
24700
|
const log = (msg) => process.stdout.write(msg + `
|
|
23666
24701
|
`);
|
|
23667
|
-
const
|
|
23668
|
-
const
|
|
24702
|
+
const GREEN4 = "\x1B[32m";
|
|
24703
|
+
const CYAN5 = "\x1B[36m";
|
|
23669
24704
|
log(renderMascot(VERSION, process.cwd()));
|
|
23670
|
-
log(`${
|
|
24705
|
+
log(`${YELLOW4}\u2501\u2501\u2501 Quick Start \u2501\u2501\u2501${RESET5}`);
|
|
23671
24706
|
log("");
|
|
23672
|
-
log(` ${
|
|
23673
|
-
log(` ${
|
|
23674
|
-
log(` ${
|
|
24707
|
+
log(` ${GREEN4}1.${RESET5} ${BOLD5}nb init${RESET5} Set up your profile (first time only)`);
|
|
24708
|
+
log(` ${GREEN4}2.${RESET5} ${BOLD5}nb scan${RESET5} Analyze your AI coding sessions`);
|
|
24709
|
+
log(` ${GREEN4}3.${RESET5} ${BOLD5}nb report --publish${RESET5} Generate & share your report`);
|
|
23675
24710
|
log("");
|
|
23676
|
-
log(`${
|
|
23677
|
-
log(`${
|
|
23678
|
-
log(`${
|
|
23679
|
-
log(`${
|
|
23680
|
-
log(`${
|
|
24711
|
+
log(`${DIM5}\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510${RESET5}`);
|
|
24712
|
+
log(`${DIM5}\u2502${RESET5} ${CYAN5}How often?${RESET5} ${DIM5}\u2502${RESET5}`);
|
|
24713
|
+
log(`${DIM5}\u2502${RESET5} \u2022 Run ${BOLD5}nb scan${RESET5} after coding sessions ${DIM5}\u2502${RESET5}`);
|
|
24714
|
+
log(`${DIM5}\u2502${RESET5} \u2022 Run ${BOLD5}nb report${RESET5} weekly to track progress ${DIM5}\u2502${RESET5}`);
|
|
24715
|
+
log(`${DIM5}\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518${RESET5}`);
|
|
23681
24716
|
log("");
|
|
23682
|
-
log(`${
|
|
24717
|
+
log(`${DIM5}Run ${BOLD5}nb --help${RESET5}${DIM5} for all commands${RESET5}`);
|
|
23683
24718
|
log("");
|
|
23684
24719
|
}
|
|
23685
24720
|
var args = process.argv.slice(2);
|
|
23686
|
-
var subcommands = ["init", "scan", "report", "dashboard", "insights", "tools", "doctor", "publish", "history", "cost", "session", "export", "pr", "badges", "cache", "setup"];
|
|
24721
|
+
var subcommands = ["init", "scan", "report", "dashboard", "insights", "tools", "doctor", "publish", "history", "cost", "session", "export", "pr", "badges", "cache", "setup", "onboard", "trending", "recommend"];
|
|
23687
24722
|
var hasSubcommand = args.some((arg) => subcommands.includes(arg));
|
|
23688
24723
|
var hasHelp = args.includes("--help") || args.includes("-h");
|
|
23689
24724
|
var hasVersion = args.includes("--version");
|
|
@@ -23712,7 +24747,11 @@ if (!hasSubcommand && !hasHelp && !hasVersion && args.length === 0) {
|
|
|
23712
24747
|
pr: prCommand,
|
|
23713
24748
|
badges: badgesCommand,
|
|
23714
24749
|
cache: cacheCommand,
|
|
23715
|
-
setup: setupCommand
|
|
24750
|
+
setup: setupCommand,
|
|
24751
|
+
onboard: onboardCommand,
|
|
24752
|
+
trending: trendingCommand,
|
|
24753
|
+
recommend: recommendCommand,
|
|
24754
|
+
upgrade: upgradeCommand
|
|
23716
24755
|
}
|
|
23717
24756
|
});
|
|
23718
24757
|
runMain(main);
|