@hasna/skills 0.1.64 → 0.1.66

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/dist/index.js CHANGED
@@ -47,8 +47,8 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
47
47
  var __require = import.meta.require;
48
48
 
49
49
  // src/lib/registry.ts
50
- import { existsSync as existsSync6, readFileSync as readFileSync5, readdirSync as readdirSync5 } from "fs";
51
- import { join as join6 } from "path";
50
+ import { existsSync as existsSync7, readFileSync as readFileSync6, readdirSync as readdirSync6 } from "fs";
51
+ import { join as join7 } from "path";
52
52
 
53
53
  // src/lib/config.ts
54
54
  import { existsSync, readFileSync, writeFileSync, mkdirSync, copyFileSync, readdirSync, statSync } from "fs";
@@ -272,15 +272,16 @@ function unsetConfig(key, scope = "project") {
272
272
  // src/lib/portable-skills.ts
273
273
  import {
274
274
  cpSync as cpSync2,
275
- existsSync as existsSync5,
275
+ existsSync as existsSync6,
276
276
  mkdirSync as mkdirSync3,
277
- readdirSync as readdirSync4,
277
+ mkdtempSync,
278
+ readdirSync as readdirSync5,
278
279
  renameSync,
279
280
  rmSync,
280
- statSync as statSync5,
281
+ statSync as statSync6,
281
282
  writeFileSync as writeFileSync3
282
283
  } from "fs";
283
- import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as join5, normalize as normalize2 } from "path";
284
+ import { basename as basename2, dirname as dirname3, isAbsolute as isAbsolute2, join as join6, normalize as normalize2 } from "path";
284
285
 
285
286
  // src/lib/registry-data/development-tools.ts
286
287
  var DEVELOPMENT_TOOLS_SKILLS = [
@@ -991,11 +992,9 @@ var SKILLS = [
991
992
  ...EVENT_MANAGEMENT_SKILLS
992
993
  ];
993
994
 
994
- // src/lib/skill-validation.ts
995
- import { existsSync as existsSync2, lstatSync, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
996
- import { isAbsolute, join as join2, normalize } from "path";
997
-
998
995
  // src/lib/hosted-skill-set.ts
996
+ import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
997
+ import { join as join2 } from "path";
999
998
  var HOSTED_RUNTIMES = new Set(["hosted"]);
1000
999
  var HOSTED_SOURCES = new Set(["remote", "private-hosted"]);
1001
1000
  function normalizeMarker(value) {
@@ -1007,6 +1006,16 @@ function isHostedMetadataPackage(pkg) {
1007
1006
  return false;
1008
1007
  return HOSTED_RUNTIMES.has(normalizeMarker(skills.runtime)) || HOSTED_SOURCES.has(normalizeMarker(skills.source));
1009
1008
  }
1009
+ function isHostedMetadataSkillDir(skillDir) {
1010
+ const pkgPath = join2(skillDir, "package.json");
1011
+ if (!existsSync2(pkgPath))
1012
+ return false;
1013
+ try {
1014
+ return isHostedMetadataPackage(JSON.parse(readFileSync2(pkgPath, "utf8")));
1015
+ } catch {
1016
+ return false;
1017
+ }
1018
+ }
1010
1019
  var HOSTED_METADATA_SET_EMPTY_ERROR = [
1011
1020
  "The hosted metadata skill set is empty, but the packaging guards that depend on it",
1012
1021
  "only mean anything while it is non-empty: an empty set makes every one of them pass",
@@ -1023,6 +1032,8 @@ var BRACE_SOURCE_EXCLUSION = new RegExp(`^!skills/\\{(${SLUG}(?:,${SLUG})+)\\}/s
1023
1032
  var SINGLE_SOURCE_EXCLUSION = new RegExp(`^!skills/(${SLUG})/src$`);
1024
1033
 
1025
1034
  // src/lib/skill-validation.ts
1035
+ import { existsSync as existsSync3, lstatSync, readFileSync as readFileSync3, readdirSync as readdirSync3, statSync as statSync3 } from "fs";
1036
+ import { isAbsolute, join as join3, normalize } from "path";
1026
1037
  var VALID_SKILL_KINDS = ["executable", "instruction"];
1027
1038
  var DOC_FILES = ["SKILL.md", "README.md", "CLAUDE.md"];
1028
1039
  var RESERVED_SKILL_ENTRIES = new Set([
@@ -1076,7 +1087,7 @@ function add(target, code, message) {
1076
1087
  target.push({ code, message });
1077
1088
  }
1078
1089
  function readJsonFile(path) {
1079
- return JSON.parse(readFileSync2(path, "utf-8"));
1090
+ return JSON.parse(readFileSync3(path, "utf-8"));
1080
1091
  }
1081
1092
  function asRecord(value) {
1082
1093
  return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
@@ -1160,7 +1171,7 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
1160
1171
  binCommands: [],
1161
1172
  docFiles: []
1162
1173
  };
1163
- if (!existsSync2(skillPath)) {
1174
+ if (!existsSync3(skillPath)) {
1164
1175
  add(issues, "skill.dir_missing", `Skill directory not found: ${skillPath}`);
1165
1176
  return {
1166
1177
  name: bareName,
@@ -1174,8 +1185,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
1174
1185
  if (!VALID_BIN_COMMAND.test(bareName)) {
1175
1186
  add(issues, "skill.name_invalid", `Skill name '${bareName}' must use lowercase letters, numbers, dots, underscores, or hyphens`);
1176
1187
  }
1177
- for (const entry of readdirSync2(skillPath).sort()) {
1178
- const entryPath = join2(skillPath, entry);
1188
+ for (const entry of readdirSync3(skillPath).sort()) {
1189
+ const entryPath = join3(skillPath, entry);
1179
1190
  if (RESERVED_SKILL_ENTRIES.has(entry)) {
1180
1191
  add(issues, "skill.reserved_file", `Reserved file '${entry}' is not allowed in skill packages`);
1181
1192
  }
@@ -1187,15 +1198,15 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
1187
1198
  }
1188
1199
  }
1189
1200
  for (const docFile of DOC_FILES) {
1190
- if (existsSync2(join2(skillPath, docFile)))
1201
+ if (existsSync3(join3(skillPath, docFile)))
1191
1202
  metadata.docFiles.push(docFile);
1192
1203
  }
1193
1204
  if (metadata.docFiles.length === 0) {
1194
1205
  add(issues, "skill.docs_missing", "Missing documentation file: expected SKILL.md, README.md, or CLAUDE.md");
1195
1206
  }
1196
- const skillMdPath = join2(skillPath, "SKILL.md");
1197
- if (existsSync2(skillMdPath)) {
1198
- const frontmatter = parseSkillFrontmatter(readFileSync2(skillMdPath, "utf-8"));
1207
+ const skillMdPath = join3(skillPath, "SKILL.md");
1208
+ if (existsSync3(skillMdPath)) {
1209
+ const frontmatter = parseSkillFrontmatter(readFileSync3(skillMdPath, "utf-8"));
1199
1210
  if (!frontmatter) {
1200
1211
  add(warnings, "skill.frontmatter_missing", "SKILL.md has no YAML frontmatter");
1201
1212
  } else {
@@ -1237,8 +1248,8 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
1237
1248
  }
1238
1249
  metadata.kind = resolvedKind;
1239
1250
  const isInstruction = resolvedKind === "instruction";
1240
- const pkgPath = join2(skillPath, "package.json");
1241
- if (!existsSync2(pkgPath)) {
1251
+ const pkgPath = join3(skillPath, "package.json");
1252
+ if (!existsSync3(pkgPath)) {
1242
1253
  if (!isInstruction)
1243
1254
  add(issues, "package.missing", "Missing package.json");
1244
1255
  } else {
@@ -1296,10 +1307,10 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
1296
1307
  add(issues, "package.bin_target_unsafe", `package.json bin '${command}' target '${target}' must stay inside the skill directory`);
1297
1308
  continue;
1298
1309
  }
1299
- const targetPath = join2(skillPath, target);
1300
- if (!existsSync2(targetPath)) {
1310
+ const targetPath = join3(skillPath, target);
1311
+ if (!existsSync3(targetPath)) {
1301
1312
  add(warnings, "package.bin_target_missing", `package.json bin '${command}' target '${target}' is not present before build`);
1302
- } else if (statSync2(targetPath).isDirectory()) {
1313
+ } else if (statSync3(targetPath).isDirectory()) {
1303
1314
  add(issues, "package.bin_target_directory", `package.json bin '${command}' target '${target}' must point to a file, not a directory`);
1304
1315
  }
1305
1316
  }
@@ -1314,18 +1325,18 @@ function validateSkillDirectory(name, skillPath, registryMeta) {
1314
1325
  metadata.runtime = "none";
1315
1326
  } else {
1316
1327
  metadata.runtime = hostedMetadata ? "hosted" : "local";
1317
- const srcDir = join2(skillPath, "src");
1328
+ const srcDir = join3(skillPath, "src");
1318
1329
  if (hostedMetadata) {
1319
- if (existsSync2(srcDir)) {
1330
+ if (existsSync3(srcDir)) {
1320
1331
  add(issues, "skill.hosted_source_forbidden", "Hosted metadata skills must not include local implementation source");
1321
1332
  }
1322
- } else if (!existsSync2(srcDir)) {
1333
+ } else if (!existsSync3(srcDir)) {
1323
1334
  add(issues, "skill.src_missing", "Missing src/ directory");
1324
- } else if (!existsSync2(join2(srcDir, "index.ts")) && !existsSync2(join2(srcDir, "index.js"))) {
1335
+ } else if (!existsSync3(join3(srcDir, "index.ts")) && !existsSync3(join3(srcDir, "index.js"))) {
1325
1336
  add(issues, "skill.src_index_missing", "Missing src/index.ts or src/index.js");
1326
1337
  } else {
1327
- const indexPath = existsSync2(join2(srcDir, "index.ts")) ? join2(srcDir, "index.ts") : join2(srcDir, "index.js");
1328
- const size = statSync2(indexPath).size;
1338
+ const indexPath = existsSync3(join3(srcDir, "index.ts")) ? join3(srcDir, "index.ts") : join3(srcDir, "index.js");
1339
+ const size = statSync3(indexPath).size;
1329
1340
  if (size < 50)
1330
1341
  add(warnings, "skill.src_index_minimal", `Source entry point is very small (${size}B)`);
1331
1342
  }
@@ -1348,9 +1359,9 @@ function validateRegistryConsistency(registry, skillsDir) {
1348
1359
  seen.add(name);
1349
1360
  return false;
1350
1361
  })));
1351
- const skillDirs = existsSync2(skillsDir) ? readdirSync2(skillsDir).filter((entry) => {
1352
- const fullPath = join2(skillsDir, entry);
1353
- return !entry.startsWith(".") && entry !== "_common" && statSync2(fullPath).isDirectory();
1362
+ const skillDirs = existsSync3(skillsDir) ? readdirSync3(skillsDir).filter((entry) => {
1363
+ const fullPath = join3(skillsDir, entry);
1364
+ return !entry.startsWith(".") && entry !== "_common" && statSync3(fullPath).isDirectory();
1354
1365
  }) : [];
1355
1366
  const directoryNames = new Set(skillDirs);
1356
1367
  const registryNameSet = new Set(registryNames);
@@ -1366,8 +1377,8 @@ function validateRegistryConsistency(registry, skillsDir) {
1366
1377
 
1367
1378
  // src/lib/skill-hash.ts
1368
1379
  import { createHash } from "crypto";
1369
- import { existsSync as existsSync3, readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
1370
- import { join as join3, sep } from "path";
1380
+ import { existsSync as existsSync4, readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
1381
+ import { join as join4, sep } from "path";
1371
1382
  var CONTENT_HASH_ALGORITHM = "sha256";
1372
1383
  var HASH_EXCLUDE_DIRS = new Set([".git", "node_modules", "dist", "build", ".turbo"]);
1373
1384
  var HASH_COVERAGE = [
@@ -1426,10 +1437,10 @@ function collectBundleFiles(skillPath) {
1426
1437
  if (seen.has(entry))
1427
1438
  continue;
1428
1439
  seen.add(entry);
1429
- const absolute = join3(skillPath, entry);
1430
- if (!existsSync3(absolute))
1440
+ const absolute = join4(skillPath, entry);
1441
+ if (!existsSync4(absolute))
1431
1442
  continue;
1432
- if (statSync3(absolute).isDirectory())
1443
+ if (statSync4(absolute).isDirectory())
1433
1444
  collectDirectory(files, absolute, entry);
1434
1445
  else
1435
1446
  collectFile(files, absolute, entry);
@@ -1437,14 +1448,14 @@ function collectBundleFiles(skillPath) {
1437
1448
  return files.sort((a, b) => a.rel < b.rel ? -1 : a.rel > b.rel ? 1 : 0);
1438
1449
  }
1439
1450
  function collectDirectory(files, dir, rel) {
1440
- for (const entry of readdirSync3(dir).sort()) {
1451
+ for (const entry of readdirSync4(dir).sort()) {
1441
1452
  if (entry.startsWith("."))
1442
1453
  continue;
1443
- const absolute = join3(dir, entry);
1454
+ const absolute = join4(dir, entry);
1444
1455
  const childRel = `${rel}/${entry}`;
1445
1456
  let stats;
1446
1457
  try {
1447
- stats = statSync3(absolute);
1458
+ stats = statSync4(absolute);
1448
1459
  } catch {
1449
1460
  continue;
1450
1461
  }
@@ -1460,7 +1471,7 @@ function collectDirectory(files, dir, rel) {
1460
1471
  }
1461
1472
  }
1462
1473
  function collectFile(files, absolute, rel) {
1463
- const buffer = readFileSync3(absolute);
1474
+ const buffer = readFileSync4(absolute);
1464
1475
  if (rel === "skill.json") {
1465
1476
  files.push({ rel: rel.split(sep).join("/"), content: new TextEncoder().encode(canonicalizeManifest(new TextDecoder().decode(buffer))) });
1466
1477
  return;
@@ -1660,14 +1671,14 @@ function validateRuntimeContract(manifest, issues, strict) {
1660
1671
  // src/lib/portable-skills-files.ts
1661
1672
  import {
1662
1673
  cpSync,
1663
- existsSync as existsSync4,
1674
+ existsSync as existsSync5,
1664
1675
  lstatSync as lstatSync2,
1665
1676
  mkdirSync as mkdirSync2,
1666
- readFileSync as readFileSync4,
1677
+ readFileSync as readFileSync5,
1667
1678
  realpathSync,
1668
1679
  writeFileSync as writeFileSync2
1669
1680
  } from "fs";
1670
- import { basename, dirname as dirname2, join as join4, relative } from "path";
1681
+ import { basename, dirname as dirname2, join as join5, relative } from "path";
1671
1682
  var ANY_SEGMENT_COPY_EXCLUDES = new Set([
1672
1683
  ".git",
1673
1684
  ".DS_Store",
@@ -1710,12 +1721,12 @@ function normalizePortableSkillName(name) {
1710
1721
  return normalized;
1711
1722
  }
1712
1723
  function readPortableSkillManifest(skillPath, fallbackName = basename(skillPath)) {
1713
- const skillJsonPath = join4(skillPath, "skill.json");
1714
- const skillMdPath = join4(skillPath, "SKILL.md");
1715
- const pkgPath = join4(skillPath, "package.json");
1716
- const jsonManifest = existsSync4(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
1717
- const frontmatter = existsSync4(skillMdPath) ? parseSkillFrontmatter(readFileSync4(skillMdPath, "utf-8")) ?? undefined : undefined;
1718
- const pkg = existsSync4(pkgPath) ? readJsonObject(pkgPath) : undefined;
1724
+ const skillJsonPath = join5(skillPath, "skill.json");
1725
+ const skillMdPath = join5(skillPath, "SKILL.md");
1726
+ const pkgPath = join5(skillPath, "package.json");
1727
+ const jsonManifest = existsSync5(skillJsonPath) ? readJsonObject(skillJsonPath) : undefined;
1728
+ const frontmatter = existsSync5(skillMdPath) ? parseSkillFrontmatter(readFileSync5(skillMdPath, "utf-8")) ?? undefined : undefined;
1729
+ const pkg = existsSync5(pkgPath) ? readJsonObject(pkgPath) : undefined;
1719
1730
  const name = normalizePortableSkillName(stringField(jsonManifest, "name") ?? frontmatter?.name ?? stringValue(pkg?.name) ?? fallbackName);
1720
1731
  const description = stringField(jsonManifest, "description") ?? frontmatter?.description ?? stringValue(pkg?.description) ?? `${name} skill`;
1721
1732
  const version = stringField(jsonManifest, "version") ?? frontmatter?.version ?? stringValue(pkg?.version) ?? PORTABLE_SKILL_DEFAULT_VERSION;
@@ -1761,7 +1772,7 @@ function createInstructionManifest(name, options) {
1761
1772
  }
1762
1773
  function writeInstructionSkillTemplate(skillPath, manifest) {
1763
1774
  mkdirSync2(skillPath, { recursive: true });
1764
- writeFileSync2(join4(skillPath, "SKILL.md"), renderInstructionSkillMd(manifest));
1775
+ writeFileSync2(join5(skillPath, "SKILL.md"), renderInstructionSkillMd(manifest));
1765
1776
  writeSkillJsonWithHash(skillPath, manifest);
1766
1777
  }
1767
1778
  function renderInstructionSkillMd(manifest) {
@@ -1810,12 +1821,12 @@ function createPortableManifest(name, options) {
1810
1821
  };
1811
1822
  }
1812
1823
  function writePortableSkillTemplate(skillPath, manifest) {
1813
- mkdirSync2(join4(skillPath, "src"), { recursive: true });
1814
- writeFileSync2(join4(skillPath, "SKILL.md"), renderSkillMd(manifest));
1815
- writeFileSync2(join4(skillPath, "AGENTS.md"), renderAgentsMd(manifest));
1816
- writeFileSync2(join4(skillPath, "package.json"), renderPackageJson(manifest));
1817
- writeFileSync2(join4(skillPath, "tsconfig.json"), renderTsconfig());
1818
- writeFileSync2(join4(skillPath, "src", "index.ts"), renderEntrypoint(manifest));
1824
+ mkdirSync2(join5(skillPath, "src"), { recursive: true });
1825
+ writeFileSync2(join5(skillPath, "SKILL.md"), renderSkillMd(manifest));
1826
+ writeFileSync2(join5(skillPath, "AGENTS.md"), renderAgentsMd(manifest));
1827
+ writeFileSync2(join5(skillPath, "package.json"), renderPackageJson(manifest));
1828
+ writeFileSync2(join5(skillPath, "tsconfig.json"), renderTsconfig());
1829
+ writeFileSync2(join5(skillPath, "src", "index.ts"), renderEntrypoint(manifest));
1819
1830
  writeSkillJsonWithHash(skillPath, manifest);
1820
1831
  }
1821
1832
  function fillContractDefaults(manifest, entrypoint) {
@@ -1840,7 +1851,7 @@ function writeSkillJsonWithHash(skillPath, manifest) {
1840
1851
  content_hash: undefined
1841
1852
  }
1842
1853
  };
1843
- writeFileSync2(join4(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withoutHash) }, null, 2)}
1854
+ writeFileSync2(join5(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withoutHash) }, null, 2)}
1844
1855
  `);
1845
1856
  const hash = computeContentHash(skillPath);
1846
1857
  const withHash = {
@@ -1850,16 +1861,16 @@ function writeSkillJsonWithHash(skillPath, manifest) {
1850
1861
  content_hash: hash
1851
1862
  }
1852
1863
  };
1853
- writeFileSync2(join4(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withHash) }, null, 2)}
1864
+ writeFileSync2(join5(skillPath, "skill.json"), `${JSON.stringify({ ...existing, ...renderSkillJsonObject(withHash) }, null, 2)}
1854
1865
  `);
1855
1866
  return withHash;
1856
1867
  }
1857
1868
  function readExistingSkillJson(skillPath) {
1858
- const path = join4(skillPath, "skill.json");
1859
- if (!existsSync4(path))
1869
+ const path = join5(skillPath, "skill.json");
1870
+ if (!existsSync5(path))
1860
1871
  return {};
1861
1872
  try {
1862
- const parsed = JSON.parse(readFileSync4(path, "utf-8"));
1873
+ const parsed = JSON.parse(readFileSync5(path, "utf-8"));
1863
1874
  return isRecord2(parsed) ? parsed : {};
1864
1875
  } catch {
1865
1876
  return {};
@@ -1889,28 +1900,28 @@ function ensurePortableSkillFiles(skillPath, manifest) {
1889
1900
  tags: next.tags?.length ? next.tags : ["custom", next.name]
1890
1901
  };
1891
1902
  const entry = next.commands[0]?.entry ?? "src/index.ts";
1892
- if (entry && !existsSync4(join4(skillPath, entry))) {
1893
- mkdirSync2(dirname2(join4(skillPath, entry)), { recursive: true });
1894
- writeFileSync2(join4(skillPath, entry), renderEntrypoint(next));
1903
+ if (entry && !existsSync5(join5(skillPath, entry))) {
1904
+ mkdirSync2(dirname2(join5(skillPath, entry)), { recursive: true });
1905
+ writeFileSync2(join5(skillPath, entry), renderEntrypoint(next));
1895
1906
  }
1896
- if (!existsSync4(join4(skillPath, "SKILL.md")))
1897
- writeFileSync2(join4(skillPath, "SKILL.md"), renderSkillMd(next));
1907
+ if (!existsSync5(join5(skillPath, "SKILL.md")))
1908
+ writeFileSync2(join5(skillPath, "SKILL.md"), renderSkillMd(next));
1898
1909
  else
1899
- writeFileSync2(join4(skillPath, "SKILL.md"), ensureSkillMdFrontmatter(readFileSync4(join4(skillPath, "SKILL.md"), "utf-8"), next));
1900
- if (!existsSync4(join4(skillPath, "AGENTS.md")))
1901
- writeFileSync2(join4(skillPath, "AGENTS.md"), renderAgentsMd(next));
1910
+ writeFileSync2(join5(skillPath, "SKILL.md"), ensureSkillMdFrontmatter(readFileSync5(join5(skillPath, "SKILL.md"), "utf-8"), next));
1911
+ if (!existsSync5(join5(skillPath, "AGENTS.md")))
1912
+ writeFileSync2(join5(skillPath, "AGENTS.md"), renderAgentsMd(next));
1902
1913
  ensurePackageJson(skillPath, next);
1903
- if (!existsSync4(join4(skillPath, "tsconfig.json")))
1904
- writeFileSync2(join4(skillPath, "tsconfig.json"), renderTsconfig());
1914
+ if (!existsSync5(join5(skillPath, "tsconfig.json")))
1915
+ writeFileSync2(join5(skillPath, "tsconfig.json"), renderTsconfig());
1905
1916
  writeSkillJsonWithHash(skillPath, next);
1906
1917
  return readPortableSkillManifest(skillPath, next.name);
1907
1918
  }
1908
1919
  function ensurePackageJson(skillPath, manifest) {
1909
- const pkgPath = join4(skillPath, "package.json");
1920
+ const pkgPath = join5(skillPath, "package.json");
1910
1921
  const first = manifest.commands[0] ?? { name: manifest.name, entry: "src/index.ts" };
1911
1922
  const commandName = normalizePortableSkillName(first.name || manifest.name);
1912
1923
  const entry = (first.entry ?? "src/index.ts").replace(/^\.\//, "");
1913
- if (!existsSync4(pkgPath)) {
1924
+ if (!existsSync5(pkgPath)) {
1914
1925
  writeFileSync2(pkgPath, renderPackageJson(manifest));
1915
1926
  return;
1916
1927
  }
@@ -1953,8 +1964,8 @@ function ensureInstructionSkillFiles(skillPath, manifest) {
1953
1964
  inputs: [],
1954
1965
  commands: []
1955
1966
  };
1956
- if (!existsSync4(join4(skillPath, "SKILL.md"))) {
1957
- writeFileSync2(join4(skillPath, "SKILL.md"), renderSkillMd(next));
1967
+ if (!existsSync5(join5(skillPath, "SKILL.md"))) {
1968
+ writeFileSync2(join5(skillPath, "SKILL.md"), renderSkillMd(next));
1958
1969
  }
1959
1970
  writeSkillJsonWithHash(skillPath, next);
1960
1971
  return readPortableSkillManifest(skillPath, next.name);
@@ -2205,7 +2216,7 @@ function inferPackageCommands(pkg, fallbackName) {
2205
2216
  return;
2206
2217
  }
2207
2218
  function readJsonObject(path) {
2208
- const parsed = JSON.parse(readFileSync4(path, "utf-8"));
2219
+ const parsed = JSON.parse(readFileSync5(path, "utf-8"));
2209
2220
  if (!isRecord2(parsed))
2210
2221
  throw new Error(`${basename(path)} must contain a JSON object`);
2211
2222
  return parsed;
@@ -2246,36 +2257,36 @@ var LEGACY_CUSTOM_DIRNAME = "custom";
2246
2257
  function getPortableSkillsRoot(options = {}) {
2247
2258
  if (options.rootDir)
2248
2259
  return options.rootDir;
2249
- const appDir = options.homeDir ? join5(options.homeDir, ".hasna", "skills") : getDataDir();
2250
- const cache = join5(appDir, SKILLS_CACHE_DIRNAME);
2260
+ const appDir = options.homeDir ? join6(options.homeDir, ".hasna", "skills") : getDataDir();
2261
+ const cache = join6(appDir, SKILLS_CACHE_DIRNAME);
2251
2262
  if (isOwnerLayoutMigrated(appDir) && safeIsDirectory(cache))
2252
2263
  return cache;
2253
- const installed = join5(appDir, INSTALLED_SKILLS_DIRNAME);
2264
+ const installed = join6(appDir, INSTALLED_SKILLS_DIRNAME);
2254
2265
  migrateLegacySkillLayout(appDir, installed);
2255
2266
  return installed;
2256
2267
  }
2257
2268
  function looksLikeSkillDirectory(path) {
2258
2269
  if (!safeIsDirectory(path))
2259
2270
  return false;
2260
- return existsSync5(join5(path, "SKILL.md")) || existsSync5(join5(path, "skill.json")) || existsSync5(join5(path, "package.json"));
2271
+ return existsSync6(join6(path, "SKILL.md")) || existsSync6(join6(path, "skill.json")) || existsSync6(join6(path, "package.json"));
2261
2272
  }
2262
2273
  function migrateLegacySkillLayout(appDir, installed) {
2263
2274
  if (!safeIsDirectory(appDir))
2264
2275
  return;
2265
2276
  const candidates = [];
2266
2277
  try {
2267
- for (const entry of readdirSync4(appDir)) {
2278
+ for (const entry of readdirSync5(appDir)) {
2268
2279
  if (entry.startsWith(".") || entry === INSTALLED_SKILLS_DIRNAME)
2269
2280
  continue;
2270
- const path = join5(appDir, entry);
2281
+ const path = join6(appDir, entry);
2271
2282
  if (entry === LEGACY_CUSTOM_DIRNAME) {
2272
2283
  if (!safeIsDirectory(path))
2273
2284
  continue;
2274
2285
  try {
2275
- for (const nested of readdirSync4(path)) {
2286
+ for (const nested of readdirSync5(path)) {
2276
2287
  if (nested.startsWith("."))
2277
2288
  continue;
2278
- const nestedPath = join5(path, nested);
2289
+ const nestedPath = join6(path, nested);
2279
2290
  if (looksLikeSkillDirectory(nestedPath))
2280
2291
  candidates.push({ from: nestedPath, name: nested });
2281
2292
  }
@@ -2289,10 +2300,10 @@ function migrateLegacySkillLayout(appDir, installed) {
2289
2300
  return;
2290
2301
  }
2291
2302
  for (const { from, name } of candidates) {
2292
- const target = join5(installed, name);
2293
- if (existsSync5(target))
2303
+ const target = join6(installed, name);
2304
+ if (existsSync6(target))
2294
2305
  continue;
2295
- const staging = join5(installed, `.migrating-${name}-${process.pid}`);
2306
+ const staging = join6(installed, `.migrating-${name}-${process.pid}`);
2296
2307
  try {
2297
2308
  rmSync(staging, { recursive: true, force: true });
2298
2309
  cpSync2(from, staging, { recursive: true, errorOnExist: false });
@@ -2305,7 +2316,7 @@ function migrateLegacySkillLayout(appDir, installed) {
2305
2316
  }
2306
2317
  }
2307
2318
  function getPortableSkillPath(name, options = {}) {
2308
- return join5(getPortableSkillsRoot(options), normalizePortableSkillName(name));
2319
+ return join6(getPortableSkillsRoot(options), normalizePortableSkillName(name));
2309
2320
  }
2310
2321
  function findPortableSkill(name, options = {}) {
2311
2322
  let normalized;
@@ -2315,7 +2326,7 @@ function findPortableSkill(name, options = {}) {
2315
2326
  return null;
2316
2327
  }
2317
2328
  const path = getPortableSkillPath(normalized, options);
2318
- if (!existsSync5(path) || !statSync5(path).isDirectory())
2329
+ if (!existsSync6(path) || !statSync6(path).isDirectory())
2319
2330
  return null;
2320
2331
  try {
2321
2332
  return summarizePortableSkill(path, normalized);
@@ -2328,10 +2339,10 @@ function listPortableSkills(options = {}) {
2328
2339
  if (!safeIsDirectory(root))
2329
2340
  return [];
2330
2341
  const skills = [];
2331
- for (const entry of readdirSync4(root).sort()) {
2342
+ for (const entry of readdirSync5(root).sort()) {
2332
2343
  if (entry.startsWith("."))
2333
2344
  continue;
2334
- const path = join5(root, entry);
2345
+ const path = join6(root, entry);
2335
2346
  if (!safeIsDirectory(path))
2336
2347
  continue;
2337
2348
  try {
@@ -2353,7 +2364,8 @@ function listPortableSkillMetas(options = {}) {
2353
2364
  tags: manifest.tags || ["custom"],
2354
2365
  version: skill.version,
2355
2366
  ...manifest.kind ? { kind: manifest.kind } : {},
2356
- source: "custom"
2367
+ source: "custom",
2368
+ ...isHostedMetadataSkillDir(skill.path) ? { serverOwned: true } : {}
2357
2369
  };
2358
2370
  });
2359
2371
  }
@@ -2364,8 +2376,8 @@ function isOfficialSkillName(name) {
2364
2376
  function scaffoldPortableSkill(name, options = {}) {
2365
2377
  const skillName = normalizePortableSkillName(name);
2366
2378
  const root = getPortableSkillsRoot(options);
2367
- const skillPath = join5(root, skillName);
2368
- if (existsSync5(skillPath)) {
2379
+ const skillPath = join6(root, skillName);
2380
+ if (existsSync6(skillPath)) {
2369
2381
  if (!options.overwrite)
2370
2382
  throw new Error(`Skill '${skillName}' already exists at ${skillPath}`);
2371
2383
  rmSync(skillPath, { recursive: true, force: true });
@@ -2383,7 +2395,7 @@ function scaffoldPortableSkill(name, options = {}) {
2383
2395
  }
2384
2396
  function portPortableSkillDirectory(sourceDir, options = {}) {
2385
2397
  const absoluteSource = normalize2(sourceDir);
2386
- if (!existsSync5(absoluteSource) || !statSync5(absoluteSource).isDirectory()) {
2398
+ if (!existsSync6(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
2387
2399
  throw new Error(`Import directory not found: ${sourceDir}`);
2388
2400
  }
2389
2401
  const continueOnError = options.continueOnError ?? true;
@@ -2394,9 +2406,9 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
2394
2406
  };
2395
2407
  const imported = [];
2396
2408
  const skipped = [];
2397
- const entries = readdirSync4(absoluteSource, { withFileTypes: true }).map((entry) => entry.name).filter((entryName) => !entryName.startsWith(".")).sort();
2409
+ const entries = readdirSync5(absoluteSource, { withFileTypes: true }).map((entry) => entry.name).filter((entryName) => !entryName.startsWith(".")).sort();
2398
2410
  for (const entryName of entries) {
2399
- const childPath = join5(absoluteSource, entryName);
2411
+ const childPath = join6(absoluteSource, entryName);
2400
2412
  if (!safeIsDirectory(childPath))
2401
2413
  continue;
2402
2414
  if (!isSkillCandidate(childPath)) {
@@ -2425,11 +2437,11 @@ function portPortableSkillDirectory(sourceDir, options = {}) {
2425
2437
  };
2426
2438
  }
2427
2439
  function isSkillCandidate(dir) {
2428
- return existsSync5(join5(dir, "SKILL.md")) || existsSync5(join5(dir, "skill.json")) || existsSync5(join5(dir, "package.json"));
2440
+ return existsSync6(join6(dir, "SKILL.md")) || existsSync6(join6(dir, "skill.json")) || existsSync6(join6(dir, "package.json"));
2429
2441
  }
2430
2442
  function portPortableSkill(sourcePath, options = {}) {
2431
2443
  const absoluteSource = normalize2(sourcePath);
2432
- if (!existsSync5(absoluteSource) || !statSync5(absoluteSource).isDirectory()) {
2444
+ if (!existsSync6(absoluteSource) || !statSync6(absoluteSource).isDirectory()) {
2433
2445
  throw new Error(`Skill source directory not found: ${sourcePath}`);
2434
2446
  }
2435
2447
  const inferred = readPortableSkillManifest(absoluteSource, basename2(absoluteSource));
@@ -2441,8 +2453,8 @@ function portPortableSkill(sourcePath, options = {}) {
2441
2453
  throw new Error(`${via} Importing it would shadow the official '${skillName}'. ` + `Pass --name to choose a different name, or --allow-shadow to override deliberately.`);
2442
2454
  }
2443
2455
  const root = getPortableSkillsRoot(options);
2444
- const destination = join5(root, skillName);
2445
- if (existsSync5(destination)) {
2456
+ const destination = join6(root, skillName);
2457
+ if (existsSync6(destination)) {
2446
2458
  if (!options.overwrite)
2447
2459
  throw new Error(`Skill '${skillName}' already exists at ${destination}`);
2448
2460
  rmSync(destination, { recursive: true, force: true });
@@ -2464,16 +2476,10 @@ function safeNormalizeName(name) {
2464
2476
  return;
2465
2477
  }
2466
2478
  }
2467
- function writeCorpusSkill(input, options = {}) {
2468
- const name = normalizePortableSkillName(input.name);
2469
- const root = getPortableSkillsRoot(options);
2470
- const skillPath = join5(root, name);
2471
- const created = !existsSync5(skillPath);
2472
- mkdirSync3(skillPath, { recursive: true });
2473
- writeFileSync3(join5(skillPath, "SKILL.md"), input.skillMd);
2479
+ function buildCorpusManifest(input, name) {
2474
2480
  const frontmatter = parseSkillFrontmatter(input.skillMd) ?? undefined;
2475
2481
  const kind = input.meta?.kind ?? parseSkillKind(frontmatter?.kind) ?? "instruction";
2476
- const manifest = {
2482
+ return {
2477
2483
  $schema: PORTABLE_SKILL_SCHEMA,
2478
2484
  standard: PORTABLE_SKILL_STANDARD,
2479
2485
  name,
@@ -2486,19 +2492,60 @@ function writeCorpusSkill(input, options = {}) {
2486
2492
  inputs: [],
2487
2493
  commands: []
2488
2494
  };
2495
+ }
2496
+ function writeCorpusSkill(input, options = {}) {
2497
+ const name = normalizePortableSkillName(input.name);
2498
+ const root = getPortableSkillsRoot(options);
2499
+ const skillPath = join6(root, name);
2500
+ const created = !existsSync6(skillPath);
2501
+ mkdirSync3(skillPath, { recursive: true });
2502
+ writeFileSync3(join6(skillPath, "SKILL.md"), input.skillMd);
2503
+ const manifest = buildCorpusManifest(input, name);
2489
2504
  writeSkillJsonWithHash(skillPath, manifest);
2490
2505
  return { name, path: skillPath, manifest, created };
2491
2506
  }
2507
+ function installCorpusSkillAtomically(input, options = {}) {
2508
+ const name = normalizePortableSkillName(input.name);
2509
+ const root = getPortableSkillsRoot(options);
2510
+ const target = join6(root, name);
2511
+ const created = !existsSync6(target);
2512
+ mkdirSync3(root, { recursive: true });
2513
+ const staging = mkdtempSync(join6(root, `.pull-${name}-`));
2514
+ let moved = false;
2515
+ let backup = null;
2516
+ try {
2517
+ writeFileSync3(join6(staging, "SKILL.md"), input.skillMd);
2518
+ const manifest = buildCorpusManifest(input, name);
2519
+ writeSkillJsonWithHash(staging, manifest);
2520
+ if (existsSync6(target)) {
2521
+ backup = mkdtempSync(join6(root, `.pull-backup-${name}-`));
2522
+ renameSync(target, join6(backup, name));
2523
+ moved = true;
2524
+ }
2525
+ renameSync(staging, target);
2526
+ if (moved && backup)
2527
+ rmSync(backup, { recursive: true, force: true });
2528
+ return { name, path: target, manifest, created };
2529
+ } catch (error) {
2530
+ rmSync(staging, { recursive: true, force: true });
2531
+ if (moved && backup && existsSync6(join6(backup, name))) {
2532
+ try {
2533
+ renameSync(join6(backup, name), target);
2534
+ } catch {}
2535
+ }
2536
+ throw error;
2537
+ }
2538
+ }
2492
2539
  function validatePortableSkillDirectory(name, skillPath) {
2493
2540
  const normalizedName = normalizePortableSkillName(name);
2494
2541
  const base = validateSkillDirectory(normalizedName, skillPath);
2495
2542
  const issues = [...base.issues];
2496
2543
  const warnings = [...base.warnings];
2497
2544
  let manifest;
2498
- if (existsSync5(skillPath)) {
2499
- const skillJsonPath = join5(skillPath, "skill.json");
2500
- const skillMdPath = join5(skillPath, "SKILL.md");
2501
- if (!existsSync5(skillJsonPath) && !existsSync5(skillMdPath)) {
2545
+ if (existsSync6(skillPath)) {
2546
+ const skillJsonPath = join6(skillPath, "skill.json");
2547
+ const skillMdPath = join6(skillPath, "SKILL.md");
2548
+ if (!existsSync6(skillJsonPath) && !existsSync6(skillMdPath)) {
2502
2549
  add3(issues, "portable.manifest_missing", "Missing portable manifest: expected SKILL.md frontmatter and/or skill.json");
2503
2550
  }
2504
2551
  try {
@@ -2517,7 +2564,7 @@ function validatePortableSkillDirectory(name, skillPath) {
2517
2564
  add3(issues, "portable.version_missing", "Portable manifest missing version");
2518
2565
  }
2519
2566
  const contractIssues = validatePortableManifestContract(manifest, {
2520
- strict: existsSync5(join5(skillPath, "skill.json")),
2567
+ strict: existsSync6(join6(skillPath, "skill.json")),
2521
2568
  skillPath
2522
2569
  });
2523
2570
  for (const issue of contractIssues)
@@ -2553,10 +2600,10 @@ function validatePortableSkillDirectory(name, skillPath) {
2553
2600
  add3(issues, "portable.command_entry_unsafe", `Command '${command.name}' entry '${command.entry}' must stay inside the skill directory`);
2554
2601
  continue;
2555
2602
  }
2556
- const entryPath = join5(skillPath, command.entry);
2557
- if (!existsSync5(entryPath))
2603
+ const entryPath = join6(skillPath, command.entry);
2604
+ if (!existsSync6(entryPath))
2558
2605
  add3(issues, "portable.command_entry_missing", `Command '${command.name}' entry '${command.entry}' is missing`);
2559
- else if (statSync5(entryPath).isDirectory())
2606
+ else if (statSync6(entryPath).isDirectory())
2560
2607
  add3(issues, "portable.command_entry_directory", `Command '${command.name}' entry '${command.entry}' must be a file`);
2561
2608
  }
2562
2609
  }
@@ -2564,7 +2611,7 @@ function validatePortableSkillDirectory(name, skillPath) {
2564
2611
  } catch (error) {
2565
2612
  add3(issues, "portable.manifest_invalid", error.message);
2566
2613
  }
2567
- if (manifest?.kind !== "instruction" && !existsSync5(join5(skillPath, "AGENTS.md"))) {
2614
+ if (manifest?.kind !== "instruction" && !existsSync6(join6(skillPath, "AGENTS.md"))) {
2568
2615
  add3(issues, "portable.agents_missing", "Missing AGENTS.md with build-out instructions for coding agents");
2569
2616
  }
2570
2617
  }
@@ -2600,13 +2647,13 @@ async function runPortableSkill(name, args, options = {}) {
2600
2647
  if (!isSafeRelativePath2(command.entry)) {
2601
2648
  return { exitCode: 1, error: `Portable skill '${name}' command entry is unsafe` };
2602
2649
  }
2603
- const entryPath = join5(skill.path, command.entry);
2604
- if (!existsSync5(entryPath)) {
2650
+ const entryPath = join6(skill.path, command.entry);
2651
+ if (!existsSync6(entryPath)) {
2605
2652
  return { exitCode: 1, error: `Entry point '${command.entry}' not found in portable skill '${name}'` };
2606
2653
  }
2607
- const pkgPath = join5(skill.path, "package.json");
2608
- const nodeModules = join5(skill.path, "node_modules");
2609
- if (existsSync5(pkgPath) && !existsSync5(nodeModules) && hasPackageDependencies(pkgPath)) {
2654
+ const pkgPath = join6(skill.path, "package.json");
2655
+ const nodeModules = join6(skill.path, "node_modules");
2656
+ if (existsSync6(pkgPath) && !existsSync6(nodeModules) && hasPackageDependencies(pkgPath)) {
2610
2657
  const install = Bun.spawn(["bun", "install", "--no-save"], {
2611
2658
  cwd: skill.path,
2612
2659
  stdout: "pipe",
@@ -2646,7 +2693,7 @@ function summarizePortableSkill(skillPath, fallbackName) {
2646
2693
  }
2647
2694
  function safeIsDirectory(path) {
2648
2695
  try {
2649
- return statSync5(path).isDirectory();
2696
+ return statSync6(path).isDirectory();
2650
2697
  } catch {
2651
2698
  return false;
2652
2699
  }
@@ -2875,20 +2922,20 @@ function parseSkillMdFrontmatter(content) {
2875
2922
  return Object.keys(result).length > 0 ? result : null;
2876
2923
  }
2877
2924
  function discoverSkillsInDir(dir, source = "custom") {
2878
- if (!existsSync6(dir))
2925
+ if (!existsSync7(dir))
2879
2926
  return [];
2880
2927
  const result = [];
2881
2928
  try {
2882
- const entries = readdirSync5(dir, { withFileTypes: true });
2929
+ const entries = readdirSync6(dir, { withFileTypes: true });
2883
2930
  for (const entry of entries) {
2884
2931
  if (!entry.isDirectory())
2885
2932
  continue;
2886
- const skillMdPath = join6(dir, entry.name, "SKILL.md");
2887
- if (!existsSync6(skillMdPath))
2933
+ const skillMdPath = join7(dir, entry.name, "SKILL.md");
2934
+ if (!existsSync7(skillMdPath))
2888
2935
  continue;
2889
2936
  let content;
2890
2937
  try {
2891
- content = readFileSync5(skillMdPath, "utf-8");
2938
+ content = readFileSync6(skillMdPath, "utf-8");
2892
2939
  } catch {
2893
2940
  continue;
2894
2941
  }
@@ -2903,6 +2950,7 @@ function discoverSkillsInDir(dir, source = "custom") {
2903
2950
  category: fm.category || "Development Tools",
2904
2951
  tags: fm.tags || [],
2905
2952
  ...fm.kind ? { kind: fm.kind } : {},
2953
+ ...isHostedMetadataSkillDir(join7(dir, entry.name)) ? { serverOwned: true } : {},
2906
2954
  source
2907
2955
  });
2908
2956
  }
@@ -2911,20 +2959,20 @@ function discoverSkillsInDir(dir, source = "custom") {
2911
2959
  }
2912
2960
  function findExtensionSkillPath(name) {
2913
2961
  const config = loadConfig();
2914
- if (!config.extensionsDir || !existsSync6(config.extensionsDir))
2962
+ if (!config.extensionsDir || !existsSync7(config.extensionsDir))
2915
2963
  return null;
2916
2964
  try {
2917
- const entries = readdirSync5(config.extensionsDir, { withFileTypes: true });
2965
+ const entries = readdirSync6(config.extensionsDir, { withFileTypes: true });
2918
2966
  for (const entry of entries) {
2919
2967
  if (!entry.isDirectory())
2920
2968
  continue;
2921
- const skillDir = join6(config.extensionsDir, entry.name);
2922
- const skillMdPath = join6(skillDir, "SKILL.md");
2923
- if (!existsSync6(skillMdPath))
2969
+ const skillDir = join7(config.extensionsDir, entry.name);
2970
+ const skillMdPath = join7(skillDir, "SKILL.md");
2971
+ if (!existsSync7(skillMdPath))
2924
2972
  continue;
2925
2973
  let content;
2926
2974
  try {
2927
- content = readFileSync5(skillMdPath, "utf-8");
2975
+ content = readFileSync6(skillMdPath, "utf-8");
2928
2976
  } catch {
2929
2977
  continue;
2930
2978
  }
@@ -2957,7 +3005,7 @@ function loadRegistry(cwd) {
2957
3005
  const official = SKILLS.map((s) => ({ ...s, source: "official" }));
2958
3006
  const extensions = config.extensionsDir ? discoverSkillsInDir(config.extensionsDir, "extension") : [];
2959
3007
  const portableCustom = listPortableSkillMetas();
2960
- const legacyCustom = discoverSkillsInDir(join6(dataDir, "custom"));
3008
+ const legacyCustom = discoverSkillsInDir(join7(dataDir, "custom"));
2961
3009
  const globalCustom = mergeCustomSkills([...legacyCustom, ...portableCustom]);
2962
3010
  registryCache = mergeSkillRegistryLists(official, extensions, globalCustom);
2963
3011
  registryCacheTime = now;
@@ -3004,26 +3052,26 @@ function getAllTags() {
3004
3052
  return Array.from(tagSet).sort();
3005
3053
  }
3006
3054
  // src/lib/installer.ts
3007
- import { existsSync as existsSync9, readFileSync as readFileSync8, rmSync as rmSync3 } from "fs";
3008
- import { dirname as dirname5, join as join9 } from "path";
3055
+ import { existsSync as existsSync10, readFileSync as readFileSync9, rmSync as rmSync3 } from "fs";
3056
+ import { dirname as dirname5, join as join10 } from "path";
3009
3057
  import { homedir as homedir3 } from "os";
3010
3058
  import { fileURLToPath } from "url";
3011
3059
 
3012
3060
  // src/lib/agent-sync.ts
3013
3061
  import {
3014
3062
  cpSync as cpSync3,
3015
- existsSync as existsSync7,
3063
+ existsSync as existsSync8,
3016
3064
  mkdirSync as mkdirSync4,
3017
- mkdtempSync,
3018
- readFileSync as readFileSync6,
3019
- readdirSync as readdirSync6,
3065
+ mkdtempSync as mkdtempSync2,
3066
+ readFileSync as readFileSync7,
3067
+ readdirSync as readdirSync7,
3020
3068
  renameSync as renameSync2,
3021
3069
  rmSync as rmSync2,
3022
- statSync as statSync6,
3070
+ statSync as statSync7,
3023
3071
  writeFileSync as writeFileSync4
3024
3072
  } from "fs";
3025
3073
  import { homedir as homedir2 } from "os";
3026
- import { basename as basename3, dirname as dirname4, join as join7 } from "path";
3074
+ import { basename as basename3, dirname as dirname4, join as join8 } from "path";
3027
3075
  // src/lib/home-migration.ts
3028
3076
  function resolveCorpusRoot(options = {}) {
3029
3077
  return getPortableSkillsRoot(options);
@@ -3048,9 +3096,9 @@ function resolveSyncAgents(arg) {
3048
3096
  function agentGlobalSkillsDir(agent, homeDir = homedir2()) {
3049
3097
  switch (agent) {
3050
3098
  case "opencode":
3051
- return join7(homeDir, ".config", "opencode", "skills");
3099
+ return join8(homeDir, ".config", "opencode", "skills");
3052
3100
  default:
3053
- return join7(homeDir, `.${agent}`, "skills");
3101
+ return join8(homeDir, `.${agent}`, "skills");
3054
3102
  }
3055
3103
  }
3056
3104
  function adaptSkillMdForAgent(skillMd, agent) {
@@ -3109,8 +3157,8 @@ function resolveSyncCorpus(options = {}) {
3109
3157
  function packageSourceRoots(source) {
3110
3158
  const roots = [];
3111
3159
  for (const sub of ["skills"]) {
3112
- const candidate = join7(source, sub);
3113
- if (existsSync7(candidate) && isDirectory(candidate))
3160
+ const candidate = join8(source, sub);
3161
+ if (existsSync8(candidate) && isDirectory(candidate))
3114
3162
  roots.push(candidate);
3115
3163
  }
3116
3164
  if (roots.length > 0)
@@ -3120,20 +3168,20 @@ function packageSourceRoots(source) {
3120
3168
  function containsSkillDirectories(path) {
3121
3169
  let entries;
3122
3170
  try {
3123
- entries = readdirSync6(path);
3171
+ entries = readdirSync7(path);
3124
3172
  } catch {
3125
3173
  return false;
3126
3174
  }
3127
3175
  return entries.some((entry) => {
3128
- const candidate = join7(path, entry);
3176
+ const candidate = join8(path, entry);
3129
3177
  if (!isDirectory(candidate))
3130
3178
  return false;
3131
- return existsSync7(join7(candidate, "SKILL.md")) || existsSync7(join7(candidate, "skill.json")) || existsSync7(join7(candidate, "package.json"));
3179
+ return existsSync8(join8(candidate, "SKILL.md")) || existsSync8(join8(candidate, "skill.json")) || existsSync8(join8(candidate, "package.json"));
3132
3180
  });
3133
3181
  }
3134
3182
  function isDirectory(path) {
3135
3183
  try {
3136
- return statSync6(path).isDirectory();
3184
+ return statSync7(path).isDirectory();
3137
3185
  } catch {
3138
3186
  return false;
3139
3187
  }
@@ -3167,7 +3215,7 @@ function syncSkillsToAgents(options = {}) {
3167
3215
  actions.push({
3168
3216
  skill: name,
3169
3217
  agent,
3170
- path: join7(agentGlobalSkillsDir(agent, homeDir), name, "SKILL.md"),
3218
+ path: join8(agentGlobalSkillsDir(agent, homeDir), name, "SKILL.md"),
3171
3219
  action: "skip",
3172
3220
  reason: "not found in this machine's corpus"
3173
3221
  });
@@ -3177,7 +3225,7 @@ function syncSkillsToAgents(options = {}) {
3177
3225
  }
3178
3226
  for (const skill of targets) {
3179
3227
  const manifest = readPortableSkillManifest(skill.path, skill.name);
3180
- const kind = manifest.kind ?? "executable";
3228
+ const kind = manifest.kind;
3181
3229
  const sourceMd = sourceSkillMd(skill.path, skill.name, manifest.description, kind, source === "source");
3182
3230
  for (const agent of agents) {
3183
3231
  const adapted = adaptSkillMdForAgent(sourceMd, agent);
@@ -3197,7 +3245,7 @@ function syncSkillsToAgents(options = {}) {
3197
3245
  }
3198
3246
  function writeManagedAgentSkill(params) {
3199
3247
  const homeDir = params.homeDir ?? homedir2();
3200
- const dir = join7(agentGlobalSkillsDir(params.agent, homeDir), params.skill);
3248
+ const dir = join8(agentGlobalSkillsDir(params.agent, homeDir), params.skill);
3201
3249
  const result = writeManagedSkillDir(dir, params.skillMd, {
3202
3250
  skill: params.skill,
3203
3251
  source: params.source,
@@ -3214,11 +3262,11 @@ function writeManagedAgentSkill(params) {
3214
3262
  };
3215
3263
  }
3216
3264
  function writeManagedSkillDir(dir, skillMd, options) {
3217
- const skillMdPath = join7(dir, "SKILL.md");
3218
- const markerPath = join7(dir, SYNC_MARKER_FILE);
3219
- const dirExists = existsSync7(dir);
3220
- const managed = existsSync7(markerPath);
3221
- const hasSkillMd = existsSync7(skillMdPath);
3265
+ const skillMdPath = join8(dir, "SKILL.md");
3266
+ const markerPath = join8(dir, SYNC_MARKER_FILE);
3267
+ const dirExists = existsSync8(dir);
3268
+ const managed = existsSync8(markerPath);
3269
+ const hasSkillMd = existsSync8(skillMdPath);
3222
3270
  if (dirExists && !managed && !hasSkillMd) {
3223
3271
  return {
3224
3272
  action: "skip",
@@ -3236,7 +3284,7 @@ function writeManagedSkillDir(dir, skillMd, options) {
3236
3284
  if (dirExists && managed && hasSkillMd && !options.force && isPointerSkillMd(skillMd)) {
3237
3285
  let existingIsStub = false;
3238
3286
  try {
3239
- existingIsStub = isPointerSkillMd(readFileSync6(skillMdPath, "utf-8"));
3287
+ existingIsStub = isPointerSkillMd(readFileSync7(skillMdPath, "utf-8"));
3240
3288
  } catch {
3241
3289
  existingIsStub = false;
3242
3290
  }
@@ -3253,11 +3301,11 @@ function writeManagedSkillDir(dir, skillMd, options) {
3253
3301
  return { action, path: skillMdPath };
3254
3302
  const parentDir = dirname4(dir);
3255
3303
  mkdirSync4(parentDir, { recursive: true });
3256
- const transactionDir = mkdtempSync(join7(parentDir, `.hasna-skills-write-${basename3(dir)}-`));
3257
- const candidateDir = join7(transactionDir, "candidate");
3258
- const backupDir = join7(transactionDir, "backup");
3259
- const candidateSkillMdPath = join7(candidateDir, "SKILL.md");
3260
- const candidateMarkerPath = join7(candidateDir, SYNC_MARKER_FILE);
3304
+ const transactionDir = mkdtempSync2(join8(parentDir, `.hasna-skills-write-${basename3(dir)}-`));
3305
+ const candidateDir = join8(transactionDir, "candidate");
3306
+ const backupDir = join8(transactionDir, "backup");
3307
+ const candidateSkillMdPath = join8(candidateDir, "SKILL.md");
3308
+ const candidateMarkerPath = join8(candidateDir, SYNC_MARKER_FILE);
3261
3309
  const marker = {
3262
3310
  managedBy: SYNC_MARKER_MANAGED_BY,
3263
3311
  skill: options.skill,
@@ -3284,9 +3332,9 @@ function writeManagedSkillDir(dir, skillMd, options) {
3284
3332
  }
3285
3333
  renameDirectory(candidateDir, dir);
3286
3334
  } catch (error) {
3287
- if (originalMoved && existsSync7(backupDir)) {
3335
+ if (originalMoved && existsSync8(backupDir)) {
3288
3336
  try {
3289
- if (existsSync7(dir))
3337
+ if (existsSync8(dir))
3290
3338
  rmSync2(dir, { recursive: true, force: true });
3291
3339
  renameDirectory(backupDir, dir);
3292
3340
  originalMoved = false;
@@ -3306,17 +3354,17 @@ function writeManagedSkillDir(dir, skillMd, options) {
3306
3354
  return { action, path: skillMdPath };
3307
3355
  }
3308
3356
  function removeManagedAgentSkill(skill, agent, homeDir = homedir2()) {
3309
- const dir = join7(agentGlobalSkillsDir(agent, homeDir), skill);
3310
- if (!existsSync7(join7(dir, SYNC_MARKER_FILE)))
3357
+ const dir = join8(agentGlobalSkillsDir(agent, homeDir), skill);
3358
+ if (!existsSync8(join8(dir, SYNC_MARKER_FILE)))
3311
3359
  return false;
3312
3360
  rmSync2(dir, { recursive: true, force: true });
3313
3361
  return true;
3314
3362
  }
3315
3363
  function sourceSkillMd(skillPath, name, description, kind, preferBundledDocs = false) {
3316
- if (kind === "instruction" || preferBundledDocs) {
3317
- const skillMdPath = join7(skillPath, "SKILL.md");
3318
- if (existsSync7(skillMdPath))
3319
- return readFileSync6(skillMdPath, "utf-8");
3364
+ if (kind === undefined || kind === "instruction" || preferBundledDocs) {
3365
+ const skillMdPath = join8(skillPath, "SKILL.md");
3366
+ if (existsSync8(skillMdPath))
3367
+ return readFileSync7(skillMdPath, "utf-8");
3320
3368
  }
3321
3369
  return pointerSkillMd(name, description);
3322
3370
  }
@@ -3346,8 +3394,8 @@ function normalizeSkillName(name) {
3346
3394
  }
3347
3395
 
3348
3396
  // src/lib/project-state.ts
3349
- import { existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
3350
- import { join as join8 } from "path";
3397
+ import { existsSync as existsSync9, mkdirSync as mkdirSync5, readFileSync as readFileSync8, writeFileSync as writeFileSync5 } from "fs";
3398
+ import { join as join9 } from "path";
3351
3399
  var VALID_PIN_SOURCES = [
3352
3400
  "official",
3353
3401
  "custom",
@@ -3362,17 +3410,17 @@ var SKILLS_PROJECT_DIR = ".skills";
3362
3410
  var PROJECT_CONFIG_FILE = "project.json";
3363
3411
  var DEFAULT_EXPORT_DIR = ".skills/exports";
3364
3412
  function getProjectStateDir(targetDir = process.cwd()) {
3365
- return join8(targetDir, SKILLS_PROJECT_DIR);
3413
+ return join9(targetDir, SKILLS_PROJECT_DIR);
3366
3414
  }
3367
3415
  function getProjectConfigPath(targetDir = process.cwd()) {
3368
- return join8(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
3416
+ return join9(getProjectStateDir(targetDir), PROJECT_CONFIG_FILE);
3369
3417
  }
3370
3418
  function loadProjectConfig(targetDir = process.cwd()) {
3371
3419
  const path = getProjectConfigPath(targetDir);
3372
- if (!existsSync8(path))
3420
+ if (!existsSync9(path))
3373
3421
  return null;
3374
3422
  try {
3375
- return normalizeProjectConfig(JSON.parse(readFileSync7(path, "utf-8")));
3423
+ return normalizeProjectConfig(JSON.parse(readFileSync8(path, "utf-8")));
3376
3424
  } catch {
3377
3425
  return null;
3378
3426
  }
@@ -3490,12 +3538,12 @@ var __dirname2 = dirname5(fileURLToPath(import.meta.url));
3490
3538
  function findSkillsDir() {
3491
3539
  let dir = __dirname2;
3492
3540
  for (let i = 0;i < 5; i++) {
3493
- const candidate = join9(dir, "skills");
3494
- if (existsSync9(candidate) && !dir.includes(".skills"))
3541
+ const candidate = join10(dir, "skills");
3542
+ if (existsSync10(candidate) && !dir.includes(".skills"))
3495
3543
  return candidate;
3496
3544
  dir = dirname5(dir);
3497
3545
  }
3498
- return join9(__dirname2, "..", "skills");
3546
+ return join10(__dirname2, "..", "skills");
3499
3547
  }
3500
3548
  var SKILLS_DIR = findSkillsDir();
3501
3549
  function getSkillPath(name) {
@@ -3503,25 +3551,25 @@ function getSkillPath(name) {
3503
3551
  const portable = findPortableSkill(skillName);
3504
3552
  if (portable)
3505
3553
  return portable.path;
3506
- const legacyCustomPath = join9(getDataDir(), "custom", skillName);
3507
- if (existsSync9(legacyCustomPath))
3554
+ const legacyCustomPath = join10(getDataDir(), "custom", skillName);
3555
+ if (existsSync10(legacyCustomPath))
3508
3556
  return legacyCustomPath;
3509
3557
  const extensionPath = findExtensionSkillPath(skillName);
3510
3558
  if (extensionPath)
3511
3559
  return extensionPath;
3512
- return join9(SKILLS_DIR, skillName);
3560
+ return join10(SKILLS_DIR, skillName);
3513
3561
  }
3514
3562
  function getCanonicalSkillName(name) {
3515
3563
  return getSkill(name)?.name ?? resolveSkillAlias(normalizeSkillSlug(name));
3516
3564
  }
3517
3565
  function skillExists(name) {
3518
- return existsSync9(getSkillPath(name));
3566
+ return existsSync10(getSkillPath(name));
3519
3567
  }
3520
3568
  function installSkill(name, options = {}) {
3521
3569
  const { targetDir = process.cwd(), overwrite = false } = options;
3522
3570
  const canonicalName = getCanonicalSkillName(name);
3523
3571
  const skillName = normalizeSkillName(canonicalName);
3524
- if (!existsSync9(getSkillPath(name))) {
3572
+ if (!existsSync10(getSkillPath(name))) {
3525
3573
  const knownOfficial = Boolean(getSkill(name));
3526
3574
  return {
3527
3575
  skill: canonicalName,
@@ -3548,7 +3596,7 @@ function installSkill(name, options = {}) {
3548
3596
  }
3549
3597
  function installSkillSource(name, _options = {}) {
3550
3598
  const canonicalName = getCanonicalSkillName(name);
3551
- if (!existsSync9(getSkillPath(name))) {
3599
+ if (!existsSync10(getSkillPath(name))) {
3552
3600
  return { skill: canonicalName, success: false, error: `Skill '${name}' not found`, mode: "source" };
3553
3601
  }
3554
3602
  return {
@@ -3569,12 +3617,12 @@ function installSkillManifest(manifest, _options = {}) {
3569
3617
  }
3570
3618
  function createLocalSkillManifest(name, generateSkillMd) {
3571
3619
  const sourcePath = getSkillPath(name);
3572
- if (!existsSync9(sourcePath))
3620
+ if (!existsSync10(sourcePath))
3573
3621
  return null;
3574
3622
  let skillMd = "";
3575
- const skillMdPath = join9(sourcePath, "SKILL.md");
3576
- if (existsSync9(skillMdPath)) {
3577
- skillMd = readFileSync8(skillMdPath, "utf-8");
3623
+ const skillMdPath = join10(sourcePath, "SKILL.md");
3624
+ if (existsSync10(skillMdPath)) {
3625
+ skillMd = readFileSync9(skillMdPath, "utf-8");
3578
3626
  } else if (generateSkillMd) {
3579
3627
  skillMd = generateSkillMd(name) ?? "";
3580
3628
  } else {
@@ -3646,20 +3694,20 @@ function getAgentSkillsDir(agent, scope = "global", projectDir) {
3646
3694
  const base = projectDir || process.cwd();
3647
3695
  switch (agent) {
3648
3696
  case "pi":
3649
- return scope === "project" ? join9(base, ".pi", "skills") : join9(homedir3(), ".pi", "agent", "skills");
3697
+ return scope === "project" ? join10(base, ".pi", "skills") : join10(homedir3(), ".pi", "agent", "skills");
3650
3698
  case "opencode":
3651
- return scope === "project" ? join9(base, ".opencode", "skills") : join9(homedir3(), ".config", "opencode", "skills");
3699
+ return scope === "project" ? join10(base, ".opencode", "skills") : join10(homedir3(), ".config", "opencode", "skills");
3652
3700
  default:
3653
- return scope === "project" ? join9(base, `.${agent}`, "skills") : join9(homedir3(), `.${agent}`, "skills");
3701
+ return scope === "project" ? join10(base, `.${agent}`, "skills") : join10(homedir3(), `.${agent}`, "skills");
3654
3702
  }
3655
3703
  }
3656
3704
  function getAgentSkillPath(name, agent, scope = "global", projectDir) {
3657
3705
  const skillName = normalizeSkillName(getCanonicalSkillName(name));
3658
- return join9(getAgentSkillsDir(agent, scope, projectDir), skillName);
3706
+ return join10(getAgentSkillsDir(agent, scope, projectDir), skillName);
3659
3707
  }
3660
3708
  function installSkillForAgent(name, options, generateSkillMd) {
3661
3709
  const canonicalName = getCanonicalSkillName(name);
3662
- if (!existsSync9(getSkillPath(name))) {
3710
+ if (!existsSync10(getSkillPath(name))) {
3663
3711
  return { skill: canonicalName, success: false, error: `Skill '${name}' not found` };
3664
3712
  }
3665
3713
  const scope = options.scope ?? "global";
@@ -3683,16 +3731,16 @@ function removeSkillForAgent(name, options) {
3683
3731
  const canonicalName = getCanonicalSkillName(name);
3684
3732
  const scope = options.scope ?? "global";
3685
3733
  const dir = getAgentSkillPath(canonicalName, options.agent, scope, options.projectDir);
3686
- if (!existsSync9(join9(dir, SYNC_MARKER_FILE)))
3734
+ if (!existsSync10(join10(dir, SYNC_MARKER_FILE)))
3687
3735
  return false;
3688
3736
  rmSync3(dir, { recursive: true, force: true });
3689
3737
  return true;
3690
3738
  }
3691
3739
  function resolveAgentSkillMd(name, generateSkillMd) {
3692
3740
  const sourcePath = getSkillPath(name);
3693
- const skillMdPath = join9(sourcePath, "SKILL.md");
3694
- if (existsSync9(skillMdPath))
3695
- return readFileSync8(skillMdPath, "utf-8");
3741
+ const skillMdPath = join10(sourcePath, "SKILL.md");
3742
+ if (existsSync10(skillMdPath))
3743
+ return readFileSync9(skillMdPath, "utf-8");
3696
3744
  if (generateSkillMd)
3697
3745
  return generateSkillMd(name);
3698
3746
  return generateMinimalSkillMd(name);
@@ -3710,7 +3758,7 @@ function warnMissingDependencies(name, targetDir) {
3710
3758
  }
3711
3759
  function generateMinimalSkillMd(name) {
3712
3760
  const sourcePath = getSkillPath(name);
3713
- if (!existsSync9(sourcePath))
3761
+ if (!existsSync10(sourcePath))
3714
3762
  return null;
3715
3763
  const canonicalName = getCanonicalSkillName(name);
3716
3764
  const meta = getSkill(canonicalName);
@@ -3725,7 +3773,7 @@ function generateMinimalSkillMd(name) {
3725
3773
  "---",
3726
3774
  ""
3727
3775
  ].filter(Boolean);
3728
- const fallbackDoc = readFileIfExists(join9(sourcePath, "README.md")) || readFileIfExists(join9(sourcePath, "CLAUDE.md"));
3776
+ const fallbackDoc = readFileIfExists(join10(sourcePath, "README.md")) || readFileIfExists(join10(sourcePath, "CLAUDE.md"));
3729
3777
  if (fallbackDoc)
3730
3778
  return `${frontmatter.join(`
3731
3779
  `)}${fallbackDoc.trim()}
@@ -3744,38 +3792,38 @@ skills run ${canonicalName}
3744
3792
  `;
3745
3793
  }
3746
3794
  function readBundledSkillVersion(name) {
3747
- const pkgPath = join9(getSkillPath(name), "package.json");
3748
- if (!existsSync9(pkgPath))
3795
+ const pkgPath = join10(getSkillPath(name), "package.json");
3796
+ if (!existsSync10(pkgPath))
3749
3797
  return "unknown";
3750
3798
  try {
3751
- const pkg = JSON.parse(readFileSync8(pkgPath, "utf-8"));
3799
+ const pkg = JSON.parse(readFileSync9(pkgPath, "utf-8"));
3752
3800
  return pkg.version || "unknown";
3753
3801
  } catch {
3754
3802
  return "unknown";
3755
3803
  }
3756
3804
  }
3757
3805
  function readFileIfExists(path) {
3758
- return existsSync9(path) ? readFileSync8(path, "utf-8") : null;
3806
+ return existsSync10(path) ? readFileSync9(path, "utf-8") : null;
3759
3807
  }
3760
3808
  function loadProjectConfigCompat(targetDir) {
3761
3809
  return loadProjectConfig(targetDir);
3762
3810
  }
3763
3811
  // src/lib/run-state.ts
3764
3812
  import { createHash as createHash2, randomBytes } from "crypto";
3765
- import { existsSync as existsSync10, mkdirSync as mkdirSync6, readFileSync as readFileSync9, readdirSync as readdirSync7, statSync as statSync7, writeFileSync as writeFileSync6 } from "fs";
3766
- import { extname, join as join10, relative as relative2 } from "path";
3813
+ import { existsSync as existsSync11, mkdirSync as mkdirSync6, readFileSync as readFileSync10, readdirSync as readdirSync8, statSync as statSync8, writeFileSync as writeFileSync6 } from "fs";
3814
+ import { extname, join as join11, relative as relative2 } from "path";
3767
3815
  function createSkillRun(params, targetDir = process.cwd()) {
3768
3816
  const now = new Date;
3769
3817
  const id = createRunId(now);
3770
3818
  const day = now.toISOString().slice(0, 10);
3771
3819
  const skillName = normalizeSkillName(params.skill);
3772
3820
  const root = getProjectStateDir(targetDir);
3773
- const runDir = join10(root, "runs", day, id);
3774
- const logsDir = join10(runDir, "logs");
3775
- const exportDir = join10(root, "exports", skillName, id);
3821
+ const runDir = join11(root, "runs", day, id);
3822
+ const logsDir = join11(runDir, "logs");
3823
+ const exportDir = join11(root, "exports", skillName, id);
3776
3824
  mkdirSync6(logsDir, { recursive: true });
3777
3825
  mkdirSync6(exportDir, { recursive: true });
3778
- mkdirSync6(join10(root, "tmp"), { recursive: true });
3826
+ mkdirSync6(join11(root, "tmp"), { recursive: true });
3779
3827
  const record = {
3780
3828
  id,
3781
3829
  skill: skillName,
@@ -3826,27 +3874,27 @@ function updateSkillRun(context, patch) {
3826
3874
  return context.record;
3827
3875
  }
3828
3876
  function writeRunLogs(context, stdout = "", stderr = "") {
3829
- writeFileSync6(join10(context.logsDir, "stdout.log"), stdout);
3830
- writeFileSync6(join10(context.logsDir, "stderr.log"), stderr);
3877
+ writeFileSync6(join11(context.logsDir, "stdout.log"), stdout);
3878
+ writeFileSync6(join11(context.logsDir, "stderr.log"), stderr);
3831
3879
  }
3832
3880
  function appendRunEvent(context, event, data = {}) {
3833
3881
  const line = JSON.stringify({ ts: new Date().toISOString(), event, ...data }) + `
3834
3882
  `;
3835
- const path = join10(context.runDir, "events.ndjson");
3836
- const previous = existsSync10(path) ? readFileSync9(path, "utf-8") : "";
3883
+ const path = join11(context.runDir, "events.ndjson");
3884
+ const previous = existsSync11(path) ? readFileSync10(path, "utf-8") : "";
3837
3885
  writeFileSync6(path, previous + line);
3838
3886
  }
3839
3887
  function listSkillRuns(targetDir = process.cwd(), limit = 50) {
3840
- const runsRoot = join10(getProjectStateDir(targetDir), "runs");
3841
- if (!existsSync10(runsRoot))
3888
+ const runsRoot = join11(getProjectStateDir(targetDir), "runs");
3889
+ if (!existsSync11(runsRoot))
3842
3890
  return [];
3843
3891
  const records = [];
3844
- for (const day of readdirSync7(runsRoot).sort().reverse()) {
3845
- const dayDir = join10(runsRoot, day);
3846
- if (!statSync7(dayDir).isDirectory())
3892
+ for (const day of readdirSync8(runsRoot).sort().reverse()) {
3893
+ const dayDir = join11(runsRoot, day);
3894
+ if (!statSync8(dayDir).isDirectory())
3847
3895
  continue;
3848
- for (const runId of readdirSync7(dayDir).sort().reverse()) {
3849
- const record = readRunRecord(join10(dayDir, runId));
3896
+ for (const runId of readdirSync8(dayDir).sort().reverse()) {
3897
+ const record = readRunRecord(join11(dayDir, runId));
3850
3898
  if (record)
3851
3899
  records.push(record);
3852
3900
  if (records.length >= limit)
@@ -3856,34 +3904,34 @@ function listSkillRuns(targetDir = process.cwd(), limit = 50) {
3856
3904
  return records;
3857
3905
  }
3858
3906
  function findSkillRun(runId, targetDir = process.cwd()) {
3859
- const runsRoot = join10(getProjectStateDir(targetDir), "runs");
3860
- if (!existsSync10(runsRoot))
3907
+ const runsRoot = join11(getProjectStateDir(targetDir), "runs");
3908
+ if (!existsSync11(runsRoot))
3861
3909
  return null;
3862
- for (const day of readdirSync7(runsRoot)) {
3863
- const record = readRunRecord(join10(runsRoot, day, runId));
3910
+ for (const day of readdirSync8(runsRoot)) {
3911
+ const record = readRunRecord(join11(runsRoot, day, runId));
3864
3912
  if (record)
3865
3913
  return record;
3866
3914
  }
3867
3915
  return null;
3868
3916
  }
3869
3917
  function getRunExportDir(runId, skill, targetDir = process.cwd()) {
3870
- return join10(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
3918
+ return join11(getProjectStateDir(targetDir), "exports", normalizeSkillName(skill), runId);
3871
3919
  }
3872
3920
  function writeRunRecord(context) {
3873
- writeFileSync6(join10(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
3921
+ writeFileSync6(join11(context.runDir, "run.json"), JSON.stringify(context.record, null, 2) + `
3874
3922
  `);
3875
3923
  }
3876
3924
  function writeArtifactsManifest(context, artifacts) {
3877
- writeFileSync6(join10(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
3925
+ writeFileSync6(join11(context.runDir, "artifacts.json"), JSON.stringify({ runId: context.record.id, artifacts }, null, 2) + `
3878
3926
  `);
3879
3927
  }
3880
3928
  function collectRunArtifacts(context) {
3881
- if (!existsSync10(context.exportDir))
3929
+ if (!existsSync11(context.exportDir))
3882
3930
  return [];
3883
3931
  const artifacts = [];
3884
3932
  for (const path of walkFiles(context.exportDir)) {
3885
- const stat = statSync7(path);
3886
- const bytes = readFileSync9(path);
3933
+ const stat = statSync8(path);
3934
+ const bytes = readFileSync10(path);
3887
3935
  artifacts.push({
3888
3936
  path: toProjectRelative(context.targetDir, path),
3889
3937
  mime: mimeForPath(path),
@@ -3894,20 +3942,20 @@ function collectRunArtifacts(context) {
3894
3942
  return artifacts.sort((a, b) => a.path.localeCompare(b.path));
3895
3943
  }
3896
3944
  function readRunRecord(runDir) {
3897
- const path = join10(runDir, "run.json");
3898
- if (!existsSync10(path))
3945
+ const path = join11(runDir, "run.json");
3946
+ if (!existsSync11(path))
3899
3947
  return null;
3900
3948
  try {
3901
- return JSON.parse(readFileSync9(path, "utf-8"));
3949
+ return JSON.parse(readFileSync10(path, "utf-8"));
3902
3950
  } catch {
3903
3951
  return null;
3904
3952
  }
3905
3953
  }
3906
3954
  function walkFiles(dir) {
3907
3955
  const files = [];
3908
- for (const entry of readdirSync7(dir)) {
3909
- const full = join10(dir, entry);
3910
- if (statSync7(full).isDirectory())
3956
+ for (const entry of readdirSync8(dir)) {
3957
+ const full = join11(dir, entry);
3958
+ if (statSync8(full).isDirectory())
3911
3959
  files.push(...walkFiles(full));
3912
3960
  else
3913
3961
  files.push(full);
@@ -3952,16 +4000,16 @@ function mimeForPath(path) {
3952
4000
  }
3953
4001
  }
3954
4002
  // src/lib/skillinfo.ts
3955
- import { existsSync as existsSync11, readFileSync as readFileSync10 } from "fs";
3956
- import { join as join11 } from "path";
4003
+ import { existsSync as existsSync12, readFileSync as readFileSync11 } from "fs";
4004
+ import { join as join12 } from "path";
3957
4005
  function isInstructionSkillDir(skillPath, meta) {
3958
4006
  if (meta?.kind === "instruction")
3959
4007
  return true;
3960
- const skillMdPath = join11(skillPath, "SKILL.md");
3961
- if (!existsSync11(skillMdPath))
4008
+ const skillMdPath = join12(skillPath, "SKILL.md");
4009
+ if (!existsSync12(skillMdPath))
3962
4010
  return false;
3963
4011
  try {
3964
- return parseSkillFrontmatter(readFileSync10(skillMdPath, "utf-8"))?.kind === "instruction";
4012
+ return parseSkillFrontmatter(readFileSync11(skillMdPath, "utf-8"))?.kind === "instruction";
3965
4013
  } catch {
3966
4014
  return false;
3967
4015
  }
@@ -3984,12 +4032,12 @@ var HOSTED_PROVIDER_ENV_PREFIXES = [
3984
4032
  ];
3985
4033
  function getSkillDocs(name) {
3986
4034
  const skillPath = getSkillPath(name);
3987
- if (!existsSync11(skillPath))
4035
+ if (!existsSync12(skillPath))
3988
4036
  return null;
3989
4037
  return {
3990
- skillMd: readIfExists(join11(skillPath, "SKILL.md")),
3991
- readme: readIfExists(join11(skillPath, "README.md")),
3992
- claudeMd: readIfExists(join11(skillPath, "CLAUDE.md"))
4038
+ skillMd: readIfExists(join12(skillPath, "SKILL.md")),
4039
+ readme: readIfExists(join12(skillPath, "README.md")),
4040
+ claudeMd: readIfExists(join12(skillPath, "CLAUDE.md"))
3993
4041
  };
3994
4042
  }
3995
4043
  function getSkillBestDoc(name) {
@@ -4000,11 +4048,11 @@ function getSkillBestDoc(name) {
4000
4048
  }
4001
4049
  function getSkillRequirements(name) {
4002
4050
  const skillPath = getSkillPath(name);
4003
- if (!existsSync11(skillPath))
4051
+ if (!existsSync12(skillPath))
4004
4052
  return null;
4005
4053
  const texts = [];
4006
4054
  for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
4007
- const content = readIfExists(join11(skillPath, file));
4055
+ const content = readIfExists(join12(skillPath, file));
4008
4056
  if (content)
4009
4057
  texts.push(content);
4010
4058
  }
@@ -4043,10 +4091,10 @@ function getSkillRequirements(name) {
4043
4091
  const skillName = normalizeSkillName(name);
4044
4092
  let cliCommand = `skills run ${skillName}`;
4045
4093
  let dependencies = {};
4046
- const pkgPath = join11(skillPath, "package.json");
4047
- if (existsSync11(pkgPath)) {
4094
+ const pkgPath = join12(skillPath, "package.json");
4095
+ if (existsSync12(pkgPath)) {
4048
4096
  try {
4049
- const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
4097
+ const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
4050
4098
  dependencies = pkg.dependencies || {};
4051
4099
  } catch {}
4052
4100
  }
@@ -4064,7 +4112,7 @@ async function runSkill(name, args, options = {}) {
4064
4112
  const meta = getSkill(name);
4065
4113
  const canonicalName = meta?.name ?? name;
4066
4114
  const skillPath = getSkillPath(canonicalName);
4067
- if (!existsSync11(skillPath)) {
4115
+ if (!existsSync12(skillPath)) {
4068
4116
  return { exitCode: 1, error: `Skill '${name}' not found` };
4069
4117
  }
4070
4118
  if (isInstructionSkillDir(skillPath, meta)) {
@@ -4073,13 +4121,13 @@ async function runSkill(name, args, options = {}) {
4073
4121
  error: `Skill '${name}' is an instruction skill (kind: instruction) and is not runnable. Instruction skills are consumed by coding agents via SKILL.md, not executed with 'skills run'.`
4074
4122
  };
4075
4123
  }
4076
- const pkgPath = join11(skillPath, "package.json");
4077
- if (!existsSync11(pkgPath)) {
4124
+ const pkgPath = join12(skillPath, "package.json");
4125
+ if (!existsSync12(pkgPath)) {
4078
4126
  return { exitCode: 1, error: `No package.json in skill '${name}'` };
4079
4127
  }
4080
4128
  let entryPoint;
4081
4129
  try {
4082
- const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
4130
+ const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
4083
4131
  if (pkg.bin) {
4084
4132
  const binValues = Object.values(pkg.bin);
4085
4133
  entryPoint = binValues[0];
@@ -4093,12 +4141,12 @@ async function runSkill(name, args, options = {}) {
4093
4141
  } catch {
4094
4142
  return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
4095
4143
  }
4096
- const entryPath = join11(skillPath, entryPoint);
4097
- if (!existsSync11(entryPath)) {
4144
+ const entryPath = join12(skillPath, entryPoint);
4145
+ if (!existsSync12(entryPath)) {
4098
4146
  return { exitCode: 1, error: `Entry point '${entryPoint}' not found in skill '${name}'` };
4099
4147
  }
4100
- const nodeModules = join11(skillPath, "node_modules");
4101
- if (!existsSync11(nodeModules)) {
4148
+ const nodeModules = join12(skillPath, "node_modules");
4149
+ if (!existsSync12(nodeModules)) {
4102
4150
  const install = Bun.spawn(["bun", "install", "--no-save"], {
4103
4151
  cwd: skillPath,
4104
4152
  stdout: "pipe",
@@ -4170,7 +4218,7 @@ function generateSkillMd(name) {
4170
4218
  if (!meta)
4171
4219
  return null;
4172
4220
  const skillPath = getSkillPath(name);
4173
- if (!existsSync11(skillPath))
4221
+ if (!existsSync12(skillPath))
4174
4222
  return null;
4175
4223
  const frontmatter = [
4176
4224
  "---",
@@ -4179,13 +4227,13 @@ function generateSkillMd(name) {
4179
4227
  "---"
4180
4228
  ].join(`
4181
4229
  `);
4182
- const readme = readIfExists(join11(skillPath, "README.md"));
4183
- const claudeMd = readIfExists(join11(skillPath, "CLAUDE.md"));
4230
+ const readme = readIfExists(join12(skillPath, "README.md"));
4231
+ const claudeMd = readIfExists(join12(skillPath, "CLAUDE.md"));
4184
4232
  let cliCommand = null;
4185
- const pkgPath = join11(skillPath, "package.json");
4186
- if (existsSync11(pkgPath)) {
4233
+ const pkgPath = join12(skillPath, "package.json");
4234
+ if (existsSync12(pkgPath)) {
4187
4235
  try {
4188
- const pkg = JSON.parse(readFileSync10(pkgPath, "utf-8"));
4236
+ const pkg = JSON.parse(readFileSync11(pkgPath, "utf-8"));
4189
4237
  if (pkg.bin) {
4190
4238
  const binKeys = Object.keys(pkg.bin);
4191
4239
  if (binKeys.length > 0)
@@ -4260,8 +4308,8 @@ function extractEnvVars(text) {
4260
4308
  }
4261
4309
  function readIfExists(path) {
4262
4310
  try {
4263
- if (existsSync11(path)) {
4264
- return readFileSync10(path, "utf-8");
4311
+ if (existsSync12(path)) {
4312
+ return readFileSync11(path, "utf-8");
4265
4313
  }
4266
4314
  } catch {}
4267
4315
  return null;
@@ -8264,22 +8312,22 @@ function requireApiUrl(action = "This command", config, env) {
8264
8312
  }
8265
8313
 
8266
8314
  // src/lib/auth-store.ts
8267
- import { existsSync as existsSync12, mkdirSync as mkdirSync7, readFileSync as readFileSync11, writeFileSync as writeFileSync7, unlinkSync } from "fs";
8268
- import { dirname as dirname6, join as join12 } from "path";
8315
+ import { existsSync as existsSync13, mkdirSync as mkdirSync7, readFileSync as readFileSync12, writeFileSync as writeFileSync7, unlinkSync } from "fs";
8316
+ import { dirname as dirname6, join as join13 } from "path";
8269
8317
  import { homedir as homedir4 } from "os";
8270
8318
  function getAuthFilePath() {
8271
- return join12(getDataDir(), "auth.json");
8319
+ return join13(getDataDir(), "auth.json");
8272
8320
  }
8273
8321
  function legacyAuthFilePath() {
8274
- return join12(process.env["HOME"] || process.env["USERPROFILE"] || homedir4(), ".skills", "auth.json");
8322
+ return join13(process.env["HOME"] || process.env["USERPROFILE"] || homedir4(), ".skills", "auth.json");
8275
8323
  }
8276
8324
  var cachedConfig;
8277
8325
  function getAuthConfig() {
8278
8326
  if (cachedConfig !== undefined)
8279
8327
  return cachedConfig;
8280
8328
  try {
8281
- const file = existsSync12(getAuthFilePath()) ? getAuthFilePath() : legacyAuthFilePath();
8282
- const raw = readFileSync11(file, "utf-8");
8329
+ const file = existsSync13(getAuthFilePath()) ? getAuthFilePath() : legacyAuthFilePath();
8330
+ const raw = readFileSync12(file, "utf-8");
8283
8331
  const config = JSON.parse(raw);
8284
8332
  if (!config.apiKey) {
8285
8333
  cachedConfig = null;
@@ -9379,24 +9427,24 @@ function createRemoteSkillsClient() {
9379
9427
  return new RemoteSkillsClient(apiKey);
9380
9428
  }
9381
9429
  // src/lib/scheduler.ts
9382
- import { existsSync as existsSync13, readFileSync as readFileSync12, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8 } from "fs";
9383
- import { join as join13 } from "path";
9430
+ import { existsSync as existsSync14, readFileSync as readFileSync13, writeFileSync as writeFileSync8, mkdirSync as mkdirSync8 } from "fs";
9431
+ import { join as join14 } from "path";
9384
9432
  function getSchedulesPath(targetDir = process.cwd()) {
9385
- return join13(targetDir, ".skills", "schedules.json");
9433
+ return join14(targetDir, ".skills", "schedules.json");
9386
9434
  }
9387
9435
  function loadSchedules(targetDir = process.cwd()) {
9388
9436
  const path = getSchedulesPath(targetDir);
9389
- if (existsSync13(path)) {
9437
+ if (existsSync14(path)) {
9390
9438
  try {
9391
- return JSON.parse(readFileSync12(path, "utf-8"));
9439
+ return JSON.parse(readFileSync13(path, "utf-8"));
9392
9440
  } catch {}
9393
9441
  }
9394
9442
  return { version: 1, schedules: [] };
9395
9443
  }
9396
9444
  function saveSchedules(data, targetDir = process.cwd()) {
9397
9445
  const path = getSchedulesPath(targetDir);
9398
- const dir = join13(targetDir, ".skills");
9399
- if (!existsSync13(dir))
9446
+ const dir = join14(targetDir, ".skills");
9447
+ if (!existsSync14(dir))
9400
9448
  mkdirSync8(dir, { recursive: true });
9401
9449
  writeFileSync8(path, JSON.stringify(data, null, 2));
9402
9450
  }
@@ -9583,8 +9631,8 @@ function recordScheduleRun(id, status, targetDir) {
9583
9631
  saveSchedules(data, targetDir);
9584
9632
  }
9585
9633
  // src/lib/pull.ts
9586
- import { existsSync as existsSync14, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync2, readFileSync as readFileSync13, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "fs";
9587
- import { dirname as dirname7, join as join14 } from "path";
9634
+ import { existsSync as existsSync15, mkdirSync as mkdirSync9, mkdtempSync as mkdtempSync3, readFileSync as readFileSync14, renameSync as renameSync3, rmSync as rmSync4, writeFileSync as writeFileSync9 } from "fs";
9635
+ import { dirname as dirname7, join as join15 } from "path";
9588
9636
 
9589
9637
  // src/lib/revision.ts
9590
9638
  import { createHash as createHash3 } from "crypto";
@@ -9875,7 +9923,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
9875
9923
  return reconcileTombstone(slug, corpusOptions);
9876
9924
  }
9877
9925
  if (bundleResponse.status === 404) {
9878
- const marker = readPullMarker(join14(getPortableSkillsRoot(corpusOptions), slug));
9926
+ const marker = readPullMarker(join15(getPortableSkillsRoot(corpusOptions), slug));
9879
9927
  if (marker && typeof marker.revisionId === "string" && marker.revisionId) {
9880
9928
  return { name: slug, success: true, purged: true, removed: false };
9881
9929
  }
@@ -9906,7 +9954,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
9906
9954
  return { name: slug, success: false, error: `Skill '${slug}' was not found on the configured Skills instance.` };
9907
9955
  }
9908
9956
  if (!meta?.revisionId) {
9909
- const marker = readPullMarker(join14(getPortableSkillsRoot(corpusOptions), slug));
9957
+ const marker = readPullMarker(join15(getPortableSkillsRoot(corpusOptions), slug));
9910
9958
  if (marker && typeof marker.revisionId === "string" && marker.revisionId) {
9911
9959
  return { name: slug, success: true, purged: true, removed: false };
9912
9960
  }
@@ -9920,7 +9968,7 @@ async function pullOne(client, rawName, corpusOptions, verify) {
9920
9968
  }
9921
9969
  throw error;
9922
9970
  }
9923
- const written = writeCorpusSkill({ name: slug, skillMd, meta }, corpusOptions);
9971
+ const written = installCorpusSkillAtomically({ name: slug, skillMd, meta }, corpusOptions);
9924
9972
  writePullMarker(written.path, {
9925
9973
  skill: slug,
9926
9974
  version: written.manifest.version,
@@ -9963,8 +10011,8 @@ function provenRevision(meta, slug, bundle) {
9963
10011
  return declared;
9964
10012
  }
9965
10013
  function reconcileTombstone(slug, corpusOptions) {
9966
- const target = join14(getPortableSkillsRoot(corpusOptions), slug);
9967
- if (!existsSync14(join14(target, PULL_MARKER_FILE))) {
10014
+ const target = join15(getPortableSkillsRoot(corpusOptions), slug);
10015
+ if (!existsSync15(join15(target, PULL_MARKER_FILE))) {
9968
10016
  return { name: slug, success: true, tombstoned: true, removed: false, leftInPlace: true };
9969
10017
  }
9970
10018
  rmSync4(target, { recursive: true, force: true });
@@ -9972,7 +10020,7 @@ function reconcileTombstone(slug, corpusOptions) {
9972
10020
  }
9973
10021
  function readPullMarker(dir) {
9974
10022
  try {
9975
- return JSON.parse(readFileSync13(join14(dir, PULL_MARKER_FILE), "utf-8"));
10023
+ return JSON.parse(readFileSync14(join15(dir, PULL_MARKER_FILE), "utf-8"));
9976
10024
  } catch {
9977
10025
  return null;
9978
10026
  }
@@ -10093,14 +10141,14 @@ function verifyBundleResponseBytes(buffer, response, verify = {}) {
10093
10141
  function installBundleAtomically(name, entries, options = {}, marker = {}) {
10094
10142
  const root = getPortableSkillsRoot(options);
10095
10143
  mkdirSync9(root, { recursive: true });
10096
- const target = join14(root, name);
10097
- const created = !existsSync14(target);
10098
- const staging = mkdtempSync2(join14(root, `.pull-${name}-`));
10144
+ const target = join15(root, name);
10145
+ const created = !existsSync15(target);
10146
+ const staging = mkdtempSync3(join15(root, `.pull-${name}-`));
10099
10147
  let moved = false;
10100
10148
  let backup = null;
10101
10149
  try {
10102
10150
  for (const entry of entries) {
10103
- const destination = join14(staging, entry.path);
10151
+ const destination = join15(staging, entry.path);
10104
10152
  mkdirSync9(dirname7(destination), { recursive: true });
10105
10153
  writeFileSync9(destination, entry.bytes, { mode: entry.mode });
10106
10154
  }
@@ -10112,9 +10160,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
10112
10160
  ...marker.signature ? { signature: marker.signature } : {},
10113
10161
  ...marker.revisionId ? { revisionId: marker.revisionId } : {}
10114
10162
  });
10115
- if (existsSync14(target)) {
10116
- backup = mkdtempSync2(join14(root, `.pull-backup-${name}-`));
10117
- renameSync3(target, join14(backup, name));
10163
+ if (existsSync15(target)) {
10164
+ backup = mkdtempSync3(join15(root, `.pull-backup-${name}-`));
10165
+ renameSync3(target, join15(backup, name));
10118
10166
  moved = true;
10119
10167
  }
10120
10168
  renameSync3(staging, target);
@@ -10122,9 +10170,9 @@ function installBundleAtomically(name, entries, options = {}, marker = {}) {
10122
10170
  rmSync4(backup, { recursive: true, force: true });
10123
10171
  } catch (error) {
10124
10172
  rmSync4(staging, { recursive: true, force: true });
10125
- if (moved && backup && existsSync14(join14(backup, name))) {
10173
+ if (moved && backup && existsSync15(join15(backup, name))) {
10126
10174
  try {
10127
- renameSync3(join14(backup, name), target);
10175
+ renameSync3(join15(backup, name), target);
10128
10176
  } catch {}
10129
10177
  }
10130
10178
  throw error;
@@ -10143,7 +10191,7 @@ function writePullMarker(dir, record) {
10143
10191
  ...record.revisionId ? { revisionId: record.revisionId } : {},
10144
10192
  syncedAt: new Date().toISOString()
10145
10193
  };
10146
- writeFileSync9(join14(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
10194
+ writeFileSync9(join15(dir, PULL_MARKER_FILE), `${JSON.stringify(marker, null, 2)}
10147
10195
  `);
10148
10196
  }
10149
10197
  async function safeMeta(client, slug) {
@@ -10294,7 +10342,7 @@ import { dirname as dirname8, relative as relative3 } from "path";
10294
10342
  // package.json
10295
10343
  var package_default = {
10296
10344
  name: "@hasna/skills",
10297
- version: "0.1.64",
10345
+ version: "0.1.66",
10298
10346
  description: "Skills library for AI coding agents",
10299
10347
  type: "module",
10300
10348
  bin: {
@@ -11302,16 +11350,16 @@ function clone2(value) {
11302
11350
  return JSON.parse(JSON.stringify(value));
11303
11351
  }
11304
11352
  // src/lib/feedback.ts
11305
- import { existsSync as existsSync15, mkdirSync as mkdirSync11 } from "fs";
11306
- import { dirname as dirname9, join as join15 } from "path";
11353
+ import { existsSync as existsSync16, mkdirSync as mkdirSync11 } from "fs";
11354
+ import { dirname as dirname9, join as join16 } from "path";
11307
11355
  import { Database } from "bun:sqlite";
11308
11356
  function getFeedbackDbPath() {
11309
- return join15(getDataDir(), "skills.db");
11357
+ return join16(getDataDir(), "skills.db");
11310
11358
  }
11311
11359
  function getFeedbackDb() {
11312
11360
  const dbPath = getFeedbackDbPath();
11313
11361
  const dir = dirname9(dbPath);
11314
- if (!existsSync15(dir))
11362
+ if (!existsSync16(dir))
11315
11363
  mkdirSync11(dir, { recursive: true });
11316
11364
  const db = new Database(dbPath);
11317
11365
  db.exec("PRAGMA journal_mode = WAL");
@@ -11348,14 +11396,14 @@ function saveFeedback(input) {
11348
11396
  // src/lib/native-storage.ts
11349
11397
  import { createHash as createHash5, createHmac as createHmac2 } from "crypto";
11350
11398
  import {
11351
- existsSync as existsSync16,
11399
+ existsSync as existsSync17,
11352
11400
  mkdirSync as mkdirSync12,
11353
- readFileSync as readFileSync14,
11354
- readdirSync as readdirSync8,
11355
- statSync as statSync8,
11401
+ readFileSync as readFileSync15,
11402
+ readdirSync as readdirSync9,
11403
+ statSync as statSync9,
11356
11404
  writeFileSync as writeFileSync11
11357
11405
  } from "fs";
11358
- import { dirname as dirname10, join as join16, normalize as normalize3, relative as relative4, sep as sep2 } from "path";
11406
+ import { dirname as dirname10, join as join17, normalize as normalize3, relative as relative4, sep as sep2 } from "path";
11359
11407
  var SKILLS_STORAGE_TABLES = [
11360
11408
  "skills_sync_records",
11361
11409
  "skills_sync_cursors"
@@ -11393,6 +11441,55 @@ var SKILLS_NATIVE_STORAGE_FALLBACK_ENV = {
11393
11441
  };
11394
11442
  var SKILLS_STORAGE_ENV = SKILLS_NATIVE_STORAGE_ENV;
11395
11443
  var SKILLS_STORAGE_FALLBACK_ENV = SKILLS_NATIVE_STORAGE_FALLBACK_ENV;
11444
+ var storageCapabilities = {
11445
+ version: 1,
11446
+ values: [
11447
+ "SKILLS_NATIVE_STORAGE_ENV",
11448
+ "SKILLS_NATIVE_STORAGE_FALLBACK_ENV",
11449
+ "SKILLS_STORAGE_ENV",
11450
+ "SKILLS_STORAGE_FALLBACK_ENV",
11451
+ "SKILLS_STORAGE_TABLES",
11452
+ "STORAGE_TABLES",
11453
+ "SkillsPostgresSyncStore",
11454
+ "SkillsS3ObjectStore",
11455
+ "buildSkillsS3ObjectUrl",
11456
+ "createSkillsPostgresSyncStore",
11457
+ "createSkillsS3ObjectStore",
11458
+ "createSkillsSnapshotSyncRecord",
11459
+ "exportSkillsLocalSnapshot",
11460
+ "getSkillsNativeStorageStatus",
11461
+ "getSkillsStorageDatabaseEnv",
11462
+ "getSkillsStorageDatabaseUrl",
11463
+ "getSkillsStorageStatus",
11464
+ "getStorageDatabaseEnv",
11465
+ "getStorageDatabaseUrl",
11466
+ "getStorageStatus",
11467
+ "importSkillsLocalSnapshot",
11468
+ "planSkillsS3SnapshotUpload",
11469
+ "resolveSkillsNativeStorageConfig",
11470
+ "resolveStorageConfig",
11471
+ "signSkillsAwsV4Request",
11472
+ "skillsPostgresSyncSchemaSql",
11473
+ "storageCapabilities",
11474
+ "uploadSkillsSnapshotFilesToS3"
11475
+ ],
11476
+ types: [
11477
+ "AwsCredentials",
11478
+ "SignSkillsAwsV4RequestOptions",
11479
+ "SkillsFetch",
11480
+ "SkillsLocalSnapshot",
11481
+ "SkillsNativeStorageConfig",
11482
+ "SkillsNativeStorageStatus",
11483
+ "SkillsPostgresQueryClient",
11484
+ "SkillsS3ObjectStoreOptions",
11485
+ "SkillsS3PutObjectOptions",
11486
+ "SkillsS3SnapshotPlanEntry",
11487
+ "SkillsS3StoredObject",
11488
+ "SkillsSnapshotFile",
11489
+ "SkillsStorageTable",
11490
+ "SkillsSyncRecord"
11491
+ ]
11492
+ };
11396
11493
  var SKILLS_ENV_NAMESPACE = "SKILLS";
11397
11494
  function resolveSkillsNativeStorageConfig(env = process.env) {
11398
11495
  assertNoRetiredModeEnvVars(env, {
@@ -11443,7 +11540,7 @@ function getSkillsNativeStorageStatus(options = {}) {
11443
11540
  local: {
11444
11541
  dataDir: getDataDir(),
11445
11542
  projectStateDir: getProjectStateDir(targetDir),
11446
- feedbackDbPath: join16(getDataDir(), "skills.db")
11543
+ feedbackDbPath: join17(getDataDir(), "skills.db")
11447
11544
  },
11448
11545
  remote: {
11449
11546
  databaseConfigured: Boolean(config.databaseUrl),
@@ -11466,9 +11563,9 @@ function getStorageStatus(options = {}) {
11466
11563
  function exportSkillsLocalSnapshot(targetDir = process.cwd(), options = {}) {
11467
11564
  const projectStateDir = getProjectStateDir(targetDir);
11468
11565
  const files = [];
11469
- if (existsSync16(projectStateDir)) {
11566
+ if (existsSync17(projectStateDir)) {
11470
11567
  for (const filePath of walkFiles2(projectStateDir)) {
11471
- const bytes = readFileSync14(filePath);
11568
+ const bytes = readFileSync15(filePath);
11472
11569
  const relativePath = toPosix(relative4(targetDir, filePath));
11473
11570
  files.push({
11474
11571
  path: relativePath,
@@ -11493,7 +11590,7 @@ function importSkillsLocalSnapshot(snapshot, targetDir = process.cwd(), options
11493
11590
  continue;
11494
11591
  }
11495
11592
  const absolutePath = resolveSnapshotPath(targetDir, file.path);
11496
- if (existsSync16(absolutePath) && !options.overwrite) {
11593
+ if (existsSync17(absolutePath) && !options.overwrite) {
11497
11594
  skipped += 1;
11498
11595
  continue;
11499
11596
  }
@@ -11799,9 +11896,9 @@ function parsePositiveInteger(value) {
11799
11896
  }
11800
11897
  function walkFiles2(dir) {
11801
11898
  const files = [];
11802
- for (const entry of readdirSync8(dir)) {
11803
- const full = join16(dir, entry);
11804
- const stats = statSync8(full);
11899
+ for (const entry of readdirSync9(dir)) {
11900
+ const full = join17(dir, entry);
11901
+ const stats = statSync9(full);
11805
11902
  if (stats.isDirectory())
11806
11903
  files.push(...walkFiles2(full));
11807
11904
  else
@@ -11817,7 +11914,7 @@ function resolveSnapshotPath(targetDir, snapshotPath) {
11817
11914
  if (!toPosix(normalizedPath).startsWith(".skills/")) {
11818
11915
  throw new Error(`Snapshot path must stay inside .skills: ${snapshotPath}`);
11819
11916
  }
11820
- return join16(targetDir, normalizedPath);
11917
+ return join17(targetDir, normalizedPath);
11821
11918
  }
11822
11919
  function normalizeS3Prefix(prefix) {
11823
11920
  return (prefix ?? "").trim().replace(/^\/+|\/+$/g, "");
@@ -11899,6 +11996,7 @@ export {
11899
11996
  unpinProjectSkill,
11900
11997
  syncSkillsToAgents,
11901
11998
  summarizeMcpToolContract,
11999
+ storageCapabilities,
11902
12000
  skillsPostgresSyncSchemaSql,
11903
12001
  skillExists,
11904
12002
  signSkillsAwsV4Request,