skilld 1.3.0 → 1.5.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 +54 -4
- package/dist/_chunks/agent.mjs +2 -1
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/assemble.mjs +1 -0
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author.mjs +478 -0
- package/dist/_chunks/author.mjs.map +1 -0
- package/dist/_chunks/cli-helpers.mjs +133 -2
- package/dist/_chunks/cli-helpers.mjs.map +1 -1
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/index2.d.mts +2 -0
- package/dist/_chunks/index2.d.mts.map +1 -1
- package/dist/_chunks/install.mjs +7 -17
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/list.mjs +43 -4
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/lockfile.mjs +140 -0
- package/dist/_chunks/lockfile.mjs.map +1 -0
- package/dist/_chunks/prepare.mjs +94 -0
- package/dist/_chunks/prepare.mjs.map +1 -0
- package/dist/_chunks/prompts.mjs +32 -43
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +1 -0
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +146 -9
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/setup.mjs +1 -1
- package/dist/_chunks/skills.mjs +28 -142
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/sources.mjs +4 -2
- package/dist/_chunks/sources.mjs.map +1 -1
- package/dist/_chunks/sync-shared.mjs +14 -0
- package/dist/_chunks/sync-shared2.mjs +1054 -0
- package/dist/_chunks/sync-shared2.mjs.map +1 -0
- package/dist/_chunks/sync.mjs +72 -1065
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/uninstall.mjs +5 -3
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/agent/index.d.mts +4 -2
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/cli.mjs +76 -10
- package/dist/cli.mjs.map +1 -1
- package/package.json +11 -10
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import "./agent.mjs";
|
|
2
|
+
import "./config.mjs";
|
|
3
|
+
import "./sanitize.mjs";
|
|
4
|
+
import { _ as resolvePkgDir, a as getShippedSkills, f as linkShippedSkill } from "./cache.mjs";
|
|
5
|
+
import "./yaml.mjs";
|
|
6
|
+
import "./markdown.mjs";
|
|
7
|
+
import { n as getSharedSkillsDir } from "./shared.mjs";
|
|
8
|
+
import "./sources.mjs";
|
|
9
|
+
import { a as targets } from "./detect.mjs";
|
|
10
|
+
import { i as linkSkillToAgents } from "./prompts.mjs";
|
|
11
|
+
import { g as resolveAgent } from "./cli-helpers.mjs";
|
|
12
|
+
import { i as readLock, s as writeLock, t as mergeLocks } from "./lockfile.mjs";
|
|
13
|
+
import { t as getProjectState } from "./skills.mjs";
|
|
14
|
+
import { join } from "pathe";
|
|
15
|
+
import { existsSync, mkdirSync, symlinkSync } from "node:fs";
|
|
16
|
+
import * as p from "@clack/prompts";
|
|
17
|
+
import { defineCommand } from "citty";
|
|
18
|
+
//#region src/commands/prepare.ts
|
|
19
|
+
const prepareCommandDef = defineCommand({
|
|
20
|
+
meta: {
|
|
21
|
+
name: "prepare",
|
|
22
|
+
description: "Restore references and sync shipped skills (for package.json hooks)"
|
|
23
|
+
},
|
|
24
|
+
args: { agent: {
|
|
25
|
+
type: "enum",
|
|
26
|
+
options: Object.keys(targets),
|
|
27
|
+
alias: "a",
|
|
28
|
+
description: "Target agent"
|
|
29
|
+
} },
|
|
30
|
+
async run({ args }) {
|
|
31
|
+
const cwd = process.cwd();
|
|
32
|
+
const agent = resolveAgent(args.agent);
|
|
33
|
+
if (!agent || agent === "none") return;
|
|
34
|
+
const agentConfig = targets[agent];
|
|
35
|
+
const shared = getSharedSkillsDir(cwd);
|
|
36
|
+
const skillsDir = shared || join(cwd, agentConfig.skillsDir);
|
|
37
|
+
const allLocks = (shared ? [shared] : Object.values(targets).map((t) => join(cwd, t.skillsDir))).map((dir) => readLock(dir)).filter((l) => !!l && Object.keys(l.skills).length > 0);
|
|
38
|
+
if (allLocks.length > 0) {
|
|
39
|
+
const lock = mergeLocks(allLocks);
|
|
40
|
+
for (const [name, info] of Object.entries(lock.skills)) {
|
|
41
|
+
if (!info.version) continue;
|
|
42
|
+
if (info.source === "shipped") {
|
|
43
|
+
if (!existsSync(join(skillsDir, name))) {
|
|
44
|
+
const match = getShippedSkills(info.packageName || name, cwd, info.version).find((s) => s.skillName === name);
|
|
45
|
+
if (match) linkShippedSkill(skillsDir, name, match.skillDir);
|
|
46
|
+
}
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
restorePkgSymlink(skillsDir, name, info, cwd);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const state = await getProjectState(cwd);
|
|
53
|
+
let shippedCount = 0;
|
|
54
|
+
if (state.shipped.length > 0) {
|
|
55
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
56
|
+
for (const entry of state.shipped) {
|
|
57
|
+
const version = state.deps.get(entry.packageName)?.replace(/^[\^~>=<]+/, "") || "0.0.0";
|
|
58
|
+
for (const skill of entry.skills) {
|
|
59
|
+
linkShippedSkill(skillsDir, skill.skillName, skill.skillDir);
|
|
60
|
+
writeLock(skillsDir, skill.skillName, {
|
|
61
|
+
packageName: entry.packageName,
|
|
62
|
+
version,
|
|
63
|
+
source: "shipped",
|
|
64
|
+
syncedAt: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
65
|
+
generator: "skilld"
|
|
66
|
+
});
|
|
67
|
+
if (shared) linkSkillToAgents(skill.skillName, shared, cwd, agent);
|
|
68
|
+
shippedCount++;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (shippedCount > 0) p.log.success(`Installed ${shippedCount} shipped skill${shippedCount > 1 ? "s" : ""}`);
|
|
72
|
+
}
|
|
73
|
+
const freshState = shippedCount > 0 ? await getProjectState(cwd) : state;
|
|
74
|
+
if (freshState.outdated.length > 0) {
|
|
75
|
+
const n = freshState.outdated.length;
|
|
76
|
+
p.log.info(`${n} package${n > 1 ? "s" : ""} ha${n > 1 ? "ve" : "s"} new features and/or breaking changes. Run \`skilld update\` to sync.`);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
/** Restore .skilld/pkg symlink to node_modules if broken */
|
|
81
|
+
function restorePkgSymlink(skillsDir, name, info, cwd) {
|
|
82
|
+
const refsDir = join(skillsDir, name, ".skilld");
|
|
83
|
+
const pkgLink = join(refsDir, "pkg");
|
|
84
|
+
if (!existsSync(join(skillsDir, name))) return;
|
|
85
|
+
if (existsSync(pkgLink)) return;
|
|
86
|
+
const pkgDir = resolvePkgDir(info.packageName || name, cwd, info.version);
|
|
87
|
+
if (!pkgDir) return;
|
|
88
|
+
mkdirSync(refsDir, { recursive: true });
|
|
89
|
+
symlinkSync(pkgDir, pkgLink);
|
|
90
|
+
}
|
|
91
|
+
//#endregion
|
|
92
|
+
export { prepareCommandDef };
|
|
93
|
+
|
|
94
|
+
//# sourceMappingURL=prepare.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepare.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 type { SkillInfo } from '../core/lockfile.ts'\nimport { existsSync, mkdirSync, symlinkSync } 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 { getShippedSkills, linkShippedSkill, resolvePkgDir } from '../cache/index.ts'\nimport { resolveAgent } from '../cli-helpers.ts'\nimport { mergeLocks, readLock, writeLock } from '../core/lockfile.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 // ── 1. Restore broken symlinks from lockfile ──\n\n const allSkillsDirs = shared\n ? [shared]\n : Object.values(agents).map(t => join(cwd, t.skillsDir))\n const allLocks = allSkillsDirs\n .map(dir => readLock(dir))\n .filter((l): l is NonNullable<typeof l> => !!l && Object.keys(l.skills).length > 0)\n\n if (allLocks.length > 0) {\n const lock = mergeLocks(allLocks)\n\n for (const [name, info] of Object.entries(lock.skills)) {\n if (!info.version)\n continue\n\n if (info.source === 'shipped') {\n const skillDir = join(skillsDir, name)\n if (!existsSync(skillDir)) {\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 continue\n }\n\n // Non-shipped: restore .skilld/pkg symlink if broken\n restorePkgSymlink(skillsDir, name, info, cwd)\n }\n }\n\n // ── 2. Auto-install shipped skills from deps ──\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 // ── 3. Report outdated skills ──\n\n // Re-read state after shipped installs so they don't show as missing\n const freshState = shippedCount > 0 ? await getProjectState(cwd) : state\n\n if (freshState.outdated.length > 0) {\n const n = freshState.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\n/** Restore .skilld/pkg symlink to node_modules if broken */\nfunction 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 // Only fix if the skill dir exists but the pkg symlink is broken\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"],"mappings":";;;;;;;;;;;;;;;;;;AAqBA,MAAa,oBAAoB,cAAc;CAC7C,MAAM;EAAE,MAAM;EAAW,aAAa;EAAuE;CAC7G,MAAM,EACJ,OAAO;EACL,MAAM;EACN,SAAS,OAAO,KAAKA,QAAO;EAC5B,OAAO;EACP,aAAa;EACd,EACF;CACD,MAAM,IAAI,EAAE,QAAQ;EAClB,MAAM,MAAM,QAAQ,KAAK;EAEzB,MAAM,QAAQ,aAAa,KAAK,MAAM;AACtC,MAAI,CAAC,SAAS,UAAU,OACtB;EAEF,MAAM,cAAcA,QAAO;EAC3B,MAAM,SAAS,mBAAmB,IAAI;EACtC,MAAM,YAAY,UAAU,KAAK,KAAK,YAAY,UAAU;EAO5D,MAAM,YAHgB,SAClB,CAAC,OAAO,GACR,OAAO,OAAOA,QAAO,CAAC,KAAI,MAAK,KAAK,KAAK,EAAE,UAAU,CAAC,EAEvD,KAAI,QAAO,SAAS,IAAI,CAAC,CACzB,QAAQ,MAAkC,CAAC,CAAC,KAAK,OAAO,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE;AAErF,MAAI,SAAS,SAAS,GAAG;GACvB,MAAM,OAAO,WAAW,SAAS;AAEjC,QAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,KAAK,OAAO,EAAE;AACtD,QAAI,CAAC,KAAK,QACR;AAEF,QAAI,KAAK,WAAW,WAAW;AAE7B,SAAI,CAAC,WADY,KAAK,WAAW,KAAK,CACb,EAAE;MAGzB,MAAM,QADU,iBADA,KAAK,eAAe,MACM,KAAK,KAAK,QAAQ,CACtC,MAAK,MAAK,EAAE,cAAc,KAAK;AACrD,UAAI,MACF,kBAAiB,WAAW,MAAM,MAAM,SAAS;;AAErD;;AAIF,sBAAkB,WAAW,MAAM,MAAM,IAAI;;;EAMjD,MAAM,QAAQ,MAAM,gBAAgB,IAAI;EACxC,IAAI,eAAe;AAEnB,MAAI,MAAM,QAAQ,SAAS,GAAG;AAC5B,aAAU,WAAW,EAAE,WAAW,MAAM,CAAC;AAEzC,QAAK,MAAM,SAAS,MAAM,SAAS;IACjC,MAAM,UAAU,MAAM,KAAK,IAAI,MAAM,YAAY,EAAE,QAAQ,cAAc,GAAG,IAAI;AAEhF,SAAK,MAAM,SAAS,MAAM,QAAQ;AAChC,sBAAiB,WAAW,MAAM,WAAW,MAAM,SAAS;AAC5D,eAAU,WAAW,MAAM,WAAW;MACpC,aAAa,MAAM;MACnB;MACA,QAAQ;MACR,2BAAU,IAAI,MAAM,EAAC,aAAa,CAAC,MAAM,IAAI,CAAC;MAC9C,WAAW;MACZ,CAAC;AAEF,SAAI,OACF,mBAAkB,MAAM,WAAW,QAAQ,KAAK,MAAM;AAExD;;;AAIJ,OAAI,eAAe,EACjB,GAAE,IAAI,QAAQ,aAAa,aAAa,gBAAgB,eAAe,IAAI,MAAM,KAAK;;EAM1F,MAAM,aAAa,eAAe,IAAI,MAAM,gBAAgB,IAAI,GAAG;AAEnE,MAAI,WAAW,SAAS,SAAS,GAAG;GAClC,MAAM,IAAI,WAAW,SAAS;AAC9B,KAAE,IAAI,KAAK,GAAG,EAAE,UAAU,IAAI,IAAI,MAAM,GAAG,KAAK,IAAI,IAAI,OAAO,IAAI,uEAAuE;;;CAG/I,CAAC;;AAGF,SAAS,kBAAkB,WAAmB,MAAc,MAAiB,KAAmB;CAC9F,MAAM,UAAU,KAAK,WAAW,MAAM,UAAU;CAChD,MAAM,UAAU,KAAK,SAAS,MAAM;AAGpC,KAAI,CAAC,WAAW,KAAK,WAAW,KAAK,CAAC,CACpC;AAEF,KAAI,WAAW,QAAQ,CACrB;CAGF,MAAM,SAAS,cADC,KAAK,eAAe,MACE,KAAK,KAAK,QAAQ;AACxD,KAAI,CAAC,OACH;AAEF,WAAU,SAAS,EAAE,WAAW,MAAM,CAAC;AACvC,aAAY,QAAQ,QAAQ"}
|
package/dist/_chunks/prompts.mjs
CHANGED
|
@@ -8,14 +8,23 @@ import { existsSync, lstatSync, mkdirSync, symlinkSync, unlinkSync, writeFileSyn
|
|
|
8
8
|
/**
|
|
9
9
|
* Dynamic budget allocation for skill sections.
|
|
10
10
|
*
|
|
11
|
-
* Total SKILL.md
|
|
12
|
-
*
|
|
13
|
-
* When a package has many releases,
|
|
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
14
|
*/
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
const TOTAL_TARGET = 500;
|
|
16
|
+
const DEFAULT_OVERHEAD = 30;
|
|
17
|
+
/** Available body lines after overhead is subtracted */
|
|
18
|
+
function remainingLines(overheadLines) {
|
|
19
|
+
return TOTAL_TARGET - (overheadLines ?? DEFAULT_OVERHEAD);
|
|
20
|
+
}
|
|
21
|
+
/** Scale max lines based on enabled section count and available remaining space. */
|
|
22
|
+
function maxLines(min, max, sectionCount, overheadLines) {
|
|
23
|
+
const remaining = remainingLines(overheadLines);
|
|
24
|
+
const sections = Math.max(1, sectionCount ?? 1);
|
|
25
|
+
const perSection = Math.floor(remaining / sections);
|
|
17
26
|
const scale = budgetScale(sectionCount);
|
|
18
|
-
return Math.max(min, Math.round(max * scale));
|
|
27
|
+
return Math.max(min, Math.min(Math.round(max * scale), perSection));
|
|
19
28
|
}
|
|
20
29
|
/** Scale item count based on enabled section count. */
|
|
21
30
|
function maxItems(min, max, sectionCount) {
|
|
@@ -76,7 +85,7 @@ function checkAbsolutePaths(content) {
|
|
|
76
85
|
}
|
|
77
86
|
//#endregion
|
|
78
87
|
//#region src/agent/prompts/optional/api-changes.ts
|
|
79
|
-
function apiChangesSection({ packageName, version, hasReleases, hasChangelog, hasDocs, hasIssues, hasDiscussions, pkgFiles, features, enabledSectionCount, releaseCount }) {
|
|
88
|
+
function apiChangesSection({ packageName, version, hasReleases, hasChangelog, hasDocs, hasIssues, hasDiscussions, pkgFiles, features, enabledSectionCount, releaseCount, overheadLines }) {
|
|
80
89
|
const [, major, minor] = version?.match(/^(\d+)\.(\d+)/) ?? [];
|
|
81
90
|
const boost = releaseBoost(releaseCount, minor ? Number(minor) : void 0);
|
|
82
91
|
const cmd = resolveSkilldCommand();
|
|
@@ -141,7 +150,7 @@ function apiChangesSection({ packageName, version, hasReleases, hasChangelog, ha
|
|
|
141
150
|
| Renamed/moved | 3 | 1 | 0 |
|
|
142
151
|
|
|
143
152
|
The "Older" column means ≤ v${Number(major) - 2}.x — these changes are NOT useful because anyone on v${major}.x already migrated past them.` : "";
|
|
144
|
-
const apiChangesMaxLines = maxLines(
|
|
153
|
+
const apiChangesMaxLines = maxLines(60, Math.round(130 * boost), enabledSectionCount, overheadLines);
|
|
145
154
|
return {
|
|
146
155
|
referenceWeights,
|
|
147
156
|
validate(content) {
|
|
@@ -185,7 +194,7 @@ Each item: BREAKING/DEPRECATED/NEW label + API name + what changed + source link
|
|
|
185
194
|
|
|
186
195
|
**Tiered format:** Top-scoring items get full detailed entries. Remaining relevant items go in a compact "**Also changed:**" line at the end — API name + brief label, separated by \` · \`. This surfaces more changes without bloating the section.`,
|
|
187
196
|
rules: [
|
|
188
|
-
`- **API Changes:** ${maxItems(
|
|
197
|
+
`- **API Changes:** ${maxItems(8, Math.round(18 * boost), enabledSectionCount)} detailed items + compact "Also changed" line for remaining, MAX ${apiChangesMaxLines} lines`,
|
|
189
198
|
"- **Every detailed item MUST have a `[source](./.skilld/...#section)` link** with a section anchor (`#heading-slug`) or line reference (`:L<line>` or `:L<start>:<end>`). If you cannot cite a specific location in a release, changelog entry, or migration doc, do NOT include the item",
|
|
190
199
|
"- **Recency:** Only include changes from the current major version and the previous→current migration. Exclude changes from older major versions entirely — users already migrated past them",
|
|
191
200
|
"- Focus on APIs that CHANGED, not general conventions or gotchas",
|
|
@@ -200,7 +209,7 @@ Each item: BREAKING/DEPRECATED/NEW label + API name + what changed + source link
|
|
|
200
209
|
}
|
|
201
210
|
//#endregion
|
|
202
211
|
//#region src/agent/prompts/optional/best-practices.ts
|
|
203
|
-
function bestPracticesSection({ packageName, hasIssues, hasDiscussions, hasReleases, hasChangelog, hasDocs, pkgFiles, features, enabledSectionCount, releaseCount, version }) {
|
|
212
|
+
function bestPracticesSection({ packageName, hasIssues, hasDiscussions, hasReleases, hasChangelog, hasDocs, pkgFiles, features, enabledSectionCount, releaseCount, version, overheadLines }) {
|
|
204
213
|
const [, , minor] = version?.match(/^(\d+)\.(\d+)/) ?? [];
|
|
205
214
|
const boost = 1 + (releaseBoost(releaseCount, minor ? Number(minor) : void 0) - 1) * .5;
|
|
206
215
|
const cmd = resolveSkilldCommand();
|
|
@@ -237,7 +246,7 @@ function bestPracticesSection({ packageName, hasIssues, hasDiscussions, hasRelea
|
|
|
237
246
|
score: 3,
|
|
238
247
|
useFor: "Only for new patterns introduced in recent versions"
|
|
239
248
|
});
|
|
240
|
-
const bpMaxLines = maxLines(
|
|
249
|
+
const bpMaxLines = maxLines(100, Math.round(250 * boost), enabledSectionCount, overheadLines);
|
|
241
250
|
return {
|
|
242
251
|
referenceWeights,
|
|
243
252
|
validate(content) {
|
|
@@ -279,7 +288,7 @@ const client = createX({ retryDelay: attempt => Math.min(1000 * 2 ** attempt, 30
|
|
|
279
288
|
|
|
280
289
|
Each item: markdown list item (-) + ${packageName}-specific pattern + why it's preferred + \`[source](./.skilld/...#section)\` link. **Prefer concise descriptions over inline code** — the source link points the agent to full examples in the docs. Only add a code block when the pattern genuinely cannot be understood from the description alone (e.g., non-obvious syntax, multi-step wiring). Most items should be description + source link only. All source links MUST use \`./.skilld/\` prefix and include a **section anchor** (\`#heading-slug\`) or **line reference** (\`:L<line>\` or \`:L<start>:<end>\`) to pinpoint the exact location. Do NOT use emoji — use plain text markers only.`,
|
|
281
290
|
rules: [
|
|
282
|
-
`- **${maxItems(
|
|
291
|
+
`- **${maxItems(6, Math.round(15 * boost), enabledSectionCount)} best practice items**`,
|
|
283
292
|
`- **MAX ${bpMaxLines} lines** for best practices section`,
|
|
284
293
|
"- **Every item MUST have a `[source](./.skilld/...#section)` link** with a section anchor (`#heading-slug`) or line reference (`:L<line>` or `:L<start>:<end>`). If you cannot cite a specific location in a reference file, do NOT include the item — unsourced items risk hallucination and will be rejected",
|
|
285
294
|
"- **Minimize inline code.** Most items should be description + source link only. The source file contains full examples the agent can read. Only add a code block when the pattern is unintuitable from the description (non-obvious syntax, surprising argument order, multi-step wiring). Aim for at most 1 in 4 items having a code block",
|
|
@@ -293,8 +302,8 @@ Each item: markdown list item (-) + ${packageName}-specific pattern + why it's p
|
|
|
293
302
|
}
|
|
294
303
|
//#endregion
|
|
295
304
|
//#region src/agent/prompts/optional/custom.ts
|
|
296
|
-
function customSection({ heading, body }, enabledSectionCount) {
|
|
297
|
-
const customMaxLines = maxLines(50, 80, enabledSectionCount);
|
|
305
|
+
function customSection({ heading, body }, enabledSectionCount, overheadLines) {
|
|
306
|
+
const customMaxLines = maxLines(50, 80, enabledSectionCount, overheadLines);
|
|
298
307
|
return {
|
|
299
308
|
validate(content) {
|
|
300
309
|
return [
|
|
@@ -375,16 +384,9 @@ function generateImportantBlock({ packageName, hasIssues, hasDiscussions, hasRel
|
|
|
375
384
|
...rows.map(([desc, cmd]) => `| ${desc} | ${cmd} |`)
|
|
376
385
|
].join("\n");
|
|
377
386
|
const cmd = resolveSkilldCommand();
|
|
378
|
-
const fallbackCmd = cmd === "skilld" ? "npx -y skilld" : "skilld";
|
|
379
387
|
return `**IMPORTANT:** Use these references${features?.search !== false ? `\n\n## Search
|
|
380
388
|
|
|
381
|
-
Use \`${cmd} search\` as your primary research tool — search before manually reading files.
|
|
382
|
-
|
|
383
|
-
\`\`\`bash
|
|
384
|
-
${cmd} search "<query>" -p ${packageName}
|
|
385
|
-
${hasIssues ? `${cmd} search "issues:<query>" -p ${packageName}\n` : ""}${hasReleases ? `${cmd} search "releases:<query>" -p ${packageName}\n` : ""}\`\`\`
|
|
386
|
-
|
|
387
|
-
Filters: \`docs:\`, \`issues:\`, \`releases:\` prefix narrows by source type.` : ""}
|
|
389
|
+
Use \`${cmd} search "query" -p ${packageName}\` as your primary research tool — search before manually reading files. Run \`${cmd} search --guide -p ${packageName}\` for full syntax.` : ""}
|
|
388
390
|
|
|
389
391
|
${table}`;
|
|
390
392
|
}
|
|
@@ -419,7 +421,7 @@ function getSectionDef(section, ctx, customPrompt) {
|
|
|
419
421
|
switch (section) {
|
|
420
422
|
case "api-changes": return apiChangesSection(ctx);
|
|
421
423
|
case "best-practices": return bestPracticesSection(ctx);
|
|
422
|
-
case "custom": return customPrompt ? customSection(customPrompt, ctx.enabledSectionCount) : null;
|
|
424
|
+
case "custom": return customPrompt ? customSection(customPrompt, ctx.enabledSectionCount, ctx.overheadLines) : null;
|
|
423
425
|
}
|
|
424
426
|
}
|
|
425
427
|
/**
|
|
@@ -459,7 +461,8 @@ function buildSectionPrompt(opts) {
|
|
|
459
461
|
pkgFiles: opts.pkgFiles,
|
|
460
462
|
features: opts.features,
|
|
461
463
|
enabledSectionCount: opts.enabledSectionCount,
|
|
462
|
-
releaseCount
|
|
464
|
+
releaseCount,
|
|
465
|
+
overheadLines: opts.overheadLines
|
|
463
466
|
}, customPrompt);
|
|
464
467
|
if (!sectionDef) return "";
|
|
465
468
|
const outputFile = SECTION_OUTPUT_FILES[section];
|
|
@@ -674,7 +677,7 @@ function unlinkSkillFromAgents(skillName, cwd, agentType) {
|
|
|
674
677
|
//#region src/agent/prompts/skill.ts
|
|
675
678
|
function generateSkillMd(opts) {
|
|
676
679
|
const header = generatePackageHeader(opts);
|
|
677
|
-
const search = !opts.eject && opts.features?.search !== false ? generateSearchBlock(opts.name
|
|
680
|
+
const search = !opts.eject && opts.features?.search !== false ? generateSearchBlock(opts.name) : "";
|
|
678
681
|
let body = opts.body;
|
|
679
682
|
if (body && opts.eject) {
|
|
680
683
|
body = body.replace(/\.\/\.skilld\//g, "./references/");
|
|
@@ -703,7 +706,7 @@ function formatShortDate(isoDate) {
|
|
|
703
706
|
"Dec"
|
|
704
707
|
][date.getUTCMonth()]} ${date.getUTCFullYear()}`;
|
|
705
708
|
}
|
|
706
|
-
function generatePackageHeader({ name, description, version, releasedAt,
|
|
709
|
+
function generatePackageHeader({ name, description, version, releasedAt, distTags, repoUrl, hasIssues, hasDiscussions, hasReleases, docsType, pkgFiles, packages, eject }) {
|
|
707
710
|
let title = `# ${name}`;
|
|
708
711
|
if (repoUrl) {
|
|
709
712
|
const url = repoUrl.startsWith("http") ? repoUrl : `https://github.com/${repoUrl}`;
|
|
@@ -716,12 +719,8 @@ function generatePackageHeader({ name, description, version, releasedAt, depende
|
|
|
716
719
|
const versionStr = dateStr ? `${version} (${dateStr})` : version;
|
|
717
720
|
lines.push("", `**Version:** ${versionStr}`);
|
|
718
721
|
}
|
|
719
|
-
if (dependencies && Object.keys(dependencies).length > 0) {
|
|
720
|
-
const deps = Object.entries(dependencies).map(([n, v]) => `${n}@${v}`).join(", ");
|
|
721
|
-
lines.push(`**Deps:** ${deps}`);
|
|
722
|
-
}
|
|
723
722
|
if (distTags && Object.keys(distTags).length > 0) {
|
|
724
|
-
const tags = Object.entries(distTags).map(([tag, info]) => {
|
|
723
|
+
const tags = Object.entries(distTags).sort(([, a], [, b]) => (b.releasedAt ?? "").localeCompare(a.releasedAt ?? "")).slice(0, 3).map(([tag, info]) => {
|
|
725
724
|
const relDate = info.releasedAt ? ` (${formatShortDate(info.releasedAt)})` : "";
|
|
726
725
|
return `${tag}: ${info.version}${relDate}`;
|
|
727
726
|
}).join(", ");
|
|
@@ -816,21 +815,11 @@ function generateFrontmatter({ name, version, description: pkgDescription, globs
|
|
|
816
815
|
lines.push("---", "", "");
|
|
817
816
|
return lines.join("\n");
|
|
818
817
|
}
|
|
819
|
-
function generateSearchBlock(name
|
|
818
|
+
function generateSearchBlock(name) {
|
|
820
819
|
const cmd = resolveSkilldCommand();
|
|
821
|
-
const fallbackCmd = cmd === "skilld" ? "npx -y skilld" : "skilld";
|
|
822
|
-
const examples = [`${cmd} search "query" -p ${name}`];
|
|
823
|
-
if (hasIssues) examples.push(`${cmd} search "issues:error handling" -p ${name}`);
|
|
824
|
-
if (hasReleases) examples.push(`${cmd} search "releases:deprecated" -p ${name}`);
|
|
825
820
|
return `## Search
|
|
826
821
|
|
|
827
|
-
Use \`${cmd} search\` instead of grepping \`.skilld/\` directories
|
|
828
|
-
|
|
829
|
-
\`\`\`bash
|
|
830
|
-
${examples.join("\n")}
|
|
831
|
-
\`\`\`
|
|
832
|
-
|
|
833
|
-
Filters: \`docs:\`, \`issues:\`, \`releases:\` prefix narrows by source type.`;
|
|
822
|
+
Use \`${cmd} search "query" -p ${name}\` instead of grepping \`.skilld/\` directories. Run \`${cmd} search --guide -p ${name}\` for full syntax, filters, and operators.`;
|
|
834
823
|
}
|
|
835
824
|
function generateFooter(relatedSkills) {
|
|
836
825
|
if (relatedSkills.length === 0) return "";
|