@hasna/skills 0.1.13 → 0.1.14

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 (197) hide show
  1. package/bin/index.js +639 -291
  2. package/bin/mcp.js +301 -180
  3. package/dist/index.d.ts +4 -2
  4. package/dist/index.js +190 -2
  5. package/dist/lib/config.d.ts +27 -0
  6. package/dist/lib/config.test.d.ts +1 -0
  7. package/dist/lib/installer.d.ts +25 -0
  8. package/dist/lib/registry.d.ts +4 -0
  9. package/dist/types/api.d.ts +74 -0
  10. package/package.json +5 -2
  11. package/skills/skill-academic-journal-matcher/bin/cli.ts +34 -0
  12. package/skills/skill-action-item-router/bin/cli.ts +34 -0
  13. package/skills/skill-ad-creative-generator/bin/cli.ts +34 -0
  14. package/skills/skill-advanced-math/bin/cli.ts +34 -0
  15. package/skills/skill-analyze-data/bin/cli.ts +19 -0
  16. package/skills/skill-anomaly-investigator/bin/cli.ts +34 -0
  17. package/skills/skill-api-test-suite/bin/cli.ts +34 -0
  18. package/skills/skill-apidocs/bin/cli.ts +87 -0
  19. package/skills/skill-audio-cleanup-lab/bin/cli.ts +6 -0
  20. package/skills/skill-audiobook-chapter-proofer/bin/cli.ts +34 -0
  21. package/skills/skill-banner-ad-suite/bin/cli.ts +34 -0
  22. package/skills/skill-benchmark-finder/bin/cli.ts +34 -0
  23. package/skills/skill-bio-sequence-tool/bin/cli.ts +34 -0
  24. package/skills/skill-blog-topic-cluster/bin/cli.ts +34 -0
  25. package/skills/skill-brand-style-guide/bin/cli.ts +19 -0
  26. package/skills/skill-brand-voice-audit/bin/cli.ts +34 -0
  27. package/skills/skill-budget-variance-analyzer/bin/cli.ts +6 -0
  28. package/skills/skill-businessactivity/bin/cli.ts +28 -0
  29. package/skills/skill-calendar-events/bin/cli.ts +34 -0
  30. package/skills/skill-campaign-metric-brief/bin/cli.ts +34 -0
  31. package/skills/skill-campaign-moodboard/bin/cli.ts +34 -0
  32. package/skills/skill-caption-style-stylist/bin/cli.ts +34 -0
  33. package/skills/skill-chemistry-calculator/bin/cli.ts +34 -0
  34. package/skills/skill-churn-risk-notifier/bin/cli.ts +34 -0
  35. package/skills/skill-citation-formatter/bin/cli.ts +34 -0
  36. package/skills/skill-classroom-newsletter-kit/bin/cli.ts +34 -0
  37. package/skills/skill-color-palette-harmonizer/bin/cli.ts +34 -0
  38. package/skills/skill-competitor-ad-analyzer/bin/cli.ts +34 -0
  39. package/skills/skill-compliance-copy-check/bin/cli.ts +34 -0
  40. package/skills/skill-compliance-report-pack/bin/cli.ts +34 -0
  41. package/skills/skill-compress-video/bin/cli.ts +19 -0
  42. package/skills/skill-consolelog/bin/cli.ts +884 -0
  43. package/skills/skill-contract-plainlanguage/bin/cli.ts +34 -0
  44. package/skills/skill-copytone-translator/bin/cli.ts +34 -0
  45. package/skills/skill-create-blog-article/bin/cli.ts +34 -0
  46. package/skills/skill-create-ebook/bin/cli.ts +34 -0
  47. package/skills/skill-crm-note-enhancer/bin/cli.ts +34 -0
  48. package/skills/skill-customer-journey-mapper/bin/cli.ts +34 -0
  49. package/skills/skill-dashboard-builder/bin/cli.ts +34 -0
  50. package/skills/skill-dashboard-narrator/bin/cli.ts +34 -0
  51. package/skills/skill-data-anonymizer/bin/cli.ts +34 -0
  52. package/skills/skill-database-explorer/bin/cli.ts +34 -0
  53. package/skills/skill-dataset-health-check/bin/cli.ts +34 -0
  54. package/skills/skill-decision-journal/bin/cli.ts +34 -0
  55. package/skills/skill-delegation-brief-writer/bin/cli.ts +34 -0
  56. package/skills/skill-destination-briefing/bin/cli.ts +34 -0
  57. package/skills/skill-diff-viewer/bin/cli.ts +34 -0
  58. package/skills/skill-domainpurchase/SKILL.md +46 -0
  59. package/skills/skill-domainpurchase/bin/cli.ts +683 -0
  60. package/skills/skill-domainsearch/SKILL.md +41 -0
  61. package/skills/skill-domainsearch/bin/cli.ts +410 -0
  62. package/skills/skill-educational-resource-finder/bin/cli.ts +34 -0
  63. package/skills/skill-email-campaign/bin/cli.ts +34 -0
  64. package/skills/skill-exam-readiness-check/bin/cli.ts +34 -0
  65. package/skills/skill-experiment-power-calculator/bin/cli.ts +34 -0
  66. package/skills/skill-extract-audio/bin/cli.ts +19 -0
  67. package/skills/skill-extract-frames/bin/cli.ts +34 -0
  68. package/skills/skill-extract-invoice/bin/cli.ts +34 -0
  69. package/skills/skill-family-activity-curator/bin/cli.ts +34 -0
  70. package/skills/skill-faq-packager/bin/cli.ts +34 -0
  71. package/skills/skill-feedback-survey-designer/bin/cli.ts +34 -0
  72. package/skills/skill-field-trip-planner/bin/cli.ts +34 -0
  73. package/skills/skill-file-organizer/bin/cli.ts +34 -0
  74. package/skills/skill-folder-tree/bin/cli.ts +34 -0
  75. package/skills/skill-forecast-scenario-lab/bin/cli.ts +34 -0
  76. package/skills/skill-form-filler/bin/cli.ts +34 -0
  77. package/skills/skill-generate-api-client/bin/cli.ts +34 -0
  78. package/skills/skill-generate-book-cover/bin/cli.ts +34 -0
  79. package/skills/skill-generate-chart/bin/cli.ts +34 -0
  80. package/skills/skill-generate-diagram/bin/cli.ts +34 -0
  81. package/skills/skill-generate-dockerfile/bin/cli.ts +34 -0
  82. package/skills/skill-generate-documentation/bin/cli.ts +34 -0
  83. package/skills/skill-generate-docx/bin/cli.ts +6 -0
  84. package/skills/skill-generate-env/bin/cli.ts +34 -0
  85. package/skills/skill-generate-excel/bin/cli.ts +34 -0
  86. package/skills/skill-generate-favicon/bin/cli.ts +34 -0
  87. package/skills/skill-generate-mock-data/bin/cli.ts +34 -0
  88. package/skills/skill-generate-pdf/bin/cli.ts +6 -0
  89. package/skills/skill-generate-pr-description/bin/cli.ts +34 -0
  90. package/skills/skill-generate-presentation/bin/cli.ts +34 -0
  91. package/skills/skill-generate-qrcode/bin/cli.ts +34 -0
  92. package/skills/skill-generate-regex/bin/cli.ts +34 -0
  93. package/skills/skill-generate-resume/bin/cli.ts +34 -0
  94. package/skills/skill-generate-sitemap/bin/cli.ts +34 -0
  95. package/skills/skill-generate-social-posts/bin/cli.ts +34 -0
  96. package/skills/skill-generate-sql/bin/cli.ts +34 -0
  97. package/skills/skill-gif-maker/bin/cli.ts +34 -0
  98. package/skills/skill-github-manager/bin/cli.ts +34 -0
  99. package/skills/skill-gmail/bin/cli.ts +34 -0
  100. package/skills/skill-goal-quarterly-roadmap/bin/cli.ts +34 -0
  101. package/skills/skill-grant-application-drafter/bin/cli.ts +34 -0
  102. package/skills/skill-grocery-basket-optimizer/bin/cli.ts +34 -0
  103. package/skills/skill-guest-communication-suite/bin/cli.ts +34 -0
  104. package/skills/skill-habit-reflection-digest/bin/cli.ts +34 -0
  105. package/skills/skill-highlight-reel-generator/bin/cli.ts +34 -0
  106. package/skills/skill-homework-feedback-coach/bin/cli.ts +34 -0
  107. package/skills/skill-hook/bunfig.toml +5 -0
  108. package/skills/skill-household-maintenance-mgr/bin/cli.ts +34 -0
  109. package/skills/skill-http-server/bin/cli.ts +34 -0
  110. package/skills/skill-implementation/bunfig.toml +5 -0
  111. package/skills/skill-implementation-agent/bin/cli.ts +34 -0
  112. package/skills/skill-implementation-plan/bin/cli.ts +34 -0
  113. package/skills/skill-implementation-todo/bin/cli.ts +34 -0
  114. package/skills/skill-inbox-priority-planner/bin/cli.ts +34 -0
  115. package/skills/skill-invoice/bin/cli.ts +20 -0
  116. package/skills/skill-invoice-dispute-helper/bin/cli.ts +34 -0
  117. package/skills/skill-itinerary-architect/bin/cli.ts +34 -0
  118. package/skills/skill-jingle-composer/bin/cli.ts +34 -0
  119. package/skills/skill-kpi-digest-generator/bin/cli.ts +34 -0
  120. package/skills/skill-lab-notebook-formatter/bin/cli.ts +34 -0
  121. package/skills/skill-landing-page-copy/bin/cli.ts +34 -0
  122. package/skills/skill-latex-table-generator/bin/cli.ts +34 -0
  123. package/skills/skill-learning-style-profiler/bin/cli.ts +34 -0
  124. package/skills/skill-lesson-plan-customizer/bin/cli.ts +34 -0
  125. package/skills/skill-livestream-runofshow/bin/cli.ts +34 -0
  126. package/skills/skill-longform-structurer/bin/cli.ts +34 -0
  127. package/skills/skill-lorem-generator/bin/cli.ts +34 -0
  128. package/skills/skill-managehook/bin/cli.ts +241 -0
  129. package/skills/skill-managemcp/bin/cli.ts +241 -0
  130. package/skills/skill-manageskill/bin/cli.ts +241 -0
  131. package/skills/skill-markdown-validator/bin/cli.ts +34 -0
  132. package/skills/skill-mcp-builder/bin/cli.ts +34 -0
  133. package/skills/skill-meal-plan-designer/bin/cli.ts +34 -0
  134. package/skills/skill-meeting-insight-summarizer/bin/cli.ts +34 -0
  135. package/skills/skill-merge-pdfs/bin/cli.ts +34 -0
  136. package/skills/skill-microcopy-generator/bin/cli.ts +34 -0
  137. package/skills/skill-mindfulness-prompt-cache/bin/cli.ts +34 -0
  138. package/skills/skill-notion-manager/bin/cli.ts +34 -0
  139. package/skills/skill-onboarding-sequence-builder/bin/cli.ts +34 -0
  140. package/skills/skill-onsite-ops-checklist/bin/cli.ts +34 -0
  141. package/skills/skill-outreach-cadence-designer/bin/cli.ts +34 -0
  142. package/skills/skill-packaging-concept-studio/bin/cli.ts +34 -0
  143. package/skills/skill-packing-plan-pro/bin/cli.ts +34 -0
  144. package/skills/skill-parent-teacher-brief/bin/cli.ts +34 -0
  145. package/skills/skill-partner-kit-assembler/bin/cli.ts +34 -0
  146. package/skills/skill-payroll-change-prepper/bin/cli.ts +34 -0
  147. package/skills/skill-persona-based-adwriter/bin/cli.ts +34 -0
  148. package/skills/skill-persona-generator/bin/cli.ts +34 -0
  149. package/skills/skill-personal-daily-ops/bin/cli.ts +34 -0
  150. package/skills/skill-pet-care-scheduler/bin/cli.ts +34 -0
  151. package/skills/skill-podcast-show-notes/bin/cli.ts +34 -0
  152. package/skills/skill-presentation-theme-maker/bin/cli.ts +34 -0
  153. package/skills/skill-press-release-drafter/bin/cli.ts +34 -0
  154. package/skills/skill-print-collateral-designer/bin/cli.ts +34 -0
  155. package/skills/skill-procurement-scorecard/bin/cli.ts +34 -0
  156. package/skills/skill-product-demo-script/bin/cli.ts +34 -0
  157. package/skills/skill-product-mockup/bin/cli.ts +34 -0
  158. package/skills/skill-project-retro-companion/bin/cli.ts +34 -0
  159. package/skills/skill-proposal-redline-advisor/bin/cli.ts +34 -0
  160. package/skills/skill-regex-tester/bin/cli.ts +34 -0
  161. package/skills/skill-remove-background/bin/cli.ts +34 -0
  162. package/skills/skill-risk-disclosure-kit/bin/cli.ts +34 -0
  163. package/skills/skill-roi-comparison-tool/bin/cli.ts +34 -0
  164. package/skills/skill-sales-call-recapper/bin/cli.ts +34 -0
  165. package/skills/skill-salescopy/bin/cli.ts +20 -0
  166. package/skills/skill-scaffold-project/bin/cli.ts +34 -0
  167. package/skills/skill-scholarship-tracker/bin/cli.ts +34 -0
  168. package/skills/skill-scientific-figure-check/bin/cli.ts +34 -0
  169. package/skills/skill-seating-chart-maker/bin/cli.ts +34 -0
  170. package/skills/skill-security-audit/bin/cli.ts +34 -0
  171. package/skills/skill-seo-brief-builder/bin/cli.ts +34 -0
  172. package/skills/skill-slack-assistant/bin/cli.ts +34 -0
  173. package/skills/skill-sleep-routine-analyzer/bin/cli.ts +34 -0
  174. package/skills/skill-social-media-kit/bin/cli.ts +34 -0
  175. package/skills/skill-split-pdf/bin/cli.ts +34 -0
  176. package/skills/skill-sponsorship-proposal-lab/bin/cli.ts +34 -0
  177. package/skills/skill-spreadsheet-cleanroom/bin/cli.ts +34 -0
  178. package/skills/skill-statistical-test-selector/bin/cli.ts +34 -0
  179. package/skills/skill-stress-relief-playbook/bin/cli.ts +34 -0
  180. package/skills/skill-study-guide-builder/bin/cli.ts +34 -0
  181. package/skills/skill-subscription-spend-watcher/bin/cli.ts +34 -0
  182. package/skills/skill-subtitle/bin/cli.ts +20 -0
  183. package/skills/skill-survey-insight-extractor/bin/cli.ts +34 -0
  184. package/skills/skill-terraform-generator/bin/cli.ts +34 -0
  185. package/skills/skill-testimonial-graphics/bin/cli.ts +34 -0
  186. package/skills/skill-timesheet/bin/cli.ts +47 -0
  187. package/skills/skill-travel-budget-balancer/bin/cli.ts +34 -0
  188. package/skills/skill-validate-config/bin/cli.ts +34 -0
  189. package/skills/skill-video-cut-suggester/bin/cli.ts +34 -0
  190. package/skills/skill-video-downloader/bin/cli.ts +34 -0
  191. package/skills/skill-video-thumbnail/bin/cli.ts +34 -0
  192. package/skills/skill-voiceover-casting-assistant/bin/cli.ts +34 -0
  193. package/skills/skill-watermark/bin/cli.ts +34 -0
  194. package/skills/skill-webcrawling/bin/cli.ts +21 -0
  195. package/skills/skill-webinar-script-coach/bin/cli.ts +34 -0
  196. package/skills/skill-wellness-progress-reporter/bin/cli.ts +34 -0
  197. package/skills/skill-workout-cycle-planner/bin/cli.ts +34 -0
