boss-css 0.0.6 → 0.0.7
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/dist/ai/server.cjs +433 -0
- package/dist/ai/server.mjs +422 -0
- package/dist/ai/skills.cjs +344 -0
- package/dist/ai/skills.mjs +343 -0
- package/dist/api/file/text.cjs +11 -0
- package/dist/api/file/text.mjs +11 -0
- package/dist/cli/tasks/init.cjs +11 -2
- package/dist/cli/tasks/init.mjs +12 -3
- package/dist/compile/jsx.cjs +77 -5
- package/dist/compile/jsx.mjs +77 -5
- package/dist/compile/transform.cjs +38 -2
- package/dist/compile/transform.mjs +38 -2
- package/dist/dev/plugin/server.cjs +19 -1
- package/dist/dev/plugin/server.mjs +19 -1
- package/dist/dev/server.cjs +84 -1
- package/dist/dev/server.mjs +84 -1
- package/dist/parser/jsx/server.cjs +32 -8
- package/dist/parser/jsx/server.mjs +32 -8
- package/dist/prop/at/server.cjs +22 -0
- package/dist/prop/at/server.mjs +22 -0
- package/dist/prop/bosswind/server.cjs +27 -0
- package/dist/prop/bosswind/server.mjs +28 -1
- package/dist/prop/bosswind/shared.cjs +15 -0
- package/dist/prop/bosswind/shared.mjs +15 -1
- package/dist/prop/pseudo/server.cjs +9 -0
- package/dist/prop/pseudo/server.mjs +10 -1
- package/dist/prop/pseudo/shared.cjs +2 -1
- package/dist/prop/pseudo/shared.mjs +1 -1
- package/dist/shared/customCss.cjs +66 -10
- package/dist/shared/customCss.mjs +66 -10
- package/dist/tasks/build.cjs +24 -1
- package/dist/tasks/build.mjs +24 -1
- package/dist/tasks/postcss.cjs +15 -0
- package/dist/tasks/postcss.mjs +15 -0
- package/dist/use/token/browser.cjs +14 -2
- package/dist/use/token/browser.mjs +14 -2
- package/dist/use/token/propMap.cjs +109 -0
- package/dist/use/token/propMap.mjs +105 -0
- package/dist/use/token/runtime-only.cjs +13 -80
- package/dist/use/token/runtime-only.mjs +13 -79
- package/dist/use/token/server.cjs +100 -97
- package/dist/use/token/server.mjs +93 -94
- package/package.json +11 -2
|
@@ -0,0 +1,433 @@
|
|
|
1
|
+
const require_rolldown_runtime = require('../_virtual/rolldown_runtime.cjs');
|
|
2
|
+
const require_text = require('../api/file/text.cjs');
|
|
3
|
+
const require_ai_skills = require('./skills.cjs');
|
|
4
|
+
let node_fs_promises = require("node:fs/promises");
|
|
5
|
+
node_fs_promises = require_rolldown_runtime.__toESM(node_fs_promises);
|
|
6
|
+
let node_path = require("node:path");
|
|
7
|
+
node_path = require_rolldown_runtime.__toESM(node_path);
|
|
8
|
+
|
|
9
|
+
//#region src/ai/server.ts
|
|
10
|
+
var server_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
|
|
11
|
+
name: () => name,
|
|
12
|
+
onBoot: () => onBoot,
|
|
13
|
+
onMetaData: () => onMetaData,
|
|
14
|
+
onSession: () => onSession
|
|
15
|
+
});
|
|
16
|
+
const name = "ai";
|
|
17
|
+
const STATIC_DOC = `### Syntax
|
|
18
|
+
- Use <$$ ...> for Boss props in JSX.
|
|
19
|
+
- Use $$.\$({ ... }) to mark prop objects for compile/runtime.
|
|
20
|
+
- Classname tokens look like color:red or hover:color:red (mostly 1:1 with CSS props).
|
|
21
|
+
|
|
22
|
+
### Tokens
|
|
23
|
+
- Prefer token keys (color="primary") over $$.token.* when available.
|
|
24
|
+
- Token overrides can be passed via the tokens prop at runtime.
|
|
25
|
+
- Prefer token shorthands for shadows (boxShadow="md") when available.
|
|
26
|
+
|
|
27
|
+
### Selectors
|
|
28
|
+
- Use pseudos for state (hover, focus, etc.).
|
|
29
|
+
- Use @at for breakpoints and media queries.
|
|
30
|
+
- Use child for nested selectors.
|
|
31
|
+
- Prefer shorthand keys (mobile:...) over at:mobile:...
|
|
32
|
+
- Prefer the device breakpoint for mobile + small screens when available.
|
|
33
|
+
|
|
34
|
+
### Values
|
|
35
|
+
- Prefer unitless numbers (padding:12) and use _ for space-separated values (padding:10_20).
|
|
36
|
+
- Prefer arrays for shorthands (padding={[0, 10]}).
|
|
37
|
+
- For custom shadows, use arrays (boxShadow={[1, 1, 0, '#fff']}).
|
|
38
|
+
|
|
39
|
+
### Globals
|
|
40
|
+
- Use $$.css() for global CSS and arbitrary selectors (body, [data-*], etc.).
|
|
41
|
+
|
|
42
|
+
### Bosswind
|
|
43
|
+
- When Bosswind is enabled, prefer shorthands (flex vs display:flex).
|
|
44
|
+
|
|
45
|
+
### Strategies
|
|
46
|
+
- inline-first: default for mixed static/dynamic props.
|
|
47
|
+
- classname-first: smaller inline styles; use function values for dynamics.
|
|
48
|
+
- runtime-only: client CSS injection only.
|
|
49
|
+
- compile pruning: keep props static when you want runtime-free output.
|
|
50
|
+
`;
|
|
51
|
+
const EVENT_NAMES = [
|
|
52
|
+
"onBoot",
|
|
53
|
+
"onReady",
|
|
54
|
+
"onParse",
|
|
55
|
+
"onPropTree",
|
|
56
|
+
"onProp",
|
|
57
|
+
"onCompileProp",
|
|
58
|
+
"onInit",
|
|
59
|
+
"onBrowserObjectStart",
|
|
60
|
+
"onSession",
|
|
61
|
+
"onMetaData"
|
|
62
|
+
];
|
|
63
|
+
const metaStore = /* @__PURE__ */ new Map();
|
|
64
|
+
let metaStoreApi = null;
|
|
65
|
+
let llmsFile = null;
|
|
66
|
+
let llmsFilePath = null;
|
|
67
|
+
const getAiConfig = (api) => {
|
|
68
|
+
return api.ai ?? api.userConfig?.ai ?? {};
|
|
69
|
+
};
|
|
70
|
+
const getBaseDir = (api, session) => {
|
|
71
|
+
if (session?.baseDir) return session.baseDir;
|
|
72
|
+
if (typeof api.baseDir === "string") return api.baseDir;
|
|
73
|
+
return process.cwd();
|
|
74
|
+
};
|
|
75
|
+
const formatLines = (lines) => {
|
|
76
|
+
const filtered = lines.filter(Boolean);
|
|
77
|
+
if (!filtered.length) return "- (none)";
|
|
78
|
+
return filtered.map((line) => `- ${line}`).join("\n");
|
|
79
|
+
};
|
|
80
|
+
const renderSection = (title, body) => {
|
|
81
|
+
const trimmed = body.trim();
|
|
82
|
+
if (!trimmed) return `## ${title}\n\n- (none)`;
|
|
83
|
+
return `## ${title}\n\n${trimmed}`;
|
|
84
|
+
};
|
|
85
|
+
const renderSectionBlock = (id, body) => {
|
|
86
|
+
return `<!-- boss:ai:${id}:start -->\n${body.trim()}\n<!-- boss:ai:${id}:end -->`;
|
|
87
|
+
};
|
|
88
|
+
const updateSectionBlocks = (input, sections) => {
|
|
89
|
+
let text = input;
|
|
90
|
+
if (!/<!-- boss:ai:/.test(text)) {
|
|
91
|
+
text = text.trim();
|
|
92
|
+
if (!text.length) text = "# Boss CSS AI\n";
|
|
93
|
+
else text += "\n\n";
|
|
94
|
+
}
|
|
95
|
+
for (const [id, body] of Object.entries(sections)) {
|
|
96
|
+
const block = renderSectionBlock(id, body);
|
|
97
|
+
const pattern = /* @__PURE__ */ new RegExp(`<!-- boss:ai:${id}:start -->[\\s\\S]*?<!-- boss:ai:${id}:end -->`);
|
|
98
|
+
if (pattern.test(text)) text = text.replace(pattern, block);
|
|
99
|
+
else text += `\n\n${block}`;
|
|
100
|
+
}
|
|
101
|
+
return text.trim() + "\n";
|
|
102
|
+
};
|
|
103
|
+
const readFileSafe = async (filePath) => {
|
|
104
|
+
try {
|
|
105
|
+
return await node_fs_promises.default.readFile(filePath, "utf8");
|
|
106
|
+
} catch {
|
|
107
|
+
return "";
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
const writeFileIfChanged = async (filePath, content) => {
|
|
111
|
+
if (await readFileSafe(filePath) === content) return;
|
|
112
|
+
await node_fs_promises.default.mkdir(node_path.default.dirname(filePath), { recursive: true });
|
|
113
|
+
await node_fs_promises.default.writeFile(filePath, content, "utf8");
|
|
114
|
+
};
|
|
115
|
+
const isValidSkillName = (value) => /^[\p{Ll}\p{Nd}]+(?:-[\p{Ll}\p{Nd}]+)*$/u.test(value) && value.length <= 64;
|
|
116
|
+
const yamlValue = (value) => JSON.stringify(value);
|
|
117
|
+
const unquoteYamlValue = (value) => {
|
|
118
|
+
const trimmed = value.trim();
|
|
119
|
+
if (trimmed.startsWith("\"") && trimmed.endsWith("\"") || trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
|
|
120
|
+
return trimmed;
|
|
121
|
+
};
|
|
122
|
+
const renderSkill = (skill) => {
|
|
123
|
+
const lines = [
|
|
124
|
+
"---",
|
|
125
|
+
`name: ${skill.name}`,
|
|
126
|
+
`description: ${yamlValue(skill.description)}`
|
|
127
|
+
];
|
|
128
|
+
if (skill.license) lines.push(`license: ${yamlValue(skill.license)}`);
|
|
129
|
+
if (skill.compatibility) lines.push(`compatibility: ${yamlValue(skill.compatibility)}`);
|
|
130
|
+
if (skill.allowedTools) lines.push(`allowed-tools: ${yamlValue(skill.allowedTools)}`);
|
|
131
|
+
if (skill.metadata && Object.keys(skill.metadata).length) {
|
|
132
|
+
lines.push("metadata:");
|
|
133
|
+
for (const [key, value] of Object.entries(skill.metadata)) lines.push(` ${key}: ${yamlValue(value)}`);
|
|
134
|
+
}
|
|
135
|
+
lines.push("---", skill.body.trim(), "");
|
|
136
|
+
return lines.join("\n");
|
|
137
|
+
};
|
|
138
|
+
const resolvePackageVersion = async (baseDir) => {
|
|
139
|
+
try {
|
|
140
|
+
const pkgPath = node_path.default.join(baseDir, "package.json");
|
|
141
|
+
const raw = await node_fs_promises.default.readFile(pkgPath, "utf8");
|
|
142
|
+
const parsed = JSON.parse(raw);
|
|
143
|
+
return typeof parsed.version === "string" ? parsed.version : null;
|
|
144
|
+
} catch {
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
const parseSkillSummary = (content) => {
|
|
149
|
+
const match = content.match(/^---\n([\s\S]*?)\n---\n?/);
|
|
150
|
+
if (!match) return null;
|
|
151
|
+
const lines = match[1].split("\n");
|
|
152
|
+
let name = "";
|
|
153
|
+
let description = "";
|
|
154
|
+
for (const line of lines) {
|
|
155
|
+
const trimmed = line.trim();
|
|
156
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
157
|
+
if (trimmed.startsWith("name:")) name = unquoteYamlValue(trimmed.slice(5).trim());
|
|
158
|
+
if (trimmed.startsWith("description:")) description = unquoteYamlValue(trimmed.slice(12).trim());
|
|
159
|
+
}
|
|
160
|
+
if (!name || !description) return null;
|
|
161
|
+
return {
|
|
162
|
+
name,
|
|
163
|
+
description
|
|
164
|
+
};
|
|
165
|
+
};
|
|
166
|
+
const fileExists = async (filePath) => {
|
|
167
|
+
try {
|
|
168
|
+
await node_fs_promises.default.access(filePath);
|
|
169
|
+
return true;
|
|
170
|
+
} catch {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
const loadCustomSkills = async (outputPath, baseDir, existingNames, log) => {
|
|
175
|
+
const entries = await node_fs_promises.default.readdir(outputPath, { withFileTypes: true });
|
|
176
|
+
const results = [];
|
|
177
|
+
for (const entry of entries) {
|
|
178
|
+
if (!entry.isDirectory()) continue;
|
|
179
|
+
const skillFile = node_path.default.join(outputPath, entry.name, "SKILL.md");
|
|
180
|
+
if (!await fileExists(skillFile)) continue;
|
|
181
|
+
const summary = parseSkillSummary(await readFileSafe(skillFile));
|
|
182
|
+
if (!summary) {
|
|
183
|
+
log.child("ai").log(`Skipping custom skill without valid frontmatter: ${skillFile}`);
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
if (!isValidSkillName(summary.name)) {
|
|
187
|
+
log.child("ai").log(`Invalid skill name "${summary.name}" in ${skillFile}`);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
if (existingNames.has(summary.name)) continue;
|
|
191
|
+
results.push({
|
|
192
|
+
name: summary.name,
|
|
193
|
+
description: summary.description,
|
|
194
|
+
path: node_path.default.relative(baseDir, skillFile),
|
|
195
|
+
source: "custom"
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
results.sort((a, b) => a.name.localeCompare(b.name));
|
|
199
|
+
return results;
|
|
200
|
+
};
|
|
201
|
+
const buildSections = (api, session) => {
|
|
202
|
+
const config = getAiConfig(api);
|
|
203
|
+
const baseDir = getBaseDir(api, session);
|
|
204
|
+
const defaultLlmsPath = node_path.default.join(api.folder ?? api.configDir ?? ".bo$$", "LLMS.md");
|
|
205
|
+
const llmsPath = config.llms?.path ?? defaultLlmsPath;
|
|
206
|
+
const llmsFullPath = node_path.default.isAbsolute(llmsPath) ? llmsPath : node_path.default.join(baseDir, llmsPath);
|
|
207
|
+
const pluginNames = api.plugins.map((plugin) => plugin.name ?? "unknown");
|
|
208
|
+
const pluginLines = api.plugins.map((plugin) => {
|
|
209
|
+
const hooks = EVENT_NAMES.filter((eventName) => Boolean(plugin[eventName]));
|
|
210
|
+
return `${plugin.name ?? "unknown"} (${hooks.join(", ") || "no hooks"})`;
|
|
211
|
+
});
|
|
212
|
+
const summaryBody = formatLines([
|
|
213
|
+
`Generated: ${(/* @__PURE__ */ new Date()).toISOString()}`,
|
|
214
|
+
`Base dir: ${baseDir}`,
|
|
215
|
+
`Config path: ${session?.configPath ?? "(unknown)"}`,
|
|
216
|
+
`LLMS path: ${llmsFullPath}`,
|
|
217
|
+
`Runtime strategy: ${api.strategy ?? "(default)"}`,
|
|
218
|
+
`Plugins: ${pluginNames.join(", ")}`
|
|
219
|
+
]);
|
|
220
|
+
const configBody = formatLines([
|
|
221
|
+
`content: ${Array.isArray(api.content) ? api.content.join(", ") : api.content ?? "(none)"}`,
|
|
222
|
+
`selectorPrefix: ${api.selectorPrefix ?? "(none)"}`,
|
|
223
|
+
`selectorScope: ${api.selectorScope ?? "(none)"}`,
|
|
224
|
+
`unit: ${api.unit ?? "px"}`,
|
|
225
|
+
`runtime.only: ${api.runtime?.only === true ? "true" : "false"}`,
|
|
226
|
+
`runtime.strategy: ${api.runtime?.strategy ?? "(default)"}`
|
|
227
|
+
]);
|
|
228
|
+
const outputsBody = formatLines([
|
|
229
|
+
`runtime: ${node_path.default.join(api.folder ?? api.configDir ?? ".bo$$", "index.js")}`,
|
|
230
|
+
`types: ${node_path.default.join(api.folder ?? api.configDir ?? ".bo$$", "index.d.ts")}`,
|
|
231
|
+
api.file.native?.hasContent ? `native runtime: ${node_path.default.join(api.folder ?? api.configDir ?? ".bo$$", "native.js")}` : "",
|
|
232
|
+
api.file.native?.hasContent ? `native types: ${node_path.default.join(api.folder ?? api.configDir ?? ".bo$$", "native.d.ts")}` : "",
|
|
233
|
+
`styles: ${api.stylesheetPath ?? node_path.default.join(api.configDir ?? ".bo$$", "styles.css")}`
|
|
234
|
+
]);
|
|
235
|
+
const customPropLines = [];
|
|
236
|
+
const seenDescriptors = /* @__PURE__ */ new Set();
|
|
237
|
+
for (const descriptor of api.dictionary.values()) {
|
|
238
|
+
if (!descriptor || descriptor.isCSSProp !== false) continue;
|
|
239
|
+
if (seenDescriptors.has(descriptor)) continue;
|
|
240
|
+
seenDescriptors.add(descriptor);
|
|
241
|
+
const alias = descriptor.aliases?.[0] ?? descriptor.property;
|
|
242
|
+
if (!alias) continue;
|
|
243
|
+
const description = descriptor.description ?? descriptor.usage ?? "";
|
|
244
|
+
customPropLines.push(description ? `${alias} — ${description}` : alias);
|
|
245
|
+
}
|
|
246
|
+
const customPropsBody = formatLines(customPropLines.sort((a, b) => a.localeCompare(b)));
|
|
247
|
+
const frameworkBody = formatLines([
|
|
248
|
+
`framework: ${typeof api.framework === "string" ? api.framework : typeof api.framework === "object" ? api.framework.name ?? "unknown" : "unknown"}`,
|
|
249
|
+
typeof api.framework === "object" && api.framework?.className ? `className: ${api.framework.className}` : "",
|
|
250
|
+
typeof api.framework === "object" && api.framework?.fileType ? `fileType: ${api.framework.fileType}` : ""
|
|
251
|
+
]);
|
|
252
|
+
const compileBody = formatLines([
|
|
253
|
+
`compile.enabled: ${api.compile ? "true" : "false"}`,
|
|
254
|
+
api.compile?.spread ? `compile.spread: true` : "",
|
|
255
|
+
api.compile?.stats ? `compile.stats: ${api.compile.stats}` : ""
|
|
256
|
+
]);
|
|
257
|
+
const sections = {
|
|
258
|
+
static: renderSection("Boss CSS usage", STATIC_DOC),
|
|
259
|
+
summary: renderSection("Summary", summaryBody),
|
|
260
|
+
config: renderSection("Config", configBody),
|
|
261
|
+
plugins: renderSection("Plugins", formatLines(pluginLines)),
|
|
262
|
+
outputs: renderSection("Outputs", outputsBody),
|
|
263
|
+
framework: renderSection("Framework", frameworkBody),
|
|
264
|
+
props: renderSection("Custom props", customPropsBody),
|
|
265
|
+
compile: renderSection("Compile", compileBody)
|
|
266
|
+
};
|
|
267
|
+
const defaultTitles = {
|
|
268
|
+
tokens: "Tokens",
|
|
269
|
+
props: "Props",
|
|
270
|
+
prepared: "Prepared components",
|
|
271
|
+
pseudos: "Pseudos",
|
|
272
|
+
at: "At (breakpoints and media)",
|
|
273
|
+
bosswind: "Bosswind",
|
|
274
|
+
boundaries: "CSS boundaries",
|
|
275
|
+
"dev-server": "Dev server"
|
|
276
|
+
};
|
|
277
|
+
const metaOrder = [
|
|
278
|
+
"tokens",
|
|
279
|
+
"props",
|
|
280
|
+
"prepared",
|
|
281
|
+
"pseudos",
|
|
282
|
+
"at",
|
|
283
|
+
"bosswind",
|
|
284
|
+
"boundaries",
|
|
285
|
+
"dev-server"
|
|
286
|
+
];
|
|
287
|
+
const orderedSections = [...metaOrder.filter((section) => metaStore.has(section)), ...Array.from(metaStore.keys()).filter((section) => !metaOrder.includes(section)).sort((a, b) => a.localeCompare(b))];
|
|
288
|
+
for (const section of orderedSections) {
|
|
289
|
+
const entries = metaStore.get(section);
|
|
290
|
+
if (!entries || entries.length === 0) continue;
|
|
291
|
+
const sorted = [...entries].sort((a, b) => (a.order ?? 0) - (b.order ?? 0));
|
|
292
|
+
const title = sorted.find((entry) => entry.title)?.title ?? defaultTitles[section] ?? section;
|
|
293
|
+
const content = sorted.map((entry) => entry.content.trim()).filter(Boolean).join("\n\n");
|
|
294
|
+
if (!content) continue;
|
|
295
|
+
sections[section] = renderSection(title, content);
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
sections,
|
|
299
|
+
llmsFullPath
|
|
300
|
+
};
|
|
301
|
+
};
|
|
302
|
+
const getLlmsFile = (api, filePath) => {
|
|
303
|
+
if (!llmsFile || llmsFilePath !== filePath) {
|
|
304
|
+
llmsFile = new require_text.default(api, { path: filePath });
|
|
305
|
+
llmsFilePath = filePath;
|
|
306
|
+
}
|
|
307
|
+
return llmsFile;
|
|
308
|
+
};
|
|
309
|
+
const writeLlms = async (api, session) => {
|
|
310
|
+
if (getAiConfig(api).llms?.enabled === false) return;
|
|
311
|
+
const { sections, llmsFullPath } = buildSections(api, session);
|
|
312
|
+
const updated = updateSectionBlocks(await readFileSafe(llmsFullPath), sections);
|
|
313
|
+
const baseDir = getBaseDir(api, session);
|
|
314
|
+
const folder = api.folder ?? ".bo$$";
|
|
315
|
+
const folderPath = node_path.default.isAbsolute(folder) ? folder : node_path.default.join(baseDir, folder);
|
|
316
|
+
const relativePath = node_path.default.relative(folderPath, llmsFullPath);
|
|
317
|
+
if (relativePath && !relativePath.startsWith("..") && !node_path.default.isAbsolute(relativePath)) {
|
|
318
|
+
const file = getLlmsFile(api, relativePath);
|
|
319
|
+
file.set("body", "llms", updated);
|
|
320
|
+
await file.write();
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
await writeFileIfChanged(llmsFullPath, updated);
|
|
324
|
+
};
|
|
325
|
+
const writeSkills = async (api, session) => {
|
|
326
|
+
const config = getAiConfig(api);
|
|
327
|
+
if (config.skills?.enabled === false) return;
|
|
328
|
+
const baseDir = getBaseDir(api, session);
|
|
329
|
+
const outputDir = config.skills?.outputDir ?? node_path.default.join(api.folder ?? api.configDir ?? ".bo$$", "skills");
|
|
330
|
+
const outputPath = node_path.default.isAbsolute(outputDir) ? outputDir : node_path.default.join(baseDir, outputDir);
|
|
331
|
+
const includeBuiltins = config.skills?.includeBuiltins !== false;
|
|
332
|
+
await node_fs_promises.default.mkdir(outputPath, { recursive: true });
|
|
333
|
+
const skills = [];
|
|
334
|
+
const packageVersion = await resolvePackageVersion(baseDir);
|
|
335
|
+
if (includeBuiltins) skills.push(...require_ai_skills.builtInSkills.map((skill) => ({
|
|
336
|
+
name: skill.name,
|
|
337
|
+
description: skill.description,
|
|
338
|
+
body: skill.body,
|
|
339
|
+
compatibility: skill.compatibility,
|
|
340
|
+
license: skill.license,
|
|
341
|
+
metadata: packageVersion ? {
|
|
342
|
+
...skill.metadata ?? {},
|
|
343
|
+
version: packageVersion
|
|
344
|
+
} : skill.metadata,
|
|
345
|
+
allowedTools: skill.allowedTools,
|
|
346
|
+
source: "builtin"
|
|
347
|
+
})));
|
|
348
|
+
const indexEntries = [];
|
|
349
|
+
const builtinNames = new Set(skills.map((skill) => skill.name));
|
|
350
|
+
for (const skill of skills) {
|
|
351
|
+
if (!isValidSkillName(skill.name)) {
|
|
352
|
+
api.log.child("ai").log(`Invalid skill name "${skill.name}"`);
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
const skillDir = node_path.default.join(outputPath, skill.name);
|
|
356
|
+
const filePath = node_path.default.join(skillDir, "SKILL.md");
|
|
357
|
+
await node_fs_promises.default.mkdir(skillDir, { recursive: true });
|
|
358
|
+
await writeFileIfChanged(filePath, renderSkill(skill));
|
|
359
|
+
indexEntries.push({
|
|
360
|
+
name: skill.name,
|
|
361
|
+
description: skill.description,
|
|
362
|
+
path: node_path.default.relative(baseDir, filePath),
|
|
363
|
+
source: skill.source
|
|
364
|
+
});
|
|
365
|
+
}
|
|
366
|
+
const customEntries = await loadCustomSkills(outputPath, baseDir, builtinNames, api.log);
|
|
367
|
+
indexEntries.push(...customEntries);
|
|
368
|
+
await writeFileIfChanged(node_path.default.join(outputPath, "index.json"), JSON.stringify(indexEntries, null, 2) + "\n");
|
|
369
|
+
};
|
|
370
|
+
const onBoot = async (api) => {
|
|
371
|
+
if (metaStoreApi !== api) {
|
|
372
|
+
metaStore.clear();
|
|
373
|
+
metaStoreApi = api ?? null;
|
|
374
|
+
}
|
|
375
|
+
llmsFile = null;
|
|
376
|
+
llmsFilePath = null;
|
|
377
|
+
};
|
|
378
|
+
const onMetaData = async (_api, payload) => {
|
|
379
|
+
if (!payload || payload.kind !== "ai") return;
|
|
380
|
+
if (_api && metaStoreApi !== _api) {
|
|
381
|
+
metaStore.clear();
|
|
382
|
+
metaStoreApi = _api;
|
|
383
|
+
}
|
|
384
|
+
const type = typeof payload.type === "string" ? payload.type : "";
|
|
385
|
+
const data = payload.data;
|
|
386
|
+
const shouldReplace = payload.replace === true || data && typeof data === "object" && data.replace === true;
|
|
387
|
+
let entry = null;
|
|
388
|
+
if (type === "skill") {
|
|
389
|
+
const content = typeof data === "string" ? data : data && typeof data.content === "string" ? String(data.content) : data && typeof data.body === "string" ? String(data.body) : "";
|
|
390
|
+
if (content) entry = {
|
|
391
|
+
section: "skills",
|
|
392
|
+
title: data && typeof data.title === "string" ? String(data.title) : typeof payload.label === "string" ? payload.label : "Skills",
|
|
393
|
+
content,
|
|
394
|
+
order: typeof data?.order === "number" ? Number(data.order) : void 0
|
|
395
|
+
};
|
|
396
|
+
} else if (data && typeof data === "object") {
|
|
397
|
+
const section = data.section;
|
|
398
|
+
const content = data.content;
|
|
399
|
+
if (typeof section === "string" && typeof content === "string") entry = {
|
|
400
|
+
section,
|
|
401
|
+
content,
|
|
402
|
+
title: typeof data.title === "string" ? String(data.title) : void 0,
|
|
403
|
+
order: typeof data.order === "number" ? Number(data.order) : void 0
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
if (!entry) return;
|
|
407
|
+
if (!/^[a-zA-Z0-9._-]+$/.test(entry.section)) return;
|
|
408
|
+
if (shouldReplace) {
|
|
409
|
+
metaStore.set(entry.section, [entry]);
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
const list = metaStore.get(entry.section) ?? [];
|
|
413
|
+
list.push(entry);
|
|
414
|
+
metaStore.set(entry.section, list);
|
|
415
|
+
};
|
|
416
|
+
const onSession = async (api, session) => {
|
|
417
|
+
if (!session) return;
|
|
418
|
+
if (session.phase !== "run" && session.phase !== "stop") return;
|
|
419
|
+
await writeLlms(api, session);
|
|
420
|
+
await writeSkills(api, session);
|
|
421
|
+
};
|
|
422
|
+
|
|
423
|
+
//#endregion
|
|
424
|
+
exports.name = name;
|
|
425
|
+
exports.onBoot = onBoot;
|
|
426
|
+
exports.onMetaData = onMetaData;
|
|
427
|
+
exports.onSession = onSession;
|
|
428
|
+
Object.defineProperty(exports, 'server_exports', {
|
|
429
|
+
enumerable: true,
|
|
430
|
+
get: function () {
|
|
431
|
+
return server_exports;
|
|
432
|
+
}
|
|
433
|
+
});
|