skilld 0.3.1 → 0.4.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/README.md CHANGED
@@ -34,22 +34,23 @@ Skilld leverages maintainers existing effort. Maintainers write great docs for u
34
34
 
35
35
  ## Features
36
36
 
37
- - 🌍 **Full Context SKILL.md** - Generates with the repo code, docs, releases, issues, discussions
38
- - 🤖 **BYO Agent** - Generate SKILL.md with or without an LLM
39
- - 📚 **Customizable** - `Best practices`, `LLM Gaps`, `Doc Map` or your own prompts
40
- - 🔍 **Semantic Search** - Token-optimized search via [retriv](https://github.com/harlan-zw/retriv)
41
- - 🎯 **Safe** - Prompt injection sanitization, version-aware output
42
- - 🤝 **Ecosystem** - [skills-npm](https://github.com/antfu/skills-npm) and `/llms.txt` support
37
+ - 🌍 **Any Source: Opt-in** - Any NPM dependency or GitHub source, docs auto-resolved
38
+ - 📦 **Bleeding Edge Context** - Latest issues, discussions, and releases synced on
39
+ every update. Always use the latest best practices and avoid deprecated patterns.
40
+ - 📚 **Opt-in LLM Sections** - Enhance skills with LLM-generated `Best practices`, `LLM Gaps`, `Doc Map`, or your own prompts
41
+ - 🔍 **Semantic Search** - Query indexed docs across all skills via [retriv](https://github.com/harlan-zw/retriv) embeddings
42
+ - 🎯 **Safe & Versioned** - Prompt injection sanitization, version-aware caching, auto-updates on new releases
43
+ - 🤝 **Ecosystem** - Compatible with [`npx skills`](https://skills.sh/) and [skills-npm](https://github.com/antfu/skills-npm)
43
44
 
44
45
  ## Quick Start
45
46
 
46
47
  Run skilld in a project to generate skills for your dependencies through a simple interactive wizard:
47
48
 
48
49
  ```bash
49
- npx skilld
50
+ npx -y skilld
50
51
  ```
51
52
 
52
- If you need to re-configure skilld, just run `npx skilld config` to update your agent, model, or preferences.
53
+ If you need to re-configure skilld, just run `npx -y skilld config` to update your agent, model, or preferences.
53
54
 
54
55
  ### Tips
55
56
 
@@ -1,8 +1,10 @@
1
- import { _ as writeSections, b as sanitizeMarkdown, h as readCachedSection, y as repairMarkdown } from "./storage.mjs";
1
+ import { n as sanitizeMarkdown, t as repairMarkdown } from "./sanitize2.mjs";
2
+ import { _ as writeSections, h as readCachedSection } from "./storage.mjs";
3
+ import { t as yamlEscape } from "./yaml.mjs";
2
4
  import { createRequire } from "node:module";
3
5
  import { homedir } from "node:os";
4
- import { dirname, join } from "pathe";
5
- import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, unlinkSync, writeFileSync } from "node:fs";
6
+ import { dirname, join, relative } from "pathe";
7
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
6
8
  import { exec, spawn, spawnSync } from "node:child_process";
7
9
  import { globby } from "globby";
8
10
  import { findDynamicImports, findStaticImports } from "mlly";
@@ -18,7 +20,6 @@ var __exportAll = (all, no_symbols) => {
18
20
  if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
19
21
  return target;
20
22
  };
21
- var __require = /* @__PURE__ */ createRequire(import.meta.url);
22
23
  const SPEC_FRONTMATTER = {
23
24
  "name": {
24
25
  name: "name",
@@ -696,16 +697,24 @@ function generateImportantBlock({ packageName, hasIssues, hasDiscussions, hasRel
696
697
  if (hasDiscussions) rows.push(["Discussions", `\`${skillDir}/.skilld/discussions/\``]);
697
698
  if (hasChangelog) rows.push(["Changelog", `\`${skillDir}/.skilld/pkg/${hasChangelog}\``]);
698
699
  if (hasReleases) rows.push(["Releases", `\`${skillDir}/.skilld/releases/\``]);
699
- return `**IMPORTANT:** Use these references
700
-
701
- | Resource | Command |
702
- |----------|---------|
703
- | Search all | \`Bash 'npx skilld search "<query>" -p ${packageName}'\` |
704
- ${[
700
+ const table = [
705
701
  "| Resource | Path |",
706
702
  "|----------|------|",
707
703
  ...rows.map(([desc, cmd]) => `| ${desc} | ${cmd} |`)
708
- ].join("\n")}`;
704
+ ].join("\n");
705
+ return `**IMPORTANT:** Use these references
706
+
707
+ ## Search
708
+
709
+ Use \`npx -y skilld search\` as your primary research tool — search before manually reading files. Hybrid semantic + keyword search across all indexed docs, issues, and releases.
710
+
711
+ \`\`\`bash
712
+ npx -y skilld search "<query>" -p ${packageName}
713
+ ${hasIssues ? `npx -y skilld search "issues:<query>" -p ${packageName}\n` : ""}${hasReleases ? `npx -y skilld search "releases:<query>" -p ${packageName}\n` : ""}\`\`\`
714
+
715
+ Filters: \`docs:\`, \`issues:\`, \`releases:\` prefix narrows by source type.
716
+
717
+ ${table}`;
709
718
  }
710
719
  function buildPreamble(opts) {
711
720
  const { packageName, skillDir, hasIssues, hasDiscussions, hasReleases, hasChangelog, docFiles, docsType = "docs", hasShippedDocs = false, versionContext } = opts;
@@ -804,27 +813,6 @@ function buildAllSectionPrompts(opts) {
804
813
  }
805
814
  return result;
806
815
  }
807
- const NEEDS_QUOTING = /[:"'\\\n\r\t#{}[\],&*!|>%@`]/;
808
- function yamlEscape(value) {
809
- if (!NEEDS_QUOTING.test(value)) return value;
810
- return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t")}"`;
811
- }
812
- function yamlUnescape(raw) {
813
- const trimmed = raw.trim();
814
- if (!trimmed) return "";
815
- if (trimmed.startsWith("\"") && trimmed.endsWith("\"")) return trimmed.slice(1, -1).replace(/\\n/g, "\n").replace(/\\r/g, "\r").replace(/\\t/g, " ").replace(/\\"/g, "\"").replace(/\\\\/g, "\\");
816
- if (trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
817
- return trimmed;
818
- }
819
- function yamlParseKV(line) {
820
- const trimmed = line.trim();
821
- const colonIdx = trimmed.indexOf(":");
822
- if (colonIdx === -1) return null;
823
- const key = trimmed.slice(0, colonIdx).trim();
824
- const rawValue = trimmed.slice(colonIdx + 1);
825
- if (!key) return null;
826
- return [key, yamlUnescape(rawValue)];
827
- }
828
816
  function sanitizeName(name) {
829
817
  return name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.\-]+|[.\-]+$/g, "").slice(0, 255) || "unnamed-skill";
830
818
  }
@@ -858,6 +846,32 @@ function installSkillForAgents(skillName, skillContent, options = {}) {
858
846
  paths
859
847
  };
860
848
  }
849
+ function linkSkillToAgents(skillName, sharedDir, cwd) {
850
+ for (const [, agent] of Object.entries(targets)) {
851
+ const agentSkillsDir = join(cwd, agent.skillsDir);
852
+ if (!existsSync(join(cwd, agent.skillsDir.split("/")[0]))) continue;
853
+ const target = join(agentSkillsDir, skillName);
854
+ let isSymlink = false;
855
+ let targetExists = false;
856
+ try {
857
+ const stat = lstatSync(target);
858
+ targetExists = true;
859
+ isSymlink = stat.isSymbolicLink();
860
+ } catch {}
861
+ if (targetExists && !isSymlink) continue;
862
+ if (isSymlink) unlinkSync(target);
863
+ mkdirSync(agentSkillsDir, { recursive: true });
864
+ symlinkSync(relative(agentSkillsDir, join(sharedDir, skillName)), target);
865
+ }
866
+ }
867
+ function unlinkSkillFromAgents(skillName, cwd) {
868
+ for (const [, agent] of Object.entries(targets)) {
869
+ const target = join(cwd, agent.skillsDir, skillName);
870
+ try {
871
+ if (lstatSync(target).isSymbolicLink()) unlinkSync(target);
872
+ } catch {}
873
+ }
874
+ }
861
875
  const FILE_PATTERN_MAP = {
862
876
  "vue": ["*.vue"],
863
877
  "svelte": ["*.svelte"],
@@ -1019,12 +1033,12 @@ function generateFrontmatter({ name, version, description: pkgDescription, globs
1019
1033
  return lines.join("\n");
1020
1034
  }
1021
1035
  function generateSearchBlock(name, hasIssues, hasReleases) {
1022
- const examples = [`npx skilld search "query" -p ${name}`];
1023
- if (hasIssues) examples.push(`npx skilld search "issues:error handling" -p ${name}`);
1024
- if (hasReleases) examples.push(`npx skilld search "releases:deprecated" -p ${name}`);
1036
+ const examples = [`npx -y skilld search "query" -p ${name}`];
1037
+ if (hasIssues) examples.push(`npx -y skilld search "issues:error handling" -p ${name}`);
1038
+ if (hasReleases) examples.push(`npx -y skilld search "releases:deprecated" -p ${name}`);
1025
1039
  return `## Search
1026
1040
 
1027
- Use \`npx skilld search\` instead of grepping \`.skilld/\` directories — hybrid semantic + keyword search across all indexed docs, issues, and releases.
1041
+ Use \`npx -y skilld search\` instead of grepping \`.skilld/\` directories — hybrid semantic + keyword search across all indexed docs, issues, and releases.
1028
1042
 
1029
1043
  \`\`\`bash
1030
1044
  ${examples.join("\n")}
@@ -1833,6 +1847,6 @@ function isNodeBuiltin(pkg) {
1833
1847
  const base = pkg.startsWith("node:") ? pkg.slice(5) : pkg;
1834
1848
  return NODE_BUILTINS.has(base.split("/")[0]);
1835
1849
  }
1836
- export { __require as S, buildSectionPrompt as _, optimizeDocs as a, getAgentVersion as b, computeSkillDirName as c, yamlEscape as d, yamlParseKV as f, buildAllSectionPrompts as g, SECTION_OUTPUT_FILES as h, getModelName as i, installSkillForAgents as l, SECTION_MERGE_ORDER as m, getAvailableModels as n, generateSkillMd as o, yamlUnescape as p, getModelLabel as r, FILE_PATTERN_MAP as s, detectImportedPackages as t, sanitizeName as u, detectInstalledAgents as v, targets as x, detectTargetAgent as y };
1850
+ export { detectInstalledAgents as _, optimizeDocs as a, targets as b, computeSkillDirName as c, sanitizeName as d, unlinkSkillFromAgents as f, buildSectionPrompt as g, buildAllSectionPrompts as h, getModelName as i, installSkillForAgents as l, SECTION_OUTPUT_FILES as m, getAvailableModels as n, generateSkillMd as o, SECTION_MERGE_ORDER as p, getModelLabel as r, FILE_PATTERN_MAP as s, detectImportedPackages as t, linkSkillToAgents as u, detectTargetAgent as v, __exportAll as x, getAgentVersion as y };
1837
1851
 
1838
1852
  //# sourceMappingURL=detect-imports.mjs.map