package/dist/index.d.ts CHANGED
@@ -7,6 +7,8 @@
7
7
  * Or use the interactive CLI:
8
8
  * skills
9
9
  */
10
- export { SKILLS, CATEGORIES, getSkill, getSkillsByCategory, searchSkills, getSkillsByTag, getAllTags, type SkillMeta, type Category, } from "./lib/registry.js";
11
- export { installSkill, installSkills, installSkillForAgent, removeSkillForAgent, getInstalledSkills, removeSkill, skillExists, getSkillPath, getAgentSkillsDir, getAgentSkillPath, AGENT_TARGETS, type InstallResult, type InstallOptions, type AgentTarget, type AgentScope, type AgentInstallOptions, } from "./lib/installer.js";
10
+ export { SKILLS, CATEGORIES, getSkill, getSkillsByCategory, searchSkills, getSkillsByTag, getAllTags, findSimilarSkills, type SkillMeta, type Category, } from "./lib/registry.js";
11
+ export { installSkill, installSkills, installSkillForAgent, removeSkillForAgent, getInstalledSkills, removeSkill, skillExists, getSkillPath, getAgentSkillsDir, getAgentSkillPath, AGENT_TARGETS, type InstallResult, type InstallOptions, type AgentTarget, type AgentScope, type AgentInstallOptions, getInstallMeta, disableSkill, enableSkill, getDisabledSkills, } from "./lib/installer.js";
12
12
  export { getSkillDocs, getSkillBestDoc, getSkillRequirements, runSkill, generateEnvExample, generateSkillMd, type SkillDocs, type SkillRequirements, } from "./lib/skillinfo.js";
