@hasnatools/skills 0.1.23 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +314 -1
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23425,10 +23425,316 @@ async function doctorCommand() {
23425
23425
  console.log();
23426
23426
  }
23427
23427
 
23428
+ // src/commands/setup.ts
23429
+ var import_prompts4 = __toESM(require_prompts3(), 1);
23430
+ import { writeFileSync as writeFileSync7 } from "fs";
23431
+ import { join as join10 } from "path";
23432
+ var SKILLS_MD_MARKER2 = "<!-- skills.md:managed -->";
23433
+ async function getAIRecommendations(prompt, availableSkills) {
23434
+ const apiKey = getApiKey();
23435
+ const endpoint = getApiEndpoint();
23436
+ const skillsContext = availableSkills.map((s) => ({
23437
+ slug: s.slug,
23438
+ name: s.name,
23439
+ description: s.description,
23440
+ category: s.category?.name || "Uncategorized",
23441
+ isFree: !s.creditsPerExecution || s.creditsPerExecution === 0,
23442
+ credits: s.creditsPerExecution || 0
23443
+ }));
23444
+ try {
23445
+ const response = await fetch(`${endpoint}/ai/recommend-skills`, {
23446
+ method: "POST",
23447
+ headers: {
23448
+ "Content-Type": "application/json",
23449
+ ...apiKey ? { Authorization: `Bearer ${apiKey}` } : {}
23450
+ },
23451
+ body: JSON.stringify({
23452
+ prompt,
23453
+ skills: skillsContext
23454
+ })
23455
+ });
23456
+ if (!response.ok) {
23457
+ return null;
23458
+ }
23459
+ const data = await response.json();
23460
+ return data;
23461
+ } catch {
23462
+ return null;
23463
+ }
23464
+ }
23465
+ function getKeywordRecommendations(prompt, availableSkills) {
23466
+ const keywords = prompt.toLowerCase();
23467
+ const recommendations = [];
23468
+ const categoryMappings = {
23469
+ saas: ["generate-api-client", "api-documentation", "generate-readme", "ci-cd-pipeline", "docker-helper", "generate-env", "security-audit", "test-generator"],
23470
+ frontend: ["generate-image", "generate-favicon", "color-palette-harmonizer", "generate-chart", "generate-diagram"],
23471
+ backend: ["generate-api-client", "api-documentation", "docker-helper", "generate-dockerfile", "generate-env", "validate-config"],
23472
+ mobile: ["generate-image", "generate-favicon", "generate-qrcode", "deep-research"],
23473
+ data: ["analyze-data", "generate-chart", "generate-excel", "convert-data", "dataset-health-check"],
23474
+ content: ["create-blog-article", "generate-image", "generate-audio", "generate-video", "generate-presentation"],
23475
+ documentation: ["generate-readme", "generate-documentation", "api-documentation", "architecture-docs", "changelog-generator"],
23476
+ testing: ["test-generator", "e2e-test-generator", "api-test-suite", "find-bug", "snapshot-testing"],
23477
+ devops: ["ci-cd-pipeline", "docker-helper", "generate-dockerfile", "terraform-generator", "kubernetes-manifests"],
23478
+ security: ["security-audit", "secrets-scanner", "sql-injection-scanner", "dependency-checker"],
23479
+ marketing: ["generate-image", "email-campaign", "social-media-kit", "seo-brief-builder", "landing-page-copy"],
23480
+ startup: ["generate-readme", "generate-pitch-deck", "persona-generator", "customer-journey-mapper", "generate-invoice"]
23481
+ };
23482
+ const matchedSlugs = new Set;
23483
+ for (const [category, slugs] of Object.entries(categoryMappings)) {
23484
+ if (keywords.includes(category)) {
23485
+ slugs.forEach((slug) => matchedSlugs.add(slug));
23486
+ }
23487
+ }
23488
+ if (matchedSlugs.size === 0) {
23489
+ ["generate-readme", "generate-documentation", "find-bug", "code-review", "generate-diagram"].forEach((s) => matchedSlugs.add(s));
23490
+ }
23491
+ for (const slug of matchedSlugs) {
23492
+ const skill = availableSkills.find((s) => s.slug === slug);
23493
+ if (skill) {
23494
+ recommendations.push({
23495
+ slug: skill.slug,
23496
+ name: skill.name,
23497
+ reason: `Useful for ${skill.category?.name || "development"} workflows`,
23498
+ priority: recommendations.length < 5 ? "essential" : "recommended",
23499
+ creditsPerExecution: skill.creditsPerExecution || 0
23500
+ });
23501
+ }
23502
+ }
23503
+ const paidSkills = availableSkills.filter((s) => s.creditsPerExecution && s.creditsPerExecution > 0);
23504
+ for (const skill of paidSkills.slice(0, 3)) {
23505
+ if (!matchedSlugs.has(skill.slug)) {
23506
+ recommendations.push({
23507
+ slug: skill.slug,
23508
+ name: skill.name,
23509
+ reason: "Premium skill with advanced capabilities",
23510
+ priority: "optional",
23511
+ creditsPerExecution: skill.creditsPerExecution || 0
23512
+ });
23513
+ }
23514
+ }
23515
+ return {
23516
+ skills: recommendations.slice(0, 15),
23517
+ summary: `Based on your project needs, I've selected ${recommendations.length} skills that would be helpful.`
23518
+ };
23519
+ }
23520
+ function displayRecommendations(recommendations) {
23521
+ console.log();
23522
+ console.log(colors.primary(recommendations.summary));
23523
+ console.log();
23524
+ const essential = recommendations.skills.filter((s) => s.priority === "essential");
23525
+ const recommended = recommendations.skills.filter((s) => s.priority === "recommended");
23526
+ const optional = recommendations.skills.filter((s) => s.priority === "optional");
23527
+ if (essential.length > 0) {
23528
+ console.log(colors.successBold("Essential Skills"));
23529
+ console.log(colors.dim("─".repeat(50)));
23530
+ essential.forEach((s, i) => {
23531
+ const priceTag = s.creditsPerExecution > 0 ? colors.warning(` [${s.creditsPerExecution} credits]`) : colors.success(" [Free]");
23532
+ console.log(` ${colors.success(String(i + 1).padStart(2, " "))}. ${skillName(s.name)}${priceTag}`);
23533
+ console.log(` ${colors.dim(s.reason)}`);
23534
+ });
23535
+ console.log();
23536
+ }
23537
+ if (recommended.length > 0) {
23538
+ console.log(colors.primaryBold("Recommended Skills"));
23539
+ console.log(colors.dim("─".repeat(50)));
23540
+ recommended.forEach((s, i) => {
23541
+ const priceTag = s.creditsPerExecution > 0 ? colors.warning(` [${s.creditsPerExecution} credits]`) : colors.success(" [Free]");
23542
+ console.log(` ${colors.primary(String(essential.length + i + 1).padStart(2, " "))}. ${skillName(s.name)}${priceTag}`);
23543
+ console.log(` ${colors.dim(s.reason)}`);
23544
+ });
23545
+ console.log();
23546
+ }
23547
+ if (optional.length > 0) {
23548
+ console.log(colors.dim("Optional Premium Skills"));
23549
+ console.log(colors.dim("─".repeat(50)));
23550
+ optional.forEach((s, i) => {
23551
+ const priceTag = s.creditsPerExecution > 0 ? colors.warning(` [${s.creditsPerExecution} credits]`) : colors.success(" [Free]");
23552
+ console.log(` ${colors.dim(String(essential.length + recommended.length + i + 1).padStart(2, " "))}. ${skillName(s.name)}${priceTag}`);
23553
+ console.log(` ${colors.dim(s.reason)}`);
23554
+ });
23555
+ console.log();
23556
+ }
23557
+ }
23558
+ function addSkillsMdMarker2(content) {
23559
+ return `${content.trim()}
23560
+
23561
+ ${SKILLS_MD_MARKER2}
23562
+ `;
23563
+ }
23564
+ async function setupCommand(promptArg, options = {}) {
23565
+ const isLocal = options.local ?? false;
23566
+ const target = options.target ?? getDefaultTarget();
23567
+ const apiKey = getApiKey();
23568
+ banner("AI-Powered Skill Setup");
23569
+ let installDir;
23570
+ if (isLocal) {
23571
+ if (!hasLocalConfig()) {
23572
+ console.log(colors.warning("Not in a skills.md project"));
23573
+ console.log(colors.dim("Run `skills init` first or use global installation"));
23574
+ return;
23575
+ }
23576
+ installDir = target === "claude" ? getProjectClaudeSkillsDir() : getProjectCodexSkillsDir();
23577
+ } else {
23578
+ installDir = target === "claude" ? getClaudeSkillsDir() : getCodexSkillsDir();
23579
+ }
23580
+ console.log(keyValue("Target", colors.primaryBold(target)));
23581
+ console.log(keyValue("Scope", colors.primaryBold(isLocal ? "project" : "global")));
23582
+ console.log(keyValue("Directory", path6(installDir)));
23583
+ console.log();
23584
+ let projectPrompt = promptArg;
23585
+ if (!projectPrompt) {
23586
+ console.log(colors.dim("Describe your project and I'll recommend the best skills to install."));
23587
+ console.log(colors.dim("Examples: 'SaaS application', 'Mobile app backend', 'Data analysis project'"));
23588
+ console.log();
23589
+ const response = await import_prompts4.default({
23590
+ type: "text",
23591
+ name: "prompt",
23592
+ message: "What are you building?",
23593
+ validate: (value) => value.length > 0 ? true : "Please describe your project"
23594
+ });
23595
+ if (!response.prompt) {
23596
+ console.log(colors.dim("Setup cancelled"));
23597
+ return;
23598
+ }
23599
+ projectPrompt = response.prompt;
23600
+ }
23601
+ const fetchSpinner = ora({
23602
+ text: "Fetching available skills...",
23603
+ color: "magenta"
23604
+ }).start();
23605
+ const skillsResult = await getAllMarketplaceSkills();
23606
+ if (skillsResult.error || !skillsResult.data) {
23607
+ fetchSpinner.fail(colors.error("Failed to fetch skills"));
23608
+ console.error(colors.error(skillsResult.error || "Could not fetch skill catalog"));
23609
+ return;
23610
+ }
23611
+ const availableSkills = skillsResult.data.skills;
23612
+ fetchSpinner.succeed(colors.success(`Found ${count(availableSkills.length)} available skills`));
23613
+ const aiSpinner = ora({
23614
+ text: "Analyzing your project needs...",
23615
+ color: "magenta"
23616
+ }).start();
23617
+ let recommendations = await getAIRecommendations(projectPrompt, availableSkills);
23618
+ if (!recommendations) {
23619
+ aiSpinner.text = "Using smart matching...";
23620
+ recommendations = getKeywordRecommendations(projectPrompt, availableSkills);
23621
+ }
23622
+ aiSpinner.succeed(colors.success(`Selected ${count(recommendations.skills.length)} skills for your project`));
23623
+ displayRecommendations(recommendations);
23624
+ const freeSkills = recommendations.skills.filter((s) => s.creditsPerExecution === 0);
23625
+ const paidSkills = recommendations.skills.filter((s) => s.creditsPerExecution > 0);
23626
+ const totalCredits = paidSkills.reduce((sum, s) => sum + s.creditsPerExecution, 0);
23627
+ console.log(colors.dim("─".repeat(50)));
23628
+ console.log(keyValue("Free skills", colors.success(String(freeSkills.length))));
23629
+ console.log(keyValue("Paid skills", colors.warning(String(paidSkills.length))));
23630
+ if (totalCredits > 0) {
23631
+ console.log(keyValue("Credits per full run", colors.warning(`${totalCredits} credits`)));
23632
+ }
23633
+ console.log();
23634
+ const { installChoice } = await import_prompts4.default({
23635
+ type: "select",
23636
+ name: "installChoice",
23637
+ message: "What would you like to install?",
23638
+ choices: [
23639
+ { title: `All ${recommendations.skills.length} recommended skills`, value: "all" },
23640
+ { title: `Only free skills (${freeSkills.length})`, value: "free" },
23641
+ { title: "Let me choose", value: "choose" },
23642
+ { title: "Cancel", value: "cancel" }
23643
+ ]
23644
+ });
23645
+ if (installChoice === "cancel" || !installChoice) {
23646
+ console.log(colors.dim("Setup cancelled"));
23647
+ return;
23648
+ }
23649
+ let skillsToInstall = [];
23650
+ if (installChoice === "all") {
23651
+ skillsToInstall = recommendations.skills;
23652
+ } else if (installChoice === "free") {
23653
+ skillsToInstall = freeSkills;
23654
+ } else if (installChoice === "choose") {
23655
+ const { selected } = await import_prompts4.default({
23656
+ type: "multiselect",
23657
+ name: "selected",
23658
+ message: "Select skills to install",
23659
+ choices: recommendations.skills.map((s) => ({
23660
+ title: `${s.name}${s.creditsPerExecution > 0 ? ` [${s.creditsPerExecution} credits]` : " [Free]"}`,
23661
+ value: s.slug,
23662
+ selected: s.priority === "essential"
23663
+ })),
23664
+ hint: "- Space to select. Enter to confirm"
23665
+ });
23666
+ if (!selected || selected.length === 0) {
23667
+ console.log(colors.dim("No skills selected"));
23668
+ return;
23669
+ }
23670
+ skillsToInstall = recommendations.skills.filter((s) => selected.includes(s.slug));
23671
+ }
23672
+ if (skillsToInstall.length === 0) {
23673
+ console.log(colors.dim("No skills to install"));
23674
+ return;
23675
+ }
23676
+ console.log();
23677
+ banner("Installing Skills");
23678
+ const total = skillsToInstall.length;
23679
+ const results = {
23680
+ success: [],
23681
+ failed: []
23682
+ };
23683
+ for (let i = 0;i < skillsToInstall.length; i++) {
23684
+ const skill = skillsToInstall[i];
23685
+ const current = i + 1;
23686
+ const percent = Math.round(current / total * 100);
23687
+ const padWidth = String(total).length;
23688
+ const progress = `[${String(current).padStart(padWidth, " ")}/${total}]`;
23689
+ process.stdout.write(`\r${colors.dim(progress)} ${progressBar(percent)} ${colors.dim(`${percent}%`)} Installing ${colors.primary(skill.name)}...`);
23690
+ process.stdout.write("\x1B[K");
23691
+ try {
23692
+ const skillResult = await installSkill(skill.slug);
23693
+ if (skillResult.error || !skillResult.data) {
23694
+ results.failed.push({ slug: skill.slug, error: skillResult.error || "Not found" });
23695
+ continue;
23696
+ }
23697
+ const skillData = skillResult.data;
23698
+ const skillDir = join10(installDir, `skill-${skill.slug}`);
23699
+ const exportsDir = join10(skillDir, "exports");
23700
+ const logsDir = join10(skillDir, "logs");
23701
+ ensureSkillsDir(skillDir);
23702
+ ensureSkillsDir(exportsDir);
23703
+ ensureSkillsDir(logsDir);
23704
+ writeFileSync7(join10(skillDir, "SKILL.md"), addSkillsMdMarker2(skillData.skillMdContent));
23705
+ if (apiKey) {
23706
+ try {
23707
+ await installSkillRemote(skill.slug);
23708
+ } catch {}
23709
+ }
23710
+ results.success.push(skill.slug);
23711
+ } catch (error) {
23712
+ results.failed.push({
23713
+ slug: skill.slug,
23714
+ error: error instanceof Error ? error.message : "Unknown error"
23715
+ });
23716
+ }
23717
+ }
23718
+ process.stdout.write("\r\x1B[K");
23719
+ completionBanner("Setup Complete");
23720
+ if (results.success.length > 0) {
23721
+ console.log(successItem(`Installed: ${colors.successBold(String(results.success.length))} skills`));
23722
+ }
23723
+ if (results.failed.length > 0) {
23724
+ console.log(errorItem(`Failed: ${colors.errorBold(String(results.failed.length))} skills`));
23725
+ }
23726
+ console.log();
23727
+ console.log(colors.dim("Your skills are ready! Run any skill with:"));
23728
+ console.log(` ${command('skills run <skill-name> -- "your prompt"')}`);
23729
+ console.log();
23730
+ console.log(colors.dim("View installed skills:"));
23731
+ console.log(` ${command("skills list")}`);
23732
+ }
23733
+
23428
23734
  // src/index.ts
