skilld 1.5.5 → 1.7.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 +32 -23
- package/dist/_chunks/agent.mjs +2 -78
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/assemble.mjs +1 -18
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author-group.mjs +17 -0
- package/dist/_chunks/author-group.mjs.map +1 -0
- package/dist/_chunks/author.mjs +8 -24
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +1 -73
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +84 -17
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/cli-helpers.mjs +3 -166
- package/dist/_chunks/cli-helpers.mjs.map +1 -1
- package/dist/_chunks/cli-helpers2.mjs +0 -11
- package/dist/_chunks/config.mjs +119 -54
- package/dist/_chunks/config.mjs.map +1 -1
- package/dist/_chunks/core.mjs +9 -0
- package/dist/_chunks/detect.mjs +29 -226
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/embedding-cache.mjs +0 -5
- package/dist/_chunks/embedding-cache2.mjs +2 -3
- package/dist/_chunks/formatting.mjs +0 -6
- package/dist/_chunks/formatting.mjs.map +1 -1
- package/dist/_chunks/index.d.mts +0 -10
- package/dist/_chunks/index.d.mts.map +1 -1
- package/dist/_chunks/index2.d.mts +3 -6
- package/dist/_chunks/index2.d.mts.map +1 -1
- package/dist/_chunks/index3.d.mts +81 -109
- package/dist/_chunks/index3.d.mts.map +1 -1
- package/dist/_chunks/install.mjs +85 -550
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/install2.mjs +554 -0
- package/dist/_chunks/install2.mjs.map +1 -0
- package/dist/_chunks/libs/@sinclair/typebox.mjs +0 -444
- package/dist/_chunks/libs/@sinclair/typebox.mjs.map +1 -1
- package/dist/_chunks/list.mjs +0 -16
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/lockfile.mjs +2 -10
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/markdown.mjs +0 -9
- package/dist/_chunks/markdown.mjs.map +1 -1
- package/dist/_chunks/package-json.mjs +0 -25
- package/dist/_chunks/package-json.mjs.map +1 -1
- package/dist/_chunks/package-registry.mjs +465 -0
- package/dist/_chunks/package-registry.mjs.map +1 -0
- package/dist/_chunks/pool2.mjs +0 -2
- package/dist/_chunks/pool2.mjs.map +1 -1
- package/dist/_chunks/prefix.mjs +108 -0
- package/dist/_chunks/prefix.mjs.map +1 -0
- package/dist/_chunks/prepare.mjs +14 -9
- package/dist/_chunks/prepare.mjs.map +1 -1
- package/dist/_chunks/prepare2.mjs +1 -19
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +6 -201
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/retriv.mjs +23 -24
- package/dist/_chunks/retriv.mjs.map +1 -1
- package/dist/_chunks/rolldown-runtime.mjs +0 -2
- package/dist/_chunks/sanitize.mjs +0 -78
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-helpers.mjs +99 -0
- package/dist/_chunks/search-helpers.mjs.map +1 -0
- package/dist/_chunks/search-interactive.mjs +1 -18
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +218 -19
- package/dist/_chunks/search.mjs.map +1 -0
- package/dist/_chunks/setup.mjs +0 -13
- package/dist/_chunks/setup.mjs.map +1 -1
- package/dist/_chunks/shared.mjs +1 -473
- package/dist/_chunks/shared.mjs.map +1 -1
- package/dist/_chunks/skills.mjs +3 -3
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/sources.mjs +1179 -1440
- package/dist/_chunks/sources.mjs.map +1 -1
- package/dist/_chunks/sync-registry.mjs +59 -0
- package/dist/_chunks/sync-registry.mjs.map +1 -0
- package/dist/_chunks/sync-shared.mjs +0 -16
- package/dist/_chunks/sync-shared2.mjs +10 -49
- package/dist/_chunks/sync-shared2.mjs.map +1 -1
- package/dist/_chunks/sync.mjs +209 -120
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +1 -21
- package/dist/_chunks/types.d.mts +0 -2
- package/dist/_chunks/types.d.mts.map +1 -1
- package/dist/_chunks/uninstall.mjs +3 -27
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/upload.mjs +152 -0
- package/dist/_chunks/upload.mjs.map +1 -0
- package/dist/_chunks/validate.mjs +1 -8
- package/dist/_chunks/validate.mjs.map +1 -1
- package/dist/_chunks/version.mjs +30 -0
- package/dist/_chunks/version.mjs.map +1 -0
- package/dist/_chunks/wizard.mjs +2 -3
- package/dist/_chunks/yaml.mjs +0 -21
- package/dist/_chunks/yaml.mjs.map +1 -1
- package/dist/agent/index.d.mts +0 -24
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +2 -9
- package/dist/cache/index.mjs +1 -3
- package/dist/cli-entry.mjs +0 -6
- package/dist/cli-entry.mjs.map +1 -1
- package/dist/cli.mjs +48 -33
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -8
- package/dist/prepare.mjs +0 -12
- package/dist/prepare.mjs.map +1 -1
- package/dist/retriv/index.mjs +0 -2
- package/dist/retriv/worker.d.mts +0 -3
- package/dist/retriv/worker.d.mts.map +1 -1
- package/dist/retriv/worker.mjs +0 -2
- package/dist/retriv/worker.mjs.map +1 -1
- package/dist/sources/index.d.mts +2 -2
- package/dist/sources/index.mjs +3 -7
- package/dist/types.d.mts +1 -1
- package/package.json +20 -21
- package/dist/_chunks/search2.mjs +0 -319
- package/dist/_chunks/search2.mjs.map +0 -1
package/dist/_chunks/prepare.mjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { t as getCacheDir } from "./version.mjs";
|
|
2
2
|
import { join } from "pathe";
|
|
3
3
|
import { existsSync, lstatSync, mkdirSync, readdirSync, rmSync, symlinkSync, unlinkSync } from "node:fs";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
function toStorageName(name) {
|
|
5
|
+
if (name.startsWith("crate:")) return `@skilld-crate/${name.slice(6)}`;
|
|
6
|
+
return name;
|
|
7
|
+
}
|
|
6
8
|
function resolvePkgDir(name, cwd, version) {
|
|
7
9
|
const nodeModulesPath = join(cwd, "node_modules", name);
|
|
8
10
|
if (existsSync(nodeModulesPath)) return nodeModulesPath;
|
|
@@ -12,18 +14,23 @@ function resolvePkgDir(name, cwd, version) {
|
|
|
12
14
|
}
|
|
13
15
|
return null;
|
|
14
16
|
}
|
|
15
|
-
/** Restore .skilld/pkg symlink to node_modules if broken */
|
|
16
17
|
function restorePkgSymlink(skillsDir, name, info, cwd) {
|
|
17
18
|
const refsDir = join(skillsDir, name, ".skilld");
|
|
18
19
|
const pkgLink = join(refsDir, "pkg");
|
|
19
20
|
if (!existsSync(join(skillsDir, name))) return;
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
try {
|
|
22
|
+
if (lstatSync(pkgLink).isSymbolicLink()) {
|
|
23
|
+
if (existsSync(pkgLink)) return;
|
|
24
|
+
unlinkSync(pkgLink);
|
|
25
|
+
} else return;
|
|
26
|
+
} catch (err) {
|
|
27
|
+
if (err.code !== "ENOENT") return;
|
|
28
|
+
}
|
|
29
|
+
const pkgDir = resolvePkgDir(toStorageName(info.packageName || name), cwd, info.version);
|
|
22
30
|
if (!pkgDir) return;
|
|
23
31
|
mkdirSync(refsDir, { recursive: true });
|
|
24
32
|
symlinkSync(pkgDir, pkgLink);
|
|
25
33
|
}
|
|
26
|
-
/** Check if package ships a skills/ directory with SKILL.md or _SKILL.md subdirs */
|
|
27
34
|
function getShippedSkills(name, cwd, version) {
|
|
28
35
|
const pkgPath = resolvePkgDir(name, cwd, version);
|
|
29
36
|
if (!pkgPath) return [];
|
|
@@ -34,7 +41,6 @@ function getShippedSkills(name, cwd, version) {
|
|
|
34
41
|
skillDir: join(skillsPath, d.name)
|
|
35
42
|
}));
|
|
36
43
|
}
|
|
37
|
-
/** Create symlink from skills dir to shipped skill dir */
|
|
38
44
|
function linkShippedSkill(baseDir, skillName, targetDir) {
|
|
39
45
|
const linkPath = join(baseDir, skillName);
|
|
40
46
|
if (existsSync(linkPath)) if (lstatSync(linkPath).isSymbolicLink()) unlinkSync(linkPath);
|
|
@@ -44,7 +50,6 @@ function linkShippedSkill(baseDir, skillName, targetDir) {
|
|
|
44
50
|
});
|
|
45
51
|
symlinkSync(targetDir, linkPath);
|
|
46
52
|
}
|
|
47
|
-
//#endregion
|
|
48
53
|
export { restorePkgSymlink as i, linkShippedSkill as n, resolvePkgDir as r, getShippedSkills as t };
|
|
49
54
|
|
|
50
55
|
//# sourceMappingURL=prepare.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepare.mjs","names":[],"sources":["../../src/core/prepare.ts"],"sourcesContent":["/**\n * Shared prepare utilities used by both the fast entry (src/prepare.ts)\n * and the full CLI command (src/commands/prepare.ts).\n *\n * Keep this module lightweight: no imports from agent/, cache/storage.ts,\n * or any module that pulls in sanitize/clack/citty.\n */\n\nimport type { SkillInfo } from './lockfile.ts'\nimport { existsSync, lstatSync, mkdirSync, readdirSync, rmSync, symlinkSync, unlinkSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { getCacheDir } from '../cache/version.ts'\n\n/** Resolve package directory: node_modules first, then global cache */\nexport function resolvePkgDir(name: string, cwd: string, version?: string): string | null {\n const nodeModulesPath = join(cwd, 'node_modules', name)\n if (existsSync(nodeModulesPath))\n return nodeModulesPath\n\n if (version) {\n const cachedPkgDir = join(getCacheDir(name, version), 'pkg')\n if (existsSync(join(cachedPkgDir, 'package.json')))\n return cachedPkgDir\n }\n\n return null\n}\n\n/** Restore .skilld/pkg symlink to node_modules if broken */\nexport function restorePkgSymlink(skillsDir: string, name: string, info: SkillInfo, cwd: string): void {\n const refsDir = join(skillsDir, name, '.skilld')\n const pkgLink = join(refsDir, 'pkg')\n\n if (!existsSync(join(skillsDir, name)))\n return\n\n if (existsSync(pkgLink))\n return\n\n const pkgName = info.packageName || name\n const pkgDir = resolvePkgDir(pkgName, cwd, info.version)\n if (!pkgDir)\n return\n\n mkdirSync(refsDir, { recursive: true })\n symlinkSync(pkgDir, pkgLink)\n}\n\nexport interface ShippedSkill {\n skillName: string\n skillDir: string\n}\n\n/** Check if package ships a skills/ directory with SKILL.md or _SKILL.md subdirs */\nexport function getShippedSkills(name: string, cwd: string, version?: string): ShippedSkill[] {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return []\n\n const skillsPath = join(pkgPath, 'skills')\n if (!existsSync(skillsPath))\n return []\n\n return readdirSync(skillsPath, { withFileTypes: true })\n .filter(d => d.isDirectory() && (existsSync(join(skillsPath, d.name, 'SKILL.md')) || existsSync(join(skillsPath, d.name, '_SKILL.md'))))\n .map(d => ({ skillName: d.name, skillDir: join(skillsPath, d.name) }))\n}\n\n/** Create symlink from skills dir to shipped skill dir */\nexport function linkShippedSkill(baseDir: string, skillName: string, targetDir: string): void {\n const linkPath = join(baseDir, skillName)\n if (existsSync(linkPath)) {\n const stat = lstatSync(linkPath)\n if (stat.isSymbolicLink())\n unlinkSync(linkPath)\n else rmSync(linkPath, { recursive: true, force: true })\n }\n symlinkSync(targetDir, linkPath)\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"prepare.mjs","names":[],"sources":["../../src/core/prepare.ts"],"sourcesContent":["/**\n * Shared prepare utilities used by both the fast entry (src/prepare.ts)\n * and the full CLI command (src/commands/prepare.ts).\n *\n * Keep this module lightweight: no imports from agent/, cache/storage.ts,\n * or any module that pulls in sanitize/clack/citty.\n */\n\nimport type { SkillInfo } from './lockfile.ts'\nimport { existsSync, lstatSync, mkdirSync, readdirSync, rmSync, symlinkSync, unlinkSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { getCacheDir } from '../cache/version.ts'\n\n/** Map lockfile identity name to storage-safe cache key (crate:X → @skilld-crate/X) */\nfunction toStorageName(name: string): string {\n if (name.startsWith('crate:'))\n return `@skilld-crate/${name.slice('crate:'.length)}`\n return name\n}\n\n/** Resolve package directory: node_modules first, then global cache */\nexport function resolvePkgDir(name: string, cwd: string, version?: string): string | null {\n const nodeModulesPath = join(cwd, 'node_modules', name)\n if (existsSync(nodeModulesPath))\n return nodeModulesPath\n\n if (version) {\n const cachedPkgDir = join(getCacheDir(name, version), 'pkg')\n if (existsSync(join(cachedPkgDir, 'package.json')))\n return cachedPkgDir\n }\n\n return null\n}\n\n/** Restore .skilld/pkg symlink to node_modules if broken */\nexport function restorePkgSymlink(skillsDir: string, name: string, info: SkillInfo, cwd: string): void {\n const refsDir = join(skillsDir, name, '.skilld')\n const pkgLink = join(refsDir, 'pkg')\n\n if (!existsSync(join(skillsDir, name)))\n return\n\n // Use lstatSync to detect dangling symlinks — existsSync follows symlinks\n // and returns false for dangling ones, causing symlinkSync to throw EEXIST\n try {\n const stat = lstatSync(pkgLink)\n if (stat.isSymbolicLink()) {\n if (existsSync(pkgLink))\n return // symlink exists and target is valid\n unlinkSync(pkgLink) // dangling symlink — remove before re-creating\n }\n else {\n return // real file/dir exists at this path\n }\n }\n catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT')\n return // permission/IO error — bail instead of masking\n }\n\n const pkgName = toStorageName(info.packageName || name)\n const pkgDir = resolvePkgDir(pkgName, cwd, info.version)\n if (!pkgDir)\n return\n\n mkdirSync(refsDir, { recursive: true })\n symlinkSync(pkgDir, pkgLink)\n}\n\nexport interface ShippedSkill {\n skillName: string\n skillDir: string\n}\n\n/** Check if package ships a skills/ directory with SKILL.md or _SKILL.md subdirs */\nexport function getShippedSkills(name: string, cwd: string, version?: string): ShippedSkill[] {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return []\n\n const skillsPath = join(pkgPath, 'skills')\n if (!existsSync(skillsPath))\n return []\n\n return readdirSync(skillsPath, { withFileTypes: true })\n .filter(d => d.isDirectory() && (existsSync(join(skillsPath, d.name, 'SKILL.md')) || existsSync(join(skillsPath, d.name, '_SKILL.md'))))\n .map(d => ({ skillName: d.name, skillDir: join(skillsPath, d.name) }))\n}\n\n/** Create symlink from skills dir to shipped skill dir */\nexport function linkShippedSkill(baseDir: string, skillName: string, targetDir: string): void {\n const linkPath = join(baseDir, skillName)\n if (existsSync(linkPath)) {\n const stat = lstatSync(linkPath)\n if (stat.isSymbolicLink())\n unlinkSync(linkPath)\n else rmSync(linkPath, { recursive: true, force: true })\n }\n symlinkSync(targetDir, linkPath)\n}\n"],"mappings":";;;AAcA,SAAS,cAAc,MAAsB;AAC3C,KAAI,KAAK,WAAW,SAAS,CAC3B,QAAO,iBAAiB,KAAK,MAAM,EAAgB;AACrD,QAAO;;AAIT,SAAgB,cAAc,MAAc,KAAa,SAAiC;CACxF,MAAM,kBAAkB,KAAK,KAAK,gBAAgB,KAAK;AACvD,KAAI,WAAW,gBAAgB,CAC7B,QAAO;AAET,KAAI,SAAS;EACX,MAAM,eAAe,KAAK,YAAY,MAAM,QAAQ,EAAE,MAAM;AAC5D,MAAI,WAAW,KAAK,cAAc,eAAe,CAAC,CAChD,QAAO;;AAGX,QAAO;;AAIT,SAAgB,kBAAkB,WAAmB,MAAc,MAAiB,KAAmB;CACrG,MAAM,UAAU,KAAK,WAAW,MAAM,UAAU;CAChD,MAAM,UAAU,KAAK,SAAS,MAAM;AAEpC,KAAI,CAAC,WAAW,KAAK,WAAW,KAAK,CAAC,CACpC;AAIF,KAAI;AAEF,MADa,UAAU,QAAQ,CACtB,gBAAgB,EAAE;AACzB,OAAI,WAAW,QAAQ,CACrB;AACF,cAAW,QAAQ;QAGnB;UAGG,KAAK;AACV,MAAK,IAA8B,SAAS,SAC1C;;CAIJ,MAAM,SAAS,cADC,cAAc,KAAK,eAAe,KAAK,EACjB,KAAK,KAAK,QAAQ;AACxD,KAAI,CAAC,OACH;AAEF,WAAU,SAAS,EAAE,WAAW,MAAM,CAAC;AACvC,aAAY,QAAQ,QAAQ;;AAS9B,SAAgB,iBAAiB,MAAc,KAAa,SAAkC;CAC5F,MAAM,UAAU,cAAc,MAAM,KAAK,QAAQ;AACjD,KAAI,CAAC,QACH,QAAO,EAAE;CAEX,MAAM,aAAa,KAAK,SAAS,SAAS;AAC1C,KAAI,CAAC,WAAW,WAAW,CACzB,QAAO,EAAE;AAEX,QAAO,YAAY,YAAY,EAAE,eAAe,MAAM,CAAC,CACpD,QAAO,MAAK,EAAE,aAAa,KAAK,WAAW,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC,IAAI,WAAW,KAAK,YAAY,EAAE,MAAM,YAAY,CAAC,EAAE,CACvI,KAAI,OAAM;EAAE,WAAW,EAAE;EAAM,UAAU,KAAK,YAAY,EAAE,KAAA;EAAO,EAAE;;AAI1E,SAAgB,iBAAiB,SAAiB,WAAmB,WAAyB;CAC5F,MAAM,WAAW,KAAK,SAAS,UAAU;AACzC,KAAI,WAAW,SAAS,CAEtB,KADa,UAAU,SAAS,CACvB,gBAAgB,CACvB,YAAW,SAAS;KACjB,QAAO,UAAU;EAAE,WAAW;EAAM,OAAO;EAAM,CAAC;AAEzD,aAAY,WAAW,SAAS"}
|
|
@@ -1,16 +1,8 @@
|
|
|
1
|
-
import "./config.mjs";
|
|
2
|
-
import "./package-json.mjs";
|
|
3
1
|
import { i as restorePkgSymlink, n as linkShippedSkill, t as getShippedSkills } from "./prepare.mjs";
|
|
4
|
-
import "./sanitize.mjs";
|
|
5
|
-
import "./cache.mjs";
|
|
6
|
-
import "./yaml.mjs";
|
|
7
|
-
import "./markdown.mjs";
|
|
8
2
|
import { n as getSharedSkillsDir } from "./shared.mjs";
|
|
9
|
-
import "./sources.mjs";
|
|
10
3
|
import { a as targets } from "./detect.mjs";
|
|
11
|
-
import {
|
|
4
|
+
import { r as linkSkillToAgents } from "./install.mjs";
|
|
12
5
|
import "./agent.mjs";
|
|
13
|
-
import "./libs/@sinclair/typebox.mjs";
|
|
14
6
|
import { b as resolveAgent } from "./cli-helpers.mjs";
|
|
15
7
|
import { i as readLock, s as writeLock } from "./lockfile.mjs";
|
|
16
8
|
import { t as getProjectState } from "./skills.mjs";
|
|
@@ -18,15 +10,6 @@ import { join } from "pathe";
|
|
|
18
10
|
import { existsSync, mkdirSync } from "node:fs";
|
|
19
11
|
import * as p from "@clack/prompts";
|
|
20
12
|
import { defineCommand } from "citty";
|
|
21
|
-
//#region src/commands/prepare.ts
|
|
22
|
-
/**
|
|
23
|
-
* Prepare command — lightweight hook for package.json "prepare" script.
|
|
24
|
-
*
|
|
25
|
-
* Designed to run on every `pnpm install` / `npm install`. Blocking, fast, no LLM calls.
|
|
26
|
-
* 1. Restore broken symlinks from lockfile (like `install` but skips doc fetching)
|
|
27
|
-
* 2. Auto-install shipped skills from deps (just symlinks + lockfile writes)
|
|
28
|
-
* 3. Report outdated skills count and suggest `skilld update`
|
|
29
|
-
*/
|
|
30
13
|
const prepareCommandDef = defineCommand({
|
|
31
14
|
meta: {
|
|
32
15
|
name: "prepare",
|
|
@@ -89,7 +72,6 @@ const prepareCommandDef = defineCommand({
|
|
|
89
72
|
}
|
|
90
73
|
}
|
|
91
74
|
});
|
|
92
|
-
//#endregion
|
|
93
75
|
export { prepareCommandDef };
|
|
94
76
|
|
|
95
77
|
//# sourceMappingURL=prepare2.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepare2.mjs","names":["agents"],"sources":["../../src/commands/prepare.ts"],"sourcesContent":["/**\n * Prepare command — lightweight hook for package.json \"prepare\" script.\n *\n * Designed to run on every `pnpm install` / `npm install`. Blocking, fast, no LLM calls.\n * 1. Restore broken symlinks from lockfile (like `install` but skips doc fetching)\n * 2. Auto-install shipped skills from deps (just symlinks + lockfile writes)\n * 3. Report outdated skills count and suggest `skilld update`\n */\n\nimport { existsSync, mkdirSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join } from 'pathe'\nimport { agents, linkSkillToAgents } from '../agent/index.ts'\nimport { resolveAgent } from '../cli-helpers.ts'\nimport { readLock, writeLock } from '../core/lockfile.ts'\nimport { getShippedSkills, linkShippedSkill, restorePkgSymlink } from '../core/prepare.ts'\nimport { getSharedSkillsDir } from '../core/shared.ts'\nimport { getProjectState } from '../core/skills.ts'\n\nexport const prepareCommandDef = defineCommand({\n meta: { name: 'prepare', description: 'Restore references and sync shipped skills (for package.json hooks)' },\n args: {\n agent: {\n type: 'enum' as const,\n options: Object.keys(agents),\n alias: 'a',\n description: 'Target agent',\n },\n },\n async run({ args }) {\n const cwd = process.cwd()\n\n const agent = resolveAgent(args.agent)\n if (!agent || agent === 'none')\n return\n\n const agentConfig = agents[agent]\n const shared = getSharedSkillsDir(cwd)\n const skillsDir = shared || join(cwd, agentConfig.skillsDir)\n\n // ── Fast path: read primary lockfile, check all skills intact ──\n\n const lock = readLock(skillsDir)\n if (lock && Object.keys(lock.skills).length > 0) {\n let allIntact = true\n\n for (const [name, info] of Object.entries(lock.skills)) {\n if (!info.version)\n continue\n\n const skillDir = join(skillsDir, name)\n if (existsSync(skillDir)) {\n // Skill dir exists; for non-shipped, also check .skilld/pkg symlink\n if (info.source !== 'shipped')\n restorePkgSymlink(skillsDir, name, info, cwd)\n continue\n }\n\n // Skill dir missing, needs restore\n allIntact = false\n\n if (info.source === 'shipped') {\n const pkgName = info.packageName || name\n const shipped = getShippedSkills(pkgName, cwd, info.version)\n const match = shipped.find(s => s.skillName === name)\n if (match)\n linkShippedSkill(skillsDir, name, match.skillDir)\n }\n }\n\n // If all skills intact, skip expensive getProjectState entirely\n if (allIntact)\n return\n }\n\n // ── Slow path: discover new shipped skills + report outdated ──\n\n const state = await getProjectState(cwd)\n let shippedCount = 0\n\n if (state.shipped.length > 0) {\n mkdirSync(skillsDir, { recursive: true })\n\n for (const entry of state.shipped) {\n const version = state.deps.get(entry.packageName)?.replace(/^[\\^~>=<]+/, '') || '0.0.0'\n\n for (const skill of entry.skills) {\n linkShippedSkill(skillsDir, skill.skillName, skill.skillDir)\n writeLock(skillsDir, skill.skillName, {\n packageName: entry.packageName,\n version,\n source: 'shipped',\n syncedAt: new Date().toISOString().split('T')[0],\n generator: 'skilld',\n })\n\n if (shared)\n linkSkillToAgents(skill.skillName, shared, cwd, agent)\n\n shippedCount++\n }\n }\n\n if (shippedCount > 0)\n p.log.success(`Installed ${shippedCount} shipped skill${shippedCount > 1 ? 's' : ''}`)\n }\n\n if (state.outdated.length > 0) {\n const n = state.outdated.length\n p.log.info(`${n} package${n > 1 ? 's' : ''} ha${n > 1 ? 've' : 's'} new features and/or breaking changes. Run \\`skilld update\\` to sync.`)\n }\n },\n})\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"prepare2.mjs","names":["agents"],"sources":["../../src/commands/prepare.ts"],"sourcesContent":["/**\n * Prepare command — lightweight hook for package.json \"prepare\" script.\n *\n * Designed to run on every `pnpm install` / `npm install`. Blocking, fast, no LLM calls.\n * 1. Restore broken symlinks from lockfile (like `install` but skips doc fetching)\n * 2. Auto-install shipped skills from deps (just symlinks + lockfile writes)\n * 3. Report outdated skills count and suggest `skilld update`\n */\n\nimport { existsSync, mkdirSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join } from 'pathe'\nimport { agents, linkSkillToAgents } from '../agent/index.ts'\nimport { resolveAgent } from '../cli-helpers.ts'\nimport { readLock, writeLock } from '../core/lockfile.ts'\nimport { getShippedSkills, linkShippedSkill, restorePkgSymlink } from '../core/prepare.ts'\nimport { getSharedSkillsDir } from '../core/shared.ts'\nimport { getProjectState } from '../core/skills.ts'\n\nexport const prepareCommandDef = defineCommand({\n meta: { name: 'prepare', description: 'Restore references and sync shipped skills (for package.json hooks)' },\n args: {\n agent: {\n type: 'enum' as const,\n options: Object.keys(agents),\n alias: 'a',\n description: 'Target agent',\n },\n },\n async run({ args }) {\n const cwd = process.cwd()\n\n const agent = resolveAgent(args.agent)\n if (!agent || agent === 'none')\n return\n\n const agentConfig = agents[agent]\n const shared = getSharedSkillsDir(cwd)\n const skillsDir = shared || join(cwd, agentConfig.skillsDir)\n\n // ── Fast path: read primary lockfile, check all skills intact ──\n\n const lock = readLock(skillsDir)\n if (lock && Object.keys(lock.skills).length > 0) {\n let allIntact = true\n\n for (const [name, info] of Object.entries(lock.skills)) {\n if (!info.version)\n continue\n\n const skillDir = join(skillsDir, name)\n if (existsSync(skillDir)) {\n // Skill dir exists; for non-shipped, also check .skilld/pkg symlink\n if (info.source !== 'shipped')\n restorePkgSymlink(skillsDir, name, info, cwd)\n continue\n }\n\n // Skill dir missing, needs restore\n allIntact = false\n\n if (info.source === 'shipped') {\n const pkgName = info.packageName || name\n const shipped = getShippedSkills(pkgName, cwd, info.version)\n const match = shipped.find(s => s.skillName === name)\n if (match)\n linkShippedSkill(skillsDir, name, match.skillDir)\n }\n }\n\n // If all skills intact, skip expensive getProjectState entirely\n if (allIntact)\n return\n }\n\n // ── Slow path: discover new shipped skills + report outdated ──\n\n const state = await getProjectState(cwd)\n let shippedCount = 0\n\n if (state.shipped.length > 0) {\n mkdirSync(skillsDir, { recursive: true })\n\n for (const entry of state.shipped) {\n const version = state.deps.get(entry.packageName)?.replace(/^[\\^~>=<]+/, '') || '0.0.0'\n\n for (const skill of entry.skills) {\n linkShippedSkill(skillsDir, skill.skillName, skill.skillDir)\n writeLock(skillsDir, skill.skillName, {\n packageName: entry.packageName,\n version,\n source: 'shipped',\n syncedAt: new Date().toISOString().split('T')[0],\n generator: 'skilld',\n })\n\n if (shared)\n linkSkillToAgents(skill.skillName, shared, cwd, agent)\n\n shippedCount++\n }\n }\n\n if (shippedCount > 0)\n p.log.success(`Installed ${shippedCount} shipped skill${shippedCount > 1 ? 's' : ''}`)\n }\n\n if (state.outdated.length > 0) {\n const n = state.outdated.length\n p.log.info(`${n} package${n > 1 ? 's' : ''} ha${n > 1 ? 've' : 's'} new features and/or breaking changes. Run \\`skilld update\\` to sync.`)\n }\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;EAoBA,SAAa,OAAA,KAAA,QAAoB;EAC/B,OAAM;EAAE,aAAM;EAAW,EAAA;OAAoF,IAAA,EAAA,QAAA;EAC7G,MAAM,MACJ,QAAO,KAAA;EACL,MAAM,QAAA,aAAA,KAAA,MAAA;AACN,MAAA,CAAA,SAAS,UAAYA,OAAO;EAC5B,MAAA,cAAO,QAAA;EACP,MAAA,SAAa,mBAAA,IAAA;EACd,MACF,YAAA,UAAA,KAAA,KAAA,YAAA,UAAA;EACD,MAAM,OAAM,SAAQ,UAAA;AAClB,MAAA,QAAY,OAAA,KAAQ,KAAK,OAAA,CAAA,SAAA,GAAA;GAEzB,IAAA,YAAc;AACd,QAAK,MAAA,CAAA,MAAS,SAAU,OACtB,QAAA,KAAA,OAAA,EAAA;AAEF,QAAM,CAAA,KAAA,QAAcA;AACpB,QAAM,WAAS,KAAA,WAAA,KAAuB,CAAA,EAAA;AACtC,SAAM,KAAA,WAAY,UAAe,mBAAiB,WAAU,MAAA,MAAA,IAAA;AAI5D;;AAEE,gBAAI;AAEJ,QAAK,KAAA,WAAa,WAAS;KACzB,MAAK,QAAK,iBACR,KAAA,eAAA,MAAA,KAAA,KAAA,QAAA,CAAA,MAAA,MAAA,EAAA,cAAA,KAAA;AAGF,SAAI,MAAA,kBADkB,WACI,MAAA,MAAA,SAAA;;;;;EAU1B,MAAI,QAAK,MAAA,gBAAsB,IAAA;MAG7B,eADgB;AAEhB,MAAA,MAAI,QACF,SAAA,GAAA;;;IAKN,MAAI,UACF,MAAA,KAAA,IAAA,MAAA,YAAA,EAAA,QAAA,cAAA,GAAA,IAAA;;AAKJ,sBAAoB,WAAA,MAAgB,WAAI,MAAA,SAAA;AACxC,eAAI,WAAe,MAAA,WAAA;MAEf,aAAM,MAAQ;MAChB;MAEA,QAAW;MACT,2BAA2B,IAAI,MAAM,EAAA,aAAc,CAAA,MAAQ,IAAA,CAAA;MAE3D,WAAW;MACT,CAAA;AACA,SAAA,OAAU,mBAAiB,MAAA,WAAW,QAAA,KAAA,MAAA;;;;OAIpC,eAAA,EAAA,GAAA,IAAA,QAAc,aAAO,aAAoB,gBAAK,eAAA,IAAA,MAAA,KAAA;;MAE/C,MAAC,SAAA,SAAA,GAAA;GAEF,MAAI,IAAA,MACF,SAAA;AAEF,KAAA,IAAA,KAAA,GAAA,EAAA,UAAA,IAAA,IAAA,MAAA,GAAA,KAAA,IAAA,IAAA,OAAA,IAAA,uEAAA;;;CAIJ,CAAA;AAIF,SAAI"}
|
package/dist/_chunks/prompts.mjs
CHANGED
|
@@ -1,43 +1,24 @@
|
|
|
1
1
|
import { n as sanitizeMarkdown, t as repairMarkdown } from "./sanitize.mjs";
|
|
2
2
|
import { t as yamlEscape } from "./yaml.mjs";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
//#region src/agent/prompts/optional/budget.ts
|
|
8
|
-
/**
|
|
9
|
-
* Dynamic budget allocation for skill sections.
|
|
10
|
-
*
|
|
11
|
-
* Total SKILL.md target is ~500 lines. Overhead (frontmatter, header, search, footer)
|
|
12
|
-
* is subtracted to get the available body budget, which is divided among enabled sections.
|
|
13
|
-
* When a package has many releases, budgets scale up.
|
|
14
|
-
*/
|
|
3
|
+
import { a as getPackageRules, i as getFilePatterns } from "./package-registry.mjs";
|
|
4
|
+
import { i as resolveSkilldCommand } from "./shared.mjs";
|
|
5
|
+
import { t as computeSkillDirName } from "./install.mjs";
|
|
6
|
+
import { dirname } from "pathe";
|
|
15
7
|
const TOTAL_TARGET = 500;
|
|
16
8
|
const DEFAULT_OVERHEAD = 30;
|
|
17
|
-
/** Available body lines after overhead is subtracted */
|
|
18
9
|
function remainingLines(overheadLines) {
|
|
19
10
|
return TOTAL_TARGET - (overheadLines ?? DEFAULT_OVERHEAD);
|
|
20
11
|
}
|
|
21
|
-
/** Scale max lines based on enabled section count and available remaining space. */
|
|
22
12
|
function maxLines(min, max, sectionCount, overheadLines) {
|
|
23
13
|
const remaining = remainingLines(overheadLines);
|
|
24
|
-
const
|
|
25
|
-
const perSection = Math.floor(remaining / sections);
|
|
14
|
+
const perSection = Math.floor(remaining / Math.max(1, sectionCount ?? 1));
|
|
26
15
|
const scale = budgetScale(sectionCount);
|
|
27
16
|
return Math.max(min, Math.min(Math.round(max * scale), perSection));
|
|
28
17
|
}
|
|
29
|
-
/** Scale item count based on enabled section count. */
|
|
30
18
|
function maxItems(min, max, sectionCount) {
|
|
31
19
|
const scale = budgetScale(sectionCount);
|
|
32
20
|
return Math.max(min, Math.round(max * scale));
|
|
33
21
|
}
|
|
34
|
-
/**
|
|
35
|
-
* Boost budget for high-churn packages based on API-level release density.
|
|
36
|
-
* Combines major/minor release count with current minor version as a churn signal.
|
|
37
|
-
*
|
|
38
|
-
* @param significantReleases - Count of major/minor releases (patch releases excluded)
|
|
39
|
-
* @param minorVersion - Current minor version number (e.g., 15 for v3.15.0)
|
|
40
|
-
*/
|
|
41
22
|
function releaseBoost(significantReleases, minorVersion) {
|
|
42
23
|
const combined = (!significantReleases ? 0 : significantReleases <= 5 ? 0 : significantReleases <= 15 ? 1 : 2) + (!minorVersion ? 0 : minorVersion <= 3 ? 0 : minorVersion <= 10 ? 1 : 2);
|
|
43
24
|
if (combined <= 0) return 1;
|
|
@@ -50,41 +31,32 @@ function budgetScale(sectionCount) {
|
|
|
50
31
|
if (sectionCount === 3) return .7;
|
|
51
32
|
return .6;
|
|
52
33
|
}
|
|
53
|
-
//#endregion
|
|
54
|
-
//#region src/agent/prompts/optional/validate.ts
|
|
55
|
-
/** Warns if content exceeds 150% of max lines */
|
|
56
34
|
function checkLineCount(content, max) {
|
|
57
35
|
const lines = content.split("\n").length;
|
|
58
36
|
if (lines > Math.round(max * 1.5)) return [{ warning: `Output ${lines} lines exceeds ${max} max by >50%` }];
|
|
59
37
|
return [];
|
|
60
38
|
}
|
|
61
|
-
/** Warns if content is fewer than 3 lines */
|
|
62
39
|
function checkSparseness(content) {
|
|
63
40
|
const lines = content.split("\n").length;
|
|
64
41
|
if (lines < 3) return [{ warning: `Output only ${lines} lines — likely too sparse` }];
|
|
65
42
|
return [];
|
|
66
43
|
}
|
|
67
|
-
/** Warns if sourced/bullets ratio is below minRatio */
|
|
68
44
|
function checkSourceCoverage(content, minRatio = .8) {
|
|
69
45
|
const bullets = (content.match(/^- /gm) || []).length;
|
|
70
46
|
const sourced = (content.match(/\[source\]/g) || []).length;
|
|
71
47
|
if (bullets > 2 && sourced / bullets < minRatio) return [{ warning: `Only ${sourced}/${bullets} items have source citations (need ${Math.round(minRatio * 100)}% coverage)` }];
|
|
72
48
|
return [];
|
|
73
49
|
}
|
|
74
|
-
/** Warns if source links are missing .skilld/ prefix */
|
|
75
50
|
function checkSourcePaths(content) {
|
|
76
51
|
const badPaths = content.match(/\[source\]\(\.\/(docs|issues|discussions|releases|pkg|guide)\//g);
|
|
77
52
|
if (badPaths?.length) return [{ warning: `${badPaths.length} source links missing .skilld/ prefix` }];
|
|
78
53
|
return [];
|
|
79
54
|
}
|
|
80
|
-
/** Warns if source links use absolute filesystem paths instead of relative ./.skilld/ paths */
|
|
81
55
|
function checkAbsolutePaths(content) {
|
|
82
56
|
const absPaths = content.match(/\[source\]\(\/[^)]+\)/g);
|
|
83
57
|
if (absPaths?.length) return [{ warning: `${absPaths.length} source links use absolute paths — must use relative ./.skilld/ paths` }];
|
|
84
58
|
return [];
|
|
85
59
|
}
|
|
86
|
-
//#endregion
|
|
87
|
-
//#region src/agent/prompts/optional/api-changes.ts
|
|
88
60
|
function apiChangesSection({ packageName, version, hasReleases, hasChangelog, hasDocs, hasIssues, hasDiscussions, pkgFiles, features, enabledSectionCount, releaseCount, overheadLines }) {
|
|
89
61
|
const [, major, minor] = version?.match(/^(\d+)\.(\d+)/) ?? [];
|
|
90
62
|
const boost = releaseBoost(releaseCount, minor ? Number(minor) : void 0);
|
|
@@ -207,8 +179,6 @@ Each item: BREAKING/DEPRECATED/NEW label + API name + what changed + source link
|
|
|
207
179
|
].filter(Boolean)
|
|
208
180
|
};
|
|
209
181
|
}
|
|
210
|
-
//#endregion
|
|
211
|
-
//#region src/agent/prompts/optional/best-practices.ts
|
|
212
182
|
function bestPracticesSection({ packageName, hasIssues, hasDiscussions, hasReleases, hasChangelog, hasDocs, pkgFiles, features, enabledSectionCount, releaseCount, version, overheadLines }) {
|
|
213
183
|
const [, , minor] = version?.match(/^(\d+)\.(\d+)/) ?? [];
|
|
214
184
|
const boost = 1 + (releaseBoost(releaseCount, minor ? Number(minor) : void 0) - 1) * .5;
|
|
@@ -300,8 +270,6 @@ Each item: markdown list item (-) + ${packageName}-specific pattern + why it's p
|
|
|
300
270
|
]
|
|
301
271
|
};
|
|
302
272
|
}
|
|
303
|
-
//#endregion
|
|
304
|
-
//#region src/agent/prompts/optional/custom.ts
|
|
305
273
|
function customSection({ heading, body }, enabledSectionCount, overheadLines) {
|
|
306
274
|
const customMaxLines = maxLines(50, 80, enabledSectionCount, overheadLines);
|
|
307
275
|
return {
|
|
@@ -324,25 +292,19 @@ Content addressing the user's instructions above, using concise examples and sou
|
|
|
324
292
|
rules: [`- **Custom section "${heading}":** MAX ${customMaxLines} lines, use \`## ${heading}\` heading`]
|
|
325
293
|
};
|
|
326
294
|
}
|
|
327
|
-
//#endregion
|
|
328
|
-
//#region src/agent/prompts/prompt.ts
|
|
329
|
-
/** Output file per section (inside .skilld/) */
|
|
330
295
|
const SECTION_OUTPUT_FILES = {
|
|
331
296
|
"best-practices": "_BEST_PRACTICES.md",
|
|
332
297
|
"api-changes": "_API_CHANGES.md",
|
|
333
298
|
"custom": "_CUSTOM.md"
|
|
334
299
|
};
|
|
335
|
-
/** Merge order for final SKILL.md body */
|
|
336
300
|
const SECTION_MERGE_ORDER = [
|
|
337
301
|
"api-changes",
|
|
338
302
|
"best-practices",
|
|
339
303
|
"custom"
|
|
340
304
|
];
|
|
341
|
-
/** Wrap section content with HTML comment markers for targeted re-assembly */
|
|
342
305
|
function wrapSection(section, content) {
|
|
343
306
|
return `<!-- skilld:${section} -->\n${content}\n<!-- /skilld:${section} -->`;
|
|
344
307
|
}
|
|
345
|
-
/** Extract marker-delimited sections from existing SKILL.md */
|
|
346
308
|
function extractMarkedSections(md) {
|
|
347
309
|
const sections = /* @__PURE__ */ new Map();
|
|
348
310
|
for (const section of SECTION_MERGE_ORDER) {
|
|
@@ -357,10 +319,6 @@ function extractMarkedSections(md) {
|
|
|
357
319
|
}
|
|
358
320
|
return sections;
|
|
359
321
|
}
|
|
360
|
-
/**
|
|
361
|
-
* Group files by parent directory with counts
|
|
362
|
-
* e.g. `/path/to/docs/api/ (15 .md files)`
|
|
363
|
-
*/
|
|
364
322
|
function formatDocTree(files) {
|
|
365
323
|
const dirs = /* @__PURE__ */ new Map();
|
|
366
324
|
for (const f of files) {
|
|
@@ -390,7 +348,6 @@ Use \`${cmd} search "query" -p ${packageName}\` as your primary research tool
|
|
|
390
348
|
|
|
391
349
|
${table}`;
|
|
392
350
|
}
|
|
393
|
-
/** Shared preamble: Security, references table, Quality Principles, doc tree */
|
|
394
351
|
function buildPreamble(opts) {
|
|
395
352
|
const { packageName, skillDir, hasIssues, hasDiscussions, hasReleases, hasChangelog, docFiles, docsType = "docs", hasShippedDocs = false, versionContext } = opts;
|
|
396
353
|
const docsSection = docFiles?.length ? `<external-docs>\n**Documentation** (use Read tool to explore):\n${formatDocTree(docFiles)}\n</external-docs>` : "";
|
|
@@ -424,19 +381,12 @@ function getSectionDef(section, ctx, customPrompt) {
|
|
|
424
381
|
case "custom": return customPrompt ? customSection(customPrompt, ctx.enabledSectionCount, ctx.overheadLines) : null;
|
|
425
382
|
}
|
|
426
383
|
}
|
|
427
|
-
/**
|
|
428
|
-
* Get the validate function for a section using default context (validators use fixed thresholds).
|
|
429
|
-
* Returns null if section has no validator.
|
|
430
|
-
*/
|
|
431
384
|
function getSectionValidator(section) {
|
|
432
385
|
return getSectionDef(section, { packageName: "" }, section === "custom" ? {
|
|
433
386
|
heading: "Custom",
|
|
434
387
|
body: ""
|
|
435
388
|
} : void 0)?.validate ?? null;
|
|
436
389
|
}
|
|
437
|
-
/**
|
|
438
|
-
* Build prompt for a single section
|
|
439
|
-
*/
|
|
440
390
|
function buildSectionPrompt(opts) {
|
|
441
391
|
const { packageName, hasIssues, hasDiscussions, hasReleases, hasChangelog, version, section, customPrompt, skillDir } = opts;
|
|
442
392
|
const versionContext = version ? ` v${version}` : "";
|
|
@@ -502,9 +452,6 @@ Write your final output to the file \`${skillDir}/.skilld/${outputFile}\` using
|
|
|
502
452
|
After writing, run \`${cmd} validate ${skillDir}/.skilld/${outputFile}\` and fix any warnings before finishing. If unavailable, use \`${fallbackCmd} validate ${skillDir}/.skilld/${outputFile}\`.
|
|
503
453
|
`;
|
|
504
454
|
}
|
|
505
|
-
/**
|
|
506
|
-
* Build prompts for all selected sections, sharing the computed preamble
|
|
507
|
-
*/
|
|
508
455
|
function buildAllSectionPrompts(opts) {
|
|
509
456
|
const result = /* @__PURE__ */ new Map();
|
|
510
457
|
for (const section of opts.sections) {
|
|
@@ -517,14 +464,6 @@ function buildAllSectionPrompts(opts) {
|
|
|
517
464
|
}
|
|
518
465
|
return result;
|
|
519
466
|
}
|
|
520
|
-
/**
|
|
521
|
-
* Transform an agent-specific prompt into a portable prompt for any LLM.
|
|
522
|
-
* - Rewrites .skilld/ paths → ./references/
|
|
523
|
-
* - Strips ## Output section (file-writing instructions)
|
|
524
|
-
* - Strips skilld search/validate instructions
|
|
525
|
-
* - Replaces tool-specific language with generic equivalents
|
|
526
|
-
* - Strips agent-specific rules
|
|
527
|
-
*/
|
|
528
467
|
function portabilizePrompt(prompt, section) {
|
|
529
468
|
let out = prompt;
|
|
530
469
|
out = out.replace(/`[^`]*\/\.skilld\//g, (m) => m.replace(/[^`]*\/\.skilld\//, "./references/"));
|
|
@@ -551,130 +490,6 @@ function portabilizePrompt(prompt, section) {
|
|
|
551
490
|
out = out.replace(/\n{3,}/g, "\n\n");
|
|
552
491
|
return out;
|
|
553
492
|
}
|
|
554
|
-
//#endregion
|
|
555
|
-
//#region src/agent/install.ts
|
|
556
|
-
/**
|
|
557
|
-
* Sanitize skill name for filesystem
|
|
558
|
-
*/
|
|
559
|
-
function sanitizeName(name) {
|
|
560
|
-
return name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.\-]+|[.\-]+$/g, "").slice(0, 255) || "unnamed-skill";
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Compute skill directory name from package name with -skilld suffix.
|
|
564
|
-
* No collisions for monorepo packages (each gets a unique name).
|
|
565
|
-
*
|
|
566
|
-
* Examples:
|
|
567
|
-
* vue → vue-skilld
|
|
568
|
-
* @unhead/vue → unhead-vue-skilld
|
|
569
|
-
* @unhead/react → unhead-react-skilld
|
|
570
|
-
*/
|
|
571
|
-
function computeSkillDirName(packageName) {
|
|
572
|
-
return `${sanitizeName(packageName)}-skilld`;
|
|
573
|
-
}
|
|
574
|
-
/**
|
|
575
|
-
* Install a skill directly to agent skill directories.
|
|
576
|
-
* When agents are explicitly specified, creates directories as needed.
|
|
577
|
-
* When falling back to auto-detection, only writes to agents whose skills dir already exists.
|
|
578
|
-
*/
|
|
579
|
-
function installSkillForAgents(skillName, skillContent, options = {}) {
|
|
580
|
-
const isGlobal = options.global ?? false;
|
|
581
|
-
const cwd = options.cwd || process.cwd();
|
|
582
|
-
const sanitized = sanitizeName(skillName);
|
|
583
|
-
const explicit = !!options.agents;
|
|
584
|
-
const targetAgents = options.agents || detectInstalledAgents();
|
|
585
|
-
const installed = [];
|
|
586
|
-
const skipped = [];
|
|
587
|
-
const paths = [];
|
|
588
|
-
const writtenDirs = /* @__PURE__ */ new Set();
|
|
589
|
-
for (const agentType of targetAgents) {
|
|
590
|
-
const agent = targets[agentType];
|
|
591
|
-
if (isGlobal && !agent.globalSkillsDir) {
|
|
592
|
-
skipped.push({
|
|
593
|
-
agent: agentType,
|
|
594
|
-
reason: "no global support"
|
|
595
|
-
});
|
|
596
|
-
continue;
|
|
597
|
-
}
|
|
598
|
-
const baseDir = isGlobal ? agent.globalSkillsDir : join(cwd, agent.skillsDir);
|
|
599
|
-
if (!explicit && !existsSync(baseDir)) {
|
|
600
|
-
skipped.push({
|
|
601
|
-
agent: agentType,
|
|
602
|
-
reason: "skills dir not found"
|
|
603
|
-
});
|
|
604
|
-
continue;
|
|
605
|
-
}
|
|
606
|
-
if (isGlobal && (writtenDirs.has(baseDir) || agent.additionalSkillsDirs.some((d) => writtenDirs.has(d)))) {
|
|
607
|
-
skipped.push({
|
|
608
|
-
agent: agentType,
|
|
609
|
-
reason: "already covered by another agent dir"
|
|
610
|
-
});
|
|
611
|
-
continue;
|
|
612
|
-
}
|
|
613
|
-
const skillDir = join(baseDir, sanitized);
|
|
614
|
-
const skilldDir = join(skillDir, ".skilld");
|
|
615
|
-
mkdirSync(skilldDir, { recursive: true });
|
|
616
|
-
writeFileSync(join(skilldDir, "_SKILL.md"), sanitizeMarkdown(repairMarkdown(skillContent)));
|
|
617
|
-
if (options.files) for (const [filename, content] of Object.entries(options.files)) writeFileSync(join(skillDir, filename), filename.endsWith(".md") ? sanitizeMarkdown(repairMarkdown(content)) : content);
|
|
618
|
-
installed.push(agentType);
|
|
619
|
-
paths.push(skillDir);
|
|
620
|
-
writtenDirs.add(baseDir);
|
|
621
|
-
}
|
|
622
|
-
return {
|
|
623
|
-
installed,
|
|
624
|
-
skipped,
|
|
625
|
-
paths
|
|
626
|
-
};
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* Create a relative symlink from the target agent's skills dir to the shared .skills/ dir.
|
|
630
|
-
* Only creates directories for the explicit target agent; other agents must already have
|
|
631
|
-
* their skills dir present. This prevents skilld from polluting projects with dirs
|
|
632
|
-
* for agents the user doesn't use (e.g. .gemini/, .agent/).
|
|
633
|
-
*/
|
|
634
|
-
function linkSkillToAgents(skillName, sharedDir, cwd, agentType) {
|
|
635
|
-
const targetAgents = agentType ? [[agentType, targets[agentType]]] : Object.entries(targets);
|
|
636
|
-
const linkedDirs = /* @__PURE__ */ new Set();
|
|
637
|
-
for (const [type, agent] of targetAgents) {
|
|
638
|
-
const agentSkillsDir = join(cwd, agent.skillsDir);
|
|
639
|
-
if (agentType === type) mkdirSync(agentSkillsDir, { recursive: true });
|
|
640
|
-
else {
|
|
641
|
-
if (!existsSync(agentSkillsDir)) continue;
|
|
642
|
-
if (agent.additionalSkillsDirs.map((d) => join(cwd, d)).some((d) => linkedDirs.has(d))) {
|
|
643
|
-
const staleTarget = join(agentSkillsDir, skillName);
|
|
644
|
-
try {
|
|
645
|
-
if (lstatSync(staleTarget).isSymbolicLink() && !existsSync(staleTarget)) unlinkSync(staleTarget);
|
|
646
|
-
} catch {}
|
|
647
|
-
continue;
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
const target = join(agentSkillsDir, skillName);
|
|
651
|
-
let isSymlink = false;
|
|
652
|
-
let targetExists = false;
|
|
653
|
-
try {
|
|
654
|
-
const stat = lstatSync(target);
|
|
655
|
-
targetExists = true;
|
|
656
|
-
isSymlink = stat.isSymbolicLink();
|
|
657
|
-
} catch {}
|
|
658
|
-
if (targetExists && !isSymlink) continue;
|
|
659
|
-
if (isSymlink) unlinkSync(target);
|
|
660
|
-
symlinkSync(relative(agentSkillsDir, join(sharedDir, skillName)), target);
|
|
661
|
-
linkedDirs.add(agentSkillsDir);
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
/**
|
|
665
|
-
* Remove per-agent symlinks for a skill when removing from shared dir.
|
|
666
|
-
*/
|
|
667
|
-
function unlinkSkillFromAgents(skillName, cwd, agentType) {
|
|
668
|
-
const targetAgents = agentType ? [[agentType, targets[agentType]]] : Object.entries(targets);
|
|
669
|
-
for (const [, agent] of targetAgents) {
|
|
670
|
-
const target = join(cwd, agent.skillsDir, skillName);
|
|
671
|
-
try {
|
|
672
|
-
if (lstatSync(target).isSymbolicLink()) unlinkSync(target);
|
|
673
|
-
} catch {}
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
//#endregion
|
|
677
|
-
//#region src/agent/prompts/skill.ts
|
|
678
493
|
function generateSkillMd(opts) {
|
|
679
494
|
const header = generatePackageHeader(opts);
|
|
680
495
|
const search = !opts.eject && opts.features?.search !== false ? generateSearchBlock(opts.name) : "";
|
|
@@ -687,7 +502,6 @@ function generateSkillMd(opts) {
|
|
|
687
502
|
const footer = generateFooter(opts.relatedSkills);
|
|
688
503
|
return sanitizeMarkdown(repairMarkdown(`${generateFrontmatter(opts)}${content}\n${footer}`));
|
|
689
504
|
}
|
|
690
|
-
/** Format ISO date as short absolute date: "Jan 2025", "Dec 2024" */
|
|
691
505
|
function formatShortDate(isoDate) {
|
|
692
506
|
const date = new Date(isoDate);
|
|
693
507
|
if (Number.isNaN(date.getTime())) return "";
|
|
@@ -739,10 +553,6 @@ function generatePackageHeader({ name, version, distTags, repoUrl, hasIssues, ha
|
|
|
739
553
|
if (refs.length > 0) lines.push(`**References:** ${refs.join(" • ")}`);
|
|
740
554
|
return lines.join("\n");
|
|
741
555
|
}
|
|
742
|
-
/**
|
|
743
|
-
* Expand a package name into keyword variants for better trigger matching.
|
|
744
|
-
* e.g. "@nuxt/ui" → ["nuxt ui", "nuxt/ui"], "vue-router" → ["vue router"]
|
|
745
|
-
*/
|
|
746
556
|
function expandPackageName(name) {
|
|
747
557
|
const variants = /* @__PURE__ */ new Set();
|
|
748
558
|
const unscoped = name.replace(/^@/, "");
|
|
@@ -757,10 +567,6 @@ function expandPackageName(name) {
|
|
|
757
567
|
variants.delete(name);
|
|
758
568
|
return [...variants];
|
|
759
569
|
}
|
|
760
|
-
/**
|
|
761
|
-
* Extract and expand GitHub repo name into keyword variants.
|
|
762
|
-
* e.g. "motion-v" → ["motion-v", "motion v"]
|
|
763
|
-
*/
|
|
764
570
|
function expandRepoName(repoUrl) {
|
|
765
571
|
const variants = /* @__PURE__ */ new Set();
|
|
766
572
|
const repoName = repoUrl.startsWith("http") ? repoUrl.split("/").pop() : repoUrl.split("/").pop();
|
|
@@ -820,7 +626,6 @@ function generateFooter(relatedSkills) {
|
|
|
820
626
|
if (relatedSkills.length === 0) return "";
|
|
821
627
|
return `\nRelated: ${relatedSkills.join(", ")}\n`;
|
|
822
628
|
}
|
|
823
|
-
|
|
824
|
-
export { sanitizeName as a, SECTION_OUTPUT_FILES as c, extractMarkedSections as d, getSectionValidator as f, maxLines as g, maxItems as h, linkSkillToAgents as i, buildAllSectionPrompts as l, wrapSection as m, computeSkillDirName as n, unlinkSkillFromAgents as o, portabilizePrompt as p, installSkillForAgents as r, SECTION_MERGE_ORDER as s, generateSkillMd as t, buildSectionPrompt as u };
|
|
629
|
+
export { buildSectionPrompt as a, portabilizePrompt as c, maxLines as d, buildAllSectionPrompts as i, wrapSection as l, SECTION_MERGE_ORDER as n, extractMarkedSections as o, SECTION_OUTPUT_FILES as r, getSectionValidator as s, generateSkillMd as t, maxItems as u };
|
|
825
630
|
|
|
826
631
|
//# sourceMappingURL=prompts.mjs.map
|