skilld 1.0.0 → 1.1.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 +45 -21
- package/dist/_chunks/agent.mjs +8 -7
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/assemble.mjs +134 -0
- package/dist/_chunks/assemble.mjs.map +1 -0
- package/dist/_chunks/cache2.mjs +1 -1
- package/dist/_chunks/detect.mjs +737 -0
- package/dist/_chunks/detect.mjs.map +1 -0
- package/dist/_chunks/embedding-cache.mjs +1 -1
- package/dist/_chunks/formatting.mjs +25 -294
- package/dist/_chunks/formatting.mjs.map +1 -1
- package/dist/_chunks/install.mjs +38 -12
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/list.mjs +3 -1
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/pool.mjs +113 -167
- package/dist/_chunks/pool.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +64 -735
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/sanitize.mjs +2 -2
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +14 -3
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +3 -1
- package/dist/_chunks/search2.mjs +180 -0
- package/dist/_chunks/search2.mjs.map +1 -0
- package/dist/_chunks/skills.mjs +292 -0
- package/dist/_chunks/skills.mjs.map +1 -0
- package/dist/_chunks/sync.mjs +313 -35
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +4 -2
- package/dist/_chunks/uninstall.mjs +6 -4
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/validate.mjs +2 -1
- package/dist/_chunks/validate.mjs.map +1 -1
- package/dist/agent/index.d.mts +29 -6
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +4 -3
- package/dist/cli.mjs +24 -13
- package/dist/cli.mjs.map +1 -1
- package/dist/retriv/index.d.mts +4 -1
- package/dist/retriv/index.d.mts.map +1 -1
- package/dist/retriv/index.mjs +25 -10
- package/dist/retriv/index.mjs.map +1 -1
- package/dist/retriv/worker.d.mts.map +1 -1
- package/dist/retriv/worker.mjs +2 -16
- package/dist/retriv/worker.mjs.map +1 -1
- package/package.json +2 -2
- package/dist/_chunks/pool2.mjs +0 -115
- package/dist/_chunks/pool2.mjs.map +0 -1
package/dist/_chunks/prompts.mjs
CHANGED
|
@@ -1,734 +1,9 @@
|
|
|
1
1
|
import { n as sanitizeMarkdown, t as repairMarkdown } from "./sanitize.mjs";
|
|
2
2
|
import { t as yamlEscape } from "./yaml.mjs";
|
|
3
3
|
import { i as resolveSkilldCommand, l as getFilePatterns, u as getPackageRules } from "./shared.mjs";
|
|
4
|
-
import {
|
|
4
|
+
import { a as targets, t as detectInstalledAgents } from "./detect.mjs";
|
|
5
5
|
import { dirname, join, relative } from "pathe";
|
|
6
6
|
import { existsSync, lstatSync, mkdirSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
7
|
-
import { spawnSync } from "node:child_process";
|
|
8
|
-
import { isWindows } from "std-env";
|
|
9
|
-
/** Common frontmatter fields from agentskills.io spec */
|
|
10
|
-
const SPEC_FRONTMATTER = {
|
|
11
|
-
"name": {
|
|
12
|
-
name: "name",
|
|
13
|
-
required: true,
|
|
14
|
-
description: "Skill identifier. Must match parent directory name.",
|
|
15
|
-
constraints: "1-64 chars, lowercase alphanumeric + hyphens"
|
|
16
|
-
},
|
|
17
|
-
"description": {
|
|
18
|
-
name: "description",
|
|
19
|
-
required: true,
|
|
20
|
-
description: "What the skill does and when to use it.",
|
|
21
|
-
constraints: "1-1024 chars"
|
|
22
|
-
},
|
|
23
|
-
"license": {
|
|
24
|
-
name: "license",
|
|
25
|
-
required: false,
|
|
26
|
-
description: "License reference"
|
|
27
|
-
},
|
|
28
|
-
"compatibility": {
|
|
29
|
-
name: "compatibility",
|
|
30
|
-
required: false,
|
|
31
|
-
description: "Environment requirements",
|
|
32
|
-
constraints: "max 500 chars"
|
|
33
|
-
},
|
|
34
|
-
"metadata": {
|
|
35
|
-
name: "metadata",
|
|
36
|
-
required: false,
|
|
37
|
-
description: "Arbitrary key-value pairs"
|
|
38
|
-
},
|
|
39
|
-
"allowed-tools": {
|
|
40
|
-
name: "allowed-tools",
|
|
41
|
-
required: false,
|
|
42
|
-
description: "Space-delimited pre-approved tools (experimental)"
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
/** Shared defaults for all agent targets */
|
|
46
|
-
const BASE_DEFAULTS = {
|
|
47
|
-
skillFilename: "SKILL.md",
|
|
48
|
-
nameMatchesDir: true,
|
|
49
|
-
namePattern: "^[a-z0-9]+(-[a-z0-9]+)*$",
|
|
50
|
-
additionalSkillsDirs: [],
|
|
51
|
-
extensions: [],
|
|
52
|
-
notes: []
|
|
53
|
-
};
|
|
54
|
-
/** Define an agent target with shared defaults applied */
|
|
55
|
-
function defineTarget(target) {
|
|
56
|
-
return {
|
|
57
|
-
...BASE_DEFAULTS,
|
|
58
|
-
...target
|
|
59
|
-
};
|
|
60
|
-
}
|
|
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
|
-
*/
|
|
74
|
-
const amp = defineTarget({
|
|
75
|
-
agent: "amp",
|
|
76
|
-
displayName: "Amp",
|
|
77
|
-
detectInstalled: () => existsSync(join(configHome$2, "amp")),
|
|
78
|
-
detectEnv: () => !!process.env.AMP_SESSION,
|
|
79
|
-
detectProject: (cwd) => existsSync(join(cwd, ".agents", "AGENTS.md")),
|
|
80
|
-
instructionFile: "AGENTS.md",
|
|
81
|
-
skillsDir: ".agents/skills",
|
|
82
|
-
globalSkillsDir: join(configHome$2, "agents/skills"),
|
|
83
|
-
additionalSkillsDirs: [
|
|
84
|
-
".claude/skills",
|
|
85
|
-
"~/.config/amp/skills",
|
|
86
|
-
"~/.claude/skills"
|
|
87
|
-
],
|
|
88
|
-
frontmatter: [{
|
|
89
|
-
...SPEC_FRONTMATTER.name,
|
|
90
|
-
description: "Unique identifier. Project skills override user-wide ones with same name."
|
|
91
|
-
}, {
|
|
92
|
-
...SPEC_FRONTMATTER.description,
|
|
93
|
-
description: "Always visible to the model; determines when skill is invoked."
|
|
94
|
-
}],
|
|
95
|
-
discoveryStrategy: "lazy",
|
|
96
|
-
discoveryNotes: "Names + descriptions visible at startup. Full SKILL.md body loads only when agent decides to invoke based on description match.",
|
|
97
|
-
agentSkillsSpec: false,
|
|
98
|
-
extensions: ["mcp.json for bundling MCP server configurations"],
|
|
99
|
-
docs: "https://ampcode.com/news/agent-skills",
|
|
100
|
-
notes: [
|
|
101
|
-
"Reads .claude/skills/ natively — emitting there covers Claude Code, Cursor, Cline, Copilot, AND Amp.",
|
|
102
|
-
"Skills can bundle MCP servers via mcp.json in the skill directory.",
|
|
103
|
-
"AGENTS.md supports @-mentions to reference files (e.g. @doc/style.md, @doc/*.md globs).",
|
|
104
|
-
"AGENTS.md files with globs frontmatter are conditionally included only when Amp reads matching files."
|
|
105
|
-
]
|
|
106
|
-
});
|
|
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
|
-
*/
|
|
121
|
-
const antigravity = defineTarget({
|
|
122
|
-
agent: "antigravity",
|
|
123
|
-
displayName: "Antigravity",
|
|
124
|
-
detectInstalled: () => existsSync(join(home$6, ".gemini/antigravity")),
|
|
125
|
-
detectEnv: () => !!process.env.ANTIGRAVITY_CLI_ALIAS,
|
|
126
|
-
detectProject: (cwd) => existsSync(join(cwd, ".agent")),
|
|
127
|
-
instructionFile: "GEMINI.md",
|
|
128
|
-
skillsDir: ".agent/skills",
|
|
129
|
-
globalSkillsDir: join(home$6, ".gemini/antigravity/skills"),
|
|
130
|
-
frontmatter: [{
|
|
131
|
-
...SPEC_FRONTMATTER.name,
|
|
132
|
-
description: "Skill identifier. Defaults to directory name if omitted."
|
|
133
|
-
}, {
|
|
134
|
-
...SPEC_FRONTMATTER.description,
|
|
135
|
-
description: "Semantic trigger for agent routing. Must be descriptive enough for LLM matching."
|
|
136
|
-
}],
|
|
137
|
-
discoveryStrategy: "lazy",
|
|
138
|
-
discoveryNotes: "Indexes name + description at startup. Full SKILL.md body loads on demand when agent semantic-matches description against user prompt.",
|
|
139
|
-
agentSkillsSpec: true,
|
|
140
|
-
docs: "https://antigravity.google/docs/skills",
|
|
141
|
-
notes: [
|
|
142
|
-
"Only `name` and `description` are used for routing; other frontmatter fields are accepted but not used for matching.",
|
|
143
|
-
"Skill directories can include scripts/, resources/, and assets/ subdirectories for supporting files.",
|
|
144
|
-
"GEMINI.md instruction file is shared with Gemini CLI. .agent/rules/*.md for always-on workspace rules."
|
|
145
|
-
]
|
|
146
|
-
});
|
|
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
|
-
*/
|
|
160
|
-
const claudeCode = defineTarget({
|
|
161
|
-
agent: "claude-code",
|
|
162
|
-
displayName: "Claude Code",
|
|
163
|
-
detectInstalled: () => existsSync(claudeHome),
|
|
164
|
-
detectEnv: () => !!(process.env.CLAUDE_CODE || process.env.CLAUDECODE || process.env.CLAUDE_CODE_ENTRYPOINT || process.env.CLAUDE_CONFIG_DIR),
|
|
165
|
-
detectProject: (cwd) => existsSync(join(cwd, ".claude")) || existsSync(join(cwd, "CLAUDE.md")),
|
|
166
|
-
cli: "claude",
|
|
167
|
-
instructionFile: "CLAUDE.md",
|
|
168
|
-
skillsDir: ".claude/skills",
|
|
169
|
-
globalSkillsDir: join(claudeHome, "skills"),
|
|
170
|
-
frontmatter: [
|
|
171
|
-
{
|
|
172
|
-
...SPEC_FRONTMATTER.name,
|
|
173
|
-
required: false,
|
|
174
|
-
description: "Skill identifier, becomes /slash-command. Defaults to directory name if omitted.",
|
|
175
|
-
constraints: "1-64 chars, ^[a-z0-9]+(-[a-z0-9]+)*$"
|
|
176
|
-
},
|
|
177
|
-
{
|
|
178
|
-
...SPEC_FRONTMATTER.description,
|
|
179
|
-
description: "What the skill does and when to use it. Used for auto-discovery matching."
|
|
180
|
-
},
|
|
181
|
-
SPEC_FRONTMATTER.license,
|
|
182
|
-
SPEC_FRONTMATTER.compatibility,
|
|
183
|
-
SPEC_FRONTMATTER.metadata,
|
|
184
|
-
SPEC_FRONTMATTER["allowed-tools"],
|
|
185
|
-
{
|
|
186
|
-
name: "disable-model-invocation",
|
|
187
|
-
required: false,
|
|
188
|
-
description: "When true, skill only loads via explicit /name invocation"
|
|
189
|
-
},
|
|
190
|
-
{
|
|
191
|
-
name: "user-invocable",
|
|
192
|
-
required: false,
|
|
193
|
-
description: "When false, hides from / menu but still auto-loads"
|
|
194
|
-
},
|
|
195
|
-
{
|
|
196
|
-
name: "argument-hint",
|
|
197
|
-
required: false,
|
|
198
|
-
description: "Hint shown during autocomplete, e.g. [issue-number]"
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
name: "model",
|
|
202
|
-
required: false,
|
|
203
|
-
description: "Model to use when skill is active"
|
|
204
|
-
},
|
|
205
|
-
{
|
|
206
|
-
name: "context",
|
|
207
|
-
required: false,
|
|
208
|
-
description: "Set to \"fork\" to run in a forked subagent context"
|
|
209
|
-
},
|
|
210
|
-
{
|
|
211
|
-
name: "agent",
|
|
212
|
-
required: false,
|
|
213
|
-
description: "Subagent type when context: fork (e.g. Explore, Plan)"
|
|
214
|
-
}
|
|
215
|
-
],
|
|
216
|
-
discoveryStrategy: "eager",
|
|
217
|
-
discoveryNotes: "Scans skill dirs at startup, reads name + description only. Full body loads on invocation. Budget: 2% of context window for all skill descriptions.",
|
|
218
|
-
agentSkillsSpec: true,
|
|
219
|
-
extensions: [
|
|
220
|
-
"disable-model-invocation",
|
|
221
|
-
"user-invocable",
|
|
222
|
-
"argument-hint",
|
|
223
|
-
"model",
|
|
224
|
-
"context",
|
|
225
|
-
"agent",
|
|
226
|
-
"hooks",
|
|
227
|
-
"$ARGUMENTS substitution",
|
|
228
|
-
"!`command` dynamic context"
|
|
229
|
-
],
|
|
230
|
-
docs: "https://code.claude.com/docs/en/skills",
|
|
231
|
-
notes: [
|
|
232
|
-
"`globs` is NOT a valid frontmatter field for skills (only for rules). Unknown fields are silently ignored.",
|
|
233
|
-
"`version` and `generated_by` should go under `metadata` map, not as top-level fields.",
|
|
234
|
-
"Skill descriptions have a char budget of 2% of context window (~16k chars fallback). Override with SLASH_COMMAND_TOOL_CHAR_BUDGET env var.",
|
|
235
|
-
"Keep SKILL.md under 500 lines. Move detailed reference to separate files.",
|
|
236
|
-
"Supports monorepo auto-discovery: nested .claude/skills/ dirs in subdirectories.",
|
|
237
|
-
"Supporting dirs: scripts/, references/, assets/ alongside SKILL.md."
|
|
238
|
-
]
|
|
239
|
-
});
|
|
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
|
-
*/
|
|
254
|
-
const cline = defineTarget({
|
|
255
|
-
agent: "cline",
|
|
256
|
-
displayName: "Cline",
|
|
257
|
-
detectInstalled: () => existsSync(join(home$5, ".cline")),
|
|
258
|
-
detectEnv: () => !!process.env.CLINE_TASK_ID,
|
|
259
|
-
detectProject: (cwd) => existsSync(join(cwd, ".cline")),
|
|
260
|
-
instructionFile: ".clinerules",
|
|
261
|
-
skillsDir: ".cline/skills",
|
|
262
|
-
globalSkillsDir: join(home$5, ".cline/skills"),
|
|
263
|
-
additionalSkillsDirs: [".clinerules/skills", ".claude/skills"],
|
|
264
|
-
frontmatter: [{
|
|
265
|
-
...SPEC_FRONTMATTER.name,
|
|
266
|
-
description: "Must exactly match the directory name."
|
|
267
|
-
}, {
|
|
268
|
-
...SPEC_FRONTMATTER.description,
|
|
269
|
-
description: "When to activate. Used for matching."
|
|
270
|
-
}],
|
|
271
|
-
discoveryStrategy: "eager",
|
|
272
|
-
discoveryNotes: "At startup reads name + description from each skill. Full content loads on-demand via use_skill tool. Dozens of skills have near-zero context cost.",
|
|
273
|
-
agentSkillsSpec: false,
|
|
274
|
-
docs: "https://docs.cline.bot/features/skills",
|
|
275
|
-
notes: [
|
|
276
|
-
"Only `name` and `description` are parsed. `version`, `globs`, etc. are silently ignored.",
|
|
277
|
-
"Cline reads .claude/skills/ as a fallback — emitting there covers both Claude Code and Cline.",
|
|
278
|
-
"Rules system (.clinerules/) is separate: always-on behavioral constraints with globs/tags frontmatter.",
|
|
279
|
-
"Global skills override project skills when names conflict.",
|
|
280
|
-
"Supporting dirs: docs/, scripts/, templates/ alongside SKILL.md."
|
|
281
|
-
]
|
|
282
|
-
});
|
|
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
|
-
*/
|
|
297
|
-
const codex = defineTarget({
|
|
298
|
-
agent: "codex",
|
|
299
|
-
displayName: "Codex",
|
|
300
|
-
detectInstalled: () => existsSync(codexHome),
|
|
301
|
-
detectEnv: () => !!(process.env.CODEX_HOME || process.env.CODEX_SESSION),
|
|
302
|
-
detectProject: (cwd) => existsSync(join(cwd, ".codex")),
|
|
303
|
-
cli: "codex",
|
|
304
|
-
instructionFile: "AGENTS.md",
|
|
305
|
-
skillsDir: ".agents/skills",
|
|
306
|
-
globalSkillsDir: join(homedir(), ".agents/skills"),
|
|
307
|
-
additionalSkillsDirs: ["~/.codex/skills", "/etc/codex/skills"],
|
|
308
|
-
frontmatter: [
|
|
309
|
-
{
|
|
310
|
-
...SPEC_FRONTMATTER.name,
|
|
311
|
-
description: "Skill identifier.",
|
|
312
|
-
constraints: "1-64 chars, ^[a-z0-9-]+$, no leading/trailing/consecutive hyphens"
|
|
313
|
-
},
|
|
314
|
-
{
|
|
315
|
-
...SPEC_FRONTMATTER.description,
|
|
316
|
-
description: "Must include when-to-use criteria. Primary triggering mechanism.",
|
|
317
|
-
constraints: "1-1024 chars, no angle brackets (< or >)"
|
|
318
|
-
},
|
|
319
|
-
SPEC_FRONTMATTER.license,
|
|
320
|
-
SPEC_FRONTMATTER["allowed-tools"],
|
|
321
|
-
SPEC_FRONTMATTER.metadata
|
|
322
|
-
],
|
|
323
|
-
discoveryStrategy: "lazy",
|
|
324
|
-
discoveryNotes: "Startup scan reads name + description + optional agents/openai.yaml. Full body loads only on invocation. Supports $1-$9 and $ARGUMENTS placeholders.",
|
|
325
|
-
agentSkillsSpec: true,
|
|
326
|
-
extensions: [
|
|
327
|
-
"agents/openai.yaml (UI metadata + MCP dependencies)",
|
|
328
|
-
"$1-$9 positional argument placeholders",
|
|
329
|
-
"AGENTS.override.md for temporary overrides"
|
|
330
|
-
],
|
|
331
|
-
docs: "https://developers.openai.com/codex/skills",
|
|
332
|
-
notes: [
|
|
333
|
-
"BUG IN CURRENT CODE: skillsDir is .codex/skills/ but should be .agents/skills/. The .codex/ directory is for config, not skills.",
|
|
334
|
-
"Description field cannot contain angle brackets (< or >).",
|
|
335
|
-
"Optional agents/openai.yaml provides UI metadata: display_name, icon, brand_color, default_prompt.",
|
|
336
|
-
"AGENTS.md walks from git root to CWD, concatenating all found files.",
|
|
337
|
-
"Live reload: detects skill file changes without restart (v0.95.0+).",
|
|
338
|
-
"Size limit: 32 KiB default (project_doc_max_bytes), configurable in ~/.codex/config.toml."
|
|
339
|
-
]
|
|
340
|
-
});
|
|
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
|
-
*/
|
|
355
|
-
const cursor = defineTarget({
|
|
356
|
-
agent: "cursor",
|
|
357
|
-
displayName: "Cursor",
|
|
358
|
-
detectInstalled: () => existsSync(join(home$4, ".cursor")),
|
|
359
|
-
detectEnv: () => !!(process.env.CURSOR_SESSION || process.env.CURSOR_TRACE_ID),
|
|
360
|
-
detectProject: (cwd) => existsSync(join(cwd, ".cursor")) || existsSync(join(cwd, ".cursorrules")),
|
|
361
|
-
instructionFile: ".cursorrules",
|
|
362
|
-
skillsDir: ".cursor/skills",
|
|
363
|
-
globalSkillsDir: join(home$4, ".cursor/skills"),
|
|
364
|
-
additionalSkillsDirs: [
|
|
365
|
-
".claude/skills",
|
|
366
|
-
".codex/skills",
|
|
367
|
-
"~/.claude/skills",
|
|
368
|
-
"~/.codex/skills"
|
|
369
|
-
],
|
|
370
|
-
frontmatter: [
|
|
371
|
-
SPEC_FRONTMATTER.name,
|
|
372
|
-
{
|
|
373
|
-
...SPEC_FRONTMATTER.description,
|
|
374
|
-
description: "Agent uses this to decide relevance for auto-invocation."
|
|
375
|
-
},
|
|
376
|
-
SPEC_FRONTMATTER.license,
|
|
377
|
-
SPEC_FRONTMATTER.compatibility,
|
|
378
|
-
SPEC_FRONTMATTER.metadata,
|
|
379
|
-
{
|
|
380
|
-
name: "disable-model-invocation",
|
|
381
|
-
required: false,
|
|
382
|
-
description: "When true, only loads via explicit /skill-name"
|
|
383
|
-
}
|
|
384
|
-
],
|
|
385
|
-
discoveryStrategy: "lazy",
|
|
386
|
-
discoveryNotes: "Reads name + description at conversation start. Full SKILL.md body loads only when agent determines relevance. Users can also invoke via /skill-name.",
|
|
387
|
-
agentSkillsSpec: true,
|
|
388
|
-
extensions: ["disable-model-invocation"],
|
|
389
|
-
docs: "https://cursor.com/docs/context/skills",
|
|
390
|
-
notes: [
|
|
391
|
-
"Cursor scans .claude/skills/ and .codex/skills/ natively — emitting to .claude/skills/ covers both Claude Code and Cursor.",
|
|
392
|
-
"The Rules system (.cursor/rules/*.mdc) is separate and uses different frontmatter (trigger, globs, alwaysApply).",
|
|
393
|
-
"Skills appear in Settings > Rules > Agent Decides section.",
|
|
394
|
-
"Supporting dirs: scripts/, references/, assets/ alongside SKILL.md."
|
|
395
|
-
]
|
|
396
|
-
});
|
|
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
|
-
*/
|
|
410
|
-
const geminiCli = defineTarget({
|
|
411
|
-
agent: "gemini-cli",
|
|
412
|
-
displayName: "Gemini CLI",
|
|
413
|
-
detectInstalled: () => existsSync(join(home$3, ".gemini")),
|
|
414
|
-
detectEnv: () => !!(process.env.GEMINI_API_KEY && process.env.GEMINI_SESSION),
|
|
415
|
-
detectProject: (cwd) => existsSync(join(cwd, ".gemini")) || existsSync(join(cwd, "AGENTS.md")),
|
|
416
|
-
cli: "gemini",
|
|
417
|
-
instructionFile: "GEMINI.md",
|
|
418
|
-
skillsDir: ".gemini/skills",
|
|
419
|
-
globalSkillsDir: join(home$3, ".gemini/skills"),
|
|
420
|
-
frontmatter: [
|
|
421
|
-
SPEC_FRONTMATTER.name,
|
|
422
|
-
{
|
|
423
|
-
...SPEC_FRONTMATTER.description,
|
|
424
|
-
description: "Primary trigger — agent uses this to match tasks."
|
|
425
|
-
},
|
|
426
|
-
SPEC_FRONTMATTER.license,
|
|
427
|
-
SPEC_FRONTMATTER.compatibility,
|
|
428
|
-
SPEC_FRONTMATTER.metadata,
|
|
429
|
-
SPEC_FRONTMATTER["allowed-tools"]
|
|
430
|
-
],
|
|
431
|
-
discoveryStrategy: "eager",
|
|
432
|
-
discoveryNotes: "Scans at session start, injects ~100 tokens per skill (name+description). Activation via activate_skill tool requires user confirmation. Skill stays active for session duration.",
|
|
433
|
-
agentSkillsSpec: true,
|
|
434
|
-
docs: "https://geminicli.com/docs/cli/skills/",
|
|
435
|
-
notes: [
|
|
436
|
-
"Management commands: /skills list, /skills enable <name>, /skills disable <name>, /skills reload.",
|
|
437
|
-
"GEMINI.md context files are separate from skills — support @file.md import syntax.",
|
|
438
|
-
"settings.json can configure additional context filenames: [\"AGENTS.md\", \"CONTEXT.md\", \"GEMINI.md\"].",
|
|
439
|
-
"scripts/, references/, assets/ directories are defined by spec but implementation is still incomplete (issue #15895)."
|
|
440
|
-
]
|
|
441
|
-
});
|
|
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
|
-
*/
|
|
455
|
-
const githubCopilot = defineTarget({
|
|
456
|
-
agent: "github-copilot",
|
|
457
|
-
displayName: "GitHub Copilot",
|
|
458
|
-
detectInstalled: () => existsSync(join(home$2, ".copilot")),
|
|
459
|
-
detectEnv: () => !!process.env.GITHUB_COPILOT_SESSION,
|
|
460
|
-
detectProject: (cwd) => existsSync(join(cwd, ".github", "copilot-instructions.md")),
|
|
461
|
-
instructionFile: ".github/copilot-instructions.md",
|
|
462
|
-
skillsDir: ".github/skills",
|
|
463
|
-
globalSkillsDir: join(home$2, ".copilot/skills"),
|
|
464
|
-
additionalSkillsDirs: [".claude/skills", "~/.claude/skills"],
|
|
465
|
-
frontmatter: [
|
|
466
|
-
SPEC_FRONTMATTER.name,
|
|
467
|
-
{
|
|
468
|
-
...SPEC_FRONTMATTER.description,
|
|
469
|
-
description: "What the skill does AND when to use it."
|
|
470
|
-
},
|
|
471
|
-
SPEC_FRONTMATTER.license,
|
|
472
|
-
SPEC_FRONTMATTER.compatibility,
|
|
473
|
-
{
|
|
474
|
-
...SPEC_FRONTMATTER.metadata,
|
|
475
|
-
description: "Arbitrary key-value pairs (e.g. version, author)"
|
|
476
|
-
},
|
|
477
|
-
SPEC_FRONTMATTER["allowed-tools"]
|
|
478
|
-
],
|
|
479
|
-
discoveryStrategy: "lazy",
|
|
480
|
-
discoveryNotes: "3-level progressive disclosure: (1) ~100 tokens for name+description, (2) full SKILL.md body <5000 tokens on activation, (3) resources from scripts/references/assets/ on demand.",
|
|
481
|
-
agentSkillsSpec: true,
|
|
482
|
-
docs: "https://docs.github.com/en/copilot/concepts/agents/about-agent-skills",
|
|
483
|
-
notes: [
|
|
484
|
-
"Copilot auto-detects .claude/skills/ as a legacy path — emitting there covers multiple agents.",
|
|
485
|
-
"Instructions system (.github/instructions/*.instructions.md) is separate, uses applyTo globs.",
|
|
486
|
-
"copilot-instructions.md at .github/ root is always applied (repo-wide).",
|
|
487
|
-
"AGENTS.md also recognized as of Aug 2025.",
|
|
488
|
-
"excludeAgent property in instructions can hide from code-review or coding-agent.",
|
|
489
|
-
"Keep SKILL.md under 500 lines / 5000 tokens for optimal loading."
|
|
490
|
-
]
|
|
491
|
-
});
|
|
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
|
-
*/
|
|
502
|
-
const goose = defineTarget({
|
|
503
|
-
agent: "goose",
|
|
504
|
-
displayName: "Goose",
|
|
505
|
-
detectInstalled: () => existsSync(join(configHome$1, "goose")),
|
|
506
|
-
detectEnv: () => !!process.env.GOOSE_SESSION,
|
|
507
|
-
detectProject: (cwd) => existsSync(join(cwd, ".goose")),
|
|
508
|
-
cli: "goose",
|
|
509
|
-
instructionFile: ".goosehints",
|
|
510
|
-
skillsDir: ".goose/skills",
|
|
511
|
-
globalSkillsDir: join(configHome$1, "goose/skills"),
|
|
512
|
-
additionalSkillsDirs: [
|
|
513
|
-
".claude/skills",
|
|
514
|
-
".agents/skills",
|
|
515
|
-
"~/.claude/skills",
|
|
516
|
-
"~/.config/agents/skills"
|
|
517
|
-
],
|
|
518
|
-
frontmatter: [{
|
|
519
|
-
...SPEC_FRONTMATTER.name,
|
|
520
|
-
description: "Skill identifier."
|
|
521
|
-
}, {
|
|
522
|
-
...SPEC_FRONTMATTER.description,
|
|
523
|
-
description: "Brief purpose statement; used for matching."
|
|
524
|
-
}],
|
|
525
|
-
discoveryStrategy: "eager",
|
|
526
|
-
discoveryNotes: "Scans all 6 directories at startup, merges discovered skills. Later directories override earlier ones on name conflict.",
|
|
527
|
-
agentSkillsSpec: false,
|
|
528
|
-
docs: "https://block.github.io/goose/docs/guides/context-engineering/using-skills/",
|
|
529
|
-
notes: [
|
|
530
|
-
"Reads .claude/skills/ natively — emitting there covers both Claude Code and Goose.",
|
|
531
|
-
"Also supports .goosehints / .goosehints.local for general project instructions (separate from skills).",
|
|
532
|
-
"Supporting files alongside SKILL.md (scripts, templates, configs) are accessible."
|
|
533
|
-
]
|
|
534
|
-
});
|
|
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
|
-
*/
|
|
548
|
-
const opencode = defineTarget({
|
|
549
|
-
agent: "opencode",
|
|
550
|
-
displayName: "OpenCode",
|
|
551
|
-
detectInstalled: () => existsSync(join(configHome, "opencode")),
|
|
552
|
-
detectEnv: () => !!process.env.OPENCODE_SESSION,
|
|
553
|
-
detectProject: (cwd) => existsSync(join(cwd, ".opencode")),
|
|
554
|
-
instructionFile: "AGENTS.md",
|
|
555
|
-
skillsDir: ".opencode/skills",
|
|
556
|
-
globalSkillsDir: join(configHome, "opencode/skills"),
|
|
557
|
-
additionalSkillsDirs: [
|
|
558
|
-
".claude/skills",
|
|
559
|
-
".agents/skills",
|
|
560
|
-
"~/.claude/skills",
|
|
561
|
-
"~/.agents/skills"
|
|
562
|
-
],
|
|
563
|
-
frontmatter: [
|
|
564
|
-
{
|
|
565
|
-
...SPEC_FRONTMATTER.name,
|
|
566
|
-
description: "Must match directory name."
|
|
567
|
-
},
|
|
568
|
-
{
|
|
569
|
-
...SPEC_FRONTMATTER.description,
|
|
570
|
-
description: "Used for matching."
|
|
571
|
-
},
|
|
572
|
-
SPEC_FRONTMATTER.license,
|
|
573
|
-
SPEC_FRONTMATTER.compatibility,
|
|
574
|
-
SPEC_FRONTMATTER.metadata
|
|
575
|
-
],
|
|
576
|
-
discoveryStrategy: "eager",
|
|
577
|
-
discoveryNotes: "Walks from CWD to git worktree root, then loads global definitions. Agents access skills via native skill tool. Skills can be permission-controlled per-agent.",
|
|
578
|
-
agentSkillsSpec: true,
|
|
579
|
-
extensions: ["Per-agent skill permissions (allow/deny/ask with glob patterns)"],
|
|
580
|
-
docs: "https://opencode.ai/docs/skills/",
|
|
581
|
-
notes: [
|
|
582
|
-
"Reads .claude/skills/ and .agents/skills/ natively — emitting to .claude/skills/ covers multiple agents.",
|
|
583
|
-
"Custom agents in .opencode/agents/ have rich config: model, temperature, tools, permission, color.",
|
|
584
|
-
"opencode.json supports an instructions field with glob patterns pointing to instruction files.",
|
|
585
|
-
"AGENTS.md (or CLAUDE.md fallback) for general instructions."
|
|
586
|
-
]
|
|
587
|
-
});
|
|
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
|
-
*/
|
|
601
|
-
const roo = defineTarget({
|
|
602
|
-
agent: "roo",
|
|
603
|
-
displayName: "Roo Code",
|
|
604
|
-
detectInstalled: () => existsSync(join(home$1, ".roo")),
|
|
605
|
-
detectEnv: () => !!process.env.ROO_SESSION,
|
|
606
|
-
detectProject: (cwd) => existsSync(join(cwd, ".roo")),
|
|
607
|
-
instructionFile: ".roorules",
|
|
608
|
-
skillsDir: ".roo/skills",
|
|
609
|
-
globalSkillsDir: join(home$1, ".roo/skills"),
|
|
610
|
-
frontmatter: [{
|
|
611
|
-
...SPEC_FRONTMATTER.name,
|
|
612
|
-
description: "Must exactly match the directory name."
|
|
613
|
-
}, {
|
|
614
|
-
...SPEC_FRONTMATTER.description,
|
|
615
|
-
description: "When to activate."
|
|
616
|
-
}],
|
|
617
|
-
discoveryStrategy: "eager",
|
|
618
|
-
discoveryNotes: "Reads all SKILL.md files at startup. File watchers detect changes during session. Uses read_file to load full content on activation.",
|
|
619
|
-
agentSkillsSpec: false,
|
|
620
|
-
extensions: ["Mode-specific skill directories: .roo/skills-{modeSlug}/"],
|
|
621
|
-
docs: "https://docs.roocode.com/features/skills",
|
|
622
|
-
notes: [
|
|
623
|
-
"Does NOT read .claude/skills/ or .agents/skills/ — requires its own .roo/skills/ directory.",
|
|
624
|
-
"Mode-specific dirs: .roo/skills-code/, .roo/skills-architect/ etc. target specific modes.",
|
|
625
|
-
"Override priority: project mode-specific > project generic > global mode-specific > global generic.",
|
|
626
|
-
"Supports symlinks for shared skill libraries across projects.",
|
|
627
|
-
"Rules system (.roo/rules/) is separate — .md/.txt files loaded alphabetically into system prompt.",
|
|
628
|
-
"Legacy fallback: .roorules file if .roo/rules/ is empty.",
|
|
629
|
-
"Skills manageable from Settings panel (v3.46.0+)."
|
|
630
|
-
]
|
|
631
|
-
});
|
|
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
|
-
*/
|
|
645
|
-
const windsurf = defineTarget({
|
|
646
|
-
agent: "windsurf",
|
|
647
|
-
displayName: "Windsurf",
|
|
648
|
-
detectInstalled: () => existsSync(join(home, ".codeium/windsurf")),
|
|
649
|
-
detectEnv: () => !!process.env.WINDSURF_SESSION,
|
|
650
|
-
detectProject: (cwd) => existsSync(join(cwd, ".windsurf")) || existsSync(join(cwd, ".windsurfrules")),
|
|
651
|
-
instructionFile: ".windsurfrules",
|
|
652
|
-
skillsDir: ".windsurf/skills",
|
|
653
|
-
globalSkillsDir: join(home, ".codeium/windsurf/skills"),
|
|
654
|
-
frontmatter: [{
|
|
655
|
-
...SPEC_FRONTMATTER.name,
|
|
656
|
-
description: "Skill identifier.",
|
|
657
|
-
constraints: "Lowercase, numbers, hyphens only"
|
|
658
|
-
}, {
|
|
659
|
-
...SPEC_FRONTMATTER.description,
|
|
660
|
-
description: "Used by Cascade for automatic invocation matching."
|
|
661
|
-
}],
|
|
662
|
-
discoveryStrategy: "eager",
|
|
663
|
-
discoveryNotes: "Cascade matches description against user requests for auto-invocation. Manual invocation via @skill-name.",
|
|
664
|
-
agentSkillsSpec: false,
|
|
665
|
-
docs: "https://docs.windsurf.com/windsurf/cascade/skills",
|
|
666
|
-
notes: [
|
|
667
|
-
"Only `name` and `description` are documented as frontmatter fields. Other fields may be silently ignored.",
|
|
668
|
-
"Rules system is separate: .windsurf/rules/*.md with trigger/globs/alwaysApply frontmatter.",
|
|
669
|
-
"Rules have a 6,000 char per-file limit and 12,000 char total limit. Skills have no documented limit.",
|
|
670
|
-
"Legacy .windsurfrules at project root still supported but deprecated.",
|
|
671
|
-
"Supporting files alongside SKILL.md are loaded via progressive disclosure."
|
|
672
|
-
]
|
|
673
|
-
});
|
|
674
|
-
const targets = {
|
|
675
|
-
"claude-code": claudeCode,
|
|
676
|
-
"cursor": cursor,
|
|
677
|
-
"windsurf": windsurf,
|
|
678
|
-
"cline": cline,
|
|
679
|
-
"codex": codex,
|
|
680
|
-
"github-copilot": githubCopilot,
|
|
681
|
-
"gemini-cli": geminiCli,
|
|
682
|
-
"goose": goose,
|
|
683
|
-
"amp": amp,
|
|
684
|
-
"opencode": opencode,
|
|
685
|
-
"roo": roo,
|
|
686
|
-
"antigravity": antigravity
|
|
687
|
-
};
|
|
688
|
-
/**
|
|
689
|
-
* Detect which agents are installed on the system
|
|
690
|
-
*/
|
|
691
|
-
function detectInstalledAgents() {
|
|
692
|
-
return Object.entries(targets).filter(([_, config]) => config.detectInstalled()).map(([type]) => type);
|
|
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
|
-
*/
|
|
701
|
-
function detectTargetAgent() {
|
|
702
|
-
for (const [type, target] of Object.entries(targets)) if (target.detectEnv()) return type;
|
|
703
|
-
const cwd = process.cwd();
|
|
704
|
-
for (const [type, target] of Object.entries(targets)) if (target.detectProject(cwd)) return type;
|
|
705
|
-
return null;
|
|
706
|
-
}
|
|
707
|
-
/**
|
|
708
|
-
* Get the version of an agent's CLI (if available)
|
|
709
|
-
*/
|
|
710
|
-
function getAgentVersion(agentType) {
|
|
711
|
-
const agent = targets[agentType];
|
|
712
|
-
if (!agent.cli) return null;
|
|
713
|
-
try {
|
|
714
|
-
const result = spawnSync(agent.cli, ["--version"], {
|
|
715
|
-
encoding: "utf-8",
|
|
716
|
-
timeout: 3e3,
|
|
717
|
-
stdio: [
|
|
718
|
-
"pipe",
|
|
719
|
-
"pipe",
|
|
720
|
-
"pipe"
|
|
721
|
-
],
|
|
722
|
-
shell: isWindows
|
|
723
|
-
});
|
|
724
|
-
if (result.status !== 0) return null;
|
|
725
|
-
const output = (result.stdout || "").trim();
|
|
726
|
-
const match = output.match(/v?(\d+\.\d+\.\d+(?:-[a-z0-9.]+)?)/);
|
|
727
|
-
return match ? match[1] : output.split("\n")[0];
|
|
728
|
-
} catch {
|
|
729
|
-
return null;
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
7
|
/**
|
|
733
8
|
* Dynamic budget allocation for skill sections.
|
|
734
9
|
*
|
|
@@ -876,7 +151,7 @@ The "Older" column means ≤ v${Number(major) - 2}.x — these changes are NOT u
|
|
|
876
151
|
const labeledBullets = (content.match(/^- (?:\*\*)?(?:BREAKING|DEPRECATED|NEW):(?:\*\*)? /gm) || []).length;
|
|
877
152
|
const alsoChangedItems = (content.match(/\*\*Also changed:\*\*/g) || []).length;
|
|
878
153
|
if (detailedBullets > 2 && labeledBullets / (detailedBullets - alsoChangedItems || 1) < .8) warnings.push({ warning: `Only ${labeledBullets}/${detailedBullets} items have BREAKING/DEPRECATED/NEW labels` });
|
|
879
|
-
if (!/^## API Changes/
|
|
154
|
+
if (!/^## API Changes/im.test(content)) warnings.push({ warning: "Missing required \"## API Changes\" heading" });
|
|
880
155
|
return warnings;
|
|
881
156
|
},
|
|
882
157
|
task: `**Find new, deprecated, and renamed APIs from version history.** Focus exclusively on APIs that changed between versions — LLMs trained on older data will use the wrong names, wrong signatures, or non-existent functions.
|
|
@@ -969,7 +244,7 @@ function bestPracticesSection({ packageName, hasIssues, hasDiscussions, hasRelea
|
|
|
969
244
|
const bullets = (content.match(/^- /gm) || []).length;
|
|
970
245
|
const codeBlocks = (content.match(/^```/gm) || []).length / 2;
|
|
971
246
|
if (bullets > 2 && codeBlocks / bullets > .5) warnings.push({ warning: `${Math.round(codeBlocks)}/${bullets} items have code blocks — prefer concise descriptions with source links` });
|
|
972
|
-
if (!/^## Best Practices/
|
|
247
|
+
if (!/^## Best Practices/im.test(content)) warnings.push({ warning: "Missing required \"## Best Practices\" heading" });
|
|
973
248
|
return warnings;
|
|
974
249
|
},
|
|
975
250
|
task: `**Extract non-obvious best practices from the references.** Focus on recommended patterns the LLM wouldn't already know: idiomatic usage, preferred configurations, performance tips, patterns that differ from what a developer would assume. Surface new patterns from recent minor releases that may post-date training data.
|
|
@@ -1043,6 +318,25 @@ const SECTION_MERGE_ORDER = [
|
|
|
1043
318
|
"best-practices",
|
|
1044
319
|
"custom"
|
|
1045
320
|
];
|
|
321
|
+
/** Wrap section content with HTML comment markers for targeted re-assembly */
|
|
322
|
+
function wrapSection(section, content) {
|
|
323
|
+
return `<!-- skilld:${section} -->\n${content}\n<!-- /skilld:${section} -->`;
|
|
324
|
+
}
|
|
325
|
+
/** Extract marker-delimited sections from existing SKILL.md */
|
|
326
|
+
function extractMarkedSections(md) {
|
|
327
|
+
const sections = /* @__PURE__ */ new Map();
|
|
328
|
+
for (const section of SECTION_MERGE_ORDER) {
|
|
329
|
+
const open = `<!-- skilld:${section} -->`;
|
|
330
|
+
const close = `<!-- /skilld:${section} -->`;
|
|
331
|
+
const start = md.indexOf(open);
|
|
332
|
+
const end = md.indexOf(close);
|
|
333
|
+
if (start !== -1 && end !== -1) sections.set(section, {
|
|
334
|
+
start,
|
|
335
|
+
end: end + close.length
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
return sections;
|
|
339
|
+
}
|
|
1046
340
|
/**
|
|
1047
341
|
* Group files by parent directory with counts
|
|
1048
342
|
* e.g. `/path/to/docs/api/ (15 .md files)`
|
|
@@ -1210,6 +504,40 @@ function buildAllSectionPrompts(opts) {
|
|
|
1210
504
|
return result;
|
|
1211
505
|
}
|
|
1212
506
|
/**
|
|
507
|
+
* Transform an agent-specific prompt into a portable prompt for any LLM.
|
|
508
|
+
* - Rewrites .skilld/ paths → ./references/
|
|
509
|
+
* - Strips ## Output section (file-writing instructions)
|
|
510
|
+
* - Strips skilld search/validate instructions
|
|
511
|
+
* - Replaces tool-specific language with generic equivalents
|
|
512
|
+
* - Strips agent-specific rules
|
|
513
|
+
*/
|
|
514
|
+
function portabilizePrompt(prompt, section) {
|
|
515
|
+
let out = prompt;
|
|
516
|
+
out = out.replace(/`[^`]*\/\.skilld\//g, (m) => m.replace(/[^`]*\/\.skilld\//, "./references/"));
|
|
517
|
+
out = out.replace(/\(\.\/\.skilld\//g, "(./references/");
|
|
518
|
+
out = out.replace(/`\.\/\.skilld\//g, "`./references/");
|
|
519
|
+
out = out.replace(/\.skilld\//g, "./references/");
|
|
520
|
+
out = out.replace(/\n## Output\n[\s\S]*$/, "");
|
|
521
|
+
out = out.replace(/\n## Search\n[\s\S]*?(?=\n\n(?:\||## |<|\*\*))/, "");
|
|
522
|
+
out = out.replace(/^- .*`skilld search`.*$/gm, "");
|
|
523
|
+
out = out.replace(/^- .*`skilld validate`.*$/gm, "");
|
|
524
|
+
out = out.replace(/,? and `skilld search`/g, "");
|
|
525
|
+
out = out.replace(/\buse Read tool to explore\b/gi, "read the files");
|
|
526
|
+
out = out.replace(/\bRead tool\b/g, "reading files");
|
|
527
|
+
out = out.replace(/\buse Read, Glob\b/gi, "read the files in");
|
|
528
|
+
out = out.replace(/\bWrite tool\b/g, "your output");
|
|
529
|
+
out = out.replace(/\bGlob\b/g, "file search");
|
|
530
|
+
out = out.replace(/\bpass `no_ignore: true`[^.]*\./g, "");
|
|
531
|
+
out = out.replace(/^- \*\*Do NOT use Task tool or spawn subagents\.\*\*.*$/gm, "");
|
|
532
|
+
out = out.replace(/^- \*\*Do NOT re-read files\*\*.*$/gm, "");
|
|
533
|
+
out = out.trimEnd();
|
|
534
|
+
const outputFile = section ? SECTION_OUTPUT_FILES[section] : void 0;
|
|
535
|
+
out += `\n\n## Output\n\nOutput the section content as plain markdown. Do not wrap in code fences.\n`;
|
|
536
|
+
if (outputFile) out += `\nSave your output as \`${outputFile}\`, then run:\n\n\`\`\`bash\nskilld assemble\n\`\`\`\n`;
|
|
537
|
+
out = out.replace(/\n{3,}/g, "\n\n");
|
|
538
|
+
return out;
|
|
539
|
+
}
|
|
540
|
+
/**
|
|
1213
541
|
* Sanitize skill name for filesystem
|
|
1214
542
|
*/
|
|
1215
543
|
function sanitizeName(name) {
|
|
@@ -1255,12 +583,12 @@ function installSkillForAgents(skillName, skillContent, options = {}) {
|
|
|
1255
583
|
};
|
|
1256
584
|
}
|
|
1257
585
|
/**
|
|
1258
|
-
* Create relative
|
|
1259
|
-
* Only targets agents whose config dir already exists in the project.
|
|
586
|
+
* Create a relative symlink from the target agent's skills dir to the shared .skills/ dir.
|
|
1260
587
|
* Replaces existing symlinks, skips real directories (user's custom skills).
|
|
1261
588
|
*/
|
|
1262
|
-
function linkSkillToAgents(skillName, sharedDir, cwd) {
|
|
1263
|
-
|
|
589
|
+
function linkSkillToAgents(skillName, sharedDir, cwd, agentType) {
|
|
590
|
+
const targetAgents = agentType ? [[agentType, targets[agentType]]] : Object.entries(targets);
|
|
591
|
+
for (const [, agent] of targetAgents) {
|
|
1264
592
|
const agentSkillsDir = join(cwd, agent.skillsDir);
|
|
1265
593
|
if (!existsSync(join(cwd, agent.skillsDir.split("/")[0]))) continue;
|
|
1266
594
|
const target = join(agentSkillsDir, skillName);
|
|
@@ -1280,8 +608,9 @@ function linkSkillToAgents(skillName, sharedDir, cwd) {
|
|
|
1280
608
|
/**
|
|
1281
609
|
* Remove per-agent symlinks for a skill when removing from shared dir.
|
|
1282
610
|
*/
|
|
1283
|
-
function unlinkSkillFromAgents(skillName, cwd) {
|
|
1284
|
-
|
|
611
|
+
function unlinkSkillFromAgents(skillName, cwd, agentType) {
|
|
612
|
+
const targetAgents = agentType ? [[agentType, targets[agentType]]] : Object.entries(targets);
|
|
613
|
+
for (const [, agent] of targetAgents) {
|
|
1285
614
|
const target = join(cwd, agent.skillsDir, skillName);
|
|
1286
615
|
try {
|
|
1287
616
|
if (lstatSync(target).isSymbolicLink()) unlinkSync(target);
|
|
@@ -1452,6 +781,6 @@ function generateFooter(relatedSkills) {
|
|
|
1452
781
|
if (relatedSkills.length === 0) return "";
|
|
1453
782
|
return `\nRelated: ${relatedSkills.join(", ")}\n`;
|
|
1454
783
|
}
|
|
1455
|
-
export {
|
|
784
|
+
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 };
|
|
1456
785
|
|
|
1457
786
|
//# sourceMappingURL=prompts.mjs.map
|