@hasna/skills 0.1.31 → 0.1.32

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
@@ -7064,12 +7064,19 @@ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync
7064
7064
  import { join as join6, dirname as dirname2 } from "path";
7065
7065
  import { homedir as homedir3 } from "os";
7066
7066
  function validKeys() {
7067
- return [...Object.keys(ENUM_KEYS), ...STRING_KEYS];
7067
+ return ["mode", ...Object.keys(ENUM_KEYS), ...STRING_KEYS];
7068
+ }
7069
+ function allowedValues(key) {
7070
+ if (key === "mode")
7071
+ return MODE_VALUES;
7072
+ return ENUM_KEYS[key];
7068
7073
  }
7069
7074
  function normalizeConfigValue(key, value) {
7070
7075
  if (typeof value !== "string")
7071
7076
  return;
7072
- const allowed = ENUM_KEYS[key];
7077
+ if (key === "mode")
7078
+ return MODE_ALIASES[value.trim().toLowerCase()];
7079
+ const allowed = allowedValues(key);
7073
7080
  if (allowed)
7074
7081
  return allowed.includes(value) ? value : undefined;
7075
7082
  if (key === "apiUrl") {
@@ -7127,15 +7134,23 @@ function loadConfig() {
7127
7134
  const projectConfig = readConfigFile(getConfigPath("project"));
7128
7135
  return { ...globalConfig2, ...projectConfig };
7129
7136
  }
7130
- var ENUM_KEYS, STRING_KEYS;
7137
+ var ENUM_KEYS, STRING_KEYS, MODE_VALUES, MODE_ALIASES;
7131
7138
  var init_config = __esm(() => {
7132
7139
  ENUM_KEYS = {
7133
- mode: ["local", "skills.md"],
7134
7140
  defaultAgent: ["claude", "codex", "gemini", "pi", "opencode", "all"],
7135
7141
  defaultScope: ["global", "project"],
7136
7142
  format: ["compact", "json", "csv"]
7137
7143
  };
7138
7144
  STRING_KEYS = ["apiUrl"];
7145
+ MODE_VALUES = ["local", "hosted"];
7146
+ MODE_ALIASES = {
7147
+ local: "local",
7148
+ offline: "local",
7149
+ hosted: "hosted",
7150
+ remote: "hosted",
7151
+ "skills.md": "hosted",
7152
+ skillsmd: "hosted"
7153
+ };
7139
7154
  });
7140
7155
 
7141
7156
  // src/lib/auth-store.ts
@@ -7148,14 +7163,14 @@ __export(exports_auth_store, {
7148
7163
  getApiKey: () => getApiKey,
7149
7164
  clearAuthConfig: () => clearAuthConfig
7150
7165
  });
7151
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync } from "fs";
7166
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync } from "fs";
7152
7167
  import { join as join7 } from "path";
7153
7168
  import { homedir as homedir4 } from "os";
