@percena/weft 0.4.0-next.0 → 0.4.0-next.10

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.
Files changed (114) hide show
  1. package/dist/action-bridge.cjs +323 -0
  2. package/dist/action-bridge.d.cts +8 -0
  3. package/dist/action-bridge.d.ts +8 -0
  4. package/dist/action-bridge.js +291 -0
  5. package/dist/chat.cjs +3851 -36
  6. package/dist/chat.d.cts +1 -874
  7. package/dist/chat.d.ts +1 -874
  8. package/dist/chat.js +3870 -36
  9. package/dist/index.cjs +12085 -1488
  10. package/dist/index.d.cts +553 -240
  11. package/dist/index.d.ts +553 -240
  12. package/dist/index.js +12118 -1447
  13. package/dist/providers-flitro.cjs +50 -307
  14. package/dist/providers-flitro.d.cts +75 -52
  15. package/dist/providers-flitro.d.ts +75 -52
  16. package/dist/providers-flitro.js +45 -287
  17. package/dist/styles/fonts/KaTeX_AMS-Regular.ttf +0 -0
  18. package/dist/styles/fonts/KaTeX_AMS-Regular.woff +0 -0
  19. package/dist/styles/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  20. package/dist/styles/fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  21. package/dist/styles/fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  22. package/dist/styles/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  23. package/dist/styles/fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  24. package/dist/styles/fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  25. package/dist/styles/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  26. package/dist/styles/fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  27. package/dist/styles/fonts/KaTeX_Fraktur-Bold.woff +0 -0
  28. package/dist/styles/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  29. package/dist/styles/fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  30. package/dist/styles/fonts/KaTeX_Fraktur-Regular.woff +0 -0
  31. package/dist/styles/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  32. package/dist/styles/fonts/KaTeX_Main-Bold.ttf +0 -0
  33. package/dist/styles/fonts/KaTeX_Main-Bold.woff +0 -0
  34. package/dist/styles/fonts/KaTeX_Main-Bold.woff2 +0 -0
  35. package/dist/styles/fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  36. package/dist/styles/fonts/KaTeX_Main-BoldItalic.woff +0 -0
  37. package/dist/styles/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  38. package/dist/styles/fonts/KaTeX_Main-Italic.ttf +0 -0
  39. package/dist/styles/fonts/KaTeX_Main-Italic.woff +0 -0
  40. package/dist/styles/fonts/KaTeX_Main-Italic.woff2 +0 -0
  41. package/dist/styles/fonts/KaTeX_Main-Regular.ttf +0 -0
  42. package/dist/styles/fonts/KaTeX_Main-Regular.woff +0 -0
  43. package/dist/styles/fonts/KaTeX_Main-Regular.woff2 +0 -0
  44. package/dist/styles/fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  45. package/dist/styles/fonts/KaTeX_Math-BoldItalic.woff +0 -0
  46. package/dist/styles/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  47. package/dist/styles/fonts/KaTeX_Math-Italic.ttf +0 -0
  48. package/dist/styles/fonts/KaTeX_Math-Italic.woff +0 -0
  49. package/dist/styles/fonts/KaTeX_Math-Italic.woff2 +0 -0
  50. package/dist/styles/fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  51. package/dist/styles/fonts/KaTeX_SansSerif-Bold.woff +0 -0
  52. package/dist/styles/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  53. package/dist/styles/fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  54. package/dist/styles/fonts/KaTeX_SansSerif-Italic.woff +0 -0
  55. package/dist/styles/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  56. package/dist/styles/fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  57. package/dist/styles/fonts/KaTeX_SansSerif-Regular.woff +0 -0
  58. package/dist/styles/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  59. package/dist/styles/fonts/KaTeX_Script-Regular.ttf +0 -0
  60. package/dist/styles/fonts/KaTeX_Script-Regular.woff +0 -0
  61. package/dist/styles/fonts/KaTeX_Script-Regular.woff2 +0 -0
  62. package/dist/styles/fonts/KaTeX_Size1-Regular.ttf +0 -0
  63. package/dist/styles/fonts/KaTeX_Size1-Regular.woff +0 -0
  64. package/dist/styles/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  65. package/dist/styles/fonts/KaTeX_Size2-Regular.ttf +0 -0
  66. package/dist/styles/fonts/KaTeX_Size2-Regular.woff +0 -0
  67. package/dist/styles/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  68. package/dist/styles/fonts/KaTeX_Size3-Regular.ttf +0 -0
  69. package/dist/styles/fonts/KaTeX_Size3-Regular.woff +0 -0
  70. package/dist/styles/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  71. package/dist/styles/fonts/KaTeX_Size4-Regular.ttf +0 -0
  72. package/dist/styles/fonts/KaTeX_Size4-Regular.woff +0 -0
  73. package/dist/styles/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  74. package/dist/styles/fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  75. package/dist/styles/fonts/KaTeX_Typewriter-Regular.woff +0 -0
  76. package/dist/styles/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  77. package/dist/styles/index.css +2 -212
  78. package/package.json +23 -49
  79. package/dist/auth.cjs +0 -241
  80. package/dist/auth.d.cts +0 -21
  81. package/dist/auth.d.ts +0 -21
  82. package/dist/auth.js +0 -208
  83. package/dist/automations.cjs +0 -3044
  84. package/dist/automations.d.cts +0 -4774
  85. package/dist/automations.d.ts +0 -4774
  86. package/dist/automations.js +0 -2965
  87. package/dist/factory.cjs +0 -5057
  88. package/dist/factory.d.cts +0 -7909
  89. package/dist/factory.d.ts +0 -7909
  90. package/dist/factory.js +0 -5008
  91. package/dist/local-runtime.cjs +0 -1387
  92. package/dist/local-runtime.d.cts +0 -3314
  93. package/dist/local-runtime.d.ts +0 -3314
  94. package/dist/local-runtime.js +0 -1345
  95. package/dist/providers.cjs +0 -6154
  96. package/dist/providers.d.cts +0 -6024
  97. package/dist/providers.d.ts +0 -6024
  98. package/dist/providers.js +0 -6110
  99. package/dist/server.cjs +0 -9137
  100. package/dist/server.d.cts +0 -9868
  101. package/dist/server.d.ts +0 -9868
  102. package/dist/server.js +0 -9118
  103. package/dist/skills-browser.cjs +0 -118
  104. package/dist/skills-browser.d.cts +0 -105
  105. package/dist/skills-browser.d.ts +0 -105
  106. package/dist/skills-browser.js +0 -88
  107. package/dist/skills.cjs +0 -505
  108. package/dist/skills.d.cts +0 -218
  109. package/dist/skills.d.ts +0 -218
  110. package/dist/skills.js +0 -458
  111. package/dist/sources.cjs +0 -1710
  112. package/dist/sources.d.cts +0 -3978
  113. package/dist/sources.d.ts +0 -3978
  114. package/dist/sources.js +0 -1675