13
+ export { loadConfig, saveConfig, getConfigPath, type SkillsConfig, type ConfigScope, } from "./lib/config.js";
14
+ export type { SkillResponse, SkillDetailResponse, CategoryResponse, TagResponse, InstallResponse, RemoveResponse, VersionResponse, ExportResponse, ImportResponse, SearchResponse, CategoryInstallResponse, ErrorResponse, } from "./types/api.js";
package/dist/index.js CHANGED
@@ -1534,8 +1534,23 @@ function getAllTags() {
1534
1534
  }
1535
1535
  return Array.from(tagSet).sort();
1536
1536
  }
1537
+ function levenshtein(a, b) {
1538
+ const m = a.length, n = b.length;
1539
+ const dp = Array.from({ length: m + 1 }, (_, i) => Array.from({ length: n + 1 }, (_2, j) => i === 0 ? j : j === 0 ? i : 0));
1540
+ for (let i = 1;i <= m; i++) {
1541
+ for (let j = 1;j <= n; j++) {
1542
+ dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
1543
+ }
1544
+ }
1545
+ return dp[m][n];
1546
+ }
1547
+ function findSimilarSkills(query, maxResults = 3) {
1548
+ const q = query.toLowerCase();
1549
+ const scored = SKILLS.map((s) => ({ name: s.name, dist: levenshtein(q, s.name.toLowerCase()) })).filter((s) => s.dist <= Math.max(3, Math.floor(q.length / 2))).sort((a, b) => a.dist - b.dist);
1550
+ return scored.slice(0, maxResults).map((s) => s.name);
1551
+ }
1537
1552
  // src/lib/installer.ts
