skilld 0.13.3 → 0.13.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/npm.mjs +110 -121
- package/dist/_chunks/npm.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +11 -3
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/utils.d.mts +1 -2
- package/dist/_chunks/utils.d.mts.map +1 -1
- package/dist/cli.mjs +3 -4
- package/dist/cli.mjs.map +1 -1
- package/package.json +2 -1
package/dist/_chunks/npm.mjs
CHANGED
|
@@ -10,8 +10,9 @@ import { gt } from "semver";
|
|
|
10
10
|
import { ofetch } from "ofetch";
|
|
11
11
|
import { crawlAndGenerate } from "@mdream/crawl";
|
|
12
12
|
import { globby } from "globby";
|
|
13
|
-
import
|
|
13
|
+
import { downloadTemplate } from "giget";
|
|
14
14
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
15
|
+
import pLimit from "p-limit";
|
|
15
16
|
import { Writable } from "node:stream";
|
|
16
17
|
import { resolvePathSync } from "mlly";
|
|
17
18
|
const BOT_USERS = new Set([
|
|
@@ -1119,11 +1120,20 @@ function parseSkillFrontmatterName(content) {
|
|
|
1119
1120
|
description: fm.description
|
|
1120
1121
|
};
|
|
1121
1122
|
}
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1123
|
+
function collectFiles(dir, prefix = "") {
|
|
1124
|
+
const files = [];
|
|
1125
|
+
if (!existsSync(dir)) return files;
|
|
1126
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
1127
|
+
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
1128
|
+
const fullPath = resolve(dir, entry.name);
|
|
1129
|
+
if (entry.isDirectory()) files.push(...collectFiles(fullPath, relPath));
|
|
1130
|
+
else if (entry.isFile()) files.push({
|
|
1131
|
+
path: relPath,
|
|
1132
|
+
content: readFileSync(fullPath, "utf-8")
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
return files;
|
|
1136
|
+
}
|
|
1127
1137
|
async function fetchGitSkills(source, onProgress) {
|
|
1128
1138
|
if (source.type === "local") return fetchLocalSkills(source);
|
|
1129
1139
|
if (source.type === "github") return fetchGitHubSkills(source, onProgress);
|
|
@@ -1153,18 +1163,7 @@ function readLocalSkill(dir, repoPath) {
|
|
|
1153
1163
|
const frontmatter = parseSkillFrontmatterName(content);
|
|
1154
1164
|
const dirName = dir.split("/").pop();
|
|
1155
1165
|
const name = frontmatter.name || dirName;
|
|
1156
|
-
const files =
|
|
1157
|
-
for (const subdir of SUPPORTING_DIRS) {
|
|
1158
|
-
const subdirPath = resolve(dir, subdir);
|
|
1159
|
-
if (!existsSync(subdirPath)) continue;
|
|
1160
|
-
for (const file of readdirSync(subdirPath, { withFileTypes: true })) {
|
|
1161
|
-
if (!file.isFile()) continue;
|
|
1162
|
-
files.push({
|
|
1163
|
-
path: `${subdir}/${file.name}`,
|
|
1164
|
-
content: readFileSync(resolve(subdirPath, file.name), "utf-8")
|
|
1165
|
-
});
|
|
1166
|
-
}
|
|
1167
|
-
}
|
|
1166
|
+
const files = collectFiles(dir).filter((f) => f.path !== "SKILL.md");
|
|
1168
1167
|
return {
|
|
1169
1168
|
name,
|
|
1170
1169
|
description: frontmatter.description || "",
|
|
@@ -1177,120 +1176,110 @@ async function fetchGitHubSkills(source, onProgress) {
|
|
|
1177
1176
|
const { owner, repo } = source;
|
|
1178
1177
|
if (!owner || !repo) return { skills: [] };
|
|
1179
1178
|
const ref = source.ref || "main";
|
|
1180
|
-
|
|
1181
|
-
const
|
|
1182
|
-
|
|
1183
|
-
if (
|
|
1184
|
-
const fallback = await $fetch(`https://ungh.cc/repos/${owner}/${repo}/files/master`).catch(() => null);
|
|
1185
|
-
if (fallback?.files?.length) return extractGitHubSkills(owner, repo, "master", fallback, source.skillPath, onProgress);
|
|
1186
|
-
}
|
|
1187
|
-
return { skills: [] };
|
|
1179
|
+
const refs = ref === "main" ? ["main", "master"] : [ref];
|
|
1180
|
+
for (const tryRef of refs) {
|
|
1181
|
+
const skills = await downloadGitHubSkills(owner, repo, tryRef, source.skillPath, onProgress);
|
|
1182
|
+
if (skills.length > 0) return { skills };
|
|
1188
1183
|
}
|
|
1189
|
-
return
|
|
1190
|
-
}
|
|
1191
|
-
async function
|
|
1192
|
-
const
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
for (const filePath of matching) {
|
|
1219
|
-
const fileContent = await fetchRawGitHub(owner, repo, ref, filePath);
|
|
1220
|
-
if (fileContent) {
|
|
1221
|
-
const relativePath = filePath.slice(prefix.length);
|
|
1222
|
-
supportingFiles.push({
|
|
1223
|
-
path: relativePath,
|
|
1224
|
-
content: fileContent
|
|
1225
|
-
});
|
|
1226
|
-
}
|
|
1184
|
+
return { skills: [] };
|
|
1185
|
+
}
|
|
1186
|
+
async function downloadGitHubSkills(owner, repo, ref, skillPath, onProgress) {
|
|
1187
|
+
const tempDir = join(tmpdir(), `skilld-${Date.now()}`);
|
|
1188
|
+
try {
|
|
1189
|
+
if (skillPath) {
|
|
1190
|
+
onProgress?.(`Downloading ${owner}/${repo}/${skillPath}@${ref}`);
|
|
1191
|
+
const { dir } = await downloadTemplate(`github:${owner}/${repo}/${skillPath}#${ref}`, {
|
|
1192
|
+
dir: tempDir,
|
|
1193
|
+
force: true
|
|
1194
|
+
});
|
|
1195
|
+
const skill = readLocalSkill(dir, skillPath);
|
|
1196
|
+
return skill ? [skill] : [];
|
|
1197
|
+
}
|
|
1198
|
+
onProgress?.(`Downloading ${owner}/${repo}/skills@${ref}`);
|
|
1199
|
+
try {
|
|
1200
|
+
const { dir } = await downloadTemplate(`github:${owner}/${repo}/skills#${ref}`, {
|
|
1201
|
+
dir: tempDir,
|
|
1202
|
+
force: true
|
|
1203
|
+
});
|
|
1204
|
+
const skills = [];
|
|
1205
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
1206
|
+
if (!entry.isDirectory()) continue;
|
|
1207
|
+
const skill = readLocalSkill(resolve(dir, entry.name), `skills/${entry.name}`);
|
|
1208
|
+
if (skill) skills.push(skill);
|
|
1209
|
+
}
|
|
1210
|
+
if (skills.length > 0) {
|
|
1211
|
+
onProgress?.(`Found ${skills.length} skill(s)`);
|
|
1212
|
+
return skills;
|
|
1227
1213
|
}
|
|
1214
|
+
} catch {}
|
|
1215
|
+
const content = await $fetch(`https://raw.githubusercontent.com/${owner}/${repo}/${ref}/SKILL.md`, { responseType: "text" }).catch(() => null);
|
|
1216
|
+
if (content) {
|
|
1217
|
+
const fm = parseSkillFrontmatterName(content);
|
|
1218
|
+
onProgress?.("Found 1 skill");
|
|
1219
|
+
return [{
|
|
1220
|
+
name: fm.name || repo,
|
|
1221
|
+
description: fm.description || "",
|
|
1222
|
+
path: "",
|
|
1223
|
+
content,
|
|
1224
|
+
files: []
|
|
1225
|
+
}];
|
|
1228
1226
|
}
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1227
|
+
return [];
|
|
1228
|
+
} catch {
|
|
1229
|
+
return [];
|
|
1230
|
+
} finally {
|
|
1231
|
+
rmSync(tempDir, {
|
|
1232
|
+
recursive: true,
|
|
1233
|
+
force: true
|
|
1235
1234
|
});
|
|
1236
|
-
}
|
|
1237
|
-
return {
|
|
1238
|
-
skills,
|
|
1239
|
-
commitSha
|
|
1240
|
-
};
|
|
1241
|
-
}
|
|
1242
|
-
async function fetchRawGitHub(owner, repo, ref, path) {
|
|
1243
|
-
return $fetch(`https://raw.githubusercontent.com/${owner}/${repo}/${ref}/${path}`, { responseType: "text" }).catch(() => null);
|
|
1235
|
+
}
|
|
1244
1236
|
}
|
|
1245
1237
|
async function fetchGitLabSkills(source, onProgress) {
|
|
1246
1238
|
const { owner, repo } = source;
|
|
1247
1239
|
if (!owner || !repo) return { skills: [] };
|
|
1248
1240
|
const ref = source.ref || "main";
|
|
1249
|
-
const
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
const skillDir = mdPath === "SKILL.md" ? "" : mdPath.replace(/\/SKILL\.md$/, "");
|
|
1261
|
-
const content = await fetchRawGitLab(owner, repo, ref, mdPath);
|
|
1262
|
-
if (!content) return;
|
|
1263
|
-
const frontmatter = parseSkillFrontmatterName(content);
|
|
1264
|
-
const dirName = skillDir ? skillDir.split("/").pop() : repo;
|
|
1265
|
-
const name = frontmatter.name || dirName;
|
|
1266
|
-
const supportingFiles = [];
|
|
1267
|
-
const prefix = skillDir ? `${skillDir}/` : "";
|
|
1268
|
-
for (const subdir of SUPPORTING_DIRS) {
|
|
1269
|
-
const subdirPrefix = `${prefix}${subdir}/`;
|
|
1270
|
-
const matching = allFiles.filter((f) => f.startsWith(subdirPrefix));
|
|
1271
|
-
for (const filePath of matching) {
|
|
1272
|
-
const fileContent = await fetchRawGitLab(owner, repo, ref, filePath);
|
|
1273
|
-
if (fileContent) {
|
|
1274
|
-
const relativePath = filePath.slice(prefix.length);
|
|
1275
|
-
supportingFiles.push({
|
|
1276
|
-
path: relativePath,
|
|
1277
|
-
content: fileContent
|
|
1278
|
-
});
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1241
|
+
const tempDir = join(tmpdir(), `skilld-gitlab-${Date.now()}`);
|
|
1242
|
+
try {
|
|
1243
|
+
const subdir = source.skillPath || "skills";
|
|
1244
|
+
onProgress?.(`Downloading ${owner}/${repo}/${subdir}@${ref}`);
|
|
1245
|
+
const { dir } = await downloadTemplate(`gitlab:${owner}/${repo}/${subdir}#${ref}`, {
|
|
1246
|
+
dir: tempDir,
|
|
1247
|
+
force: true
|
|
1248
|
+
});
|
|
1249
|
+
if (source.skillPath) {
|
|
1250
|
+
const skill = readLocalSkill(dir, source.skillPath);
|
|
1251
|
+
return { skills: skill ? [skill] : [] };
|
|
1281
1252
|
}
|
|
1282
|
-
skills
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1253
|
+
const skills = [];
|
|
1254
|
+
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
1255
|
+
if (!entry.isDirectory()) continue;
|
|
1256
|
+
const skill = readLocalSkill(resolve(dir, entry.name), `skills/${entry.name}`);
|
|
1257
|
+
if (skill) skills.push(skill);
|
|
1258
|
+
}
|
|
1259
|
+
if (skills.length > 0) {
|
|
1260
|
+
onProgress?.(`Found ${skills.length} skill(s)`);
|
|
1261
|
+
return { skills };
|
|
1262
|
+
}
|
|
1263
|
+
const content = await $fetch(`https://gitlab.com/${owner}/${repo}/-/raw/${ref}/SKILL.md`, { responseType: "text" }).catch(() => null);
|
|
1264
|
+
if (content) {
|
|
1265
|
+
const fm = parseSkillFrontmatterName(content);
|
|
1266
|
+
return { skills: [{
|
|
1267
|
+
name: fm.name || repo,
|
|
1268
|
+
description: fm.description || "",
|
|
1269
|
+
path: "",
|
|
1270
|
+
content,
|
|
1271
|
+
files: []
|
|
1272
|
+
}] };
|
|
1273
|
+
}
|
|
1274
|
+
return { skills: [] };
|
|
1275
|
+
} catch {
|
|
1276
|
+
return { skills: [] };
|
|
1277
|
+
} finally {
|
|
1278
|
+
rmSync(tempDir, {
|
|
1279
|
+
recursive: true,
|
|
1280
|
+
force: true
|
|
1288
1281
|
});
|
|
1289
|
-
}
|
|
1290
|
-
return { skills };
|
|
1291
|
-
}
|
|
1292
|
-
async function fetchRawGitLab(owner, repo, ref, path) {
|
|
1293
|
-
return $fetch(`https://gitlab.com/${owner}/${repo}/-/raw/${ref}/${path}`, { responseType: "text" }).catch(() => null);
|
|
1282
|
+
}
|
|
1294
1283
|
}
|
|
1295
1284
|
async function fetchLlmsUrl(docsUrl) {
|
|
1296
1285
|
const llmsUrl = `${new URL(docsUrl).origin}/llms.txt`;
|