@hasna/skills 0.1.24 → 0.1.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bin/mcp.js CHANGED
@@ -28561,9 +28561,8 @@ class StdioServerTransport {
28561
28561
  }
28562
28562
 
28563
28563
  // src/mcp/index.ts
28564
- import { existsSync as existsSync9, mkdirSync as mkdirSync6, readdirSync as readdirSync7, statSync as statSync3 } from "fs";
28565
- import { join as join10, dirname as dirname3 } from "path";
28566
- import { homedir as homedir9 } from "os";
28564
+ import { existsSync as existsSync10, readdirSync as readdirSync7, statSync as statSync3 } from "fs";
28565
+ import { join as join11 } from "path";
28567
28566
 
28568
28567
  // node_modules/@hasna/cloud/dist/index.js
28569
28568
  import { createRequire } from "module";
@@ -38746,12 +38745,12 @@ init_adapter();
38746
38745
  // package.json
38747
38746
  var package_default = {
38748
38747
  name: "@hasna/skills",
38749
- version: "0.1.24",
38748
+ version: "0.1.26",
38750
38749
  description: "Skills library for AI coding agents",
38751
38750
  type: "module",
38752
38751
  bin: {
38753
- skills: "./bin/index.js",
38754
- "skills-mcp": "./bin/mcp.js"
38752
+ skills: "bin/index.js",
38753
+ "skills-mcp": "bin/mcp.js"
38755
38754
  },
38756
38755
  exports: {
38757
38756
  ".": {
@@ -40529,7 +40528,7 @@ function discoverSkillsInDir(dir) {
40529
40528
  const fm = parseSkillMdFrontmatter(content);
40530
40529
  if (!fm?.name)
40531
40530
  continue;
40532
- const name = fm.name.replace(/^skill-/, "");
40531
+ const name = fm.name;
40533
40532
  result.push({
40534
40533
  name,
40535
40534
  displayName: fm.displayName || name.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
@@ -41342,6 +41341,51 @@ function removeSchedule(idOrName, targetDir) {
41342
41341
  return true;
41343
41342
  }
41344
41343
 
41344
+ // src/lib/feedback.ts
41345
+ import { existsSync as existsSync9, mkdirSync as mkdirSync6 } from "fs";
41346
+ import { homedir as homedir9 } from "os";
41347
+ import { dirname as dirname3, join as join10 } from "path";
41348
+ function getFeedbackDbPath() {
41349
+ return process.env.SKILLS_FEEDBACK_DB_PATH || join10(homedir9(), ".hasna", "skills", "skills.db");
41350
+ }
41351
+ function getFeedbackDb() {
41352
+ const dbPath = getFeedbackDbPath();
41353
+ const dir = dirname3(dbPath);
41354
+ if (!existsSync9(dir))
41355
+ mkdirSync6(dir, { recursive: true });
41356
+ const db = new SqliteAdapter(dbPath);
41357
+ db.exec("PRAGMA journal_mode = WAL");
41358
+ db.exec([
41359
+ "CREATE TABLE IF NOT EXISTS feedback (",
41360
+ "id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),",
41361
+ "message TEXT NOT NULL,",
41362
+ "email TEXT,",
41363
+ "category TEXT DEFAULT 'general',",
41364
+ "agent TEXT,",
41365
+ "version TEXT,",
41366
+ "machine_id TEXT,",
41367
+ "created_at TEXT NOT NULL DEFAULT (datetime('now'))",
41368
+ ")"
41369
+ ].join(" "));
41370
+ try {
41371
+ db.exec("ALTER TABLE feedback ADD COLUMN agent TEXT");
41372
+ } catch {}
41373
+ return db;
41374
+ }
41375
+ function saveFeedback2(input) {
41376
+ const message = input.message.trim();
41377
+ if (!message)
41378
+ throw new Error("Feedback message is required");
41379
+ const category = input.category ?? "general";
41380
+ const db = getFeedbackDb();
41381
+ try {
41382
+ db.run("INSERT INTO feedback (message, email, category, agent, version) VALUES (?, ?, ?, ?, ?)", [message, input.email || null, category, input.agent || null, input.version || null]);
41383
+ } finally {
41384
+ db.close();
41385
+ }
41386
+ return { saved: true, category, path: getFeedbackDbPath() };
41387
+ }
41388
+
41345
41389
  // src/mcp/index.ts
41346
41390
  var server = new McpServer({
41347
41391
  name: "skills",
@@ -41696,13 +41740,13 @@ server.registerTool("whoami", {
41696
41740
  const agents = [];
41697
41741
  for (const agent of AGENT_TARGETS) {
41698
41742
  const agentSkillsPath = getAgentSkillsDir(agent, "global");
41699
- const exists = existsSync9(agentSkillsPath);
41743
+ const exists = existsSync10(agentSkillsPath);
41700
41744
  let skillCount = 0;
41701
41745
  if (exists) {
41702
41746
  try {
41703
41747
  skillCount = readdirSync7(agentSkillsPath).filter((f) => {
41704
- const full = join10(agentSkillsPath, f);
41705
- return f.startsWith("skill-") && statSync3(full).isDirectory();
41748
+ const full = join11(agentSkillsPath, f);
41749
+ return !f.startsWith(".") && statSync3(full).isDirectory();
41706
41750
  }).length;
41707
41751
  } catch {}
41708
41752
  }
@@ -41782,17 +41826,17 @@ server.registerTool("validate_skill", {
41782
41826
  }, async ({ name }) => {
41783
41827
  const skillPath = getSkillPath(name);
41784
41828
  const issues = [];
41785
- if (!existsSync9(skillPath)) {
41829
+ if (!existsSync10(skillPath)) {
41786
41830
  return {
41787
41831
  content: [{ type: "text", text: JSON.stringify({ name, valid: false, issues: [`Skill directory not found: ${skillPath}`] }) }]
41788
41832
  };
41789
41833
  }
41790
- if (!existsSync9(join10(skillPath, "SKILL.md")))
41834
+ if (!existsSync10(join11(skillPath, "SKILL.md")))
41791
41835
  issues.push("Missing SKILL.md");
41792
- if (!existsSync9(join10(skillPath, "tsconfig.json")))
41836
+ if (!existsSync10(join11(skillPath, "tsconfig.json")))
41793
41837
  issues.push("Missing tsconfig.json");
41794
- const pkgPath = join10(skillPath, "package.json");
41795
- if (!existsSync9(pkgPath)) {
41838
+ const pkgPath = join11(skillPath, "package.json");
41839
+ if (!existsSync10(pkgPath)) {
41796
41840
  issues.push("Missing package.json");
41797
41841
  } else {
41798
41842
  try {
@@ -41803,10 +41847,10 @@ server.registerTool("validate_skill", {
41803
41847
  issues.push("package.json is invalid JSON");
41804
41848
  }
41805
41849
  }
41806
- const srcDir = join10(skillPath, "src");
41807
- if (!existsSync9(srcDir)) {
41850
+ const srcDir = join11(skillPath, "src");
41851
+ if (!existsSync10(srcDir)) {
41808
41852
  issues.push("Missing src/ directory");
41809
- } else if (!existsSync9(join10(srcDir, "index.ts"))) {
41853
+ } else if (!existsSync10(join11(srcDir, "index.ts"))) {
41810
41854
  issues.push("Missing src/index.ts");
41811
41855
  }
41812
41856
  const valid = issues.length === 0;
@@ -41930,23 +41974,10 @@ server.tool("list_agents", "List all registered agents.", {}, async () => {
41930
41974
  return { content: [{ type: "text", text: "No agents registered." }] };
41931
41975
  return { content: [{ type: "text", text: JSON.stringify(agents, null, 2) }] };
41932
41976
  });
41933
- function getFeedbackDb() {
41934
- const home = homedir9();
41935
- const dbPath = join10(home, ".hasna", "skills", "skills.db");
41936
- const dir = dirname3(dbPath);
41937
- if (!existsSync9(dir))
41938
- mkdirSync6(dir, { recursive: true });
41939
- const db = new SqliteAdapter(dbPath);
41940
- db.exec("PRAGMA journal_mode = WAL");
41941
- db.exec("CREATE TABLE IF NOT EXISTS feedback (id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))), message TEXT NOT NULL, email TEXT, category TEXT DEFAULT 'general', version TEXT, machine_id TEXT, created_at TEXT NOT NULL DEFAULT (datetime('now')))");
41942
- return db;
41943
- }
41944
- server.tool("send_feedback", "Send feedback about this service", { message: exports_external.string(), email: exports_external.string().optional(), category: exports_external.enum(["bug", "feature", "general"]).optional() }, async (params) => {
41977
+ server.tool("send_feedback", "Send feedback about this service", { message: exports_external.string(), email: exports_external.string().optional(), agent: exports_external.string().optional(), category: exports_external.enum(["bug", "feature", "general"]).optional() }, async (params) => {
41945
41978
  try {
41946
- const db = getFeedbackDb();
41947
- db.run("INSERT INTO feedback (message, email, category, version) VALUES (?, ?, ?, ?)", [params.message, params.email || null, params.category || "general", package_default.version]);
41948
- db.close();
41949
- return { content: [{ type: "text", text: "Feedback saved. Thank you!" }] };
41979
+ const result = saveFeedback2({ ...params, version: package_default.version });
41980
+ return { content: [{ type: "text", text: JSON.stringify(result) }] };
41950
41981
  } catch (e) {
41951
41982
  return { content: [{ type: "text", text: String(e) }], isError: true };
41952
41983
  }
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerFeedback(parent: Command): void;
@@ -0,0 +1,2 @@
1
+ import type { Command } from "commander";
2
+ export declare function registerRegistry(parent: Command): void;
package/dist/index.d.ts CHANGED
@@ -11,5 +11,8 @@ export { SKILLS, BASIC_SKILL_NAMES, CATEGORIES, getSkill, getSkillsByCategory, s
11
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
13
  export { loadConfig, saveConfig, getConfigPath, type SkillsConfig, type ConfigScope, } from "./lib/config.js";
14
+ export { buildSkillsApiUrl, getConfiguredApiUrl, loadRemoteRegistry, parseRemoteRegistryPayload, type RemoteRegistryOptions, } from "./lib/remote-registry.js";
14
15
  export { addSchedule, listSchedules, removeSchedule, setScheduleEnabled, getDueSchedules, recordScheduleRun, validateCron, getNextRun, type SkillSchedule, } from "./lib/scheduler.js";
16
+ export { parseSkillFrontmatter, validateRegistryConsistency, validateSkillDirectory, type RegistryConsistencyResult, type SkillFrontmatter, type SkillValidationMessage, type SkillValidationResult, } from "./lib/skill-validation.js";
17
+ export { createRegistrySyncArtifact, writeRegistrySyncArtifact, type RegistrySyncArtifact, type RegistrySyncOptions, type RegistrySyncSkill, } from "./lib/registry-sync.js";
15
18
  export type { SkillResponse, SkillDetailResponse, CategoryResponse, TagResponse, InstallResponse, RemoveResponse, VersionResponse, ExportResponse, ImportResponse, SearchResponse, CategoryInstallResponse, ErrorResponse, } from "./types/api.js";