1538
- import { existsSync, cpSync, mkdirSync, writeFileSync, rmSync, readdirSync, statSync, readFileSync } from "fs";
1553
+ import { existsSync, cpSync, mkdirSync, writeFileSync, rmSync, readdirSync, statSync, readFileSync, accessSync, constants } from "fs";
1539
1554
  import { join, dirname } from "path";
1540
1555
  import { homedir } from "os";
1541
1556
  import { fileURLToPath } from "url";
@@ -1602,6 +1617,7 @@ function installSkill(name, options = {}) {
1602
1617
  }
1603
1618
  });
1604
1619
  updateSkillsIndex(destDir);
1620
+ recordInstall(destDir, name);
1605
1621
  const meta = getSkill(name);
1606
1622
  if (meta?.dependencies && meta.dependencies.length > 0) {
1607
1623
  const installed = getInstalledSkills(targetDir);
@@ -1630,7 +1646,9 @@ function installSkills(names, options = {}) {
1630
1646
  }
1631
1647
  function updateSkillsIndex(skillsDir) {
1632
1648
  const indexPath = join(skillsDir, "index.ts");
1633
- const skills = readdirSync(skillsDir).filter((f) => f.startsWith("skill-") && !f.includes("."));
1649
+ const meta = loadMeta(skillsDir);
1650
+ const disabledSet = new Set(meta.disabled || []);
1651
+ const skills = readdirSync(skillsDir).filter((f) => f.startsWith("skill-") && !f.includes(".") && !disabledSet.has(f.replace("skill-", "")));
1634
1652
  const exports = skills.map((s) => {
1635
1653
  const name = s.replace("skill-", "").replace(/-/g, "_");
1636
1654
  return `export * as ${name} from './${s}/src/index.js';`;
@@ -1645,6 +1663,74 @@ ${exports}
1645
1663
  `;
1646
1664
  writeFileSync(indexPath, content);
1647
1665
  }
1666
+ function getMetaPath(skillsDir) {
1667
+ return join(skillsDir, ".meta.json");
1668
+ }
1669
+ function loadMeta(skillsDir) {
1670
+ const metaPath = getMetaPath(skillsDir);
1671
+ if (existsSync(metaPath)) {
1672
+ try {
1673
+ return JSON.parse(readFileSync(metaPath, "utf-8"));
1674
+ } catch {}
1675
+ }
1676
+ return { skills: {} };
1677
+ }
1678
+ function saveMeta(skillsDir, meta) {
1679
+ writeFileSync(getMetaPath(skillsDir), JSON.stringify(meta, null, 2));
1680
+ }
1681
+ function recordInstall(skillsDir, name) {
1682
+ const meta = loadMeta(skillsDir);
1683
+ const skillName = normalizeSkillName(name);
1684
+ let version = "unknown";
1685
+ try {
1686
+ const pkgPath = join(skillsDir, skillName, "package.json");
1687
+ if (existsSync(pkgPath)) {
1688
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
1689
+ version = pkg.version || "unknown";
1690
+ }
1691
+ } catch {}
1692
+ meta.skills[name] = { installedAt: new Date().toISOString(), version };
1693
+ saveMeta(skillsDir, meta);
1694
+ }
1695
+ function recordRemove(skillsDir, name) {
1696
+ const meta = loadMeta(skillsDir);
1697
+ delete meta.skills[name];
1698
+ saveMeta(skillsDir, meta);
1699
+ }
1700
+ function getInstallMeta(targetDir = process.cwd()) {
1701
+ return loadMeta(join(targetDir, ".skills"));
1702
+ }
1703
+ function disableSkill(name, targetDir = process.cwd()) {
1704
+ const skillsDir = join(targetDir, ".skills");
1705
+ const skillName = normalizeSkillName(name);
1706
+ if (!existsSync(join(skillsDir, skillName)))
1707
+ return false;
1708
+ const meta = loadMeta(skillsDir);
1709
+ const disabled = new Set(meta.disabled || []);
1710
+ if (disabled.has(name))
1711
+ return false;
1712
+ disabled.add(name);
1713
+ meta.disabled = [...disabled];
1714
+ saveMeta(skillsDir, meta);
1715
+ updateSkillsIndex(skillsDir);
1716
+ return true;
1717
+ }
1718
+ function enableSkill(name, targetDir = process.cwd()) {
1719
+ const skillsDir = join(targetDir, ".skills");
1720
+ const meta = loadMeta(skillsDir);
1721
+ const disabled = new Set(meta.disabled || []);
1722
+ if (!disabled.has(name))
1723
+ return false;
1724
+ disabled.delete(name);
1725
+ meta.disabled = [...disabled];
1726
+ saveMeta(skillsDir, meta);
1727
+ updateSkillsIndex(skillsDir);
1728
+ return true;
1729
+ }
1730
+ function getDisabledSkills(targetDir = process.cwd()) {
1731
+ const meta = loadMeta(join(targetDir, ".skills"));
1732
+ return meta.disabled || [];
1733
+ }
1648
1734
  function getInstalledSkills(targetDir = process.cwd()) {
1649
1735
  const skillsDir = join(targetDir, ".skills");
1650
1736
  if (!existsSync(skillsDir)) {
@@ -1664,6 +1750,7 @@ function removeSkill(name, targetDir = process.cwd()) {
1664
1750
  }
1665
1751
  rmSync(skillPath, { recursive: true, force: true });
1666
1752
  updateSkillsIndex(skillsDir);
1753
+ recordRemove(skillsDir, name);
1667
1754
  return true;
1668
1755
  }
1669
1756
  var AGENT_TARGETS = ["claude", "codex", "gemini"];
@@ -1696,6 +1783,30 @@ function installSkillForAgent(name, options, generateSkillMd) {
1696
1783
  return { skill: name, success: false, error: `No SKILL.md found and could not generate one for '${name}'` };
1697
1784
  }
1698
1785
  const destDir = getAgentSkillPath(name, agent, scope, projectDir);
1786
+ if (scope === "global") {
1787
+ const agentBaseDir = join(homedir(), `.${agent}`);
1788
+ if (!existsSync(agentBaseDir)) {
1789
+ const agentLabels = {
1790
+ claude: "Claude Code",
1791
+ codex: "Codex CLI",
1792
+ gemini: "Gemini CLI"
1793
+ };
1794
+ return {
1795
+ skill: name,
1796
+ success: false,
1797
+ error: `Agent directory ${agentBaseDir} does not exist. Is ${agentLabels[agent]} installed?`
1798
+ };
1799
+ }
1800
+ try {
1801
+ accessSync(agentBaseDir, constants.W_OK);
1802
+ } catch {
1803
+ return {
1804
+ skill: name,
1805
+ success: false,
1806
+ error: `Agent directory ${agentBaseDir} is not writable. Check permissions.`
1807
+ };
1808
+ }
1809
+ }
1699
1810
  try {
1700
1811
  mkdirSync(destDir, { recursive: true });
1701
1812
  writeFileSync(join(destDir, "SKILL.md"), skillMdContent);
@@ -1998,12 +2109,83 @@ function readIfExists(path) {
1998
2109
  } catch {}
1999
2110
  return null;
2000
2111
  }
2112
+ // src/lib/config.ts
2113
+ import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
2114
+ import { join as join3, dirname as dirname2 } from "path";
2115
+ import { homedir as homedir2 } from "os";
2116
+ var VALID_KEYS = {
2117
+ defaultAgent: ["claude", "codex", "gemini", "all"],
2118
+ defaultScope: ["global", "project"],
2119
+ format: ["compact", "json", "csv"]
2120
+ };
2121
+ function getConfigPath(scope) {
2122
+ if (scope === "global") {
2123
+ return join3(homedir2(), ".skillsrc");
2124
+ }
2125
+ return join3(process.cwd(), "skills.config.json");
2126
+ }
2127
+ function readConfigFile(path) {
2128
+ if (!existsSync3(path))
2129
+ return {};
2130
+ try {
2131
+ const raw = readFileSync3(path, "utf-8");
2132
+ const parsed = JSON.parse(raw);
2133
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
2134
+ return {};
2135
+ const config = {};
2136
+ for (const [key, allowed] of Object.entries(VALID_KEYS)) {
2137
+ const val = parsed[key];
2138
+ if (typeof val === "string" && allowed.includes(val)) {
2139
+ config[key] = val;
2140
+ }
2141
+ }
2142
+ return config;
2143
+ } catch {
2144
+ return {};
2145
+ }
2146
+ }
2147
+ function loadConfig() {
2148
+ const globalConfig = readConfigFile(getConfigPath("global"));
2149
+ const projectConfig = readConfigFile(getConfigPath("project"));
2150
+ return { ...globalConfig, ...projectConfig };
2151
+ }
2152
+ function saveConfig(key, value, scope = "project") {
2153
+ if (!(key in VALID_KEYS)) {
2154
+ throw new Error(`Unknown config key: ${key}. Valid keys: ${Object.keys(VALID_KEYS).join(", ")}`);
2155
+ }
2156
+ const allowed = VALID_KEYS[key];
2157
+ if (!allowed.includes(value)) {
2158
+ throw new Error(`Invalid value '${value}' for ${key}. Allowed: ${allowed.join(", ")}`);
2159
+ }
2160
+ const filePath = getConfigPath(scope);
2161
+ let existing = {};
2162
+ if (existsSync3(filePath)) {
2163
+ try {
2164
+ existing = JSON.parse(readFileSync3(filePath, "utf-8"));
2165
+ if (typeof existing !== "object" || existing === null || Array.isArray(existing)) {
2166
+ existing = {};
2167
+ }
2168
+ } catch {
2169
+ existing = {};
2170
+ }
2171
+ } else {
2172
+ const dir = dirname2(filePath);
2173
+ if (!existsSync3(dir)) {
2174
+ mkdirSync2(dir, { recursive: true });
2175
+ }
2176
+ }
2177
+ existing[key] = value;
2178
+ writeFileSync2(filePath, JSON.stringify(existing, null, 2) + `
2179
+ `);
2180
+ }
2001
2181
  export {
2002
2182
  skillExists,
2003
2183
  searchSkills,
2184
+ saveConfig,
2004
2185
  runSkill,
2005
2186
  removeSkillForAgent,
2006
2187
  removeSkill,
2188
+ loadConfig,
2007
2189
  installSkills,
2008
2190
  installSkillForAgent,
2009
2191
  installSkill,
@@ -2015,11 +2197,17 @@ export {
2015
2197
  getSkillBestDoc,
2016
2198
  getSkill,
2017
2199
  getInstalledSkills,
2200
+ getInstallMeta,
2201
+ getDisabledSkills,
2202
+ getConfigPath,
2018
2203
  getAllTags,
2019
2204
  getAgentSkillsDir,
2020
2205
  getAgentSkillPath,
2021
2206
  generateSkillMd,
2022
2207
  generateEnvExample,
2208
+ findSimilarSkills,
2209
+ enableSkill,
2210
+ disableSkill,
2023
2211
  SKILLS,
2024
2212
  CATEGORIES,
2025
2213
  AGENT_TARGETS
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Config file support for Open Skills
3
+ *
4
+ * Loads configuration from:
5
+ * 1. Project-local: ./skills.config.json (highest priority)
6
+ * 2. Global: ~/.skillsrc (JSON format, lowest priority)
7
+ *
8
+ * Values from the project config override global config.
9
+ */
10
+ export interface SkillsConfig {
11
+ defaultAgent?: "claude" | "codex" | "gemini" | "all";
12
+ defaultScope?: "global" | "project";
13
+ format?: "compact" | "json" | "csv";
14
+ }
15
+ export type ConfigScope = "global" | "project";
16
+ /**
17
+ * Get the config file path for a given scope
18
+ */
19
+ export declare function getConfigPath(scope: ConfigScope): string;
20
+ /**
21
+ * Load merged config: project-local overrides global
22
+ */
23
+ export declare function loadConfig(): SkillsConfig;
24
+ /**
25
+ * Save a single config key-value pair to the specified scope
26
+ */
27
+ export declare function saveConfig(key: string, value: string, scope?: ConfigScope): void;
@@ -0,0 +1 @@
1
+ export {};
@@ -27,6 +27,30 @@ export declare function installSkill(name: string, options?: InstallOptions): In
27
27
  * Install multiple skills
28
28
  */
29
29
  export declare function installSkills(names: string[], options?: InstallOptions): InstallResult[];
30
+ interface SkillMeta {
31
+ installedAt: string;
32
+ version: string;
33
+ }
34
+ interface MetaFile {
35
+ skills: Record<string, SkillMeta>;
36
+ disabled?: string[];
37
+ }
38
+ /**
39
+ * Get installation metadata for installed skills
40
+ */
41
+ export declare function getInstallMeta(targetDir?: string): MetaFile;
42
+ /**
43
+ * Disable a skill (exclude from .skills/index.ts without removing files)
44
+ */
45
+ export declare function disableSkill(name: string, targetDir?: string): boolean;
46
+ /**
47
+ * Enable a previously disabled skill (re-add to .skills/index.ts)
48
+ */
49
+ export declare function enableSkill(name: string, targetDir?: string): boolean;
50
+ /**
51
+ * Get list of disabled skills
52
+ */
53
+ export declare function getDisabledSkills(targetDir?: string): string[];
30
54
  /**
31
55
  * Get list of installed skills in a directory
32
56
  */
@@ -65,3 +89,4 @@ export declare function installSkillForAgent(name: string, options: AgentInstall
65
89
  * Remove a skill from an agent's skill directory
66
90
  */
67
91
  export declare function removeSkillForAgent(name: string, options: AgentInstallOptions): boolean;
92
+ export {};
@@ -23,3 +23,7 @@ export declare function getSkillsByTag(tag: string): SkillMeta[];
23
23
  * Return all unique tags across every skill, sorted alphabetically.
24
24
  */
25
25
  export declare function getAllTags(): string[];
26
+ /**
27
+ * Find skills with names similar to the given query (for "did you mean?" suggestions)
28
+ */
29
+ export declare function findSimilarSkills(query: string, maxResults?: number): string[];
@@ -0,0 +1,74 @@
1
+ /**
2
+ * Shared API response types used by both the HTTP server and the dashboard.
3
+ * Import from "@hasna/skills" to get type-safe API responses.
4
+ */
5
+ export interface SkillResponse {
6
+ name: string;
7
+ displayName: string;
8
+ description: string;
9
+ category: string;
10
+ tags: string[];
11
+ installed: boolean;
12
+ envVars: string[];
13
+ envVarsSet: string[];
14
+ systemDeps: string[];
15
+ cliCommand: string | null;
16
+ }
17
+ export interface SkillDetailResponse extends SkillResponse {
18
+ docs: string | null;
19
+ }
20
+ export interface CategoryResponse {
21
+ name: string;
22
+ count: number;
23
+ }
24
+ export interface TagResponse {
25
+ name: string;
26
+ count: number;
27
+ }
28
+ export interface InstallResponse {
29
+ skill: string;
30
+ success: boolean;
31
+ error?: string;
32
+ results?: Array<{
33
+ skill: string;
34
+ success: boolean;
35
+ error?: string;
36
+ }>;
37
+ }
38
+ export interface RemoveResponse {
39
+ skill: string;
40
+ success: boolean;
41
+ }
42
+ export interface VersionResponse {
43
+ version: string;
44
+ name: string;
45
+ }
46
+ export interface ExportResponse {
47
+ version: number;
48
+ skills: string[];
49
+ timestamp: string;
50
+ }
51
+ export interface ImportResponse {
52
+ imported: number;
53
+ total: number;
54
+ results: Array<{
55
+ skill: string;
56
+ success: boolean;
57
+ error?: string;
58
+ }>;
59
+ }
60
+ export interface SearchResponse extends SkillResponse {
61
+ }
62
+ export interface CategoryInstallResponse {
63
+ category: string;
64
+ count: number;
65
+ success: boolean;
66
+ results: Array<{
67
+ skill: string;
68
+ success: boolean;
69
+ error?: string;
70
+ }>;
71
+ }
72
+ export interface ErrorResponse {
73
+ error: string;
74
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.1.13",
3
+ "version": "0.1.14",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,9 +23,12 @@
23
23
  "main": "./dist/index.js",
24
24
  "types": "./dist/index.d.ts",
25
25
  "scripts": {
26
- "build": "bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
26
+ "clean": "rm -rf bin/ dist/",
27
+ "build": "bun run clean && bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
27
28
  "test": "bun test",
28
29
  "dev": "bun run ./src/cli/index.tsx",
30
+ "dev:watch": "bun --watch run ./src/cli/index.tsx",
31
+ "dev:mcp": "bun --watch run ./src/mcp/index.ts",
29
32
  "typecheck": "tsc --noEmit",
30
33
  "prepublishOnly": "bun run build",
31
34
  "dashboard:dev": "cd dashboard && bun run dev",
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { Command } from "commander";
4
+ import { homedir } from "os";
5
+ import { join } from "path";
6
+
7
+ function getDataDir(): string {
8
+ return process.env.DATA_DIR || join(homedir(), ".skill", "skill-academic-journal-matcher");
9
+ }
10
+
11
+ const program = new Command();
12
+
13
+ program
14
+ .name("skill-academic-journal-matcher")
15
+ .description("Academic Journal Matcher skill")
16
+ .version("0.1.0");
17
+
18
+ program
19
+ .command("run")
20
+ .description("Run the skill")
21
+ .option("-o, --output <path>", "Output directory", join(getDataDir(), "output"))
22
+ .allowUnknownOption(true)
23
+ .action(async (options, command) => {
24
+ try {
25
+ const args = command.args;
26
+ process.env.DATA_DIR = process.env.DATA_DIR || getDataDir();
27
+ await import("../src/index.js");
28
+ } catch (err) {
29
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
30
+ process.exit(1);
31
+ }
32
+ });
33
+
34
+ program.parse();
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { Command } from "commander";
4
+ import { homedir } from "os";
5
+ import { join } from "path";
6
+
7
+ function getDataDir(): string {
8
+ return process.env.DATA_DIR || join(homedir(), ".skill", "skill-action-item-router");
9
+ }
10
+
11
+ const program = new Command();
12
+
13
+ program
14
+ .name("skill-action-item-router")
15
+ .description("Action Item Router skill")
16
+ .version("0.1.0");
17
+
18
+ program
19
+ .command("run")
20
+ .description("Run the skill")
21
+ .option("-o, --output <path>", "Output directory", join(getDataDir(), "output"))
22
+ .allowUnknownOption(true)
23
+ .action(async (options, command) => {
24
+ try {
25
+ const args = command.args;
26
+ process.env.DATA_DIR = process.env.DATA_DIR || getDataDir();
27
+ await import("../src/index.js");
28
+ } catch (err) {
29
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
30
+ process.exit(1);
31
+ }
32
+ });
33
+
34
+ program.parse();
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { Command } from "commander";
4
+ import { homedir } from "os";
5
+ import { join } from "path";
6
+
7
+ function getDataDir(): string {
8
+ return process.env.DATA_DIR || join(homedir(), ".skill", "skill-ad-creative-generator");
9
+ }
10
+
11
+ const program = new Command();
12
+
13
+ program
14
+ .name("skill-ad-creative-generator")
15
+ .description("Ad Creative Generator skill")
16
+ .version("0.1.0");
17
+
18
+ program
19
+ .command("run")
20
+ .description("Run the skill")
21
+ .option("-o, --output <path>", "Output directory", join(getDataDir(), "output"))
22
+ .allowUnknownOption(true)
23
+ .action(async (options, command) => {
24
+ try {
25
+ const args = command.args;
26
+ process.env.DATA_DIR = process.env.DATA_DIR || getDataDir();
27
+ await import("../src/index.js");
28
+ } catch (err) {
29
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
30
+ process.exit(1);
31
+ }
32
+ });
33
+
34
+ program.parse();
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { Command } from "commander";
4
+ import { homedir } from "os";
5
+ import { join } from "path";
6
+
7
+ function getDataDir(): string {
8
+ return process.env.DATA_DIR || join(homedir(), ".skill", "skill-advanced-math");
9
+ }
10
+
11
+ const program = new Command();
12
+
13
+ program
14
+ .name("skill-advanced-math")
15
+ .description("Advanced Math skill")
16
+ .version("0.1.0");
17
+
18
+ program
19
+ .command("run")
20
+ .description("Run the skill")
21
+ .option("-o, --output <path>", "Output directory", join(getDataDir(), "output"))
22
+ .allowUnknownOption(true)
23
+ .action(async (options, command) => {
24
+ try {
25
+ const args = command.args;
26
+ process.env.DATA_DIR = process.env.DATA_DIR || getDataDir();
27
+ await import("../src/index.js");
28
+ } catch (err) {
29
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
30
+ process.exit(1);
31
+ }
32
+ });
33
+
34
+ program.parse();
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env bun
2
+ import { Command } from "commander";
3
+
4
+ const program = new Command();
5
+
6
+ program
7
+ .name("skill-analyze-data")
8
+ .description("Data science insights for CSV and JSON")
9
+ .version("0.1.0");
10
+
11
+ program
12
+ .command("run", { isDefault: true })
13
+ .description("Run the skill")
14
+ .allowUnknownOption(true)
15
+ .action(async () => {
16
+ await import("../src/index.js");
17
+ });
18
+
19
+ program.parse();
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { Command } from "commander";
4
+ import { homedir } from "os";
5
+ import { join } from "path";
6
+
7
+ function getDataDir(): string {
8
+ return process.env.DATA_DIR || join(homedir(), ".skill", "skill-anomaly-investigator");
9
+ }
10
+
11
+ const program = new Command();
12
+
13
+ program
14
+ .name("skill-anomaly-investigator")
15
+ .description("Anomaly Investigator skill")
16
+ .version("0.1.0");
17
+
18
+ program
19
+ .command("run")
20
+ .description("Run the skill")
21
+ .option("-o, --output <path>", "Output directory", join(getDataDir(), "output"))
22
+ .allowUnknownOption(true)
23
+ .action(async (options, command) => {
24
+ try {
25
+ const args = command.args;
26
+ process.env.DATA_DIR = process.env.DATA_DIR || getDataDir();
27
+ await import("../src/index.js");
28
+ } catch (err) {
29
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
30
+ process.exit(1);
31
+ }
32
+ });
33
+
34
+ program.parse();
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { Command } from "commander";
4
+ import { homedir } from "os";
5
+ import { join } from "path";
6
+
7
+ function getDataDir(): string {
8
+ return process.env.DATA_DIR || join(homedir(), ".skill", "skill-api-test-suite");
9
+ }
10
+
11
+ const program = new Command();
12
+
13
+ program
14
+ .name("skill-api-test-suite")
15
+ .description("Api Test Suite skill")
16
+ .version("0.1.0");
17
+
18
+ program
19
+ .command("run")
20
+ .description("Run the skill")
21
+ .option("-o, --output <path>", "Output directory", join(getDataDir(), "output"))
22
+ .allowUnknownOption(true)
23
+ .action(async (options, command) => {
24
+ try {
25
+ const args = command.args;
26
+ process.env.DATA_DIR = process.env.DATA_DIR || getDataDir();
27
+ await import("../src/index.js");
28
+ } catch (err) {
29
+ console.error(`Error: ${err instanceof Error ? err.message : err}`);
30
+ process.exit(1);
31
+ }
32
+ });
33
+
34
+ program.parse();