7154
7169
  function getAuthConfig() {
7155
7170
  if (cachedConfig !== undefined)
7156
7171
  return cachedConfig;
7157
7172
  try {
7158
- const raw = readFileSync7(AUTH_FILE, "utf-8");
7173
+ const raw = readFileSync7(existsSync7(AUTH_FILE) ? AUTH_FILE : LEGACY_AUTH_FILE, "utf-8");
7159
7174
  const config2 = JSON.parse(raw);
7160
7175
  if (!config2.apiKey || !config2.email) {
7161
7176
  cachedConfig = null;
@@ -7169,7 +7184,7 @@ function getAuthConfig() {
7169
7184
  }
7170
7185
  }
7171
7186
  function saveAuthConfig(config2) {
7172
- mkdirSync4(AUTH_DIR, { recursive: true });
7187
+ mkdirSync4(AUTH_DIR, { recursive: true, mode: 448 });
7173
7188
  writeFileSync4(AUTH_FILE, JSON.stringify(config2, null, 2) + `
7174
7189
  `, { mode: 384 });
7175
7190
  cachedConfig = config2;
@@ -7178,6 +7193,9 @@ function clearAuthConfig() {
7178
7193
  try {
7179
7194
  unlinkSync(AUTH_FILE);
7180
7195
  } catch {}
7196
+ try {
7197
+ unlinkSync(LEGACY_AUTH_FILE);
7198
+ } catch {}
7181
7199
  cachedConfig = null;
7182
7200
  }
7183
7201
  function getApiKey() {
@@ -7200,11 +7218,12 @@ function normalizeSkillsApiOrigin(apiUrl) {
7200
7218
  function getApiUrl() {
7201
7219
  return normalizeSkillsApiOrigin(process.env.SKILLS_API_URL || loadConfig().apiUrl || "https://skills.md");
7202
7220
  }
7203
- var AUTH_DIR, AUTH_FILE, cachedConfig;
7221
+ var AUTH_DIR, AUTH_FILE, LEGACY_AUTH_FILE, cachedConfig;
7204
7222
  var init_auth_store = __esm(() => {
7205
7223
  init_config();
7206
- AUTH_DIR = join7(homedir4(), ".skills");
7224
+ AUTH_DIR = join7(homedir4(), ".hasna", "skills");
7207
7225
  AUTH_FILE = join7(AUTH_DIR, "auth.json");
7226
+ LEGACY_AUTH_FILE = join7(homedir4(), ".skills", "auth.json");
7208
7227
  });
7209
7228
 
7210
7229
  // src/lib/remote-client.ts
@@ -21768,7 +21787,7 @@ class StdioServerTransport {
21768
21787
  // package.json
21769
21788
  var package_default = {
21770
21789
  name: "@hasna/skills",
21771
- version: "0.1.31",
21790
+ version: "0.1.32",
21772
21791
  description: "Skills library for AI coding agents",
21773
21792
  type: "module",
21774
21793
  bin: {
@@ -32882,7 +32901,7 @@ function registerDiscoveryTools(server) {
32882
32901
  }
32883
32902
 
32884
32903
  // src/mcp/operation-tools.ts
32885
- import { existsSync as existsSync7, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
32904
+ import { existsSync as existsSync8, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
32886
32905
  import { join as join8 } from "path";
32887
32906
 
32888
32907
  // src/lib/run-state.ts
@@ -33271,7 +33290,7 @@ function registerOperationTools(server) {
33271
33290
  });
33272
33291
  if (isPremiumSkill2(skillName) && !apiKey) {
33273
33292
  const cost = formatCost2(costCents ?? 0);
33274
- const error48 = `${skillName} is a hosted skill (${cost}). Run: skills setup --mode skills.md && skills auth login`;
33293
+ const error48 = `${skillName} is a hosted skill (${cost}). Run: skills setup --mode hosted && skills auth login`;
33275
33294
  writeRunLogs(runContext, "", error48 + `
33276
33295
  `);
33277
33296
  const run = completeSkillRun(runContext, { status: "failed", error: error48, costCents });
@@ -33307,9 +33326,9 @@ function registerOperationTools(server) {
33307
33326
  nextActions: remoteRunNextActions(remoteRunId)
33308
33327
  });
33309
33328
  } catch (err) {
33310
- console.error(`[skills] skills.md API failed for ${skillName}, falling back to local:`, err.message);
33329
+ console.error(`[skills] hosted API failed for ${skillName}, falling back to local:`, err.message);
33311
33330
  if (isPremiumSkill2(skillName)) {
33312
- const error48 = `Hosted skill ${skillName} requires skills.md access: ${err.message}`;
33331
+ const error48 = `Hosted skill ${skillName} requires hosted access: ${err.message}`;
33313
33332
  writeRunLogs(runContext, "", error48 + `
33314
33333
  `);
33315
33334
  const localRun2 = completeSkillRun(runContext, { status: "failed", error: error48 });
@@ -33350,7 +33369,7 @@ function registerOperationTools(server) {
33350
33369
  const { getApiKey: getApiKey2 } = await Promise.resolve().then(() => (init_auth_store(), exports_auth_store));
33351
33370
  const apiKey = getApiKey2();
33352
33371
  if (!apiKey) {
33353
- return mcpError("AUTH_REQUIRED", "Remote run status requires skills.md access. Run: skills auth login", ["skills auth login"]);
33372
+ return mcpError("AUTH_REQUIRED", "Remote run status requires hosted access. Run: skills auth login", ["skills auth login"]);
33354
33373
  }
33355
33374
  const localRun = findSkillRun(run_id);
33356
33375
  const remoteRunId = localRun?.remoteRunId || run_id;
@@ -33436,7 +33455,7 @@ function registerOperationTools(server) {
33436
33455
  const agents = [];
33437
33456
  for (const agent of AGENT_TARGETS) {
33438
33457
  const agentSkillsPath = getAgentSkillsDir(agent, "global");
33439
- const exists = existsSync7(agentSkillsPath);
33458
+ const exists = existsSync8(agentSkillsPath);
33440
33459
  let skillCount = 0;
33441
33460
  if (exists) {
33442
33461
  try {
@@ -33462,7 +33481,7 @@ function registerOperationTools(server) {
33462
33481
  }
33463
33482
 
33464
33483
  // src/lib/feedback.ts
33465
- import { existsSync as existsSync8, mkdirSync as mkdirSync5 } from "fs";
33484
+ import { existsSync as existsSync9, mkdirSync as mkdirSync5 } from "fs";
33466
33485
  import { homedir as homedir5 } from "os";
33467
33486
  import { dirname as dirname3, join as join9 } from "path";
33468
33487
  import { Database } from "bun:sqlite";
@@ -33472,7 +33491,7 @@ function getFeedbackDbPath() {
33472
33491
  function getFeedbackDb() {
33473
33492
  const dbPath = getFeedbackDbPath();
33474
33493
  const dir = dirname3(dbPath);
33475
- if (!existsSync8(dir))
33494
+ if (!existsSync9(dir))
33476
33495
  mkdirSync5(dir, { recursive: true });
33477
33496
  const db = new Database(dbPath);
33478
33497
  db.exec("PRAGMA journal_mode = WAL");
@@ -33621,14 +33640,14 @@ function registerResourceMetaTools(server) {
33621
33640
  }
33622
33641
 
33623
33642
  // src/lib/scheduler.ts
33624
- import { existsSync as existsSync9, readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6 } from "fs";
33643
+ import { existsSync as existsSync10, readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync6 } from "fs";
33625
33644
  import { join as join10 } from "path";
33626
33645
  function getSchedulesPath(targetDir = process.cwd()) {
33627
33646
  return join10(targetDir, ".skills", "schedules.json");
33628
33647
  }
33629
33648
  function loadSchedules(targetDir = process.cwd()) {
33630
33649
  const path = getSchedulesPath(targetDir);
33631
- if (existsSync9(path)) {
33650
+ if (existsSync10(path)) {
33632
33651
  try {
33633
33652
  return JSON.parse(readFileSync8(path, "utf-8"));
33634
33653
  } catch {}
@@ -33638,7 +33657,7 @@ function loadSchedules(targetDir = process.cwd()) {
33638
33657
  function saveSchedules(data, targetDir = process.cwd()) {
33639
33658
  const path = getSchedulesPath(targetDir);
33640
33659
  const dir = join10(targetDir, ".skills");
33641
- if (!existsSync9(dir))
33660
+ if (!existsSync10(dir))
33642
33661
  mkdirSync6(dir, { recursive: true });
33643
33662
  writeFileSync5(path, JSON.stringify(data, null, 2));
33644
33663
  }
@@ -33799,7 +33818,7 @@ function removeSchedule(idOrName, targetDir) {
33799
33818
  }
33800
33819
 
33801
33820
  // src/lib/skill-validation.ts
33802
- import { existsSync as existsSync10, lstatSync, readFileSync as readFileSync9, readdirSync as readdirSync4, statSync as statSync3 } from "fs";
33821
+ import { existsSync as existsSync11, lstatSync, readFileSync as readFileSync9, readdirSync as readdirSync4, statSync as statSync3 } from "fs";
33803
33822
  import { isAbsolute, join as join11, normalize } from "path";
33804
33823
  var DOC_FILES = ["SKILL.md", "README.md", "CLAUDE.md"];
33805
33824
  var RESERVED_SKILL_ENTRIES = new Set([
@@ -33916,7 +33935,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
33916
33935
  binCommands: [],
33917
33936
  docFiles: []
33918
33937
  };
33919
- if (!existsSync10(skillPath)) {
33938
+ if (!existsSync11(skillPath)) {
33920
33939
  add(issues, "skill.dir_missing", `Skill directory not found: ${skillPath}`);
33921
33940
  return {
33922
33941
  name: bareName,
@@ -33943,14 +33962,14 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
33943
33962
  }
33944
33963
  }
33945
33964
  for (const docFile of DOC_FILES) {
33946
- if (existsSync10(join11(skillPath, docFile)))
33965
+ if (existsSync11(join11(skillPath, docFile)))
33947
33966
  metadata.docFiles.push(docFile);
33948
33967
  }
33949
33968
  if (metadata.docFiles.length === 0) {
33950
33969
  add(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
33951
33970
  }
33952
33971
  const skillMdPath = join11(skillPath, "SKILL.md");
33953
- if (existsSync10(skillMdPath)) {
33972
+ if (existsSync11(skillMdPath)) {
33954
33973
  const frontmatter = parseSkillFrontmatter(readFileSync9(skillMdPath, "utf-8"));
33955
33974
  if (!frontmatter) {
33956
33975
  add(warnings, "skill.frontmatter_missing", "SKILL.md has no YAML frontmatter");
@@ -33985,7 +34004,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
33985
34004
  add(warnings, "skill.skill_md_missing", "Missing SKILL.md; registry docs may need generated agent-facing instructions");
33986
34005
  }
33987
34006
  const pkgPath = join11(skillPath, "package.json");
33988
- if (!existsSync10(pkgPath)) {
34007
+ if (!existsSync11(pkgPath)) {
33989
34008
  add(issues, "package.missing", "Missing package.json");
33990
34009
  } else {
33991
34010
  try {
@@ -34030,7 +34049,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
34030
34049
  continue;
34031
34050
  }
34032
34051
  const targetPath = join11(skillPath, target);
34033
- if (!existsSync10(targetPath)) {
34052
+ if (!existsSync11(targetPath)) {
34034
34053
  add(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
34035
34054
  } else if (statSync3(targetPath).isDirectory()) {
34036
34055
  add(issues, "package.bin_target_directory", `package.json bin '${command}' target '${target}' must point to a file, not a directory`);
@@ -34043,12 +34062,12 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
34043
34062
  }
34044
34063
  }
34045
34064
  const srcDir = join11(skillPath, "src");
34046
- if (!existsSync10(srcDir)) {
34065
+ if (!existsSync11(srcDir)) {
34047
34066
  add(issues, "skill.src_missing", "Missing src/ directory");
34048
- } else if (!existsSync10(join11(srcDir, "index.ts")) && !existsSync10(join11(srcDir, "index.js"))) {
34067
+ } else if (!existsSync11(join11(srcDir, "index.ts")) && !existsSync11(join11(srcDir, "index.js"))) {
34049
34068
  add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
34050
34069
  } else {
34051
- const indexPath = existsSync10(join11(srcDir, "index.ts")) ? join11(srcDir, "index.ts") : join11(srcDir, "index.js");
34070
+ const indexPath = existsSync11(join11(srcDir, "index.ts")) ? join11(srcDir, "index.ts") : join11(srcDir, "index.js");
34052
34071
  const size = statSync3(indexPath).size;
34053
34072
  if (size < 50)
34054
34073
  add(warnings, "skill.src_index_minimal", `Source entry point is very small (${size}B)`);
@@ -0,0 +1,13 @@
1
+ import type { Command } from "commander";
2
+ import { type SkillsConfig } from "../lib/config.js";
3
+ export interface FirstRunOnboardingInput {
4
+ argv: string[];
5
+ commandName?: string;
6
+ config: SkillsConfig;
7
+ isInteractive: boolean;
8
+ testMode?: boolean;
9
+ }
10
+ export declare function getRootCommandName(actionCommand: Command): string;
11
+ export declare function shouldShowFirstRunOnboarding(input: FirstRunOnboardingInput): boolean;
12
+ export declare function getFirstRunOnboardingMessage(): string;
13
+ export declare function maybePrintFirstRunOnboarding(actionCommand: Command, argv: string[], isInteractive: boolean): void;
package/dist/index.js CHANGED
@@ -3395,19 +3395,34 @@ import { existsSync as existsSync6, readFileSync as readFileSync6, writeFileSync
3395
3395
  import { join as join6, dirname as dirname2 } from "path";
3396
3396
  import { homedir as homedir3 } from "os";
3397
3397
  var ENUM_KEYS = {
3398
- mode: ["local", "skills.md"],
3399
3398
  defaultAgent: ["claude", "codex", "gemini", "pi", "opencode", "all"],
3400
3399
  defaultScope: ["global", "project"],
3401
3400
  format: ["compact", "json", "csv"]
3402
3401
  };
3403
3402
  var STRING_KEYS = ["apiUrl"];
3403
+ var MODE_VALUES = ["local", "hosted"];
3404
+ var MODE_ALIASES = {
3405
+ local: "local",
3406
+ offline: "local",
3407
+ hosted: "hosted",
3408
+ remote: "hosted",
3409
+ "skills.md": "hosted",
3410
+ skillsmd: "hosted"
3411
+ };
3404
3412
  function validKeys() {
3405
- return [...Object.keys(ENUM_KEYS), ...STRING_KEYS];
3413
+ return ["mode", ...Object.keys(ENUM_KEYS), ...STRING_KEYS];
3414
+ }
3415
+ function allowedValues(key) {
3416
+ if (key === "mode")
3417
+ return MODE_VALUES;
3418
+ return ENUM_KEYS[key];
3406
3419
  }
3407
3420
  function normalizeConfigValue(key, value) {
3408
3421
  if (typeof value !== "string")
3409
3422
  return;
3410
- const allowed = ENUM_KEYS[key];
3423
+ if (key === "mode")
3424
+ return MODE_ALIASES[value.trim().toLowerCase()];
3425
+ const allowed = allowedValues(key);
3411
3426
  if (allowed)
3412
3427
  return allowed.includes(value) ? value : undefined;
3413
3428
  if (key === "apiUrl") {
@@ -3471,7 +3486,7 @@ function saveConfig(key, value, scope = "project") {
3471
3486
  }
3472
3487
  const normalized = normalizeConfigValue(key, value);
3473
3488
  if (normalized === undefined) {
3474
- const allowed = ENUM_KEYS[key];
3489
+ const allowed = allowedValues(key);
3475
3490
  throw new Error(allowed ? `Invalid value '${value}' for ${key}. Allowed: ${allowed.join(", ")}` : `Invalid value '${value}' for ${key}. Expected an http(s) URL`);
3476
3491
  }
3477
3492
  const filePath = getConfigPath(scope);
@@ -17028,17 +17043,18 @@ function date4(params) {
17028
17043
  // node_modules/zod/v4/classic/external.js
17029
17044
  config(en_default());
17030
17045
  // src/lib/auth-store.ts
17031
- import { mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync } from "fs";
17046
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, writeFileSync as writeFileSync4, unlinkSync } from "fs";
17032
17047
  import { join as join7 } from "path";
17033
17048
  import { homedir as homedir4 } from "os";
17034
- var AUTH_DIR = join7(homedir4(), ".skills");
17049
+ var AUTH_DIR = join7(homedir4(), ".hasna", "skills");
17035
17050
  var AUTH_FILE = join7(AUTH_DIR, "auth.json");
17051
+ var LEGACY_AUTH_FILE = join7(homedir4(), ".skills", "auth.json");
17036
17052
  var cachedConfig;
17037
17053
  function getAuthConfig() {
17038
17054
  if (cachedConfig !== undefined)
17039
17055
  return cachedConfig;
17040
17056
  try {
17041
- const raw = readFileSync7(AUTH_FILE, "utf-8");
17057
+ const raw = readFileSync7(existsSync7(AUTH_FILE) ? AUTH_FILE : LEGACY_AUTH_FILE, "utf-8");
17042
17058
  const config2 = JSON.parse(raw);
17043
17059
  if (!config2.apiKey || !config2.email) {
17044
17060
  cachedConfig = null;
@@ -17472,14 +17488,14 @@ function createRemoteSkillsClient() {
17472
17488
  return new RemoteSkillsClient(apiKey);
17473
17489
  }
17474
17490
  // src/lib/scheduler.ts
17475
- import { existsSync as existsSync7, readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "fs";
17491
+ import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync5, mkdirSync as mkdirSync5 } from "fs";
17476
17492
  import { join as join8 } from "path";
17477
17493
  function getSchedulesPath(targetDir = process.cwd()) {
17478
17494
  return join8(targetDir, ".skills", "schedules.json");
17479
17495
  }
17480
17496
  function loadSchedules(targetDir = process.cwd()) {
17481
17497
  const path = getSchedulesPath(targetDir);
17482
- if (existsSync7(path)) {
17498
+ if (existsSync8(path)) {
17483
17499
  try {
17484
17500
  return JSON.parse(readFileSync8(path, "utf-8"));
17485
17501
  } catch {}
@@ -17489,7 +17505,7 @@ function loadSchedules(targetDir = process.cwd()) {
17489
17505
  function saveSchedules(data, targetDir = process.cwd()) {
17490
17506
  const path = getSchedulesPath(targetDir);
17491
17507
  const dir = join8(targetDir, ".skills");
17492
- if (!existsSync7(dir))
17508
+ if (!existsSync8(dir))
17493
17509
  mkdirSync5(dir, { recursive: true });
17494
17510
  writeFileSync5(path, JSON.stringify(data, null, 2));
17495
17511
  }
@@ -17676,7 +17692,7 @@ function recordScheduleRun(id, status, targetDir) {
17676
17692
  saveSchedules(data, targetDir);
17677
17693
  }
17678
17694
  // src/lib/skill-validation.ts
17679
- import { existsSync as existsSync8, lstatSync, readFileSync as readFileSync9, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
17695
+ import { existsSync as existsSync9, lstatSync, readFileSync as readFileSync9, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
17680
17696
  import { isAbsolute, join as join9, normalize } from "path";
17681
17697
  var DOC_FILES = ["SKILL.md", "README.md", "CLAUDE.md"];
17682
17698
  var RESERVED_SKILL_ENTRIES = new Set([
@@ -17793,7 +17809,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
17793
17809
  binCommands: [],
17794
17810
  docFiles: []
17795
17811
  };
17796
- if (!existsSync8(skillPath)) {
17812
+ if (!existsSync9(skillPath)) {
17797
17813
  add(issues, "skill.dir_missing", `Skill directory not found: ${skillPath}`);
17798
17814
  return {
17799
17815
  name: bareName,
@@ -17820,14 +17836,14 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
17820
17836
  }
17821
17837
  }
17822
17838
  for (const docFile of DOC_FILES) {
17823
- if (existsSync8(join9(skillPath, docFile)))
17839
+ if (existsSync9(join9(skillPath, docFile)))
17824
17840
  metadata.docFiles.push(docFile);
17825
17841
  }
17826
17842
  if (metadata.docFiles.length === 0) {
17827
17843
  add(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
17828
17844
  }
17829
17845
  const skillMdPath = join9(skillPath, "SKILL.md");
17830
- if (existsSync8(skillMdPath)) {
17846
+ if (existsSync9(skillMdPath)) {
17831
17847
  const frontmatter = parseSkillFrontmatter(readFileSync9(skillMdPath, "utf-8"));
17832
17848
  if (!frontmatter) {
17833
17849
  add(warnings, "skill.frontmatter_missing", "SKILL.md has no YAML frontmatter");
@@ -17862,7 +17878,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
17862
17878
  add(warnings, "skill.skill_md_missing", "Missing SKILL.md; registry docs may need generated agent-facing instructions");
17863
17879
  }
17864
17880
  const pkgPath = join9(skillPath, "package.json");
17865
- if (!existsSync8(pkgPath)) {
17881
+ if (!existsSync9(pkgPath)) {
17866
17882
  add(issues, "package.missing", "Missing package.json");
17867
17883
  } else {
17868
17884
  try {
@@ -17907,7 +17923,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
17907
17923
  continue;
17908
17924
  }
17909
17925
  const targetPath = join9(skillPath, target);
17910
- if (!existsSync8(targetPath)) {
17926
+ if (!existsSync9(targetPath)) {
17911
17927
  add(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
17912
17928
  } else if (statSync2(targetPath).isDirectory()) {
17913
17929
  add(issues, "package.bin_target_directory", `package.json bin '${command}' target '${target}' must point to a file, not a directory`);
@@ -17920,12 +17936,12 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
17920
17936
  }
17921
17937
  }
17922
17938
  const srcDir = join9(skillPath, "src");
17923
- if (!existsSync8(srcDir)) {
17939
+ if (!existsSync9(srcDir)) {
17924
17940
  add(issues, "skill.src_missing", "Missing src/ directory");
17925
- } else if (!existsSync8(join9(srcDir, "index.ts")) && !existsSync8(join9(srcDir, "index.js"))) {
17941
+ } else if (!existsSync9(join9(srcDir, "index.ts")) && !existsSync9(join9(srcDir, "index.js"))) {
17926
17942
  add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
17927
17943
  } else {
17928
- const indexPath = existsSync8(join9(srcDir, "index.ts")) ? join9(srcDir, "index.ts") : join9(srcDir, "index.js");
17944
+ const indexPath = existsSync9(join9(srcDir, "index.ts")) ? join9(srcDir, "index.ts") : join9(srcDir, "index.js");
17929
17945
  const size = statSync2(indexPath).size;
17930
17946
  if (size < 50)
17931
17947
  add(warnings, "skill.src_index_minimal", `Source entry point is very small (${size}B)`);
@@ -17948,7 +17964,7 @@ function validateRegistryConsistency(registry2, skillsDir) {
17948
17964
  seen.add(name);
17949
17965
  return false;
17950
17966
  })));
17951
- const skillDirs = existsSync8(skillsDir) ? readdirSync3(skillsDir).filter((entry) => {
17967
+ const skillDirs = existsSync9(skillsDir) ? readdirSync3(skillsDir).filter((entry) => {
17952
17968
  const fullPath = join9(skillsDir, entry);
17953
17969
  return !entry.startsWith(".") && entry !== "_common" && statSync2(fullPath).isDirectory();
17954
17970
  }) : [];
@@ -17969,7 +17985,7 @@ import { dirname as dirname3, relative as relative2 } from "path";
17969
17985
  // package.json
17970
17986
  var package_default = {
17971
17987
  name: "@hasna/skills",
17972
- version: "0.1.31",
17988
+ version: "0.1.32",
17973
17989
  description: "Skills library for AI coding agents",
17974
17990
  type: "module",
17975
17991
  bin: {
@@ -18763,7 +18779,7 @@ function clone2(value) {
18763
18779
  return JSON.parse(JSON.stringify(value));
18764
18780
  }
18765
18781
  // src/lib/feedback.ts
18766
- import { existsSync as existsSync9, mkdirSync as mkdirSync7 } from "fs";
18782
+ import { existsSync as existsSync10, mkdirSync as mkdirSync7 } from "fs";
18767
18783
  import { homedir as homedir5 } from "os";
18768
18784
  import { dirname as dirname4, join as join10 } from "path";
18769
18785
  import { Database } from "bun:sqlite";
@@ -18773,7 +18789,7 @@ function getFeedbackDbPath() {
18773
18789
  function getFeedbackDb() {
18774
18790
  const dbPath = getFeedbackDbPath();
18775
18791
  const dir = dirname4(dbPath);
18776
- if (!existsSync9(dir))
18792
+ if (!existsSync10(dir))
18777
18793
  mkdirSync7(dir, { recursive: true });
18778
18794
  const db = new Database(dbPath);
18779
18795
  db.exec("PRAGMA journal_mode = WAL");
@@ -9,7 +9,7 @@
9
9
  * Values from the project config override global config.
10
10
  */
11
11
  export interface SkillsConfig {
12
- mode?: "local" | "skills.md";
12
+ mode?: "local" | "hosted";
13
13
  defaultAgent?: "claude" | "codex" | "gemini" | "pi" | "opencode" | "all";
14
14
  defaultScope?: "global" | "project";
15
15
  format?: "compact" | "json" | "csv";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/skills",
3
- "version": "0.1.31",
3
+ "version": "0.1.32",
4
4
  "description": "Skills library for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {