@hasna/skills 0.1.11 → 0.1.13

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 +58 -16
  2. package/bin/mcp.js +1 -1
  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.11",
1881
+ version: "0.1.13",
1882
1882
  description: "Skills library for AI coding agents",
1883
1883
  type: "module",
1884
1884
  bin: {
@@ -35253,6 +35253,18 @@ function json2(data, status = 200) {
35253
35253
  function isValidSkillName(name) {
35254
35254
  return /^[a-z0-9-]+$/.test(name);
35255
35255
  }
35256
+ function pickFields(obj, fields) {
35257
+ if (fields.length === 0)
35258
+ return obj;
35259
+ const rec = obj;
35260
+ return Object.fromEntries(fields.filter((f) => (f in rec)).map((f) => [f, rec[f]]));
35261
+ }
35262
+ function parseFields(searchParams) {
35263
+ const raw = searchParams.get("fields");
35264
+ if (!raw)
35265
+ return [];
35266
+ return raw.split(",").map((f) => f.trim()).filter(Boolean);
35267
+ }
35256
35268
  function getAllSkillsWithStatus() {
35257
35269
  const installed = new Set(getInstalledSkills());
35258
35270
  return SKILLS.map((meta3) => {
@@ -35289,7 +35301,9 @@ function createFetchHandler(options) {
35289
35301
  const path = url2.pathname;
35290
35302
  const method = req.method;
35291
35303
  if (path === "/api/skills" && method === "GET") {
35292
- return json2(getAllSkillsWithStatus());
35304
+ const fields = parseFields(url2.searchParams);
35305
+ const skills = getAllSkillsWithStatus();
35306
+ return json2(fields.length ? skills.map((s) => pickFields(s, fields)) : skills);
35293
35307
  }
35294
35308
  if (path === "/api/categories" && method === "GET") {
35295
35309
  const counts = CATEGORIES.map((cat) => ({
@@ -35312,12 +35326,13 @@ function createFetchHandler(options) {
35312
35326
  const query = url2.searchParams.get("q") || "";
35313
35327
  if (!query.trim())
35314
35328
  return json2([]);
35329
+ const fields = parseFields(url2.searchParams);
35315
35330
  const results = searchSkills(query);
35316
35331
  const installed = new Set(getInstalledSkills());
35317
- return json2(results.map((meta3) => {
35332
+ const mapped = results.map((meta3) => {
35318
35333
  const reqs = getSkillRequirements(meta3.name);
35319
35334
  const envVars = reqs?.envVars || [];
35320
- return {
35335
+ const obj = {
35321
35336
  name: meta3.name,
35322
35337
  displayName: meta3.displayName,
35323
35338
  description: meta3.description,
@@ -35329,7 +35344,9 @@ function createFetchHandler(options) {
35329
35344
  systemDeps: reqs?.systemDeps || [],
35330
35345
  cliCommand: reqs?.cliCommand || null
35331
35346
  };
35332
- }));
35347
+ return fields.length ? pickFields(obj, fields) : obj;
35348
+ });
35349
+ return json2(mapped);
35333
35350
  }
35334
35351
  const singleMatch = path.match(/^\/api\/skills\/([^/]+)$/);
35335
35352
  if (singleMatch && method === "GET") {
@@ -35339,11 +35356,12 @@ function createFetchHandler(options) {
35339
35356
  const meta3 = getSkill(name);
35340
35357
  if (!meta3)
35341
35358
  return json2({ error: `Skill '${name}' not found` }, 404);
35359
+ const fields = parseFields(url2.searchParams);
35342
35360
  const reqs = getSkillRequirements(name);
35343
35361
  const docs = getSkillBestDoc(name);
35344
35362
  const installed = new Set(getInstalledSkills());
35345
35363
  const envVars = reqs?.envVars || [];
35346
- return json2({
35364
+ const obj = {
35347
35365
  name: meta3.name,
35348
35366
  displayName: meta3.displayName,
35349
35367
  description: meta3.description,
@@ -35355,7 +35373,8 @@ function createFetchHandler(options) {
35355
35373
  systemDeps: reqs?.systemDeps || [],
35356
35374
  cliCommand: reqs?.cliCommand || null,
35357
35375
  docs: docs || null
35358
- });
35376
+ };
35377
+ return json2(fields.length ? pickFields(obj, fields) : obj);
35359
35378
  }
35360
35379
  const docsMatch = path.match(/^\/api\/skills\/([^/]+)\/docs$/);
35361
35380
  if (docsMatch && method === "GET") {
@@ -35383,18 +35402,13 @@ function createFetchHandler(options) {
35383
35402
  const results = agents.map((agent) => installSkillForAgent(name, { agent, scope }, generateSkillMd));
35384
35403
  const allSuccess = results.every((r) => r.success);
35385
35404
  const errors4 = results.filter((r) => !r.success).map((r) => r.error);
35386
- return json2({
35387
- skill: name,
35388
- success: allSuccess,
35389
- results,
35390
- ...errors4.length > 0 ? { error: errors4.join("; ") } : {}
35391
- }, allSuccess ? 200 : 400);
35405
+ return json2(allSuccess ? { skill: name, success: true } : { skill: name, success: false, results, error: errors4.join("; ") }, allSuccess ? 200 : 400);
35392
35406
  } catch (e) {
35393
35407
  return json2({ skill: name, success: false, error: e instanceof Error ? e.message : "Unknown error" }, 400);
35394
35408
  }
35395
35409
  } else {
35396
35410
  const result = installSkill(name);
35397
- return json2(result, result.success ? 200 : 400);
35411
+ return json2(result.success ? { skill: name, success: true } : { skill: name, success: false, error: result.error }, result.success ? 200 : 400);
35398
35412
  }
35399
35413
  }
35400
35414
  if (path === "/api/skills/install-category" && method === "POST") {
@@ -36859,8 +36873,9 @@ Skills installed to .skills/`));
36859
36873
  process.exitCode = 1;
36860
36874
  }
36861
36875
  });
36862
- program2.command("list").alias("ls").option("-c, --category <category>", "Filter by category").option("-i, --installed", "Show only installed skills", false).option("-t, --tags <tags>", "Filter by comma-separated tags (OR logic, case-insensitive)").option("--json", "Output as JSON", false).option("--brief", "One line per skill: name \u2014 description [category]", false).description("List available or installed skills").action((options) => {
36876
+ program2.command("list").alias("ls").option("-c, --category <category>", "Filter by category").option("-i, --installed", "Show only installed skills", false).option("-t, --tags <tags>", "Filter by comma-separated tags (OR logic, case-insensitive)").option("--json", "Output as JSON", false).option("--brief", "One line per skill: name \u2014 description [category]", false).option("--format <format>", "Output format: compact (names only) or csv (name,category,description)").description("List available or installed skills").action((options) => {
36863
36877
  const brief = options.brief && !options.json;
36878
+ const fmt = !options.json ? options.format : undefined;
36864
36879
  if (options.installed) {
36865
36880
  const installed = getInstalledSkills();
36866
36881
  if (options.json) {
@@ -36940,6 +36955,19 @@ Skills matching tags [${tagFilter.join(", ")}] (${skills.length}):
36940
36955
  console.log(JSON.stringify(SKILLS, null, 2));
36941
36956
  return;
36942
36957
  }
36958
+ if (fmt === "compact") {
36959
+ for (const s of SKILLS)
36960
+ console.log(s.name);
36961
+ return;
36962
+ }
36963
+ if (fmt === "csv") {
36964
+ console.log("name,category,description");
36965
+ for (const s of SKILLS) {
36966
+ const desc = s.description.replace(/"/g, '""');
36967
+ console.log(`${s.name},${s.category},"${desc}"`);
36968
+ }
36969
+ return;
36970
+ }
36943
36971
  if (brief) {
36944
36972
  const sorted = [...SKILLS].sort((a, b) => {
36945
36973
  const catCmp = a.category.localeCompare(b.category);
@@ -36962,7 +36990,7 @@ Available skills (${SKILLS.length}):
36962
36990
  console.log();
36963
36991
  }
36964
36992
  });
36965
- program2.command("search").argument("<query>", "Search term").option("--json", "Output as JSON", false).option("--brief", "One line per skill: name \u2014 description [category]", false).option("-c, --category <category>", "Filter results by category").option("-t, --tags <tags>", "Filter results by comma-separated tags (OR logic, case-insensitive)").description("Search for skills").action((query, options) => {
36993
+ program2.command("search").argument("<query>", "Search term").option("--json", "Output as JSON", false).option("--brief", "One line per skill: name \u2014 description [category]", false).option("--format <format>", "Output format: compact (names only) or csv (name,category,description)").option("-c, --category <category>", "Filter results by category").option("-t, --tags <tags>", "Filter results by comma-separated tags (OR logic, case-insensitive)").description("Search for skills").action((query, options) => {
36966
36994
  let results = searchSkills(query);
36967
36995
  if (options.category) {
36968
36996
  const category = CATEGORIES.find((c) => c.toLowerCase() === options.category.toLowerCase());
@@ -36979,6 +37007,7 @@ program2.command("search").argument("<query>", "Search term").option("--json", "
36979
37007
  results = results.filter((s) => s.tags.some((tag) => tagFilter.includes(tag.toLowerCase())));
36980
37008
  }
36981
37009
  const brief = options.brief && !options.json;
37010
+ const fmt = !options.json ? options.format : undefined;
36982
37011
  if (options.json) {
36983
37012
  console.log(JSON.stringify(results, null, 2));
36984
37013
  return;
@@ -36987,6 +37016,19 @@ program2.command("search").argument("<query>", "Search term").option("--json", "
36987
37016
  console.log(chalk2.dim(`No skills found for "${query}"`));
36988
37017
  return;
36989
37018
  }
37019
+ if (fmt === "compact") {
37020
+ for (const s of results)
37021
+ console.log(s.name);
37022
+ return;
37023
+ }
37024
+ if (fmt === "csv") {
37025
+ console.log("name,category,description");
37026
+ for (const s of results) {
37027
+ const desc = s.description.replace(/"/g, '""');
37028
+ console.log(`${s.name},${s.category},"${desc}"`);
37029
+ }
37030
+ return;
37031
+ }
36990
37032
  if (brief) {
36991
37033
  for (const s of results) {
36992
37034
  console.log(`${s.name} \u2014 ${s.description} [${s.category}]`);
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.11",
28607
+ version: "0.1.13",
28608
28608
  description: "Skills library for AI coding agents",
28609
28609
  type: "module",
28610
28610
  bin: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {