@hasna/skills 0.1.8 → 0.1.10

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 (3) hide show
  1. package/bin/index.js +85 -26
  2. package/bin/mcp.js +84 -25
  3. package/package.json +1 -1
package/bin/index.js CHANGED
@@ -1878,7 +1878,7 @@ var package_default;
1878
1878
  var init_package = __esm(() => {
1879
1879
  package_default = {
1880
1880
  name: "@hasna/skills",
1881
- version: "0.1.8",
1881
+ version: "0.1.10",
1882
1882
  description: "Skills library for AI coding agents",
1883
1883
  type: "module",
1884
1884
  bin: {
@@ -34785,6 +34785,9 @@ var exports_mcp = {};
34785
34785
  import { existsSync as existsSync3, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
34786
34786
  import { join as join3 } from "path";
34787
34787
  import { homedir as homedir2 } from "os";
34788
+ function stripNulls(obj) {
34789
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== null && v !== undefined && !(Array.isArray(v) && v.length === 0)));
34790
+ }
34788
34791
  async function main() {
34789
34792
  const transport = new StdioServerTransport;
34790
34793
  await server.connect(transport);
@@ -34804,33 +34807,37 @@ var init_mcp2 = __esm(() => {
34804
34807
  });
34805
34808
  server.registerTool("list_skills", {
34806
34809
  title: "List Skills",
34807
- description: "List all available skills, optionally filtered by category",
34810
+ description: "List skills. Returns {name,category} by default; detail:true for full objects.",
34808
34811
  inputSchema: {
34809
- category: exports_external.string().optional().describe("Filter by category name")
34812
+ category: exports_external.string().optional().describe("Filter by category"),
34813
+ detail: exports_external.boolean().optional().describe("Return full objects (default: false)")
34810
34814
  }
34811
- }, async ({ category }) => {
34815
+ }, async ({ category, detail }) => {
34812
34816
  const skills = category ? getSkillsByCategory(category) : SKILLS;
34817
+ const result = detail ? skills : skills.map((s) => ({ name: s.name, category: s.category }));
34813
34818
  return {
34814
- content: [{ type: "text", text: JSON.stringify(skills, null, 2) }]
34819
+ content: [{ type: "text", text: JSON.stringify(result) }]
34815
34820
  };
34816
34821
  });
34817
34822
  server.registerTool("search_skills", {
34818
34823
  title: "Search Skills",
34819
- description: "Search skills by query string (matches name, description, and tags)",
34824
+ description: "Search skills by name, description, or tags. Returns compact list by default.",
34820
34825
  inputSchema: {
34821
- query: exports_external.string().describe("Search query")
34826
+ query: exports_external.string().describe("Search query (fuzzy-matched)"),
34827
+ detail: exports_external.boolean().optional().describe("Return full objects (default: false)")
34822
34828
  }
34823
- }, async ({ query }) => {
34829
+ }, async ({ query, detail }) => {
34824
34830
  const results = searchSkills(query);
34831
+ const out = detail ? results : results.map((s) => ({ name: s.name, category: s.category }));
34825
34832
  return {
34826
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
34833
+ content: [{ type: "text", text: JSON.stringify(out) }]
34827
34834
  };
34828
34835
  });
34829
34836
  server.registerTool("get_skill_info", {
34830
34837
  title: "Get Skill Info",
34831
- description: "Get detailed metadata about a skill including requirements, env vars, and dependencies",
34838
+ description: "Get skill metadata, env vars, and dependencies.",
34832
34839
  inputSchema: {
34833
- name: exports_external.string().describe("Skill name (e.g. 'image', 'deep-research')")
34840
+ name: exports_external.string().describe("Skill name (e.g. 'image')")
34834
34841
  }
34835
34842
  }, async ({ name }) => {
34836
34843
  const skill = getSkill(name);
@@ -34838,13 +34845,14 @@ var init_mcp2 = __esm(() => {
34838
34845
  return { content: [{ type: "text", text: `Skill '${name}' not found` }], isError: true };
34839
34846
  }
34840
34847
  const reqs = getSkillRequirements(name);
34848
+ const result = stripNulls({ ...skill, ...reqs });
34841
34849
  return {
34842
- content: [{ type: "text", text: JSON.stringify({ ...skill, ...reqs }, null, 2) }]
34850
+ content: [{ type: "text", text: JSON.stringify(result) }]
34843
34851
  };
34844
34852
  });
34845
34853
  server.registerTool("get_skill_docs", {
34846
34854
  title: "Get Skill Docs",
34847
- description: "Get documentation for a skill (SKILL.md, README.md, or CLAUDE.md)",
34855
+ description: "Get skill documentation (SKILL.md > README.md > CLAUDE.md).",
34848
34856
  inputSchema: {
34849
34857
  name: exports_external.string().describe("Skill name")
34850
34858
  }
@@ -34857,7 +34865,7 @@ var init_mcp2 = __esm(() => {
34857
34865
  });
34858
34866
  server.registerTool("install_skill", {
34859
34867
  title: "Install Skill",
34860
- description: "Install a skill. Without --for, installs full source to .skills/. With --for, copies SKILL.md to agent skill directory.",
34868
+ description: "Install a skill to .skills/ or to an agent dir (for: claude|codex|gemini|all).",
34861
34869
  inputSchema: {
34862
34870
  name: exports_external.string().describe("Skill name to install"),
34863
34871
  for: exports_external.string().optional().describe("Agent target: claude, codex, gemini, or all"),
@@ -34888,7 +34896,7 @@ var init_mcp2 = __esm(() => {
34888
34896
  });
34889
34897
  server.registerTool("install_category", {
34890
34898
  title: "Install Category",
34891
- description: "Install all skills in a category. Optionally install for a specific agent (claude, codex, gemini, or all) with a given scope.",
34899
+ description: "Install all skills in a category, optionally for a specific agent.",
34892
34900
  inputSchema: {
34893
34901
  category: exports_external.string().describe("Category name (case-insensitive, e.g. 'Event Management')"),
34894
34902
  for: exports_external.string().optional().describe("Agent target: claude, codex, gemini, or all"),
@@ -34934,7 +34942,7 @@ var init_mcp2 = __esm(() => {
34934
34942
  });
34935
34943
  server.registerTool("remove_skill", {
34936
34944
  title: "Remove Skill",
34937
- description: "Remove an installed skill. Without --for, removes from .skills/. With --for, removes from agent skill directory.",
34945
+ description: "Remove a skill from .skills/ or from an agent dir.",
34938
34946
  inputSchema: {
34939
34947
  name: exports_external.string().describe("Skill name to remove"),
34940
34948
  for: exports_external.string().optional().describe("Agent target: claude, codex, gemini, or all"),
@@ -34967,7 +34975,7 @@ var init_mcp2 = __esm(() => {
34967
34975
  });
34968
34976
  server.registerTool("list_categories", {
34969
34977
  title: "List Categories",
34970
- description: "List all skill categories with counts"
34978
+ description: "List all 17 skill categories with skill counts."
34971
34979
  }, async () => {
34972
34980
  const cats = CATEGORIES.map((category) => ({
34973
34981
  name: category,
@@ -34977,7 +34985,7 @@ var init_mcp2 = __esm(() => {
34977
34985
  });
34978
34986
  server.registerTool("list_tags", {
34979
34987
  title: "List Tags",
34980
- description: "List all unique tags across all skills with their occurrence counts"
34988
+ description: "List all unique skill tags with occurrence counts."
34981
34989
  }, async () => {
34982
34990
  const tagCounts = new Map;
34983
34991
  for (const skill of SKILLS) {
@@ -34990,7 +34998,7 @@ var init_mcp2 = __esm(() => {
34990
34998
  });
34991
34999
  server.registerTool("get_requirements", {
34992
35000
  title: "Get Requirements",
34993
- description: "Get environment variables, system dependencies, and npm dependencies for a skill",
35001
+ description: "Get env vars, system deps, and npm dependencies for a skill.",
34994
35002
  inputSchema: {
34995
35003
  name: exports_external.string().describe("Skill name")
34996
35004
  }
@@ -35003,7 +35011,7 @@ var init_mcp2 = __esm(() => {
35003
35011
  });
35004
35012
  server.registerTool("run_skill", {
35005
35013
  title: "Run Skill",
35006
- description: "Run a skill by name with optional arguments. Returns the exit code and any error message.",
35014
+ description: "Run a skill by name with optional arguments.",
35007
35015
  inputSchema: {
35008
35016
  name: exports_external.string().describe("Skill name to run"),
35009
35017
  args: exports_external.array(exports_external.string()).optional().describe("Arguments to pass to the skill")
@@ -35026,7 +35034,7 @@ var init_mcp2 = __esm(() => {
35026
35034
  });
35027
35035
  server.registerTool("export_skills", {
35028
35036
  title: "Export Skills",
35029
- description: "Export the list of currently installed skills as a JSON payload that can be imported elsewhere"
35037
+ description: "Export installed skills as a JSON payload for import elsewhere."
35030
35038
  }, async () => {
35031
35039
  const skills = getInstalledSkills();
35032
35040
  const payload = {
@@ -35038,7 +35046,7 @@ var init_mcp2 = __esm(() => {
35038
35046
  });
35039
35047
  server.registerTool("import_skills", {
35040
35048
  title: "Import Skills",
35041
- description: "Install a list of skills from an export payload. Supports agent-specific installs via the 'for' parameter.",
35049
+ description: "Install skills from an export payload. Supports agent installs via 'for'.",
35042
35050
  inputSchema: {
35043
35051
  skills: exports_external.array(exports_external.string()).describe("List of skill names to install"),
35044
35052
  for: exports_external.string().optional().describe("Agent target: claude, codex, gemini, or all"),
@@ -35080,7 +35088,7 @@ var init_mcp2 = __esm(() => {
35080
35088
  });
35081
35089
  server.registerTool("whoami", {
35082
35090
  title: "Skills Whoami",
35083
- description: "Show setup summary: package version, installed skills, agent configurations, skills directory location, and working directory"
35091
+ description: "Show setup summary: version, installed skills, agent configs, cwd."
35084
35092
  }, async () => {
35085
35093
  const version2 = package_default.version;
35086
35094
  const cwd = process.cwd();
@@ -35113,11 +35121,11 @@ var init_mcp2 = __esm(() => {
35113
35121
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
35114
35122
  });
35115
35123
  server.registerResource("Skills Registry", "skills://registry", {
35116
- description: "Full list of all available skills as JSON"
35124
+ description: "Compact skill list [{name,category}]. Use skills://{name} for detail."
35117
35125
  }, async () => ({
35118
35126
  contents: [{
35119
35127
  uri: "skills://registry",
35120
- text: JSON.stringify(SKILLS, null, 2),
35128
+ text: JSON.stringify(SKILLS.map((s) => ({ name: s.name, category: s.category }))),
35121
35129
  mimeType: "application/json"
35122
35130
  }]
35123
35131
  }));
@@ -35135,6 +35143,57 @@ var init_mcp2 = __esm(() => {
35135
35143
  }]
35136
35144
  };
35137
35145
  });
35146
+ server.registerTool("search_tools", {
35147
+ title: "Search Tools",
35148
+ description: "List tool names, optionally filtered by keyword.",
35149
+ inputSchema: { query: exports_external.string().optional().describe("Keyword filter") }
35150
+ }, async ({ query }) => {
35151
+ const all = [
35152
+ "list_skills",
35153
+ "search_skills",
35154
+ "get_skill_info",
35155
+ "get_skill_docs",
35156
+ "install_skill",
35157
+ "install_category",
35158
+ "remove_skill",
35159
+ "list_categories",
35160
+ "list_tags",
35161
+ "get_requirements",
35162
+ "run_skill",
35163
+ "export_skills",
35164
+ "import_skills",
35165
+ "whoami",
35166
+ "search_tools",
35167
+ "describe_tools"
35168
+ ];
35169
+ const matches = query ? all.filter((n) => n.includes(query.toLowerCase())) : all;
35170
+ return { content: [{ type: "text", text: matches.join(", ") }] };
35171
+ });
35172
+ server.registerTool("describe_tools", {
35173
+ title: "Describe Tools",
35174
+ description: "Get descriptions for specific tools by name.",
35175
+ inputSchema: { names: exports_external.array(exports_external.string()).describe("Tool names from search_tools") }
35176
+ }, async ({ names }) => {
35177
+ const descriptions = {
35178
+ list_skills: "List skills {name,category}. Params: category?, detail?",
35179
+ search_skills: "Search skills by name/tags. Params: query, detail?",
35180
+ get_skill_info: "Get skill metadata and env vars. Params: name",
35181
+ get_skill_docs: "Get skill documentation. Params: name",
35182
+ install_skill: "Install a skill for an agent. Params: name, agent?",
35183
+ install_category: "Install all skills in a category. Params: category, agent?",
35184
+ remove_skill: "Remove an installed skill. Params: name, agent?",
35185
+ list_categories: "List skill categories with counts.",
35186
+ list_tags: "List all tags across skills.",
35187
+ get_requirements: "Get skill requirements/dependencies. Params: name",
35188
+ run_skill: "Execute a skill. Params: name, args?",
35189
+ export_skills: "Export skill config. Params: format?",
35190
+ import_skills: "Import skill config. Params: data",
35191
+ whoami: "Show setup: version, installed skills, agent configs."
35192
+ };
35193
+ const result = names.map((n) => `${n}: ${descriptions[n] || "See tool schema"}`).join(`
35194
+ `);
35195
+ return { content: [{ type: "text", text: result }] };
35196
+ });
35138
35197
  main().catch((error48) => {
35139
35198
  console.error("MCP server error:", error48);
35140
35199
  process.exit(1);
@@ -36687,7 +36746,7 @@ var program2 = new Command;
36687
36746
  program2.name("skills").description("Install AI agent skills for your project").version(package_default.version).option("--verbose", "Enable verbose logging", false).enablePositionalOptions();
36688
36747
  program2.command("interactive", { isDefault: true }).alias("i").description("Interactive skill browser (TUI)").action(() => {
36689
36748
  if (!isTTY) {
36690
- console.log(JSON.stringify(SKILLS, null, 2));
36749
+ console.log(JSON.stringify(SKILLS.map((s) => ({ name: s.name, category: s.category }))));
36691
36750
  process.exit(0);
36692
36751
  }
36693
36752
  render(/* @__PURE__ */ jsxDEV7(App, {}, undefined, false, undefined, this));
package/bin/mcp.js CHANGED
@@ -28604,7 +28604,7 @@ import { homedir as homedir2 } from "os";
28604
28604
  // package.json
28605
28605
  var package_default = {
28606
28606
  name: "@hasna/skills",
28607
- version: "0.1.8",
28607
+ version: "0.1.10",
28608
28608
  description: "Skills library for AI coding agents",
28609
28609
  type: "module",
28610
28610
  bin: {
@@ -30630,35 +30630,42 @@ var server = new McpServer({
30630
30630
  name: "skills",
30631
30631
  version: package_default.version
30632
30632
  });
30633
+ function stripNulls(obj) {
30634
+ return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== null && v !== undefined && !(Array.isArray(v) && v.length === 0)));
30635
+ }
30633
30636
  server.registerTool("list_skills", {
30634
30637
  title: "List Skills",
30635
- description: "List all available skills, optionally filtered by category",
30638
+ description: "List skills. Returns {name,category} by default; detail:true for full objects.",
30636
30639
  inputSchema: {
30637
- category: exports_external.string().optional().describe("Filter by category name")
30640
+ category: exports_external.string().optional().describe("Filter by category"),
30641
+ detail: exports_external.boolean().optional().describe("Return full objects (default: false)")
30638
30642
  }
30639
- }, async ({ category }) => {
30643
+ }, async ({ category, detail }) => {
30640
30644
  const skills = category ? getSkillsByCategory(category) : SKILLS;
30645
+ const result = detail ? skills : skills.map((s) => ({ name: s.name, category: s.category }));
30641
30646
  return {
30642
- content: [{ type: "text", text: JSON.stringify(skills, null, 2) }]
30647
+ content: [{ type: "text", text: JSON.stringify(result) }]
30643
30648
  };
30644
30649
  });
30645
30650
  server.registerTool("search_skills", {
30646
30651
  title: "Search Skills",
30647
- description: "Search skills by query string (matches name, description, and tags)",
30652
+ description: "Search skills by name, description, or tags. Returns compact list by default.",
30648
30653
  inputSchema: {
30649
- query: exports_external.string().describe("Search query")
30654
+ query: exports_external.string().describe("Search query (fuzzy-matched)"),
30655
+ detail: exports_external.boolean().optional().describe("Return full objects (default: false)")
30650
30656
  }
30651
- }, async ({ query }) => {
30657
+ }, async ({ query, detail }) => {
30652
30658
  const results = searchSkills(query);
30659
+ const out = detail ? results : results.map((s) => ({ name: s.name, category: s.category }));
30653
30660
  return {
30654
- content: [{ type: "text", text: JSON.stringify(results, null, 2) }]
30661
+ content: [{ type: "text", text: JSON.stringify(out) }]
30655
30662
  };
30656
30663
  });
30657
30664
  server.registerTool("get_skill_info", {
30658
30665
  title: "Get Skill Info",
30659
- description: "Get detailed metadata about a skill including requirements, env vars, and dependencies",
30666
+ description: "Get skill metadata, env vars, and dependencies.",
30660
30667
  inputSchema: {
30661
- name: exports_external.string().describe("Skill name (e.g. 'image', 'deep-research')")
30668
+ name: exports_external.string().describe("Skill name (e.g. 'image')")
30662
30669
  }
30663
30670
  }, async ({ name }) => {
30664
30671
  const skill = getSkill(name);
@@ -30666,13 +30673,14 @@ server.registerTool("get_skill_info", {
30666
30673
  return { content: [{ type: "text", text: `Skill '${name}' not found` }], isError: true };
30667
30674
  }
30668
30675
  const reqs = getSkillRequirements(name);
30676
+ const result = stripNulls({ ...skill, ...reqs });
30669
30677
  return {
30670
- content: [{ type: "text", text: JSON.stringify({ ...skill, ...reqs }, null, 2) }]
30678
+ content: [{ type: "text", text: JSON.stringify(result) }]
30671
30679
  };
30672
30680
  });
30673
30681
  server.registerTool("get_skill_docs", {
30674
30682
  title: "Get Skill Docs",
30675
- description: "Get documentation for a skill (SKILL.md, README.md, or CLAUDE.md)",
30683
+ description: "Get skill documentation (SKILL.md > README.md > CLAUDE.md).",
30676
30684
  inputSchema: {
30677
30685
  name: exports_external.string().describe("Skill name")
30678
30686
  }
@@ -30685,7 +30693,7 @@ server.registerTool("get_skill_docs", {
30685
30693
  });
30686
30694
  server.registerTool("install_skill", {
30687
30695
  title: "Install Skill",
30688
- description: "Install a skill. Without --for, installs full source to .skills/. With --for, copies SKILL.md to agent skill directory.",
30696
+ description: "Install a skill to .skills/ or to an agent dir (for: claude|codex|gemini|all).",
30689
30697
  inputSchema: {
30690
30698
  name: exports_external.string().describe("Skill name to install"),
30691
30699
  for: exports_external.string().optional().describe("Agent target: claude, codex, gemini, or all"),
@@ -30716,7 +30724,7 @@ server.registerTool("install_skill", {
30716
30724
  });
30717
30725
  server.registerTool("install_category", {
30718
30726
  title: "Install Category",
30719
- description: "Install all skills in a category. Optionally install for a specific agent (claude, codex, gemini, or all) with a given scope.",
30727
+ description: "Install all skills in a category, optionally for a specific agent.",
30720
30728
  inputSchema: {
30721
30729
  category: exports_external.string().describe("Category name (case-insensitive, e.g. 'Event Management')"),
30722
30730
  for: exports_external.string().optional().describe("Agent target: claude, codex, gemini, or all"),
@@ -30762,7 +30770,7 @@ server.registerTool("install_category", {
30762
30770
  });
30763
30771
  server.registerTool("remove_skill", {
30764
30772
  title: "Remove Skill",
30765
- description: "Remove an installed skill. Without --for, removes from .skills/. With --for, removes from agent skill directory.",
30773
+ description: "Remove a skill from .skills/ or from an agent dir.",
30766
30774
  inputSchema: {
30767
30775
  name: exports_external.string().describe("Skill name to remove"),
30768
30776
  for: exports_external.string().optional().describe("Agent target: claude, codex, gemini, or all"),
@@ -30795,7 +30803,7 @@ server.registerTool("remove_skill", {
30795
30803
  });
30796
30804
  server.registerTool("list_categories", {
30797
30805
  title: "List Categories",
30798
- description: "List all skill categories with counts"
30806
+ description: "List all 17 skill categories with skill counts."
30799
30807
  }, async () => {
30800
30808
  const cats = CATEGORIES.map((category) => ({
30801
30809
  name: category,
@@ -30805,7 +30813,7 @@ server.registerTool("list_categories", {
30805
30813
  });
30806
30814
  server.registerTool("list_tags", {
30807
30815
  title: "List Tags",
30808
- description: "List all unique tags across all skills with their occurrence counts"
30816
+ description: "List all unique skill tags with occurrence counts."
30809
30817
  }, async () => {
30810
30818
  const tagCounts = new Map;
30811
30819
  for (const skill of SKILLS) {
@@ -30818,7 +30826,7 @@ server.registerTool("list_tags", {
30818
30826
  });
30819
30827
  server.registerTool("get_requirements", {
30820
30828
  title: "Get Requirements",
30821
- description: "Get environment variables, system dependencies, and npm dependencies for a skill",
30829
+ description: "Get env vars, system deps, and npm dependencies for a skill.",
30822
30830
  inputSchema: {
30823
30831
  name: exports_external.string().describe("Skill name")
30824
30832
  }
@@ -30831,7 +30839,7 @@ server.registerTool("get_requirements", {
30831
30839
  });
30832
30840
  server.registerTool("run_skill", {
30833
30841
  title: "Run Skill",
30834
- description: "Run a skill by name with optional arguments. Returns the exit code and any error message.",
30842
+ description: "Run a skill by name with optional arguments.",
30835
30843
  inputSchema: {
30836
30844
  name: exports_external.string().describe("Skill name to run"),
30837
30845
  args: exports_external.array(exports_external.string()).optional().describe("Arguments to pass to the skill")
@@ -30854,7 +30862,7 @@ server.registerTool("run_skill", {
30854
30862
  });
30855
30863
  server.registerTool("export_skills", {
30856
30864
  title: "Export Skills",
30857
- description: "Export the list of currently installed skills as a JSON payload that can be imported elsewhere"
30865
+ description: "Export installed skills as a JSON payload for import elsewhere."
30858
30866
  }, async () => {
30859
30867
  const skills = getInstalledSkills();
30860
30868
  const payload = {
@@ -30866,7 +30874,7 @@ server.registerTool("export_skills", {
30866
30874
  });
30867
30875
  server.registerTool("import_skills", {
30868
30876
  title: "Import Skills",
30869
- description: "Install a list of skills from an export payload. Supports agent-specific installs via the 'for' parameter.",
30877
+ description: "Install skills from an export payload. Supports agent installs via 'for'.",
30870
30878
  inputSchema: {
30871
30879
  skills: exports_external.array(exports_external.string()).describe("List of skill names to install"),
30872
30880
  for: exports_external.string().optional().describe("Agent target: claude, codex, gemini, or all"),
@@ -30908,7 +30916,7 @@ server.registerTool("import_skills", {
30908
30916
  });
30909
30917
  server.registerTool("whoami", {
30910
30918
  title: "Skills Whoami",
30911
- description: "Show setup summary: package version, installed skills, agent configurations, skills directory location, and working directory"
30919
+ description: "Show setup summary: version, installed skills, agent configs, cwd."
30912
30920
  }, async () => {
30913
30921
  const version2 = package_default.version;
30914
30922
  const cwd = process.cwd();
@@ -30941,11 +30949,11 @@ server.registerTool("whoami", {
30941
30949
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
30942
30950
  });
30943
30951
  server.registerResource("Skills Registry", "skills://registry", {
30944
- description: "Full list of all available skills as JSON"
30952
+ description: "Compact skill list [{name,category}]. Use skills://{name} for detail."
30945
30953
  }, async () => ({
30946
30954
  contents: [{
30947
30955
  uri: "skills://registry",
30948
- text: JSON.stringify(SKILLS, null, 2),
30956
+ text: JSON.stringify(SKILLS.map((s) => ({ name: s.name, category: s.category }))),
30949
30957
  mimeType: "application/json"
30950
30958
  }]
30951
30959
  }));
@@ -30963,6 +30971,57 @@ server.registerResource("Skill Info", new ResourceTemplate("skills://{name}", {
30963
30971
  }]
30964
30972
  };
30965
30973
  });
30974
+ server.registerTool("search_tools", {
30975
+ title: "Search Tools",
30976
+ description: "List tool names, optionally filtered by keyword.",
30977
+ inputSchema: { query: exports_external.string().optional().describe("Keyword filter") }
30978
+ }, async ({ query }) => {
30979
+ const all = [
30980
+ "list_skills",
30981
+ "search_skills",
30982
+ "get_skill_info",
30983
+ "get_skill_docs",
30984
+ "install_skill",
30985
+ "install_category",
30986
+ "remove_skill",
30987
+ "list_categories",
30988
+ "list_tags",
30989
+ "get_requirements",
30990
+ "run_skill",
30991
+ "export_skills",
30992
+ "import_skills",
30993
+ "whoami",
30994
+ "search_tools",
30995
+ "describe_tools"
30996
+ ];
30997
+ const matches = query ? all.filter((n) => n.includes(query.toLowerCase())) : all;
30998
+ return { content: [{ type: "text", text: matches.join(", ") }] };
30999
+ });
31000
+ server.registerTool("describe_tools", {
31001
+ title: "Describe Tools",
31002
+ description: "Get descriptions for specific tools by name.",
31003
+ inputSchema: { names: exports_external.array(exports_external.string()).describe("Tool names from search_tools") }
31004
+ }, async ({ names }) => {
31005
+ const descriptions = {
31006
+ list_skills: "List skills {name,category}. Params: category?, detail?",
31007
+ search_skills: "Search skills by name/tags. Params: query, detail?",
31008
+ get_skill_info: "Get skill metadata and env vars. Params: name",
31009
+ get_skill_docs: "Get skill documentation. Params: name",
31010
+ install_skill: "Install a skill for an agent. Params: name, agent?",
31011
+ install_category: "Install all skills in a category. Params: category, agent?",
31012
+ remove_skill: "Remove an installed skill. Params: name, agent?",
31013
+ list_categories: "List skill categories with counts.",
31014
+ list_tags: "List all tags across skills.",
31015
+ get_requirements: "Get skill requirements/dependencies. Params: name",
31016
+ run_skill: "Execute a skill. Params: name, args?",
31017
+ export_skills: "Export skill config. Params: format?",
31018
+ import_skills: "Import skill config. Params: data",
31019
+ whoami: "Show setup: version, installed skills, agent configs."
31020
+ };
31021
+ const result = names.map((n) => `${n}: ${descriptions[n] || "See tool schema"}`).join(`
31022
+ `);
31023
+ return { content: [{ type: "text", text: result }] };
31024
+ });
30966
31025
  async function main() {
30967
31026
  const transport = new StdioServerTransport;
30968
31027
  await server.connect(transport);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {