@skillkit/core 1.10.0 → 1.12.0

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
@@ -284,7 +284,7 @@ var init_local_models = __esm({
284
284
  if (done) break;
285
285
  const canContinue = fileStream.write(Buffer.from(value));
286
286
  if (!canContinue) {
287
- await new Promise((resolve5) => fileStream.once("drain", resolve5));
287
+ await new Promise((resolve6) => fileStream.once("drain", resolve6));
288
288
  }
289
289
  downloaded += value.length;
290
290
  onProgress?.({
@@ -295,8 +295,8 @@ var init_local_models = __esm({
295
295
  });
296
296
  }
297
297
  fileStream.end();
298
- await new Promise((resolve5, reject) => {
299
- fileStream.on("finish", resolve5);
298
+ await new Promise((resolve6, reject) => {
299
+ fileStream.on("finish", resolve6);
300
300
  fileStream.on("error", reject);
301
301
  });
302
302
  await fs.promises.rename(tempPath, modelPath);
@@ -3658,7 +3658,7 @@ function getConfigFormat(agent) {
3658
3658
 
3659
3659
  // src/skills.ts
3660
3660
  import { existsSync, readdirSync, readFileSync } from "fs";
3661
- import { join, basename } from "path";
3661
+ import { join, basename, resolve, sep } from "path";
3662
3662
  import { parse as parseYaml } from "yaml";
3663
3663
  var SKILL_DISCOVERY_PATHS = [
3664
3664
  "skills",
@@ -3971,8 +3971,9 @@ function validateSkill(skillPath) {
3971
3971
  return { valid: errors.length === 0, errors, warnings };
3972
3972
  }
3973
3973
  function isPathInside(child, parent) {
3974
- const relative5 = child.replace(parent, "");
3975
- return !relative5.startsWith("..") && !relative5.includes("/..");
3974
+ const resolved = resolve(child);
3975
+ const resolvedParent = resolve(parent);
3976
+ return resolved === resolvedParent || resolved.startsWith(resolvedParent + sep);
3976
3977
  }
3977
3978
 
3978
3979
  // src/config.ts
@@ -4368,7 +4369,7 @@ var BitbucketProvider = class {
4368
4369
 
4369
4370
  // src/providers/local.ts
4370
4371
  import { existsSync as existsSync6, statSync, realpathSync } from "fs";
4371
- import { join as join6, resolve, basename as basename5 } from "path";
4372
+ import { join as join6, resolve as resolve2, basename as basename5 } from "path";
4372
4373
  import { homedir as homedir2 } from "os";
4373
4374
  var LocalProvider = class {
4374
4375
  type = "local";
@@ -4382,7 +4383,7 @@ var LocalProvider = class {
4382
4383
  if (source.startsWith("~/")) {
4383
4384
  expandedPath = join6(homedir2(), source.slice(2));
4384
4385
  }
4385
- const absolutePath = resolve(expandedPath);
4386
+ const absolutePath = resolve2(expandedPath);
4386
4387
  const dirName = basename5(absolutePath);
4387
4388
  return {
4388
4389
  owner: "local",
@@ -4438,7 +4439,7 @@ var LocalProvider = class {
4438
4439
 
4439
4440
  // src/providers/wellknown.ts
4440
4441
  import { existsSync as existsSync7, mkdirSync as mkdirSync2, writeFileSync as writeFileSync2, rmSync as rmSync4 } from "fs";
4441
- import { join as join7, basename as basename6, resolve as resolve2, sep } from "path";
4442
+ import { join as join7, basename as basename6, resolve as resolve3, sep as sep2 } from "path";
4442
4443
  import { tmpdir as tmpdir4 } from "os";
4443
4444
  import { randomUUID as randomUUID4 } from "crypto";
4444
4445
  function sanitizeSkillName(name) {
@@ -4521,9 +4522,9 @@ var WellKnownProvider = class {
4521
4522
  continue;
4522
4523
  }
4523
4524
  const skillDir = join7(tempDir, safeName);
4524
- const resolvedSkillDir = resolve2(skillDir);
4525
- const resolvedTempDir = resolve2(tempDir);
4526
- if (!resolvedSkillDir.startsWith(resolvedTempDir + sep) && resolvedSkillDir !== resolvedTempDir) {
4525
+ const resolvedSkillDir = resolve3(skillDir);
4526
+ const resolvedTempDir = resolve3(tempDir);
4527
+ if (!resolvedSkillDir.startsWith(resolvedTempDir + sep2) && resolvedSkillDir !== resolvedTempDir) {
4527
4528
  continue;
4528
4529
  }
4529
4530
  mkdirSync2(skillDir, { recursive: true });
@@ -4591,7 +4592,7 @@ function generateWellKnownIndex(skills) {
4591
4592
  }
4592
4593
  function generateWellKnownStructure(outputDir, skills) {
4593
4594
  const wellKnownDir = join7(outputDir, ".well-known", "skills");
4594
- const resolvedWellKnownDir = resolve2(wellKnownDir);
4595
+ const resolvedWellKnownDir = resolve3(wellKnownDir);
4595
4596
  mkdirSync2(wellKnownDir, { recursive: true });
4596
4597
  const indexSkills = [];
4597
4598
  const skillPaths = [];
@@ -4601,8 +4602,8 @@ function generateWellKnownStructure(outputDir, skills) {
4601
4602
  continue;
4602
4603
  }
4603
4604
  const skillDir = join7(wellKnownDir, safeName);
4604
- const resolvedSkillDir = resolve2(skillDir);
4605
- if (!resolvedSkillDir.startsWith(resolvedWellKnownDir + sep) && resolvedSkillDir !== resolvedWellKnownDir) {
4605
+ const resolvedSkillDir = resolve3(skillDir);
4606
+ if (!resolvedSkillDir.startsWith(resolvedWellKnownDir + sep2) && resolvedSkillDir !== resolvedWellKnownDir) {
4606
4607
  continue;
4607
4608
  }
4608
4609
  mkdirSync2(skillDir, { recursive: true });
@@ -8402,7 +8403,7 @@ var SkillExecutionEngine = class {
8402
8403
  const startTime = /* @__PURE__ */ new Date();
8403
8404
  const taskId = task.id || randomUUID7();
8404
8405
  try {
8405
- await new Promise((resolve5) => setTimeout(resolve5, 100));
8406
+ await new Promise((resolve6) => setTimeout(resolve6, 100));
8406
8407
  const endTime = /* @__PURE__ */ new Date();
8407
8408
  return {
8408
8409
  taskId,
@@ -8739,7 +8740,7 @@ async function executeWithAgent(agentType, prompt, options = {}) {
8739
8740
  });
8740
8741
  }
8741
8742
  async function executeCommand(command, args, options = {}) {
8742
- return new Promise((resolve5) => {
8743
+ return new Promise((resolve6) => {
8743
8744
  const startTime = Date.now();
8744
8745
  let stdout = "";
8745
8746
  let stderr = "";
@@ -8762,7 +8763,7 @@ async function executeCommand(command, args, options = {}) {
8762
8763
  });
8763
8764
  child.on("error", (error) => {
8764
8765
  if (timeoutId) clearTimeout(timeoutId);
8765
- resolve5({
8766
+ resolve6({
8766
8767
  success: false,
8767
8768
  output: stdout,
8768
8769
  error: error.message,
@@ -8772,7 +8773,7 @@ async function executeCommand(command, args, options = {}) {
8772
8773
  });
8773
8774
  child.on("close", (code) => {
8774
8775
  if (timeoutId) clearTimeout(timeoutId);
8775
- resolve5({
8776
+ resolve6({
8776
8777
  success: code === 0 && !timedOut,
8777
8778
  output: stdout,
8778
8779
  error: timedOut ? "Execution timed out" : stderr || void 0,
@@ -8967,7 +8968,7 @@ function createSimulatedSkillExecutor(options = {}) {
8967
8968
  const { delay = 100, shouldFail, onExecute } = options;
8968
8969
  return async (skillName, _config) => {
8969
8970
  onExecute?.(skillName);
8970
- await new Promise((resolve5) => setTimeout(resolve5, delay));
8971
+ await new Promise((resolve6) => setTimeout(resolve6, delay));
8971
8972
  const failed = shouldFail?.(skillName) ?? false;
8972
8973
  return {
8973
8974
  success: !failed,
@@ -9416,12 +9417,12 @@ function assertEnvVarSet(assertion, startTime) {
9416
9417
  };
9417
9418
  }
9418
9419
  async function checkPortAvailable(port) {
9419
- return new Promise((resolve5) => {
9420
+ return new Promise((resolve6) => {
9420
9421
  const server = createServer();
9421
- server.once("error", () => resolve5(false));
9422
+ server.once("error", () => resolve6(false));
9422
9423
  server.once("listening", () => {
9423
9424
  server.close();
9424
- resolve5(true);
9425
+ resolve6(true);
9425
9426
  });
9426
9427
  server.listen(port, "127.0.0.1");
9427
9428
  });
@@ -13195,7 +13196,7 @@ function createTeamManager(projectPath) {
13195
13196
 
13196
13197
  // src/team/bundle.ts
13197
13198
  import { existsSync as existsSync27, readFileSync as readFileSync17, writeFileSync as writeFileSync15, mkdirSync as mkdirSync16, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
13198
- import { join as join26, basename as basename9, resolve as resolve3, relative, dirname as dirname8, sep as sep2 } from "path";
13199
+ import { join as join26, basename as basename9, resolve as resolve4, relative, dirname as dirname8, sep as sep3 } from "path";
13199
13200
  import { createHash } from "crypto";
13200
13201
  var BUNDLE_VERSION = 1;
13201
13202
  var SkillBundle = class {
@@ -13360,7 +13361,7 @@ function importBundle(bundlePath, targetDir, options = {}) {
13360
13361
  try {
13361
13362
  const content = readFileSync17(bundlePath, "utf-8");
13362
13363
  const data = JSON.parse(content);
13363
- const absoluteTargetDir = resolve3(targetDir);
13364
+ const absoluteTargetDir = resolve4(targetDir);
13364
13365
  for (const skill of data.manifest.skills) {
13365
13366
  if (!skill.name || skill.name.includes("/") || skill.name.includes("\\") || skill.name === ".." || skill.name === "." || skill.name.startsWith(".")) {
13366
13367
  errors.push(`Skill has invalid name: ${skill.name}`);
@@ -13372,9 +13373,9 @@ function importBundle(bundlePath, targetDir, options = {}) {
13372
13373
  continue;
13373
13374
  }
13374
13375
  const skillDir = join26(absoluteTargetDir, skill.name);
13375
- const resolvedSkillDir = resolve3(skillDir);
13376
+ const resolvedSkillDir = resolve4(skillDir);
13376
13377
  const relativeToTarget = relative(absoluteTargetDir, resolvedSkillDir);
13377
- if (relativeToTarget.startsWith("..") || relativeToTarget.startsWith(sep2)) {
13378
+ if (relativeToTarget.startsWith("..") || relativeToTarget.startsWith(sep3)) {
13378
13379
  errors.push(`Skill "${skill.name}" would escape target directory`);
13379
13380
  continue;
13380
13381
  }
@@ -13387,9 +13388,9 @@ function importBundle(bundlePath, targetDir, options = {}) {
13387
13388
  }
13388
13389
  const files = parseSkillContent2(skillContent);
13389
13390
  for (const [filePath, fileContent] of Object.entries(files)) {
13390
- const fullPath = resolve3(skillDir, filePath);
13391
+ const fullPath = resolve4(skillDir, filePath);
13391
13392
  const relativeToSkill = relative(skillDir, fullPath);
13392
- if (relativeToSkill.startsWith("..") || relativeToSkill.startsWith(sep2)) {
13393
+ if (relativeToSkill.startsWith("..") || relativeToSkill.startsWith(sep3)) {
13393
13394
  errors.push(`Skill "${skill.name}" contains invalid file path: ${filePath}`);
13394
13395
  continue;
13395
13396
  }
@@ -17856,8 +17857,8 @@ var PlanExecutor = class {
17856
17857
  pause() {
17857
17858
  if (!this.isPaused) {
17858
17859
  this.isPaused = true;
17859
- this.resumePromise = new Promise((resolve5) => {
17860
- this.resumeResolve = resolve5;
17860
+ this.resumePromise = new Promise((resolve6) => {
17861
+ this.resumeResolve = resolve6;
17861
17862
  });
17862
17863
  this.emit("plan:paused", {});
17863
17864
  }
@@ -20541,7 +20542,7 @@ function loadAndConvertSkill(skill, options) {
20541
20542
 
20542
20543
  // src/skill-translator.ts
20543
20544
  import { readFileSync as readFileSync25, existsSync as existsSync36, writeFileSync as writeFileSync19, mkdirSync as mkdirSync20 } from "fs";
20544
- import { join as join37, basename as basename12, dirname as dirname12, resolve as resolve4, relative as relative3, isAbsolute as isAbsolute2 } from "path";
20545
+ import { join as join37, basename as basename12, dirname as dirname12, resolve as resolve5, relative as relative3, isAbsolute as isAbsolute2 } from "path";
20545
20546
  import { parse as parseYaml11, stringify as stringifyYaml8 } from "yaml";
20546
20547
  var AGENT_SKILL_FORMATS = Object.fromEntries(
20547
20548
  Object.entries(AGENT_CONFIG).map(([agent, config]) => [
@@ -20780,8 +20781,8 @@ function writeTranslatedSkill(result, rootDir, options) {
20780
20781
  };
20781
20782
  }
20782
20783
  try {
20783
- const rootPath = resolve4(rootDir);
20784
- const filePath = resolve4(rootDir, result.targetDir, result.filename);
20784
+ const rootPath = resolve5(rootDir);
20785
+ const filePath = resolve5(rootDir, result.targetDir, result.filename);
20785
20786
  const targetPath = dirname12(filePath);
20786
20787
  const relPath = relative3(rootPath, filePath);
20787
20788
  if (relPath.startsWith("..") || isAbsolute2(relPath)) {
@@ -21930,7 +21931,7 @@ var AGENT_INSTRUCTION_TEMPLATES = {
21930
21931
 
21931
21932
  // src/primer/analyzer.ts
21932
21933
  import { existsSync as existsSync39, readFileSync as readFileSync28, readdirSync as readdirSync11 } from "fs";
21933
- import { join as join40, basename as basename14, relative as relative4, sep as sep3 } from "path";
21934
+ import { join as join40, basename as basename14, relative as relative4, sep as sep4 } from "path";
21934
21935
  var PACKAGE_MANAGER_FILES = {
21935
21936
  "package-lock.json": "npm",
21936
21937
  "pnpm-lock.yaml": "pnpm",
@@ -22418,7 +22419,7 @@ var PrimerAnalyzer = class {
22418
22419
  let files = 0;
22419
22420
  let directories = 0;
22420
22421
  for (const file of this.files) {
22421
- if (file.includes(sep3)) {
22422
+ if (file.includes(sep4)) {
22422
22423
  directories++;
22423
22424
  }
22424
22425
  files++;
@@ -25458,7 +25459,7 @@ var ExecutionManager = class {
25458
25459
  this.metrics.stepMetrics.set(stepName, existing);
25459
25460
  }
25460
25461
  delay(ms) {
25461
- return new Promise((resolve5) => setTimeout(resolve5, ms));
25462
+ return new Promise((resolve6) => setTimeout(resolve6, ms));
25462
25463
  }
25463
25464
  };
25464
25465
  function createExecutionManager(config) {
@@ -25657,6 +25658,477 @@ init_vector_store();
25657
25658
  init_rrf();
25658
25659
  init_expansion();
25659
25660
  init_hybrid();
25661
+
25662
+ // src/registry/community.ts
25663
+ import { readFileSync as readFileSync34, existsSync as existsSync48 } from "fs";
25664
+ import { join as join48, dirname as dirname19 } from "path";
25665
+ import { fileURLToPath as fileURLToPath2 } from "url";
25666
+ var CommunityRegistry = class {
25667
+ constructor(skillsMdPath) {
25668
+ this.skillsMdPath = skillsMdPath;
25669
+ }
25670
+ name = "community";
25671
+ entries = [];
25672
+ loaded = false;
25673
+ load() {
25674
+ if (this.loaded) return;
25675
+ this.loaded = true;
25676
+ const paths = this.skillsMdPath ? [this.skillsMdPath] : [
25677
+ join48(process.cwd(), "registry", "SKILLS.md"),
25678
+ join48(dirname19(fileURLToPath2(import.meta.url)), "..", "..", "..", "..", "registry", "SKILLS.md")
25679
+ ];
25680
+ for (const path4 of paths) {
25681
+ if (!existsSync48(path4)) continue;
25682
+ try {
25683
+ const content = readFileSync34(path4, "utf-8");
25684
+ this.entries = this.parse(content);
25685
+ return;
25686
+ } catch {
25687
+ continue;
25688
+ }
25689
+ }
25690
+ }
25691
+ parse(content) {
25692
+ const results = [];
25693
+ let currentCategory = "";
25694
+ for (const line of content.split("\n")) {
25695
+ const headerMatch = line.match(/^##\s+(.+)/);
25696
+ if (headerMatch) {
25697
+ currentCategory = headerMatch[1].trim();
25698
+ continue;
25699
+ }
25700
+ const entryMatch = line.match(/^-\s+\[([^\]]+)\]\(([^)]+)\)\s*-\s*(.+)/);
25701
+ if (entryMatch) {
25702
+ results.push({
25703
+ name: entryMatch[1].trim(),
25704
+ url: entryMatch[2].trim(),
25705
+ description: entryMatch[3].trim(),
25706
+ category: currentCategory
25707
+ });
25708
+ }
25709
+ }
25710
+ return results;
25711
+ }
25712
+ async search(query, options) {
25713
+ this.load();
25714
+ const limit = options?.limit ?? 20;
25715
+ const q = query.toLowerCase();
25716
+ const matched = this.entries.filter(
25717
+ (e) => e.name.toLowerCase().includes(q) || e.description.toLowerCase().includes(q) || e.category.toLowerCase().includes(q)
25718
+ );
25719
+ return matched.slice(0, limit).map((e) => ({
25720
+ name: e.name,
25721
+ description: e.description,
25722
+ source: e.url,
25723
+ registry: this.name
25724
+ }));
25725
+ }
25726
+ getAll() {
25727
+ this.load();
25728
+ return [...this.entries];
25729
+ }
25730
+ getCategories() {
25731
+ this.load();
25732
+ return [...new Set(this.entries.map((e) => e.category))];
25733
+ }
25734
+ };
25735
+
25736
+ // src/registry/index.ts
25737
+ var RateLimitError = class extends Error {
25738
+ constructor(registry) {
25739
+ super(`Rate limited by ${registry} API. Authenticate with a token or wait before retrying.`);
25740
+ this.name = "RateLimitError";
25741
+ }
25742
+ };
25743
+ var GitHubSkillRegistry = class {
25744
+ name = "github";
25745
+ baseUrl = "https://api.github.com";
25746
+ async search(query, options) {
25747
+ const limit = options?.limit ?? 20;
25748
+ const timeoutMs = options?.timeoutMs ?? 1e4;
25749
+ const searchQuery = `SKILL.md ${query} in:path,file`;
25750
+ const controller = new AbortController();
25751
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
25752
+ try {
25753
+ const headers = {
25754
+ Accept: "application/vnd.github.v3+json",
25755
+ "User-Agent": "skillkit-cli"
25756
+ };
25757
+ const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
25758
+ if (token) {
25759
+ headers.Authorization = `Bearer ${token}`;
25760
+ }
25761
+ const response = await fetch(
25762
+ `${this.baseUrl}/search/code?q=${encodeURIComponent(searchQuery)}&per_page=${limit}`,
25763
+ {
25764
+ headers,
25765
+ signal: controller.signal
25766
+ }
25767
+ );
25768
+ clearTimeout(timer);
25769
+ if (!response.ok) {
25770
+ if (response.status === 403) {
25771
+ throw new RateLimitError(this.name);
25772
+ }
25773
+ return [];
25774
+ }
25775
+ const data = await response.json();
25776
+ if (!data.items) return [];
25777
+ const seen = /* @__PURE__ */ new Set();
25778
+ const skills = [];
25779
+ for (const item of data.items) {
25780
+ const repo = item.repository.full_name;
25781
+ if (seen.has(repo)) continue;
25782
+ seen.add(repo);
25783
+ const pathParts = item.path.split("/");
25784
+ const skillName = pathParts.length > 1 ? pathParts[pathParts.length - 2] : repo.split("/").pop() || repo;
25785
+ skills.push({
25786
+ name: skillName,
25787
+ description: item.repository.description || "",
25788
+ source: item.repository.html_url,
25789
+ registry: this.name,
25790
+ path: item.path,
25791
+ stars: item.repository.stargazers_count,
25792
+ updatedAt: item.repository.updated_at
25793
+ });
25794
+ }
25795
+ return skills;
25796
+ } catch (err) {
25797
+ clearTimeout(timer);
25798
+ if (err instanceof RateLimitError) throw err;
25799
+ return [];
25800
+ }
25801
+ }
25802
+ };
25803
+ var FederatedSearch = class {
25804
+ registries = [];
25805
+ addRegistry(registry) {
25806
+ this.registries.push(registry);
25807
+ }
25808
+ async search(query, options) {
25809
+ const limit = options?.limit ?? 20;
25810
+ const results = await Promise.allSettled(
25811
+ this.registries.map((r) => r.search(query, { limit }))
25812
+ );
25813
+ const allSkills = [];
25814
+ const activeRegistries = [];
25815
+ for (let i = 0; i < results.length; i++) {
25816
+ const result = results[i];
25817
+ if (result.status === "fulfilled" && result.value.length > 0) {
25818
+ allSkills.push(...result.value);
25819
+ activeRegistries.push(this.registries[i].name);
25820
+ } else if (result.status === "rejected" && result.reason instanceof RateLimitError) {
25821
+ throw result.reason;
25822
+ }
25823
+ }
25824
+ const seen = /* @__PURE__ */ new Set();
25825
+ const deduplicated = [];
25826
+ for (const skill of allSkills) {
25827
+ const key = `${skill.source}:${skill.name}`;
25828
+ if (!seen.has(key)) {
25829
+ seen.add(key);
25830
+ deduplicated.push(skill);
25831
+ }
25832
+ }
25833
+ deduplicated.sort((a, b) => (b.stars ?? 0) - (a.stars ?? 0));
25834
+ return {
25835
+ skills: deduplicated.slice(0, limit),
25836
+ registries: activeRegistries,
25837
+ total: deduplicated.length,
25838
+ query
25839
+ };
25840
+ }
25841
+ };
25842
+
25843
+ // src/cache/memory.ts
25844
+ var DEFAULT_MAX_SIZE = 1e3;
25845
+ var DEFAULT_TTL_MS = 24 * 60 * 60 * 1e3;
25846
+ var MemoryCache = class {
25847
+ store = /* @__PURE__ */ new Map();
25848
+ maxSize;
25849
+ ttlMs;
25850
+ hitCount = 0;
25851
+ missCount = 0;
25852
+ constructor(options) {
25853
+ this.maxSize = options?.maxSize ?? DEFAULT_MAX_SIZE;
25854
+ this.ttlMs = options?.ttlMs ?? DEFAULT_TTL_MS;
25855
+ }
25856
+ get(key) {
25857
+ const entry = this.store.get(key);
25858
+ if (!entry) {
25859
+ this.missCount++;
25860
+ return void 0;
25861
+ }
25862
+ if (Date.now() > entry.expiresAt) {
25863
+ this.store.delete(key);
25864
+ this.missCount++;
25865
+ return void 0;
25866
+ }
25867
+ entry.lastAccessed = Date.now();
25868
+ this.hitCount++;
25869
+ return entry.value;
25870
+ }
25871
+ set(key, value) {
25872
+ if (this.store.size >= this.maxSize && !this.store.has(key)) {
25873
+ this.evictLRU();
25874
+ }
25875
+ const now = Date.now();
25876
+ this.store.set(key, {
25877
+ value,
25878
+ expiresAt: now + this.ttlMs,
25879
+ lastAccessed: now
25880
+ });
25881
+ }
25882
+ delete(key) {
25883
+ return this.store.delete(key);
25884
+ }
25885
+ has(key) {
25886
+ const entry = this.store.get(key);
25887
+ if (!entry) return false;
25888
+ if (Date.now() > entry.expiresAt) {
25889
+ this.store.delete(key);
25890
+ return false;
25891
+ }
25892
+ return true;
25893
+ }
25894
+ clear() {
25895
+ this.store.clear();
25896
+ this.hitCount = 0;
25897
+ this.missCount = 0;
25898
+ }
25899
+ stats() {
25900
+ const total = this.hitCount + this.missCount;
25901
+ return {
25902
+ hits: this.hitCount,
25903
+ misses: this.missCount,
25904
+ size: this.store.size,
25905
+ maxSize: this.maxSize,
25906
+ hitRate: total > 0 ? this.hitCount / total : 0
25907
+ };
25908
+ }
25909
+ evictLRU() {
25910
+ let oldestKey = null;
25911
+ let oldestTime = Infinity;
25912
+ for (const [key, entry] of this.store) {
25913
+ if (entry.lastAccessed < oldestTime) {
25914
+ oldestTime = entry.lastAccessed;
25915
+ oldestKey = key;
25916
+ }
25917
+ }
25918
+ if (oldestKey) {
25919
+ this.store.delete(oldestKey);
25920
+ }
25921
+ }
25922
+ };
25923
+
25924
+ // src/ranking/relevance.ts
25925
+ var WEIGHTS = {
25926
+ contentAvailability: 40,
25927
+ queryMatch: 30,
25928
+ popularity: 15,
25929
+ references: 15
25930
+ };
25931
+ var RelevanceRanker = class {
25932
+ rank(skills, query) {
25933
+ const results = skills.map((skill) => {
25934
+ const breakdown = this.score(skill, query);
25935
+ const score = breakdown.contentAvailability + breakdown.queryMatch + breakdown.popularity + breakdown.referenceScore;
25936
+ return { skill, score, breakdown };
25937
+ });
25938
+ results.sort((a, b) => b.score - a.score);
25939
+ return results;
25940
+ }
25941
+ score(skill, query) {
25942
+ return {
25943
+ contentAvailability: this.scoreContent(skill),
25944
+ queryMatch: query ? this.scoreQuery(skill, query) : 0,
25945
+ popularity: this.scorePopularity(skill),
25946
+ referenceScore: this.scoreReferences(skill)
25947
+ };
25948
+ }
25949
+ scoreContent(skill) {
25950
+ let score = 0;
25951
+ if (skill.description && skill.description.length > 0) score += 20;
25952
+ if (skill.content && skill.content.length > 0) score += 20;
25953
+ return score;
25954
+ }
25955
+ scoreQuery(skill, query) {
25956
+ const q = query.toLowerCase();
25957
+ const name = skill.name.toLowerCase();
25958
+ if (name === q) return WEIGHTS.queryMatch;
25959
+ if (name.includes(q) || q.includes(name)) {
25960
+ return WEIGHTS.queryMatch * 0.7;
25961
+ }
25962
+ const desc = (skill.description || "").toLowerCase();
25963
+ const content = (skill.content || "").toLowerCase();
25964
+ const searchable = `${name} ${desc} ${content}`;
25965
+ const words = q.split(/\s+/).filter(Boolean);
25966
+ const matched = words.filter((w) => searchable.includes(w)).length;
25967
+ if (words.length === 0) return 0;
25968
+ return Math.round(WEIGHTS.queryMatch * (matched / words.length) * 0.6);
25969
+ }
25970
+ scorePopularity(skill) {
25971
+ const count = (skill.stars ?? 0) + (skill.installs ?? 0);
25972
+ if (count <= 0) return 0;
25973
+ return Math.min(WEIGHTS.popularity, Math.round(Math.log10(count + 1) * 5));
25974
+ }
25975
+ scoreReferences(skill) {
25976
+ if (!skill.references || skill.references.length === 0) return 0;
25977
+ return Math.min(WEIGHTS.references, skill.references.length * 5);
25978
+ }
25979
+ };
25980
+
25981
+ // src/parser/references.ts
25982
+ import { readdirSync as readdirSync12, statSync as statSync9, existsSync as existsSync49 } from "fs";
25983
+ import { join as join49 } from "path";
25984
+ var REFERENCE_DIRS = ["references", "resources", "docs", "examples", "assets", "scripts"];
25985
+ var DIR_TYPE_MAP = {
25986
+ references: "resource",
25987
+ resources: "resource",
25988
+ docs: "doc",
25989
+ examples: "example",
25990
+ assets: "asset",
25991
+ scripts: "resource"
25992
+ };
25993
+ function discoverReferences(skillDir) {
25994
+ const refs = [];
25995
+ for (const dir of REFERENCE_DIRS) {
25996
+ const fullPath = join49(skillDir, dir);
25997
+ if (!existsSync49(fullPath)) continue;
25998
+ try {
25999
+ const stat = statSync9(fullPath);
26000
+ if (!stat.isDirectory()) continue;
26001
+ } catch {
26002
+ continue;
26003
+ }
26004
+ const type = DIR_TYPE_MAP[dir] || "resource";
26005
+ try {
26006
+ const entries = readdirSync12(fullPath);
26007
+ for (const entry of entries) {
26008
+ const entryPath = join49(fullPath, entry);
26009
+ try {
26010
+ const entryStat = statSync9(entryPath);
26011
+ if (entryStat.isFile()) {
26012
+ refs.push({
26013
+ path: join49(dir, entry),
26014
+ type,
26015
+ name: entry
26016
+ });
26017
+ }
26018
+ } catch {
26019
+ continue;
26020
+ }
26021
+ }
26022
+ } catch {
26023
+ continue;
26024
+ }
26025
+ }
26026
+ return refs;
26027
+ }
26028
+ function stripFrontmatter(raw) {
26029
+ const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
26030
+ if (!match) {
26031
+ const emptyMatch = raw.match(/^---\r?\n---\r?\n?([\s\S]*)$/);
26032
+ if (emptyMatch) {
26033
+ return { frontmatter: {}, body: emptyMatch[1] };
26034
+ }
26035
+ return { frontmatter: {}, body: raw };
26036
+ }
26037
+ const fmBlock = match[1];
26038
+ const body = match[2];
26039
+ const frontmatter = {};
26040
+ for (const line of fmBlock.split("\n")) {
26041
+ const colonIdx = line.indexOf(":");
26042
+ if (colonIdx === -1) continue;
26043
+ const key = line.slice(0, colonIdx).trim();
26044
+ const value = line.slice(colonIdx + 1).trim();
26045
+ if (key) {
26046
+ frontmatter[key] = value;
26047
+ }
26048
+ }
26049
+ return { frontmatter, body };
26050
+ }
26051
+ function parseSkillMd(raw, skillDir) {
26052
+ const { frontmatter, body } = stripFrontmatter(raw);
26053
+ const references = skillDir ? discoverReferences(skillDir) : [];
26054
+ return {
26055
+ frontmatter,
26056
+ body,
26057
+ references,
26058
+ raw
26059
+ };
26060
+ }
26061
+
26062
+ // src/runtime/injector.ts
26063
+ function parseSource2(source) {
26064
+ const parts = source.replace(/^https?:\/\/github\.com\//, "").split("/");
26065
+ if (parts.length < 2) {
26066
+ throw new Error(`Invalid source format: "${source}". Expected "owner/repo".`);
26067
+ }
26068
+ return { owner: parts[0], repo: parts[1] };
26069
+ }
26070
+ var SkillInjector = class {
26071
+ cache;
26072
+ constructor(cacheTtlMs) {
26073
+ this.cache = new MemoryCache({
26074
+ maxSize: 200,
26075
+ ttlMs: cacheTtlMs ?? 24 * 60 * 60 * 1e3
26076
+ });
26077
+ }
26078
+ async fetch(source, skillId) {
26079
+ const cacheKey = `${source}:${skillId}`;
26080
+ const cached = this.cache.get(cacheKey);
26081
+ if (cached) return cached;
26082
+ const { owner, repo } = parseSource2(source);
26083
+ const raw = await this.fetchRawSkillMd(owner, repo, skillId);
26084
+ const parsed = parseSkillMd(raw);
26085
+ const result = {
26086
+ source: { owner, repo },
26087
+ skillId,
26088
+ parsed,
26089
+ fetchedAt: Date.now()
26090
+ };
26091
+ this.cache.set(cacheKey, result);
26092
+ return result;
26093
+ }
26094
+ async inject(source, skillId) {
26095
+ const fetched = await this.fetch(source, skillId);
26096
+ return fetched.parsed.body;
26097
+ }
26098
+ async fetchRawSkillMd(owner, repo, skillId) {
26099
+ const paths = [
26100
+ `${skillId}/SKILL.md`,
26101
+ `skills/${skillId}/SKILL.md`,
26102
+ `SKILL.md`
26103
+ ];
26104
+ const headers = {
26105
+ Accept: "application/vnd.github.v3.raw",
26106
+ "User-Agent": "skillkit-runtime"
26107
+ };
26108
+ const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
26109
+ if (token) {
26110
+ headers.Authorization = `Bearer ${token}`;
26111
+ }
26112
+ for (const path4 of paths) {
26113
+ const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path4}`;
26114
+ try {
26115
+ const response = await fetch(url, { headers });
26116
+ if (response.ok) {
26117
+ return await response.text();
26118
+ }
26119
+ } catch {
26120
+ continue;
26121
+ }
26122
+ }
26123
+ throw new Error(`SKILL.md not found in ${owner}/${repo} for skill "${skillId}"`);
26124
+ }
26125
+ clearCache() {
26126
+ this.cache.clear();
26127
+ }
26128
+ cacheStats() {
26129
+ return this.cache.stats();
26130
+ }
26131
+ };
25660
26132
  export {
25661
26133
  AGENT_CLI_CONFIGS,
25662
26134
  AGENT_CONFIG,
@@ -25687,6 +26159,7 @@ export {
25687
26159
  CUSTOM_AGENT_FORMAT_MAP,
25688
26160
  CommandGenerator,
25689
26161
  CommandRegistry,
26162
+ CommunityRegistry,
25690
26163
  ConnectorCategorySchema,
25691
26164
  ConnectorConfigSchema,
25692
26165
  ConnectorMappingSchema,
@@ -25713,9 +26186,11 @@ export {
25713
26186
  ExecutionManager,
25714
26187
  ExecutionStepSchema,
25715
26188
  ExecutionStepStatusSchema,
26189
+ FederatedSearch,
25716
26190
  GITHUB_ACTION_TEMPLATE,
25717
26191
  GITLAB_CI_TEMPLATE,
25718
26192
  GitHubProvider,
26193
+ GitHubSkillRegistry,
25719
26194
  GitLabProvider,
25720
26195
  GitProvider,
25721
26196
  HookManager,
@@ -25731,6 +26206,7 @@ export {
25731
26206
  MARKETPLACE_CACHE_FILE,
25732
26207
  MODEL_REGISTRY,
25733
26208
  MarketplaceAggregator,
26209
+ MemoryCache,
25734
26210
  MemoryCompressor,
25735
26211
  MemoryEnabledEngine,
25736
26212
  MemoryIndexStore,
@@ -25753,10 +26229,12 @@ export {
25753
26229
  PrimerGenerator,
25754
26230
  ProjectDetector,
25755
26231
  QueryExpander,
26232
+ RateLimitError,
25756
26233
  ReasoningEngine,
25757
26234
  ReasoningProviderSchema,
25758
26235
  ReasoningRecommendationEngine,
25759
26236
  RecommendationEngine,
26237
+ RelevanceRanker,
25760
26238
  RuleBasedCompressor,
25761
26239
  SEARCH_PLANNING_PROMPT,
25762
26240
  SESSION_FILE,
@@ -25769,6 +26247,7 @@ export {
25769
26247
  SkillChunkSchema,
25770
26248
  SkillExecutionEngine,
25771
26249
  SkillFrontmatter,
26250
+ SkillInjector,
25772
26251
  SkillLocation,
25773
26252
  SkillMdTranslator,
25774
26253
  SkillMetadata,
@@ -25878,6 +26357,7 @@ export {
25878
26357
  discoverAgentsFromPath,
25879
26358
  discoverAgentsRecursive,
25880
26359
  discoverGlobalAgents,
26360
+ discoverReferences,
25881
26361
  discoverSkills,
25882
26362
  dryRunExecutor,
25883
26363
  enableGuideline,
@@ -26044,6 +26524,7 @@ export {
26044
26524
  parseSkill,
26045
26525
  parseSkillContent,
26046
26526
  parseSkillContentToCanonical,
26527
+ parseSkillMd,
26047
26528
  parseSkillToCanonical,
26048
26529
  parseSource,
26049
26530
  parseWorkflow,
@@ -26080,6 +26561,7 @@ export {
26080
26561
  shellExecutor,
26081
26562
  skillMdTranslator,
26082
26563
  skillToSubagent,
26564
+ stripFrontmatter,
26083
26565
  suggestMappingsFromMcp,
26084
26566
  supportsAutoDiscovery,
26085
26567
  supportsSlashCommands,