23429
23735
  var indigo12 = colors.primary;
23430
23736
  var program2 = new Command;
23431
- program2.name("skills").description("CLI for skills.md - AI Agent Skills Marketplace").version("0.1.23");
23737
+ program2.name("skills").description("CLI for skills.md - AI Agent Skills Marketplace").version("0.1.24");
23432
23738
  program2.command("init").description("Initialize skills.md in current project").option("-f, --force", "Force re-initialization (removes existing .skills/)").action((options) => {
23433
23739
  initCommand({ force: options.force });
23434
23740
  });
@@ -23460,6 +23766,9 @@ program2.command("uninstall [name]").alias("remove").description("Uninstall skil
23460
23766
  force: options.force
23461
23767
  });
23462
23768
  });
23769
+ program2.command("setup [prompt]").description("AI-powered skill setup wizard - recommends skills based on your project").option("-l, --local", "Install to current project instead of global").option("-t, --target <target>", "Target platform (claude, codex)").action((prompt, options) => {
23770
+ setupCommand(prompt, { local: options.local, target: options.target });
23771
+ });
23463
23772
  program2.command("download <name>").alias("dl").description("Download a skill with full source code (if available)").option("-l, --local", "Download to current project instead of global").option("-t, --target <target>", "Target platform (claude, codex)").action((name, options) => {
23464
23773
  downloadCommand(name, {
23465
23774
  local: options.local,
@@ -23550,6 +23859,10 @@ ${indigo12.bold("Examples:")}
23550
23859
  ${source_default.dim("# Install globally for Claude Code")}
23551
23860
  $ skills install code-review -g -t claude
23552
23861
 
23862
+ ${source_default.dim("# AI-powered setup wizard")}
23863
+ $ skills setup
23864
+ $ skills setup "SaaS application with API"
23865
+
23553
23866
  ${source_default.dim("# List installed skills")}
23554
23867
  $ skills list
23555
23868
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasnatools/skills",
3
- "version": "0.1.23",
3
+ "version": "0.1.24",
4
4
  "description": "CLI for skills.md - AI Agent Skills Marketplace",
5
5
  "type": "module",
6
6
  "bin": {