package/dist/skills.js DELETED
@@ -1,458 +0,0 @@
1
- // ../packages/skills/dist/chunk-IAAI7RH5.js
2
- var AGENTS_PLUGIN_NAME = ".agents";
3
- function createSkillActivationPlan(options) {
4
- const enabledSources = new Set(options.enabledSourceSlugs ?? []);
5
- const selected = new Set(options.selectedSkillSlugs ?? []);
6
- const promptMentions = parseSkillMentions(options.prompt ?? "");
7
- const filePaths = options.filePaths ?? [];
8
- const activations = [];
9
- const seen = /* @__PURE__ */ new Set();
10
- for (const skill of options.skills) {
11
- const reason = activationReason(skill, {
12
- selected,
13
- promptMentions,
14
- filePaths
15
- });
16
- if (!reason || seen.has(skill.slug)) continue;
17
- seen.add(skill.slug);
18
- activations.push({ skill, reason });
19
- }
20
- const requiredSourceSlugs = unique(activations.flatMap(
21
- (activation) => activation.skill.metadata.requiredSources ?? []
22
- ));
23
- const missingRequiredSourceSlugs = requiredSourceSlugs.filter((source) => !enabledSources.has(source));
24
- const policyExtensions = activations.flatMap(({ skill }) => (skill.metadata.alwaysAllow ?? []).map((toolName) => ({
25
- toolName,
26
- scope: { type: "skill", skillSlug: skill.slug }
27
- })));
28
- const prerequisiteFiles = activations.map(({ skill }) => `${skill.path}/SKILL.md`).filter((path) => options.prerequisiteFileExists?.(path) ?? true);
29
- return {
30
- activeSkillSlugs: activations.map((activation) => activation.skill.slug),
31
- activations,
32
- requiredSourceSlugs,
33
- missingRequiredSourceSlugs,
34
- policyExtensions,
35
- providerInstructions: buildProviderInstructions(activations),
36
- prerequisiteFiles
37
- };
38
- }
39
- function activationReason(skill, context) {
40
- if (context.promptMentions.has(skill.slug)) return "prompt-mention";
41
- if (context.selected.has(skill.slug)) return "host-selection";
42
- if (matchesAnyGlob(skill.metadata.globs ?? [], context.filePaths)) return "file-glob";
43
- return void 0;
44
- }
45
- function parseSkillMentions(prompt) {
46
- const mentions = /* @__PURE__ */ new Set();
47
- for (const match of prompt.matchAll(/@([A-Za-z0-9_-]+)/g)) {
48
- mentions.add(match[1]);
49
- }
50
- return mentions;
51
- }
52
- function matchesAnyGlob(globs, filePaths) {
53
- return globs.some((glob) => filePaths.some((filePath) => globMatches(glob, filePath)));
54
- }
55
- function buildProviderInstructions(activations) {
56
- return activations.map(({ skill }) => `# ${skill.metadata.name}
57
-
58
- ${skill.content}`).join("\n\n");
59
- }
60
- function unique(values) {
61
- return [...new Set(values)];
62
- }
63
- function globMatches(pattern, value) {
64
- const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "__DOUBLE_STAR__").replace(/\*/g, "[^/]*").replace(/__DOUBLE_STAR__/g, ".*");
65
- return new RegExp(`^${escaped}$`).test(value);
66
- }
67
- function formatSkillDirective(prerequisiteFiles) {
68
- if (prerequisiteFiles.length === 0) return void 0;
69
- const fileList = prerequisiteFiles.map((f) => `- ${f}`).join("\n");
70
- return [
71
- "Before proceeding with the user's request, you MUST read the following skill instruction files:",
72
- fileList,
73
- "Do not take any other action until you have read these files."
74
- ].join("\n");
75
- }
76
- function prependSkillDirective(message, prerequisiteFiles) {
77
- const directive = formatSkillDirective(prerequisiteFiles);
78
- if (!directive) return message;
79
- return `${directive}
80
-
81
- ${message}`;
82
- }
83
-
84
- // ../packages/skills/dist/index.js
85
- import matter from "gray-matter";
86
- import {
87
- existsSync,
88
- mkdirSync,
89
- readFileSync,
90
- readdirSync,
91
- rmSync,
92
- statSync,
93
- writeFileSync
94
- } from "fs";
95
- import { homedir } from "os";
96
- import { join as join2 } from "path";
97
- import matter2 from "gray-matter";
98
- import { join } from "path";
99
- function validateSkillDefinitionContent(content, file = "SKILL.md") {
100
- const errors = [];
101
- const warnings = [];
102
- let parsed;
103
- try {
104
- parsed = matter(content);
105
- } catch (error) {
106
- errors.push(issue(
107
- file,
108
- "frontmatter",
109
- `Invalid skill frontmatter: ${error instanceof Error ? error.message : "Unknown error"}`,
110
- "error"
111
- ));
112
- return result(errors, warnings);
113
- }
114
- const data = parsed.data && typeof parsed.data === "object" ? parsed.data : {};
115
- if (!isNonEmptyString(data.name)) {
116
- errors.push(issue(file, "frontmatter.name", "Skill metadata requires name", "error"));
117
- }
118
- if (!isNonEmptyString(data.description)) {
119
- errors.push(issue(file, "frontmatter.description", "Skill metadata requires description", "error"));
120
- }
121
- validateStringArray(data.globs, "frontmatter.globs", file, errors);
122
- validateStringArray(data.alwaysAllow, "frontmatter.alwaysAllow", file, errors);
123
- validateRequiredSources(data.requiredSources, file, errors);
124
- if (!data.globs && !data.requiredSources) {
125
- warnings.push(issue(
126
- file,
127
- "frontmatter",
128
- "Skill has no activation metadata",
129
- "warning",
130
- "Add globs, requiredSources, or select the skill explicitly from the host UI."
131
- ));
132
- }
133
- if (!parsed.content.trim()) {
134
- warnings.push(issue(
135
- file,
136
- "content",
137
- "Skill body is empty",
138
- "warning",
139
- "Add provider instructions to make the skill useful when activated."
140
- ));
141
- }
142
- return result(errors, warnings);
143
- }
144
- function validateRequiredSources(value, file, errors) {
145
- if (value === void 0) return;
146
- if (typeof value === "string") return;
147
- validateStringArray(value, "frontmatter.requiredSources", file, errors);
148
- }
149
- function validateStringArray(value, path, file, errors) {
150
- if (value === void 0) return;
151
- if (!Array.isArray(value)) {
152
- errors.push(issue(file, path, `${leafName(path)} must be an array of strings`, "error"));
153
- return;
154
- }
155
- value.forEach((entry, index) => {
156
- if (typeof entry !== "string") {
157
- errors.push(issue(file, `${path}[${index}]`, `${leafName(path)} entries must be strings`, "error"));
158
- }
159
- });
160
- }
161
- function issue(file, path, message, severity, suggestion) {
162
- return {
163
- file,
164
- path,
165
- message,
166
- severity,
167
- ...suggestion ? { suggestion } : {}
168
- };
169
- }
170
- function result(errors, warnings) {
171
- return {
172
- valid: errors.length === 0,
173
- errors,
174
- warnings
175
- };
176
- }
177
- function isNonEmptyString(value) {
178
- return typeof value === "string" && value.trim().length > 0;
179
- }
180
- function leafName(path) {
181
- return path.split(".").at(-1) ?? path;
182
- }
183
- function getWorkspaceSkillsPath(workspaceRoot) {
184
- return join(workspaceRoot, "skills");
185
- }
186
- function validateIconValue(value, context) {
187
- if (value === void 0 || value === null) return void 0;
188
- if (typeof value !== "string") return void 0;
189
- if (/^[\p{Emoji}\u200d\ufe0f]+$/u.test(value)) return value;
190
- if (value.startsWith("http://") || value.startsWith("https://")) return value;
191
- console.warn(`[${context}] Invalid icon value: "${value}". Only emoji and URLs are supported.`);
192
- return void 0;
193
- }
194
- function findIconFile(dirPath) {
195
- return void 0;
196
- }
197
- async function downloadIcon(dirPath, iconUrl, context) {
198
- console.warn(`[${context}] Icon download stub: would download ${iconUrl}`);
199
- return null;
200
- }
201
- function needsIconDownload(icon, iconPath) {
202
- if (!icon) return false;
203
- if (icon.startsWith("http://") || icon.startsWith("https://")) {
204
- return !iconPath;
205
- }
206
- return false;
207
- }
208
- var GLOBAL_AGENT_SKILLS_DIR = join2(homedir(), ".agents", "skills");
209
- var PROJECT_AGENT_SKILLS_DIR = ".agents/skills";
210
- function normalizeRequiredSources(value) {
211
- const asArray = typeof value === "string" ? [value] : Array.isArray(value) ? value : void 0;
212
- if (!asArray) return void 0;
213
- const normalized = Array.from(new Set(
214
- asArray.filter((entry) => typeof entry === "string").map((entry) => entry.trim()).filter(Boolean)
215
- ));
216
- return normalized.length > 0 ? normalized : void 0;
217
- }
218
- function parseSkillFile(content) {
219
- try {
220
- const parsed = matter2(content);
221
- if (!parsed.data.name || !parsed.data.description) {
222
- return null;
223
- }
224
- const icon = validateIconValue(parsed.data.icon, "Skills");
225
- return {
226
- metadata: {
227
- name: parsed.data.name,
228
- description: parsed.data.description,
229
- globs: parsed.data.globs,
230
- alwaysAllow: parsed.data.alwaysAllow,
231
- icon,
232
- requiredSources: normalizeRequiredSources(parsed.data.requiredSources)
233
- },
234
- body: parsed.content
235
- };
236
- } catch {
237
- return null;
238
- }
239
- }
240
- function loadSkillFromDir(skillsDir, slug, source) {
241
- const skillDir = join2(skillsDir, slug);
242
- const skillFile = join2(skillDir, "SKILL.md");
243
- if (!existsSync(skillDir) || !statSync(skillDir).isDirectory()) {
244
- return null;
245
- }
246
- if (!existsSync(skillFile)) {
247
- return null;
248
- }
249
- let content;
250
- try {
251
- content = readFileSync(skillFile, "utf-8");
252
- } catch {
253
- return null;
254
- }
255
- const parsed = parseSkillFile(content);
256
- if (!parsed) {
257
- return null;
258
- }
259
- return {
260
- slug,
261
- metadata: parsed.metadata,
262
- content: parsed.body,
263
- iconPath: findIconFile(skillDir),
264
- path: skillDir,
265
- source
266
- };
267
- }
268
- function loadSkillsFromDir(skillsDir, source) {
269
- if (!existsSync(skillsDir)) {
270
- return [];
271
- }
272
- const skills = [];
273
- try {
274
- const entries = readdirSync(skillsDir, { withFileTypes: true });
275
- for (const entry of entries) {
276
- if (!entry.isDirectory()) continue;
277
- const skill = loadSkillFromDir(skillsDir, entry.name, source);
278
- if (skill) {
279
- skills.push(skill);
280
- }
281
- }
282
- } catch {
283
- }
284
- return skills;
285
- }
286
- function loadSkill(workspaceRoot, slug) {
287
- const skillsDir = getWorkspaceSkillsPath(workspaceRoot);
288
- return loadSkillFromDir(skillsDir, slug, "workspace");
289
- }
290
- function loadWorkspaceSkills(workspaceRoot) {
291
- const skillsDir = getWorkspaceSkillsPath(workspaceRoot);
292
- return loadSkillsFromDir(skillsDir, "workspace");
293
- }
294
- var skillsCache = /* @__PURE__ */ new Map();
295
- var SKILLS_CACHE_TTL = 5 * 6e4;
296
- function invalidateSkillsCache() {
297
- skillsCache.clear();
298
- }
299
- function loadAllSkills(workspaceRoot, projectRoot) {
300
- const cacheKey = `${workspaceRoot}::${projectRoot ?? ""}`;
301
- const now = Date.now();
302
- const cached = skillsCache.get(cacheKey);
303
- if (cached && now - cached.ts < SKILLS_CACHE_TTL) {
304
- return cached.skills;
305
- }
306
- const skillsBySlug = /* @__PURE__ */ new Map();
307
- for (const skill of loadSkillsFromDir(GLOBAL_AGENT_SKILLS_DIR, "global")) {
308
- skillsBySlug.set(skill.slug, skill);
309
- }
310
- for (const skill of loadWorkspaceSkills(workspaceRoot)) {
311
- skillsBySlug.set(skill.slug, skill);
312
- }
313
- if (projectRoot) {
314
- const projectSkillsDir = join2(projectRoot, PROJECT_AGENT_SKILLS_DIR);
315
- for (const skill of loadSkillsFromDir(projectSkillsDir, "project")) {
316
- skillsBySlug.set(skill.slug, skill);
317
- }
318
- }
319
- const result2 = Array.from(skillsBySlug.values());
320
- skillsCache.set(cacheKey, { skills: result2, ts: now });
321
- return result2;
322
- }
323
- function loadSkillBySlug(workspaceRoot, slug, projectRoot) {
324
- if (projectRoot) {
325
- const projectSkillsDir = join2(projectRoot, PROJECT_AGENT_SKILLS_DIR);
326
- const skill = loadSkillFromDir(projectSkillsDir, slug, "project");
327
- if (skill) return skill;
328
- }
329
- const workspaceSkill = loadSkillFromDir(getWorkspaceSkillsPath(workspaceRoot), slug, "workspace");
330
- if (workspaceSkill) return workspaceSkill;
331
- return loadSkillFromDir(GLOBAL_AGENT_SKILLS_DIR, slug, "global");
332
- }
333
- function getSkillIconPath(workspaceRoot, slug) {
334
- const skillsDir = getWorkspaceSkillsPath(workspaceRoot);
335
- const skillDir = join2(skillsDir, slug);
336
- if (!existsSync(skillDir)) {
337
- return null;
338
- }
339
- return findIconFile(skillDir) || null;
340
- }
341
- function deleteSkill(workspaceRoot, slug) {
342
- const skillsDir = getWorkspaceSkillsPath(workspaceRoot);
343
- const skillDir = join2(skillsDir, slug);
344
- if (!existsSync(skillDir)) {
345
- return false;
346
- }
347
- try {
348
- rmSync(skillDir, { recursive: true });
349
- return true;
350
- } catch {
351
- return false;
352
- }
353
- }
354
- function createSkill(workspaceRoot, input) {
355
- const skillsDir = getWorkspaceSkillsPath(workspaceRoot);
356
- const skillDir = join2(skillsDir, input.slug);
357
- const skillFile = join2(skillDir, "SKILL.md");
358
- const frontmatter = {
359
- name: input.name,
360
- description: input.description
361
- };
362
- if (input.globs) frontmatter.globs = input.globs;
363
- if (input.alwaysAllow) frontmatter.alwaysAllow = input.alwaysAllow;
364
- if (input.icon) {
365
- const validated = validateIconValue(input.icon, "Skills");
366
- if (validated) frontmatter.icon = validated;
367
- }
368
- if (input.requiredSources) frontmatter.requiredSources = input.requiredSources;
369
- const fileContent = matter2.stringify(input.content, frontmatter);
370
- mkdirSync(skillDir, { recursive: true });
371
- writeFileSync(skillFile, fileContent, "utf-8");
372
- invalidateSkillsCache();
373
- const loaded = loadSkillFromDir(skillsDir, input.slug, "workspace");
374
- if (!loaded) {
375
- throw new Error(`Failed to load newly created skill: ${input.slug}`);
376
- }
377
- return loaded;
378
- }
379
- function updateSkill(workspaceRoot, slug, patch) {
380
- const skillsDir = getWorkspaceSkillsPath(workspaceRoot);
381
- const existing = loadSkillFromDir(skillsDir, slug, "workspace");
382
- if (!existing) {
383
- throw new Error(`Skill not found: ${slug}`);
384
- }
385
- const frontmatter = {
386
- name: patch.name ?? existing.metadata.name,
387
- description: patch.description ?? existing.metadata.description
388
- };
389
- const globs = patch.globs ?? existing.metadata.globs;
390
- if (globs) frontmatter.globs = globs;
391
- const alwaysAllow = patch.alwaysAllow ?? existing.metadata.alwaysAllow;
392
- if (alwaysAllow) frontmatter.alwaysAllow = alwaysAllow;
393
- const icon = patch.icon ?? existing.metadata.icon;
394
- if (icon) {
395
- const validated = validateIconValue(icon, "Skills");
396
- if (validated) frontmatter.icon = validated;
397
- }
398
- const requiredSources = patch.requiredSources ?? existing.metadata.requiredSources;
399
- if (requiredSources) frontmatter.requiredSources = requiredSources;
400
- const content = patch.content ?? existing.content;
401
- const fileContent = matter2.stringify(content, frontmatter);
402
- const skillFile = join2(skillsDir, slug, "SKILL.md");
403
- writeFileSync(skillFile, fileContent, "utf-8");
404
- invalidateSkillsCache();
405
- const loaded = loadSkillFromDir(skillsDir, slug, "workspace");
406
- if (!loaded) {
407
- throw new Error(`Failed to load updated skill: ${slug}`);
408
- }
409
- return loaded;
410
- }
411
- function skillExists(workspaceRoot, slug) {
412
- const skillsDir = getWorkspaceSkillsPath(workspaceRoot);
413
- const skillDir = join2(skillsDir, slug);
414
- const skillFile = join2(skillDir, "SKILL.md");
415
- return existsSync(skillDir) && existsSync(skillFile);
416
- }
417
- function listSkillSlugs(workspaceRoot) {
418
- const skillsDir = getWorkspaceSkillsPath(workspaceRoot);
419
- if (!existsSync(skillsDir)) {
420
- return [];
421
- }
422
- try {
423
- return readdirSync(skillsDir, { withFileTypes: true }).filter((entry) => {
424
- if (!entry.isDirectory()) return false;
425
- const skillFile = join2(skillsDir, entry.name, "SKILL.md");
426
- return existsSync(skillFile);
427
- }).map((entry) => entry.name);
428
- } catch {
429
- return [];
430
- }
431
- }
432
- async function downloadSkillIcon(skillDir, iconUrl) {
433
- return downloadIcon(skillDir, iconUrl, "Skills");
434
- }
435
- function skillNeedsIconDownload(skill) {
436
- return needsIconDownload(skill.metadata.icon, skill.iconPath);
437
- }
438
- export {
439
- AGENTS_PLUGIN_NAME,
440
- GLOBAL_AGENT_SKILLS_DIR,
441
- PROJECT_AGENT_SKILLS_DIR,
442
- createSkill,
443
- createSkillActivationPlan,
444
- deleteSkill,
445
- downloadSkillIcon,
446
- formatSkillDirective,
447
- getSkillIconPath,
448
- invalidateSkillsCache,
449
- listSkillSlugs,
450
- loadAllSkills,
451
- loadSkill,
452
- loadSkillBySlug,
453
- prependSkillDirective,
454
- skillExists,
455
- skillNeedsIconDownload,
456
- updateSkill,
457
- validateSkillDefinitionContent
458
- };