skilld 0.3.2 โ†’ 0.4.1

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,13 +1,16 @@
1
1
  import { _ as writeSections, b as sanitizeMarkdown, h as readCachedSection, y as repairMarkdown } from "./storage.mjs";
2
+ import { t as yamlEscape } from "./yaml.mjs";
2
3
  import { createRequire } from "node:module";
3
4
  import { homedir } from "node:os";
4
- import { dirname, join } from "pathe";
5
- import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, unlinkSync, writeFileSync } from "node:fs";
5
+ import { dirname, join, relative } from "pathe";
6
+ import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, realpathSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
6
7
  import { exec, spawn, spawnSync } from "node:child_process";
7
8
  import { globby } from "globby";
8
9
  import { findDynamicImports, findStaticImports } from "mlly";
9
10
  import { createHash } from "node:crypto";
11
+ import { promisify } from "node:util";
10
12
  import { readFile } from "node:fs/promises";
13
+ import { parseSync } from "oxc-parser";
11
14
  var __defProp = Object.defineProperty;
12
15
  var __exportAll = (all, no_symbols) => {
13
16
  let target = {};
@@ -695,16 +698,24 @@ function generateImportantBlock({ packageName, hasIssues, hasDiscussions, hasRel
695
698
  if (hasDiscussions) rows.push(["Discussions", `\`${skillDir}/.skilld/discussions/\``]);
696
699
  if (hasChangelog) rows.push(["Changelog", `\`${skillDir}/.skilld/pkg/${hasChangelog}\``]);
697
700
  if (hasReleases) rows.push(["Releases", `\`${skillDir}/.skilld/releases/\``]);
698
- return `**IMPORTANT:** Use these references
699
-
700
- | Resource | Command |
701
- |----------|---------|
702
- | Search all | \`Bash 'npx skilld search "<query>" -p ${packageName}'\` |
703
- ${[
701
+ const table = [
704
702
  "| Resource | Path |",
705
703
  "|----------|------|",
706
704
  ...rows.map(([desc, cmd]) => `| ${desc} | ${cmd} |`)
707
- ].join("\n")}`;
705
+ ].join("\n");
706
+ return `**IMPORTANT:** Use these references
707
+
708
+ ## Search
709
+
710
+ 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.
711
+
712
+ \`\`\`bash
713
+ npx -y skilld search "<query>" -p ${packageName}
714
+ ${hasIssues ? `npx -y skilld search "issues:<query>" -p ${packageName}\n` : ""}${hasReleases ? `npx -y skilld search "releases:<query>" -p ${packageName}\n` : ""}\`\`\`
715
+
716
+ Filters: \`docs:\`, \`issues:\`, \`releases:\` prefix narrows by source type.
717
+
718
+ ${table}`;
708
719
  }
709
720
  function buildPreamble(opts) {
710
721
  const { packageName, skillDir, hasIssues, hasDiscussions, hasReleases, hasChangelog, docFiles, docsType = "docs", hasShippedDocs = false, versionContext } = opts;
@@ -803,27 +814,6 @@ function buildAllSectionPrompts(opts) {
803
814
  }
804
815
  return result;
805
816
  }
806
- const NEEDS_QUOTING = /[:"'\\\n\r\t#{}[\],&*!|>%@`]/;
807
- function yamlEscape(value) {
808
- if (!NEEDS_QUOTING.test(value)) return value;
809
- return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t")}"`;
810
- }
811
- function yamlUnescape(raw) {
812
- const trimmed = raw.trim();
813
- if (!trimmed) return "";
814
- 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, "\\");
815
- if (trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
816
- return trimmed;
817
- }
818
- function yamlParseKV(line) {
819
- const trimmed = line.trim();
820
- const colonIdx = trimmed.indexOf(":");
821
- if (colonIdx === -1) return null;
822
- const key = trimmed.slice(0, colonIdx).trim();
823
- const rawValue = trimmed.slice(colonIdx + 1);
824
- if (!key) return null;
825
- return [key, yamlUnescape(rawValue)];
826
- }
827
817
  function sanitizeName(name) {
828
818
  return name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.\-]+|[.\-]+$/g, "").slice(0, 255) || "unnamed-skill";
829
819
  }
@@ -857,6 +847,32 @@ function installSkillForAgents(skillName, skillContent, options = {}) {
857
847
  paths
858
848
  };
859
849
  }
850
+ function linkSkillToAgents(skillName, sharedDir, cwd) {
851
+ for (const [, agent] of Object.entries(targets)) {
852
+ const agentSkillsDir = join(cwd, agent.skillsDir);
853
+ if (!existsSync(join(cwd, agent.skillsDir.split("/")[0]))) continue;
854
+ const target = join(agentSkillsDir, skillName);
855
+ let isSymlink = false;
856
+ let targetExists = false;
857
+ try {
858
+ const stat = lstatSync(target);
859
+ targetExists = true;
860
+ isSymlink = stat.isSymbolicLink();
861
+ } catch {}
862
+ if (targetExists && !isSymlink) continue;
863
+ if (isSymlink) unlinkSync(target);
864
+ mkdirSync(agentSkillsDir, { recursive: true });
865
+ symlinkSync(relative(agentSkillsDir, join(sharedDir, skillName)), target);
866
+ }
867
+ }
868
+ function unlinkSkillFromAgents(skillName, cwd) {
869
+ for (const [, agent] of Object.entries(targets)) {
870
+ const target = join(cwd, agent.skillsDir, skillName);
871
+ try {
872
+ if (lstatSync(target).isSymbolicLink()) unlinkSync(target);
873
+ } catch {}
874
+ }
875
+ }
860
876
  const FILE_PATTERN_MAP = {
861
877
  "vue": ["*.vue"],
862
878
  "svelte": ["*.svelte"],
@@ -1018,12 +1034,12 @@ function generateFrontmatter({ name, version, description: pkgDescription, globs
1018
1034
  return lines.join("\n");
1019
1035
  }
1020
1036
  function generateSearchBlock(name, hasIssues, hasReleases) {
1021
- const examples = [`npx skilld search "query" -p ${name}`];
1022
- if (hasIssues) examples.push(`npx skilld search "issues:error handling" -p ${name}`);
1023
- if (hasReleases) examples.push(`npx skilld search "releases:deprecated" -p ${name}`);
1037
+ const examples = [`npx -y skilld search "query" -p ${name}`];
1038
+ if (hasIssues) examples.push(`npx -y skilld search "issues:error handling" -p ${name}`);
1039
+ if (hasReleases) examples.push(`npx -y skilld search "releases:deprecated" -p ${name}`);
1024
1040
  return `## Search
1025
1041
 
1026
- Use \`npx skilld search\` instead of grepping \`.skilld/\` directories โ€” hybrid semantic + keyword search across all indexed docs, issues, and releases.
1042
+ Use \`npx -y skilld search\` instead of grepping \`.skilld/\` directories โ€” hybrid semantic + keyword search across all indexed docs, issues, and releases.
1027
1043
 
1028
1044
  \`\`\`bash
1029
1045
  ${examples.join("\n")}
@@ -1300,7 +1316,6 @@ function getModelLabel(id) {
1300
1316
  return `${targets[config.agentId]?.displayName ?? config.cli} ยท ${config.name}`;
1301
1317
  }
1302
1318
  async function getAvailableModels() {
1303
- const { promisify } = await import("node:util");
1304
1319
  const execAsync = promisify(exec);
1305
1320
  const agentsWithCli = detectInstalledAgents().filter((id) => targets[id].cli);
1306
1321
  const cliChecks = await Promise.all(agentsWithCli.map(async (agentId) => {
@@ -1718,7 +1733,6 @@ function extractModuleStrings(node) {
1718
1733
  async function detectNuxtModules(cwd) {
1719
1734
  const config = await findNuxtConfig(cwd);
1720
1735
  if (!config) return [];
1721
- const { parseSync } = await import("oxc-parser");
1722
1736
  const modules = extractModuleStrings(parseSync(config.path, config.content).program);
1723
1737
  const seen = /* @__PURE__ */ new Set();
1724
1738
  const packages = [];
@@ -1832,6 +1846,6 @@ function isNodeBuiltin(pkg) {
1832
1846
  const base = pkg.startsWith("node:") ? pkg.slice(5) : pkg;
1833
1847
  return NODE_BUILTINS.has(base.split("/")[0]);
1834
1848
  }
1835
- export { 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 };
1849
+ 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 };
1836
1850
 
1837
1851
  //# sourceMappingURL=detect-imports.mjs.map