skilld 0.15.2 → 0.15.4
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 +1 -0
- package/dist/_chunks/{detect-imports.mjs → agent.mjs} +42 -6
- package/dist/_chunks/agent.mjs.map +1 -0
- package/dist/_chunks/{storage.mjs → cache.mjs} +81 -1
- package/dist/_chunks/cache.mjs.map +1 -0
- package/dist/_chunks/cache2.mjs +6 -0
- package/dist/_chunks/config.mjs +23 -0
- package/dist/_chunks/config.mjs.map +1 -1
- package/dist/_chunks/config2.mjs +12 -0
- package/dist/_chunks/{embedding-cache2.mjs → embedding-cache.mjs} +1 -1
- package/dist/_chunks/embedding-cache.mjs.map +1 -0
- package/dist/_chunks/formatting.mjs +86 -0
- package/dist/_chunks/formatting.mjs.map +1 -0
- package/dist/_chunks/{version.d.mts → index.d.mts} +1 -1
- package/dist/_chunks/index.d.mts.map +1 -0
- package/dist/_chunks/{utils.d.mts → index2.d.mts} +1 -1
- package/dist/_chunks/index2.d.mts.map +1 -0
- package/dist/_chunks/install.mjs +15 -0
- package/dist/_chunks/list.mjs +13 -0
- package/dist/_chunks/markdown.mjs +7 -0
- package/dist/_chunks/markdown.mjs.map +1 -1
- package/dist/_chunks/{pool2.mjs → pool.mjs} +1 -1
- package/dist/_chunks/pool.mjs.map +1 -0
- package/dist/_chunks/prompts.mjs +232 -0
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/remove.mjs +12 -0
- package/dist/_chunks/sanitize.mjs +71 -0
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +14 -0
- package/dist/_chunks/search-interactive2.mjs +236 -0
- package/dist/_chunks/search-interactive2.mjs.map +1 -0
- package/dist/_chunks/search.mjs +171 -0
- package/dist/_chunks/search.mjs.map +1 -0
- package/dist/_chunks/search2.mjs +13 -0
- package/dist/_chunks/shared.mjs +4 -0
- package/dist/_chunks/shared.mjs.map +1 -1
- package/dist/_chunks/skills.mjs +552 -0
- package/dist/_chunks/skills.mjs.map +1 -0
- package/dist/_chunks/{npm.mjs → sources.mjs} +401 -4
- package/dist/_chunks/sources.mjs.map +1 -0
- package/dist/_chunks/status.mjs +13 -0
- package/dist/_chunks/sync.mjs +2026 -0
- package/dist/_chunks/sync.mjs.map +1 -0
- package/dist/_chunks/sync2.mjs +14 -0
- package/dist/_chunks/uninstall.mjs +15 -0
- package/dist/_chunks/validate.mjs +3 -0
- package/dist/_chunks/validate.mjs.map +1 -1
- package/dist/_chunks/yaml.mjs +19 -0
- package/dist/_chunks/yaml.mjs.map +1 -1
- package/dist/agent/index.d.mts +1 -1
- package/dist/agent/index.mjs +4 -3
- package/dist/cache/index.d.mts +2 -2
- package/dist/cache/index.mjs +2 -1
- package/dist/cli.mjs +173 -3082
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +2 -3
- package/dist/index.mjs +4 -4
- package/dist/retriv/index.d.mts.map +1 -1
- package/dist/retriv/index.mjs +26 -5
- package/dist/retriv/index.mjs.map +1 -1
- package/dist/retriv/worker.mjs +3 -3
- package/dist/sources/index.d.mts +2 -2
- package/dist/sources/index.mjs +2 -1
- package/dist/types.d.mts +2 -3
- package/package.json +10 -10
- package/dist/_chunks/detect-imports.mjs.map +0 -1
- package/dist/_chunks/embedding-cache2.mjs.map +0 -1
- package/dist/_chunks/npm.mjs.map +0 -1
- package/dist/_chunks/pool2.mjs.map +0 -1
- package/dist/_chunks/storage.mjs.map +0 -1
- package/dist/_chunks/utils.d.mts.map +0 -1
- package/dist/_chunks/version.d.mts.map +0 -1
package/dist/_chunks/prompts.mjs
CHANGED
|
@@ -6,6 +6,7 @@ import { dirname, join, relative } from "pathe";
|
|
|
6
6
|
import { existsSync, lstatSync, mkdirSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { spawnSync } from "node:child_process";
|
|
8
8
|
import { isWindows } from "std-env";
|
|
9
|
+
/** Common frontmatter fields from agentskills.io spec */
|
|
9
10
|
const SPEC_FRONTMATTER = {
|
|
10
11
|
"name": {
|
|
11
12
|
name: "name",
|
|
@@ -41,6 +42,7 @@ const SPEC_FRONTMATTER = {
|
|
|
41
42
|
description: "Space-delimited pre-approved tools (experimental)"
|
|
42
43
|
}
|
|
43
44
|
};
|
|
45
|
+
/** Shared defaults for all agent targets */
|
|
44
46
|
const BASE_DEFAULTS = {
|
|
45
47
|
skillFilename: "SKILL.md",
|
|
46
48
|
nameMatchesDir: true,
|
|
@@ -49,6 +51,7 @@ const BASE_DEFAULTS = {
|
|
|
49
51
|
extensions: [],
|
|
50
52
|
notes: []
|
|
51
53
|
};
|
|
54
|
+
/** Define an agent target with shared defaults applied */
|
|
52
55
|
function defineTarget(target) {
|
|
53
56
|
return {
|
|
54
57
|
...BASE_DEFAULTS,
|
|
@@ -56,6 +59,18 @@ function defineTarget(target) {
|
|
|
56
59
|
};
|
|
57
60
|
}
|
|
58
61
|
const configHome$2 = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
62
|
+
/**
|
|
63
|
+
* Amp (Sourcegraph)
|
|
64
|
+
*
|
|
65
|
+
* Uses .agents/skills/ as primary project path. Also reads .claude/skills/.
|
|
66
|
+
* Skills can bundle MCP servers via mcp.json in the skill directory.
|
|
67
|
+
*
|
|
68
|
+
* AGENTS.md (or AGENT.md / CLAUDE.md fallback) for general instructions,
|
|
69
|
+
* supports @-mentions to reference other files and glob-based conditional includes.
|
|
70
|
+
*
|
|
71
|
+
* @see https://ampcode.com/news/agent-skills
|
|
72
|
+
* @see https://ampcode.com/manual
|
|
73
|
+
*/
|
|
59
74
|
const amp = defineTarget({
|
|
60
75
|
agent: "amp",
|
|
61
76
|
displayName: "Amp",
|
|
@@ -90,6 +105,19 @@ const amp = defineTarget({
|
|
|
90
105
|
]
|
|
91
106
|
});
|
|
92
107
|
const home$6 = homedir();
|
|
108
|
+
/**
|
|
109
|
+
* Antigravity (Google)
|
|
110
|
+
*
|
|
111
|
+
* Agent-first IDE (VS Code fork) powered by Gemini. Skills live in
|
|
112
|
+
* .agent/skills/ (workspace) or ~/.gemini/antigravity/skills/ (global).
|
|
113
|
+
* Uses semantic matching on description to auto-invoke skills.
|
|
114
|
+
*
|
|
115
|
+
* Adopted the Agent Skills open standard (agentskills.io) in Jan 2026.
|
|
116
|
+
* Only `name` and `description` are used for routing; body loads on demand.
|
|
117
|
+
*
|
|
118
|
+
* @see https://antigravity.google/docs/skills
|
|
119
|
+
* @see https://codelabs.developers.google.com/getting-started-with-antigravity-skills
|
|
120
|
+
*/
|
|
93
121
|
const antigravity = defineTarget({
|
|
94
122
|
agent: "antigravity",
|
|
95
123
|
displayName: "Antigravity",
|
|
@@ -117,6 +145,18 @@ const antigravity = defineTarget({
|
|
|
117
145
|
]
|
|
118
146
|
});
|
|
119
147
|
const claudeHome = process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
|
|
148
|
+
/**
|
|
149
|
+
* Claude Code (Anthropic CLI)
|
|
150
|
+
*
|
|
151
|
+
* Follows the Agent Skills open standard (agentskills.io) plus Claude-specific
|
|
152
|
+
* extensions like `disable-model-invocation`, `user-invocable`, `context`, etc.
|
|
153
|
+
*
|
|
154
|
+
* Skills are discovered at startup — only `name` + `description` are read initially.
|
|
155
|
+
* Full SKILL.md body loads when the agent invokes the skill (via Skill tool or auto-match).
|
|
156
|
+
*
|
|
157
|
+
* @see https://code.claude.com/docs/en/skills
|
|
158
|
+
* @see https://agentskills.io/specification
|
|
159
|
+
*/
|
|
120
160
|
const claudeCode = defineTarget({
|
|
121
161
|
agent: "claude-code",
|
|
122
162
|
displayName: "Claude Code",
|
|
@@ -198,6 +238,19 @@ const claudeCode = defineTarget({
|
|
|
198
238
|
]
|
|
199
239
|
});
|
|
200
240
|
const home$5 = homedir();
|
|
241
|
+
/**
|
|
242
|
+
* Cline (VS Code extension)
|
|
243
|
+
*
|
|
244
|
+
* Has TWO systems: Rules (.clinerules/) and Skills (.cline/skills/).
|
|
245
|
+
* We target Skills. Cline also reads .claude/skills/ as a fallback,
|
|
246
|
+
* so emitting to .claude/skills/ covers both Claude Code and Cline.
|
|
247
|
+
*
|
|
248
|
+
* Only `name` and `description` are parsed from frontmatter.
|
|
249
|
+
* All other fields are stripped/ignored.
|
|
250
|
+
*
|
|
251
|
+
* @see https://docs.cline.bot/features/skills
|
|
252
|
+
* @see https://docs.cline.bot/features/cline-rules
|
|
253
|
+
*/
|
|
201
254
|
const cline = defineTarget({
|
|
202
255
|
agent: "cline",
|
|
203
256
|
displayName: "Cline",
|
|
@@ -228,6 +281,19 @@ const cline = defineTarget({
|
|
|
228
281
|
]
|
|
229
282
|
});
|
|
230
283
|
const codexHome = process.env.CODEX_HOME || join(homedir(), ".codex");
|
|
284
|
+
/**
|
|
285
|
+
* OpenAI Codex CLI
|
|
286
|
+
*
|
|
287
|
+
* IMPORTANT: Codex uses `.agents/skills/` for project-level skills,
|
|
288
|
+
* NOT `.codex/skills/`. The `.codex/` directory is for config (config.toml).
|
|
289
|
+
* `~/.codex/skills/` works only as a legacy user-global path.
|
|
290
|
+
*
|
|
291
|
+
* Codex also has AGENTS.md (or AGENTS.override.md) for general instructions,
|
|
292
|
+
* which walks from git root to CWD concatenating found files.
|
|
293
|
+
*
|
|
294
|
+
* @see https://developers.openai.com/codex/skills
|
|
295
|
+
* @see https://developers.openai.com/codex/guides/agents-md/
|
|
296
|
+
*/
|
|
231
297
|
const codex = defineTarget({
|
|
232
298
|
agent: "codex",
|
|
233
299
|
displayName: "Codex",
|
|
@@ -273,6 +339,19 @@ const codex = defineTarget({
|
|
|
273
339
|
]
|
|
274
340
|
});
|
|
275
341
|
const home$4 = homedir();
|
|
342
|
+
/**
|
|
343
|
+
* Cursor (AI code editor)
|
|
344
|
+
*
|
|
345
|
+
* Has TWO systems: Rules (.cursor/rules/*.mdc) and Skills (.cursor/skills/).
|
|
346
|
+
* We target the Skills system which follows the Agent Skills spec.
|
|
347
|
+
*
|
|
348
|
+
* Cursor natively scans .claude/skills/ and .codex/skills/ in addition to
|
|
349
|
+
* its own .cursor/skills/ — so .claude/skills/ output works for both
|
|
350
|
+
* Claude Code and Cursor with zero duplication.
|
|
351
|
+
*
|
|
352
|
+
* @see https://cursor.com/docs/context/skills
|
|
353
|
+
* @see https://cursor.com/docs/context/rules
|
|
354
|
+
*/
|
|
276
355
|
const cursor = defineTarget({
|
|
277
356
|
agent: "cursor",
|
|
278
357
|
displayName: "Cursor",
|
|
@@ -316,6 +395,18 @@ const cursor = defineTarget({
|
|
|
316
395
|
]
|
|
317
396
|
});
|
|
318
397
|
const home$3 = homedir();
|
|
398
|
+
/**
|
|
399
|
+
* Google Gemini CLI
|
|
400
|
+
*
|
|
401
|
+
* Follows the Agent Skills open standard (agentskills.io).
|
|
402
|
+
* Skills are activated via `activate_skill` tool with user confirmation.
|
|
403
|
+
*
|
|
404
|
+
* Also has GEMINI.md context files (analogous to CLAUDE.md) which support
|
|
405
|
+
* @file.md import syntax for modular composition.
|
|
406
|
+
*
|
|
407
|
+
* @see https://geminicli.com/docs/cli/skills/
|
|
408
|
+
* @see https://geminicli.com/docs/cli/creating-skills/
|
|
409
|
+
*/
|
|
319
410
|
const geminiCli = defineTarget({
|
|
320
411
|
agent: "gemini-cli",
|
|
321
412
|
displayName: "Gemini CLI",
|
|
@@ -349,6 +440,18 @@ const geminiCli = defineTarget({
|
|
|
349
440
|
]
|
|
350
441
|
});
|
|
351
442
|
const home$2 = homedir();
|
|
443
|
+
/**
|
|
444
|
+
* GitHub Copilot
|
|
445
|
+
*
|
|
446
|
+
* Has TWO systems: Instructions (.github/instructions/*.instructions.md)
|
|
447
|
+
* and Skills (.github/skills/). We target Skills.
|
|
448
|
+
*
|
|
449
|
+
* Copilot also auto-detects .claude/skills/ as a legacy path,
|
|
450
|
+
* so .claude/skills/ output works for Claude Code, Cursor, Cline, AND Copilot.
|
|
451
|
+
*
|
|
452
|
+
* @see https://docs.github.com/en/copilot/concepts/agents/about-agent-skills
|
|
453
|
+
* @see https://docs.github.com/copilot/customizing-copilot/adding-custom-instructions-for-github-copilot
|
|
454
|
+
*/
|
|
352
455
|
const githubCopilot = defineTarget({
|
|
353
456
|
agent: "github-copilot",
|
|
354
457
|
displayName: "GitHub Copilot",
|
|
@@ -387,6 +490,15 @@ const githubCopilot = defineTarget({
|
|
|
387
490
|
]
|
|
388
491
|
});
|
|
389
492
|
const configHome$1 = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
493
|
+
/**
|
|
494
|
+
* Goose (Block)
|
|
495
|
+
*
|
|
496
|
+
* Scans 6 directories for skills, including .claude/skills/ and .agents/skills/
|
|
497
|
+
* for cross-agent compatibility. Later directories override earlier ones on
|
|
498
|
+
* name conflict.
|
|
499
|
+
*
|
|
500
|
+
* @see https://block.github.io/goose/docs/guides/context-engineering/using-skills/
|
|
501
|
+
*/
|
|
390
502
|
const goose = defineTarget({
|
|
391
503
|
agent: "goose",
|
|
392
504
|
displayName: "Goose",
|
|
@@ -421,6 +533,18 @@ const goose = defineTarget({
|
|
|
421
533
|
]
|
|
422
534
|
});
|
|
423
535
|
const configHome = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
536
|
+
/**
|
|
537
|
+
* OpenCode (SST)
|
|
538
|
+
*
|
|
539
|
+
* Walks from CWD up to git worktree root searching for skill dirs.
|
|
540
|
+
* Reads .claude/skills/ and .agents/skills/ in addition to .opencode/skills/.
|
|
541
|
+
*
|
|
542
|
+
* Has a rich agent system: .opencode/agents/ with per-agent model/tool configuration.
|
|
543
|
+
* Skills can be permission-controlled per-agent with allow/deny/ask + glob patterns.
|
|
544
|
+
*
|
|
545
|
+
* @see https://opencode.ai/docs/skills/
|
|
546
|
+
* @see https://opencode.ai/docs/rules/
|
|
547
|
+
*/
|
|
424
548
|
const opencode = defineTarget({
|
|
425
549
|
agent: "opencode",
|
|
426
550
|
displayName: "OpenCode",
|
|
@@ -462,6 +586,18 @@ const opencode = defineTarget({
|
|
|
462
586
|
]
|
|
463
587
|
});
|
|
464
588
|
const home$1 = homedir();
|
|
589
|
+
/**
|
|
590
|
+
* Roo Code (VS Code extension)
|
|
591
|
+
*
|
|
592
|
+
* IMPORTANT: Roo does NOT read .claude/skills/ or .agents/skills/.
|
|
593
|
+
* It requires its own .roo/skills/ directory — no cross-compat shortcuts.
|
|
594
|
+
*
|
|
595
|
+
* Unique feature: mode-specific skill directories (.roo/skills-{modeSlug}/)
|
|
596
|
+
* allow targeting skills to specific modes (code, architect, etc.).
|
|
597
|
+
*
|
|
598
|
+
* @see https://docs.roocode.com/features/skills
|
|
599
|
+
* @see https://docs.roocode.com/features/custom-instructions
|
|
600
|
+
*/
|
|
465
601
|
const roo = defineTarget({
|
|
466
602
|
agent: "roo",
|
|
467
603
|
displayName: "Roo Code",
|
|
@@ -494,6 +630,18 @@ const roo = defineTarget({
|
|
|
494
630
|
]
|
|
495
631
|
});
|
|
496
632
|
const home = homedir();
|
|
633
|
+
/**
|
|
634
|
+
* Windsurf (Codeium editor)
|
|
635
|
+
*
|
|
636
|
+
* Has TWO systems: Rules (.windsurf/rules/*.md) and Skills (.windsurf/skills/).
|
|
637
|
+
* We target Skills. Rules have a separate frontmatter schema with trigger/globs.
|
|
638
|
+
*
|
|
639
|
+
* Skills only document `name` and `description` as frontmatter fields.
|
|
640
|
+
* Cascade uses "progressive disclosure" for supporting files.
|
|
641
|
+
*
|
|
642
|
+
* @see https://docs.windsurf.com/windsurf/cascade/skills
|
|
643
|
+
* @see https://docs.windsurf.com/windsurf/cascade/memories
|
|
644
|
+
*/
|
|
497
645
|
const windsurf = defineTarget({
|
|
498
646
|
agent: "windsurf",
|
|
499
647
|
displayName: "Windsurf",
|
|
@@ -537,15 +685,28 @@ const targets = {
|
|
|
537
685
|
"roo": roo,
|
|
538
686
|
"antigravity": antigravity
|
|
539
687
|
};
|
|
688
|
+
/**
|
|
689
|
+
* Detect which agents are installed on the system
|
|
690
|
+
*/
|
|
540
691
|
function detectInstalledAgents() {
|
|
541
692
|
return Object.entries(targets).filter(([_, config]) => config.detectInstalled()).map(([type]) => type);
|
|
542
693
|
}
|
|
694
|
+
/**
|
|
695
|
+
* Detect the target agent (where skills are installed) from env vars and cwd.
|
|
696
|
+
* This is NOT the generator LLM — it determines the skills directory.
|
|
697
|
+
*
|
|
698
|
+
* Priority: env vars first (running inside agent), then project dirs.
|
|
699
|
+
* Iteration order of the agents record determines priority.
|
|
700
|
+
*/
|
|
543
701
|
function detectTargetAgent() {
|
|
544
702
|
for (const [type, target] of Object.entries(targets)) if (target.detectEnv()) return type;
|
|
545
703
|
const cwd = process.cwd();
|
|
546
704
|
for (const [type, target] of Object.entries(targets)) if (target.detectProject(cwd)) return type;
|
|
547
705
|
return null;
|
|
548
706
|
}
|
|
707
|
+
/**
|
|
708
|
+
* Get the version of an agent's CLI (if available)
|
|
709
|
+
*/
|
|
549
710
|
function getAgentVersion(agentType) {
|
|
550
711
|
const agent = targets[agentType];
|
|
551
712
|
if (!agent.cli) return null;
|
|
@@ -568,14 +729,30 @@ function getAgentVersion(agentType) {
|
|
|
568
729
|
return null;
|
|
569
730
|
}
|
|
570
731
|
}
|
|
732
|
+
/**
|
|
733
|
+
* Dynamic budget allocation for skill sections.
|
|
734
|
+
*
|
|
735
|
+
* Total SKILL.md body should stay under ~300 lines (≈5,000 words per Agent Skills guide).
|
|
736
|
+
* When more sections are enabled, each gets proportionally less space.
|
|
737
|
+
* When a package has many releases, API changes budget scales up to capture more churn.
|
|
738
|
+
*/
|
|
739
|
+
/** Scale max lines based on enabled section count. Solo sections get full budget, 4 sections ~60%. */
|
|
571
740
|
function maxLines(min, max, sectionCount) {
|
|
572
741
|
const scale = budgetScale(sectionCount);
|
|
573
742
|
return Math.max(min, Math.round(max * scale));
|
|
574
743
|
}
|
|
744
|
+
/** Scale item count based on enabled section count. */
|
|
575
745
|
function maxItems(min, max, sectionCount) {
|
|
576
746
|
const scale = budgetScale(sectionCount);
|
|
577
747
|
return Math.max(min, Math.round(max * scale));
|
|
578
748
|
}
|
|
749
|
+
/**
|
|
750
|
+
* Boost budget for high-churn packages based on API-level release density.
|
|
751
|
+
* Combines major/minor release count with current minor version as a churn signal.
|
|
752
|
+
*
|
|
753
|
+
* @param significantReleases - Count of major/minor releases (patch releases excluded)
|
|
754
|
+
* @param minorVersion - Current minor version number (e.g., 15 for v3.15.0)
|
|
755
|
+
*/
|
|
579
756
|
function releaseBoost(significantReleases, minorVersion) {
|
|
580
757
|
const combined = (!significantReleases ? 0 : significantReleases <= 5 ? 0 : significantReleases <= 15 ? 1 : 2) + (!minorVersion ? 0 : minorVersion <= 3 ? 0 : minorVersion <= 10 ? 1 : 2);
|
|
581
758
|
if (combined <= 0) return 1;
|
|
@@ -588,27 +765,32 @@ function budgetScale(sectionCount) {
|
|
|
588
765
|
if (sectionCount === 3) return .7;
|
|
589
766
|
return .6;
|
|
590
767
|
}
|
|
768
|
+
/** Warns if content exceeds 150% of max lines */
|
|
591
769
|
function checkLineCount(content, max) {
|
|
592
770
|
const lines = content.split("\n").length;
|
|
593
771
|
if (lines > Math.round(max * 1.5)) return [{ warning: `Output ${lines} lines exceeds ${max} max by >50%` }];
|
|
594
772
|
return [];
|
|
595
773
|
}
|
|
774
|
+
/** Warns if content is fewer than 3 lines */
|
|
596
775
|
function checkSparseness(content) {
|
|
597
776
|
const lines = content.split("\n").length;
|
|
598
777
|
if (lines < 3) return [{ warning: `Output only ${lines} lines — likely too sparse` }];
|
|
599
778
|
return [];
|
|
600
779
|
}
|
|
780
|
+
/** Warns if sourced/bullets ratio is below minRatio */
|
|
601
781
|
function checkSourceCoverage(content, minRatio = .8) {
|
|
602
782
|
const bullets = (content.match(/^- /gm) || []).length;
|
|
603
783
|
const sourced = (content.match(/\[source\]/g) || []).length;
|
|
604
784
|
if (bullets > 2 && sourced / bullets < minRatio) return [{ warning: `Only ${sourced}/${bullets} items have source citations (need ${Math.round(minRatio * 100)}% coverage)` }];
|
|
605
785
|
return [];
|
|
606
786
|
}
|
|
787
|
+
/** Warns if source links are missing .skilld/ prefix */
|
|
607
788
|
function checkSourcePaths(content) {
|
|
608
789
|
const badPaths = content.match(/\[source\]\(\.\/(docs|issues|discussions|releases|pkg|guide)\//g);
|
|
609
790
|
if (badPaths?.length) return [{ warning: `${badPaths.length} source links missing .skilld/ prefix` }];
|
|
610
791
|
return [];
|
|
611
792
|
}
|
|
793
|
+
/** Warns if source links use absolute filesystem paths instead of relative ./.skilld/ paths */
|
|
612
794
|
function checkAbsolutePaths(content) {
|
|
613
795
|
const absPaths = content.match(/\[source\]\(\/[^)]+\)/g);
|
|
614
796
|
if (absPaths?.length) return [{ warning: `${absPaths.length} source links use absolute paths — must use relative ./.skilld/ paths` }];
|
|
@@ -849,16 +1031,22 @@ Content addressing the user's instructions above, using concise examples and sou
|
|
|
849
1031
|
rules: [`- **Custom section "${heading}":** MAX ${customMaxLines} lines, use \`## ${heading}\` heading`]
|
|
850
1032
|
};
|
|
851
1033
|
}
|
|
1034
|
+
/** Output file per section (inside .skilld/) */
|
|
852
1035
|
const SECTION_OUTPUT_FILES = {
|
|
853
1036
|
"best-practices": "_BEST_PRACTICES.md",
|
|
854
1037
|
"api-changes": "_API_CHANGES.md",
|
|
855
1038
|
"custom": "_CUSTOM.md"
|
|
856
1039
|
};
|
|
1040
|
+
/** Merge order for final SKILL.md body */
|
|
857
1041
|
const SECTION_MERGE_ORDER = [
|
|
858
1042
|
"api-changes",
|
|
859
1043
|
"best-practices",
|
|
860
1044
|
"custom"
|
|
861
1045
|
];
|
|
1046
|
+
/**
|
|
1047
|
+
* Group files by parent directory with counts
|
|
1048
|
+
* e.g. `/path/to/docs/api/ (15 .md files)`
|
|
1049
|
+
*/
|
|
862
1050
|
function formatDocTree(files) {
|
|
863
1051
|
const dirs = /* @__PURE__ */ new Map();
|
|
864
1052
|
for (const f of files) {
|
|
@@ -895,6 +1083,7 @@ Filters: \`docs:\`, \`issues:\`, \`releases:\` prefix narrows by source type.` :
|
|
|
895
1083
|
|
|
896
1084
|
${table}`;
|
|
897
1085
|
}
|
|
1086
|
+
/** Shared preamble: Security, references table, Quality Principles, doc tree */
|
|
898
1087
|
function buildPreamble(opts) {
|
|
899
1088
|
const { packageName, skillDir, hasIssues, hasDiscussions, hasReleases, hasChangelog, docFiles, docsType = "docs", hasShippedDocs = false, versionContext } = opts;
|
|
900
1089
|
const docsSection = docFiles?.length ? `<external-docs>\n**Documentation** (use Read tool to explore):\n${formatDocTree(docFiles)}\n</external-docs>` : "";
|
|
@@ -928,12 +1117,19 @@ function getSectionDef(section, ctx, customPrompt) {
|
|
|
928
1117
|
case "custom": return customPrompt ? customSection(customPrompt, ctx.enabledSectionCount) : null;
|
|
929
1118
|
}
|
|
930
1119
|
}
|
|
1120
|
+
/**
|
|
1121
|
+
* Get the validate function for a section using default context (validators use fixed thresholds).
|
|
1122
|
+
* Returns null if section has no validator.
|
|
1123
|
+
*/
|
|
931
1124
|
function getSectionValidator(section) {
|
|
932
1125
|
return getSectionDef(section, { packageName: "" }, section === "custom" ? {
|
|
933
1126
|
heading: "Custom",
|
|
934
1127
|
body: ""
|
|
935
1128
|
} : void 0)?.validate ?? null;
|
|
936
1129
|
}
|
|
1130
|
+
/**
|
|
1131
|
+
* Build prompt for a single section
|
|
1132
|
+
*/
|
|
937
1133
|
function buildSectionPrompt(opts) {
|
|
938
1134
|
const { packageName, hasIssues, hasDiscussions, hasReleases, hasChangelog, version, section, customPrompt, skillDir } = opts;
|
|
939
1135
|
const versionContext = version ? ` v${version}` : "";
|
|
@@ -998,6 +1194,9 @@ Write your final output to the file \`${skillDir}/.skilld/${outputFile}\` using
|
|
|
998
1194
|
After writing, run \`${cmd} validate ${skillDir}/.skilld/${outputFile}\` and fix any warnings before finishing. If unavailable, use \`${fallbackCmd} validate ${skillDir}/.skilld/${outputFile}\`.
|
|
999
1195
|
`;
|
|
1000
1196
|
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Build prompts for all selected sections, sharing the computed preamble
|
|
1199
|
+
*/
|
|
1001
1200
|
function buildAllSectionPrompts(opts) {
|
|
1002
1201
|
const result = /* @__PURE__ */ new Map();
|
|
1003
1202
|
for (const section of opts.sections) {
|
|
@@ -1010,12 +1209,28 @@ function buildAllSectionPrompts(opts) {
|
|
|
1010
1209
|
}
|
|
1011
1210
|
return result;
|
|
1012
1211
|
}
|
|
1212
|
+
/**
|
|
1213
|
+
* Sanitize skill name for filesystem
|
|
1214
|
+
*/
|
|
1013
1215
|
function sanitizeName(name) {
|
|
1014
1216
|
return name.toLowerCase().replace(/[^a-z0-9._]+/g, "-").replace(/^[.\-]+|[.\-]+$/g, "").slice(0, 255) || "unnamed-skill";
|
|
1015
1217
|
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Compute skill directory name from package name with -skilld suffix.
|
|
1220
|
+
* No collisions for monorepo packages (each gets a unique name).
|
|
1221
|
+
*
|
|
1222
|
+
* Examples:
|
|
1223
|
+
* vue → vue-skilld
|
|
1224
|
+
* @unhead/vue → unhead-vue-skilld
|
|
1225
|
+
* @unhead/react → unhead-react-skilld
|
|
1226
|
+
*/
|
|
1016
1227
|
function computeSkillDirName(packageName) {
|
|
1017
1228
|
return `${sanitizeName(packageName)}-skilld`;
|
|
1018
1229
|
}
|
|
1230
|
+
/**
|
|
1231
|
+
* Install a skill directly to agent skill directories
|
|
1232
|
+
* Writes to each agent's skill folder in the project (e.g., .claude/skills/package-name/)
|
|
1233
|
+
*/
|
|
1019
1234
|
function installSkillForAgents(skillName, skillContent, options = {}) {
|
|
1020
1235
|
const isGlobal = options.global ?? false;
|
|
1021
1236
|
const cwd = options.cwd || process.cwd();
|
|
@@ -1039,6 +1254,11 @@ function installSkillForAgents(skillName, skillContent, options = {}) {
|
|
|
1039
1254
|
paths
|
|
1040
1255
|
};
|
|
1041
1256
|
}
|
|
1257
|
+
/**
|
|
1258
|
+
* Create relative symlinks from each detected agent's skills dir to the shared .skills/ dir.
|
|
1259
|
+
* Only targets agents whose config dir already exists in the project.
|
|
1260
|
+
* Replaces existing symlinks, skips real directories (user's custom skills).
|
|
1261
|
+
*/
|
|
1042
1262
|
function linkSkillToAgents(skillName, sharedDir, cwd) {
|
|
1043
1263
|
for (const [, agent] of Object.entries(targets)) {
|
|
1044
1264
|
const agentSkillsDir = join(cwd, agent.skillsDir);
|
|
@@ -1057,6 +1277,9 @@ function linkSkillToAgents(skillName, sharedDir, cwd) {
|
|
|
1057
1277
|
symlinkSync(relative(agentSkillsDir, join(sharedDir, skillName)), target);
|
|
1058
1278
|
}
|
|
1059
1279
|
}
|
|
1280
|
+
/**
|
|
1281
|
+
* Remove per-agent symlinks for a skill when removing from shared dir.
|
|
1282
|
+
*/
|
|
1060
1283
|
function unlinkSkillFromAgents(skillName, cwd) {
|
|
1061
1284
|
for (const [, agent] of Object.entries(targets)) {
|
|
1062
1285
|
const target = join(cwd, agent.skillsDir, skillName);
|
|
@@ -1077,6 +1300,7 @@ function generateSkillMd(opts) {
|
|
|
1077
1300
|
const footer = generateFooter(opts.relatedSkills);
|
|
1078
1301
|
return sanitizeMarkdown(repairMarkdown(`${generateFrontmatter(opts)}${content}\n${footer}`));
|
|
1079
1302
|
}
|
|
1303
|
+
/** Format ISO date as short absolute date: "Jan 2025", "Dec 2024" */
|
|
1080
1304
|
function formatShortDate(isoDate) {
|
|
1081
1305
|
const date = new Date(isoDate);
|
|
1082
1306
|
if (Number.isNaN(date.getTime())) return "";
|
|
@@ -1137,6 +1361,10 @@ function generatePackageHeader({ name, description, version, releasedAt, depende
|
|
|
1137
1361
|
if (refs.length > 0) lines.push(`**References:** ${refs.join(" • ")}`);
|
|
1138
1362
|
return lines.join("\n");
|
|
1139
1363
|
}
|
|
1364
|
+
/**
|
|
1365
|
+
* Expand a package name into keyword variants for better trigger matching.
|
|
1366
|
+
* e.g. "@nuxt/ui" → ["nuxt ui", "nuxt/ui"], "vue-router" → ["vue router"]
|
|
1367
|
+
*/
|
|
1140
1368
|
function expandPackageName(name) {
|
|
1141
1369
|
const variants = /* @__PURE__ */ new Set();
|
|
1142
1370
|
const unscoped = name.replace(/^@/, "");
|
|
@@ -1151,6 +1379,10 @@ function expandPackageName(name) {
|
|
|
1151
1379
|
variants.delete(name);
|
|
1152
1380
|
return [...variants];
|
|
1153
1381
|
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Extract and expand GitHub repo name into keyword variants.
|
|
1384
|
+
* e.g. "motion-v" → ["motion-v", "motion v"]
|
|
1385
|
+
*/
|
|
1154
1386
|
function expandRepoName(repoUrl) {
|
|
1155
1387
|
const variants = /* @__PURE__ */ new Set();
|
|
1156
1388
|
const repoName = repoUrl.startsWith("http") ? repoUrl.split("/").pop() : repoUrl.split("/").pop();
|