skilld 0.9.6 → 0.10.1
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/detect-imports.mjs +101 -68
- package/dist/_chunks/detect-imports.mjs.map +1 -1
- package/dist/_chunks/npm.mjs +204 -121
- package/dist/_chunks/npm.mjs.map +1 -1
- package/dist/_chunks/storage.mjs +12 -1
- package/dist/_chunks/storage.mjs.map +1 -1
- package/dist/_chunks/utils.d.mts +18 -2
- package/dist/_chunks/utils.d.mts.map +1 -1
- package/dist/_chunks/version.d.mts.map +1 -1
- package/dist/_chunks/yaml.mjs +7 -1
- package/dist/_chunks/yaml.mjs.map +1 -1
- package/dist/agent/index.d.mts +4 -0
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/cli.mjs +410 -271
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/sources/index.d.mts +2 -2
- package/dist/sources/index.mjs +3 -3
- package/dist/types.d.mts +1 -1
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -5,8 +5,8 @@ import { a as getShippedSkills, b as sanitizeMarkdown, c as linkCachedDir, d as
|
|
|
5
5
|
import "./cache/index.mjs";
|
|
6
6
|
import { n as clearEmbeddingCache } from "./_chunks/embedding-cache.mjs";
|
|
7
7
|
import { closePool, createIndex, openPool, searchPooled, searchSnippets } from "./retriv/index.mjs";
|
|
8
|
-
import { i as getBlogPreset, n as yamlParseKV, r as yamlUnescape, t as yamlEscape } from "./_chunks/yaml.mjs";
|
|
9
|
-
import { $ as
|
|
8
|
+
import { c as getPrereleaseChangelogRef, i as getBlogPreset, n as yamlParseKV, r as yamlUnescape, t as yamlEscape } from "./_chunks/yaml.mjs";
|
|
9
|
+
import { $ as SHARED_SKILLS_DIR, E as normalizeLlmsLinks, F as fetchBlogReleases, K as parseGitHubUrl, L as fetchReleaseNotes, M as fetchGitHubDiscussions, N as formatDiscussionAsMarkdown, O as fetchGitSkills, P as generateDiscussionIndex, Q as isGhAvailable, R as generateReleaseIndex, S as downloadLlmsDocs, V as $fetch, X as formatIssueAsMarkdown, Y as fetchGitHubIssues, Z as generateIssueIndex, b as resolveGitHubRepo, d as resolvePackageDocs, et as getSharedSkillsDir, f as resolvePackageDocsWithAttempts, h as fetchGitDocs, i as fetchPkgDist, j as resolveEntryFiles, k as parseGitSkillInput, n as fetchNpmPackage, nt as semverGt, p as searchNpmPackages, q as parsePackageSpec, r as fetchNpmRegistryMeta, s as readLocalDependencies, t as fetchLatestVersion, tt as mapInsert, u as resolveLocalPackageDocs, v as fetchReadmeContent, w as fetchLlmsTxt, y as isShallowGitDocs, z as isPrerelease } from "./_chunks/npm.mjs";
|
|
10
10
|
import "./sources/index.mjs";
|
|
11
11
|
import { S as targets, _ as maxItems, a as getModelName, b as detectTargetAgent, c as computeSkillDirName, d as sanitizeName, f as unlinkSkillFromAgents, i as getModelLabel, n as createToolProgress, o as optimizeDocs, r as getAvailableModels, s as generateSkillMd, t as detectImportedPackages, u as linkSkillToAgents, v as maxLines, x as getAgentVersion, y as detectInstalledAgents } from "./_chunks/detect-imports.mjs";
|
|
12
12
|
import "./agent/index.mjs";
|
|
@@ -960,7 +960,8 @@ async function fetchAndCacheResources(opts) {
|
|
|
960
960
|
results.push(...batchResults);
|
|
961
961
|
}
|
|
962
962
|
for (const r of results) if (r) {
|
|
963
|
-
const
|
|
963
|
+
const stripped = gitDocs.docsPrefix ? r.file.replace(gitDocs.docsPrefix, "") : r.file;
|
|
964
|
+
const cachePath = stripped.startsWith("docs/") ? stripped : `docs/${stripped}`;
|
|
964
965
|
cachedDocs.push({
|
|
965
966
|
path: cachePath,
|
|
966
967
|
content: r.content
|
|
@@ -1150,7 +1151,8 @@ async function fetchAndCacheResources(opts) {
|
|
|
1150
1151
|
const gh = parseGitHubUrl(resolved.repoUrl);
|
|
1151
1152
|
if (gh) {
|
|
1152
1153
|
onProgress("Fetching releases via GitHub API");
|
|
1153
|
-
const
|
|
1154
|
+
const changelogRef = isPrerelease(version) ? getPrereleaseChangelogRef(packageName) : void 0;
|
|
1155
|
+
const releaseDocs = await fetchReleaseNotes(gh.owner, gh.repo, version, resolved.gitRef, packageName, opts.from, changelogRef).catch(() => []);
|
|
1154
1156
|
let blogDocs = [];
|
|
1155
1157
|
if (getBlogPreset(packageName)) {
|
|
1156
1158
|
onProgress("Fetching blog release notes");
|
|
@@ -1275,6 +1277,258 @@ function copyCachedSubdir(cacheDir, refsDir, subdir) {
|
|
|
1275
1277
|
}
|
|
1276
1278
|
walk(srcDir, "");
|
|
1277
1279
|
}
|
|
1280
|
+
async function ensureGitignore(skillsDir, cwd, isGlobal) {
|
|
1281
|
+
if (isGlobal) return;
|
|
1282
|
+
const gitignorePath = join(cwd, ".gitignore");
|
|
1283
|
+
const pattern = ".skilld";
|
|
1284
|
+
if (existsSync(gitignorePath)) {
|
|
1285
|
+
if (readFileSync(gitignorePath, "utf-8").split("\n").some((line) => line.trim() === pattern)) return;
|
|
1286
|
+
}
|
|
1287
|
+
if (!isInteractive()) {
|
|
1288
|
+
const entry = `\n# Skilld references (recreated by \`skilld install\`)\n${pattern}\n`;
|
|
1289
|
+
if (existsSync(gitignorePath)) appendFileSync(gitignorePath, `${readFileSync(gitignorePath, "utf-8").endsWith("\n") ? "" : "\n"}${entry}`);
|
|
1290
|
+
else writeFileSync(gitignorePath, entry);
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
p.log.info(`\x1B[1mGit guidance:\x1B[0m\n \x1B[32m✓\x1B[0m Commit: \x1B[36m${skillsDir}/*/SKILL.md\x1B[0m\n \x1B[32m✓\x1B[0m Commit: \x1B[36m${skillsDir}/skilld-lock.yaml\x1B[0m\n \x1B[31m✗\x1B[0m Ignore: \x1B[36m${pattern}\x1B[0m \x1B[90m(recreated by \`skilld install\`)\x1B[0m`);
|
|
1294
|
+
const add = await p.confirm({
|
|
1295
|
+
message: `Add \`${pattern}\` to .gitignore?`,
|
|
1296
|
+
initialValue: true
|
|
1297
|
+
});
|
|
1298
|
+
if (p.isCancel(add) || !add) return;
|
|
1299
|
+
const entry = `\n# Skilld references (recreated by \`skilld install\`)\n${pattern}\n`;
|
|
1300
|
+
if (existsSync(gitignorePath)) appendFileSync(gitignorePath, `${readFileSync(gitignorePath, "utf-8").endsWith("\n") ? "" : "\n"}${entry}`);
|
|
1301
|
+
else writeFileSync(gitignorePath, entry);
|
|
1302
|
+
p.log.success("Updated .gitignore");
|
|
1303
|
+
}
|
|
1304
|
+
const SKILLD_MARKER_START = "<!-- skilld -->";
|
|
1305
|
+
const SKILLD_MARKER_END = "<!-- /skilld -->";
|
|
1306
|
+
const SKILLD_INSTRUCTIONS = `${SKILLD_MARKER_START}
|
|
1307
|
+
Before modifying code, evaluate each installed skill against the current task.
|
|
1308
|
+
For each skill, determine YES/NO relevance and invoke all YES skills before proceeding.
|
|
1309
|
+
${SKILLD_MARKER_END}`;
|
|
1310
|
+
async function ensureAgentInstructions(agent, cwd, isGlobal) {
|
|
1311
|
+
if (isGlobal) return;
|
|
1312
|
+
const agentConfig = targets[agent];
|
|
1313
|
+
if (!agentConfig.instructionFile) return;
|
|
1314
|
+
const filePath = join(cwd, agentConfig.instructionFile);
|
|
1315
|
+
if (existsSync(filePath)) {
|
|
1316
|
+
if (readFileSync(filePath, "utf-8").includes(SKILLD_MARKER_START)) return;
|
|
1317
|
+
}
|
|
1318
|
+
if (!isInteractive()) {
|
|
1319
|
+
if (existsSync(filePath)) appendFileSync(filePath, `${readFileSync(filePath, "utf-8").endsWith("\n") ? "" : "\n"}\n${SKILLD_INSTRUCTIONS}\n`);
|
|
1320
|
+
else writeFileSync(filePath, `${SKILLD_INSTRUCTIONS}\n`);
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
p.note(SKILLD_INSTRUCTIONS, `Will be added to ${agentConfig.instructionFile}`);
|
|
1324
|
+
const add = await p.confirm({
|
|
1325
|
+
message: `Add skill activation instructions to ${agentConfig.instructionFile}?`,
|
|
1326
|
+
initialValue: true
|
|
1327
|
+
});
|
|
1328
|
+
if (p.isCancel(add) || !add) return;
|
|
1329
|
+
if (existsSync(filePath)) appendFileSync(filePath, `${readFileSync(filePath, "utf-8").endsWith("\n") ? "" : "\n"}\n${SKILLD_INSTRUCTIONS}\n`);
|
|
1330
|
+
else writeFileSync(filePath, `${SKILLD_INSTRUCTIONS}\n`);
|
|
1331
|
+
p.log.success(`Updated ${agentConfig.instructionFile}`);
|
|
1332
|
+
}
|
|
1333
|
+
async function selectModel(skipPrompt) {
|
|
1334
|
+
const config = readConfig();
|
|
1335
|
+
const available = await getAvailableModels();
|
|
1336
|
+
if (available.length === 0) {
|
|
1337
|
+
p.log.warn("No LLM CLIs found (claude, gemini, codex)");
|
|
1338
|
+
return null;
|
|
1339
|
+
}
|
|
1340
|
+
if (config.model && available.some((m) => m.id === config.model)) return config.model;
|
|
1341
|
+
if (skipPrompt) return available.find((m) => m.recommended)?.id ?? available[0].id;
|
|
1342
|
+
const modelChoice = await p.select({
|
|
1343
|
+
message: "Model for SKILL.md generation",
|
|
1344
|
+
options: available.map((m) => ({
|
|
1345
|
+
label: m.recommended ? `${m.name} (Recommended)` : m.name,
|
|
1346
|
+
value: m.id,
|
|
1347
|
+
hint: `${m.agentName} · ${m.hint}`
|
|
1348
|
+
})),
|
|
1349
|
+
initialValue: available.find((m) => m.recommended)?.id ?? available[0].id
|
|
1350
|
+
});
|
|
1351
|
+
if (p.isCancel(modelChoice)) {
|
|
1352
|
+
p.cancel("Cancelled");
|
|
1353
|
+
return null;
|
|
1354
|
+
}
|
|
1355
|
+
updateConfig({ model: modelChoice });
|
|
1356
|
+
return modelChoice;
|
|
1357
|
+
}
|
|
1358
|
+
const DEFAULT_SECTIONS = ["best-practices", "api-changes"];
|
|
1359
|
+
async function selectSkillSections(message = "Generate SKILL.md with LLM") {
|
|
1360
|
+
p.log.info("More sections = less budget each. Fewer sections = deeper coverage.");
|
|
1361
|
+
const selected = await p.multiselect({
|
|
1362
|
+
message,
|
|
1363
|
+
options: [
|
|
1364
|
+
{
|
|
1365
|
+
label: "API changes",
|
|
1366
|
+
value: "api-changes",
|
|
1367
|
+
hint: "new/deprecated APIs from version history"
|
|
1368
|
+
},
|
|
1369
|
+
{
|
|
1370
|
+
label: "Best practices",
|
|
1371
|
+
value: "best-practices",
|
|
1372
|
+
hint: "gotchas, pitfalls, patterns"
|
|
1373
|
+
},
|
|
1374
|
+
{
|
|
1375
|
+
label: "Doc map",
|
|
1376
|
+
value: "api",
|
|
1377
|
+
hint: "compact index of exports linked to source files"
|
|
1378
|
+
},
|
|
1379
|
+
{
|
|
1380
|
+
label: "Custom section",
|
|
1381
|
+
value: "custom",
|
|
1382
|
+
hint: "add your own section"
|
|
1383
|
+
}
|
|
1384
|
+
],
|
|
1385
|
+
initialValues: DEFAULT_SECTIONS,
|
|
1386
|
+
required: false
|
|
1387
|
+
});
|
|
1388
|
+
if (p.isCancel(selected)) return {
|
|
1389
|
+
sections: [],
|
|
1390
|
+
cancelled: true
|
|
1391
|
+
};
|
|
1392
|
+
const sections = selected;
|
|
1393
|
+
if (sections.length === 0) return {
|
|
1394
|
+
sections: [],
|
|
1395
|
+
cancelled: false
|
|
1396
|
+
};
|
|
1397
|
+
if (sections.length > 1) {
|
|
1398
|
+
const n = sections.length;
|
|
1399
|
+
const budgetLines = [];
|
|
1400
|
+
for (const s of sections) switch (s) {
|
|
1401
|
+
case "api-changes":
|
|
1402
|
+
budgetLines.push(` API changes ≤${maxLines(50, 80, n)} lines, ${maxItems(6, 12, n)} items`);
|
|
1403
|
+
break;
|
|
1404
|
+
case "best-practices":
|
|
1405
|
+
budgetLines.push(` Best practices ≤${maxLines(80, 150, n)} lines, ${maxItems(4, 10, n)} items`);
|
|
1406
|
+
break;
|
|
1407
|
+
case "api":
|
|
1408
|
+
budgetLines.push(` Doc map ≤${maxLines(15, 25, n)} lines`);
|
|
1409
|
+
break;
|
|
1410
|
+
case "custom":
|
|
1411
|
+
budgetLines.push(` Custom ≤${maxLines(50, 80, n)} lines`);
|
|
1412
|
+
break;
|
|
1413
|
+
}
|
|
1414
|
+
p.log.info(`Budget (${n} sections):\n${budgetLines.join("\n")}`);
|
|
1415
|
+
}
|
|
1416
|
+
let customPrompt;
|
|
1417
|
+
if (sections.includes("custom")) {
|
|
1418
|
+
const heading = await p.text({
|
|
1419
|
+
message: "Section heading",
|
|
1420
|
+
placeholder: "e.g. \"Migration from v2\" or \"SSR Patterns\""
|
|
1421
|
+
});
|
|
1422
|
+
if (p.isCancel(heading)) return {
|
|
1423
|
+
sections: [],
|
|
1424
|
+
cancelled: true
|
|
1425
|
+
};
|
|
1426
|
+
const body = await p.text({
|
|
1427
|
+
message: "Instructions for this section",
|
|
1428
|
+
placeholder: "e.g. \"Document breaking changes and migration steps from v2 to v3\""
|
|
1429
|
+
});
|
|
1430
|
+
if (p.isCancel(body)) return {
|
|
1431
|
+
sections: [],
|
|
1432
|
+
cancelled: true
|
|
1433
|
+
};
|
|
1434
|
+
customPrompt = {
|
|
1435
|
+
heading,
|
|
1436
|
+
body
|
|
1437
|
+
};
|
|
1438
|
+
}
|
|
1439
|
+
return {
|
|
1440
|
+
sections,
|
|
1441
|
+
customPrompt,
|
|
1442
|
+
cancelled: false
|
|
1443
|
+
};
|
|
1444
|
+
}
|
|
1445
|
+
async function selectLlmConfig(presetModel, message) {
|
|
1446
|
+
if (presetModel) return {
|
|
1447
|
+
model: presetModel,
|
|
1448
|
+
sections: DEFAULT_SECTIONS
|
|
1449
|
+
};
|
|
1450
|
+
if (!isInteractive()) {
|
|
1451
|
+
const model = await selectModel(true);
|
|
1452
|
+
if (!model) return null;
|
|
1453
|
+
return {
|
|
1454
|
+
model,
|
|
1455
|
+
sections: DEFAULT_SECTIONS
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
const model = await selectModel(false);
|
|
1459
|
+
if (!model) return null;
|
|
1460
|
+
const modelName = getModelName(model);
|
|
1461
|
+
const { sections, customPrompt, cancelled } = await selectSkillSections(message ? `${message} (${modelName})` : `Generate SKILL.md with ${modelName}`);
|
|
1462
|
+
if (cancelled || sections.length === 0) return null;
|
|
1463
|
+
return {
|
|
1464
|
+
model,
|
|
1465
|
+
sections,
|
|
1466
|
+
customPrompt
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
async function enhanceSkillWithLLM(opts) {
|
|
1470
|
+
const { packageName, version, skillDir, dirName, model, resolved, relatedSkills, hasIssues, hasDiscussions, hasReleases, hasChangelog, docsType, hasShippedDocs: shippedDocs, pkgFiles, force, debug, sections, customPrompt, packages, features, eject } = opts;
|
|
1471
|
+
const effectiveFeatures = eject && features ? {
|
|
1472
|
+
...features,
|
|
1473
|
+
search: false
|
|
1474
|
+
} : features;
|
|
1475
|
+
const llmLog = p.taskLog({ title: `Agent exploring ${packageName}` });
|
|
1476
|
+
const docFiles = listReferenceFiles(skillDir);
|
|
1477
|
+
const { optimized, wasOptimized, usage, cost, warnings, debugLogsDir } = await optimizeDocs({
|
|
1478
|
+
packageName,
|
|
1479
|
+
skillDir,
|
|
1480
|
+
model,
|
|
1481
|
+
version,
|
|
1482
|
+
hasGithub: hasIssues || hasDiscussions,
|
|
1483
|
+
hasReleases,
|
|
1484
|
+
hasChangelog,
|
|
1485
|
+
docFiles,
|
|
1486
|
+
docsType,
|
|
1487
|
+
hasShippedDocs: shippedDocs,
|
|
1488
|
+
noCache: force,
|
|
1489
|
+
debug,
|
|
1490
|
+
sections,
|
|
1491
|
+
customPrompt,
|
|
1492
|
+
features: effectiveFeatures,
|
|
1493
|
+
pkgFiles,
|
|
1494
|
+
onProgress: createToolProgress(llmLog)
|
|
1495
|
+
});
|
|
1496
|
+
if (wasOptimized) {
|
|
1497
|
+
const costParts = [];
|
|
1498
|
+
if (usage) {
|
|
1499
|
+
const totalK = Math.round(usage.totalTokens / 1e3);
|
|
1500
|
+
costParts.push(`${totalK}k tokens`);
|
|
1501
|
+
}
|
|
1502
|
+
if (cost) costParts.push(`$${cost.toFixed(2)}`);
|
|
1503
|
+
const costSuffix = costParts.length > 0 ? ` (${costParts.join(", ")})` : "";
|
|
1504
|
+
llmLog.success(`Generated best practices${costSuffix}`);
|
|
1505
|
+
if (debugLogsDir) p.log.info(`Debug logs: ${debugLogsDir}`);
|
|
1506
|
+
if (warnings?.length) for (const w of warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
|
|
1507
|
+
const skillMd = generateSkillMd({
|
|
1508
|
+
name: packageName,
|
|
1509
|
+
version,
|
|
1510
|
+
releasedAt: resolved.releasedAt,
|
|
1511
|
+
dependencies: resolved.dependencies,
|
|
1512
|
+
distTags: resolved.distTags,
|
|
1513
|
+
body: optimized,
|
|
1514
|
+
relatedSkills,
|
|
1515
|
+
hasIssues,
|
|
1516
|
+
hasDiscussions,
|
|
1517
|
+
hasReleases,
|
|
1518
|
+
hasChangelog,
|
|
1519
|
+
docsType,
|
|
1520
|
+
hasShippedDocs: shippedDocs,
|
|
1521
|
+
pkgFiles,
|
|
1522
|
+
generatedBy: getModelLabel(model),
|
|
1523
|
+
dirName,
|
|
1524
|
+
packages,
|
|
1525
|
+
repoUrl: resolved.repoUrl,
|
|
1526
|
+
features,
|
|
1527
|
+
eject
|
|
1528
|
+
});
|
|
1529
|
+
writeFileSync(join(skillDir, "SKILL.md"), skillMd);
|
|
1530
|
+
} else llmLog.error("LLM optimization failed");
|
|
1531
|
+
}
|
|
1278
1532
|
const TELEMETRY_URL = "https://add-skill.vercel.sh/t";
|
|
1279
1533
|
const SKILLS_VERSION = "1.3.9";
|
|
1280
1534
|
function isEnabled() {
|
|
@@ -1300,6 +1554,10 @@ async function syncGitSkills(opts) {
|
|
|
1300
1554
|
spin.start(`Fetching skills from ${label}`);
|
|
1301
1555
|
const { skills, commitSha } = await fetchGitSkills(source, (msg) => spin.message(msg));
|
|
1302
1556
|
if (skills.length === 0) {
|
|
1557
|
+
if (source.type === "github" && source.owner && source.repo) {
|
|
1558
|
+
spin.stop(`No pre-authored skills in ${label}, generating from repo docs...`);
|
|
1559
|
+
return syncGitHubRepo(opts);
|
|
1560
|
+
}
|
|
1303
1561
|
spin.stop(`No skills found in ${label}`);
|
|
1304
1562
|
return;
|
|
1305
1563
|
}
|
|
@@ -1353,6 +1611,140 @@ async function syncGitSkills(opts) {
|
|
|
1353
1611
|
const names = selected.map((s) => `\x1B[36m${s.name}\x1B[0m`).join(", ");
|
|
1354
1612
|
p.log.success(`Installed ${names}`);
|
|
1355
1613
|
}
|
|
1614
|
+
async function syncGitHubRepo(opts) {
|
|
1615
|
+
const { source, agent, global: isGlobal, yes } = opts;
|
|
1616
|
+
const owner = source.owner;
|
|
1617
|
+
const repo = source.repo;
|
|
1618
|
+
const cwd = process.cwd();
|
|
1619
|
+
const spin = timedSpinner();
|
|
1620
|
+
spin.start(`Resolving ${owner}/${repo}`);
|
|
1621
|
+
const resolved = await resolveGitHubRepo(owner, repo, (msg) => spin.message(msg));
|
|
1622
|
+
if (!resolved) {
|
|
1623
|
+
spin.stop(`Could not find docs for ${owner}/${repo}`);
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
const repoUrl = `https://github.com/${owner}/${repo}`;
|
|
1627
|
+
const packageName = `${owner}-${repo}`;
|
|
1628
|
+
const version = resolved.version || "main";
|
|
1629
|
+
const versionKey = getVersionKey(version);
|
|
1630
|
+
const useCache = isCached(packageName, version);
|
|
1631
|
+
spin.stop(`Resolved ${owner}/${repo}@${useCache ? versionKey : version}${useCache ? " (cached)" : ""}`);
|
|
1632
|
+
ensureCacheDir();
|
|
1633
|
+
const baseDir = resolveBaseDir(cwd, agent, isGlobal);
|
|
1634
|
+
const skillDirName = sanitizeName(`${owner}-${repo}`);
|
|
1635
|
+
const skillDir = join(baseDir, skillDirName);
|
|
1636
|
+
mkdirSync(skillDir, { recursive: true });
|
|
1637
|
+
const features = readConfig().features ?? defaultFeatures;
|
|
1638
|
+
const resSpin = timedSpinner();
|
|
1639
|
+
resSpin.start("Finding resources");
|
|
1640
|
+
const resources = await fetchAndCacheResources({
|
|
1641
|
+
packageName,
|
|
1642
|
+
resolved,
|
|
1643
|
+
version,
|
|
1644
|
+
useCache,
|
|
1645
|
+
features,
|
|
1646
|
+
from: opts.from,
|
|
1647
|
+
onProgress: (msg) => resSpin.message(msg)
|
|
1648
|
+
});
|
|
1649
|
+
const resParts = [];
|
|
1650
|
+
if (resources.docsToIndex.length > 0) {
|
|
1651
|
+
const docCount = resources.docsToIndex.filter((d) => d.metadata?.type === "doc").length;
|
|
1652
|
+
if (docCount > 0) resParts.push(`${docCount} docs`);
|
|
1653
|
+
}
|
|
1654
|
+
if (resources.hasIssues) resParts.push("issues");
|
|
1655
|
+
if (resources.hasDiscussions) resParts.push("discussions");
|
|
1656
|
+
if (resources.hasReleases) resParts.push("releases");
|
|
1657
|
+
resSpin.stop(`Fetched ${resParts.length > 0 ? resParts.join(", ") : "resources"}`);
|
|
1658
|
+
for (const w of resources.warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
|
|
1659
|
+
linkAllReferences(skillDir, packageName, cwd, version, resources.docsType, void 0, features);
|
|
1660
|
+
if (features.search) {
|
|
1661
|
+
const idxSpin = timedSpinner();
|
|
1662
|
+
idxSpin.start("Creating search index");
|
|
1663
|
+
await indexResources({
|
|
1664
|
+
packageName,
|
|
1665
|
+
version,
|
|
1666
|
+
cwd,
|
|
1667
|
+
docsToIndex: resources.docsToIndex,
|
|
1668
|
+
features,
|
|
1669
|
+
onProgress: (msg) => idxSpin.message(msg)
|
|
1670
|
+
});
|
|
1671
|
+
idxSpin.stop("Search index ready");
|
|
1672
|
+
}
|
|
1673
|
+
const hasChangelog = detectChangelog(resolvePkgDir(packageName, cwd, version), getCacheDir(packageName, version));
|
|
1674
|
+
const shippedDocs = hasShippedDocs(packageName, cwd, version);
|
|
1675
|
+
const pkgFiles = getPkgKeyFiles(packageName, cwd, version);
|
|
1676
|
+
writeLock(baseDir, skillDirName, {
|
|
1677
|
+
packageName,
|
|
1678
|
+
version,
|
|
1679
|
+
repo: `${owner}/${repo}`,
|
|
1680
|
+
source: resources.docSource,
|
|
1681
|
+
syncedAt: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
|
|
1682
|
+
generator: "skilld"
|
|
1683
|
+
});
|
|
1684
|
+
const baseSkillMd = generateSkillMd({
|
|
1685
|
+
name: packageName,
|
|
1686
|
+
version,
|
|
1687
|
+
releasedAt: resolved.releasedAt,
|
|
1688
|
+
description: resolved.description,
|
|
1689
|
+
relatedSkills: [],
|
|
1690
|
+
hasIssues: resources.hasIssues,
|
|
1691
|
+
hasDiscussions: resources.hasDiscussions,
|
|
1692
|
+
hasReleases: resources.hasReleases,
|
|
1693
|
+
hasChangelog,
|
|
1694
|
+
docsType: resources.docsType,
|
|
1695
|
+
hasShippedDocs: shippedDocs,
|
|
1696
|
+
pkgFiles,
|
|
1697
|
+
dirName: skillDirName,
|
|
1698
|
+
repoUrl,
|
|
1699
|
+
features
|
|
1700
|
+
});
|
|
1701
|
+
writeFileSync(join(skillDir, "SKILL.md"), baseSkillMd);
|
|
1702
|
+
p.log.success(`Created base skill: ${relative(cwd, skillDir)}`);
|
|
1703
|
+
if (!readConfig().skipLlm && (!yes || opts.model)) {
|
|
1704
|
+
const llmConfig = await selectLlmConfig(opts.model);
|
|
1705
|
+
if (llmConfig) {
|
|
1706
|
+
p.log.step(getModelLabel(llmConfig.model));
|
|
1707
|
+
await enhanceSkillWithLLM({
|
|
1708
|
+
packageName,
|
|
1709
|
+
version,
|
|
1710
|
+
skillDir,
|
|
1711
|
+
dirName: skillDirName,
|
|
1712
|
+
model: llmConfig.model,
|
|
1713
|
+
resolved,
|
|
1714
|
+
relatedSkills: [],
|
|
1715
|
+
hasIssues: resources.hasIssues,
|
|
1716
|
+
hasDiscussions: resources.hasDiscussions,
|
|
1717
|
+
hasReleases: resources.hasReleases,
|
|
1718
|
+
hasChangelog,
|
|
1719
|
+
docsType: resources.docsType,
|
|
1720
|
+
hasShippedDocs: shippedDocs,
|
|
1721
|
+
pkgFiles,
|
|
1722
|
+
force: opts.force,
|
|
1723
|
+
debug: opts.debug,
|
|
1724
|
+
sections: llmConfig.sections,
|
|
1725
|
+
customPrompt: llmConfig.customPrompt,
|
|
1726
|
+
features
|
|
1727
|
+
});
|
|
1728
|
+
}
|
|
1729
|
+
}
|
|
1730
|
+
const shared = !isGlobal && getSharedSkillsDir(cwd);
|
|
1731
|
+
if (shared) linkSkillToAgents(skillDirName, shared, cwd);
|
|
1732
|
+
if (!isGlobal) {
|
|
1733
|
+
registerProject(cwd);
|
|
1734
|
+
await ensureGitignore(shared || targets[agent].skillsDir, cwd, isGlobal);
|
|
1735
|
+
await ensureAgentInstructions(agent, cwd, isGlobal);
|
|
1736
|
+
}
|
|
1737
|
+
await shutdownWorker();
|
|
1738
|
+
track({
|
|
1739
|
+
event: "install",
|
|
1740
|
+
source: `${owner}/${repo}`,
|
|
1741
|
+
skills: skillDirName,
|
|
1742
|
+
agents: agent,
|
|
1743
|
+
...isGlobal && { global: "1" },
|
|
1744
|
+
sourceType: "github-generated"
|
|
1745
|
+
});
|
|
1746
|
+
p.outro(`Synced ${owner}/${repo} to ${relative(cwd, skillDir)}`);
|
|
1747
|
+
}
|
|
1356
1748
|
const STATUS_ICONS = {
|
|
1357
1749
|
pending: "○",
|
|
1358
1750
|
resolving: "◐",
|
|
@@ -1466,9 +1858,10 @@ async function syncPackagesParallel(config) {
|
|
|
1466
1858
|
await shutdownWorker();
|
|
1467
1859
|
p.outro(`${pastVerb} ${successfulPkgs.length}/${packages.length} packages`);
|
|
1468
1860
|
}
|
|
1469
|
-
async function syncBaseSkill(
|
|
1861
|
+
async function syncBaseSkill(packageSpec, config, cwd, update) {
|
|
1862
|
+
const { name: packageName, tag: requestedTag } = parsePackageSpec(packageSpec);
|
|
1470
1863
|
const localVersion = (await readLocalDependencies(cwd).catch(() => [])).find((d) => d.name === packageName)?.version;
|
|
1471
|
-
const { package: resolvedPkg, attempts } = await resolvePackageDocsWithAttempts(packageName, {
|
|
1864
|
+
const { package: resolvedPkg, attempts } = await resolvePackageDocsWithAttempts(requestedTag ? packageSpec : packageName, {
|
|
1472
1865
|
version: localVersion,
|
|
1473
1866
|
cwd,
|
|
1474
1867
|
onProgress: (step) => update(packageName, "resolving", RESOLVE_STEP_LABELS[step])
|
|
@@ -1612,6 +2005,7 @@ async function enhanceWithLLM(packageName, data, config, cwd, update, sections,
|
|
|
1612
2005
|
sections,
|
|
1613
2006
|
customPrompt,
|
|
1614
2007
|
features: data.features,
|
|
2008
|
+
pkgFiles: data.pkgFiles,
|
|
1615
2009
|
onProgress: (progress) => {
|
|
1616
2010
|
const status = progress.type === "reasoning" ? "exploring" : "generating";
|
|
1617
2011
|
const sectionPrefix = progress.section ? `[${progress.section}] ` : "";
|
|
@@ -1740,17 +2134,8 @@ async function runWizard() {
|
|
|
1740
2134
|
p.outro("Thanks, you're all set! Change config anytime with `skilld config`.");
|
|
1741
2135
|
}
|
|
1742
2136
|
var sync_exports = /* @__PURE__ */ __exportAll({
|
|
1743
|
-
DEFAULT_SECTIONS: () => DEFAULT_SECTIONS,
|
|
1744
|
-
SKILLD_MARKER_END: () => SKILLD_MARKER_END,
|
|
1745
|
-
SKILLD_MARKER_START: () => SKILLD_MARKER_START,
|
|
1746
2137
|
addCommandDef: () => addCommandDef,
|
|
1747
2138
|
ejectCommandDef: () => ejectCommandDef,
|
|
1748
|
-
enhanceSkillWithLLM: () => enhanceSkillWithLLM,
|
|
1749
|
-
ensureAgentInstructions: () => ensureAgentInstructions,
|
|
1750
|
-
ensureGitignore: () => ensureGitignore,
|
|
1751
|
-
selectLlmConfig: () => selectLlmConfig,
|
|
1752
|
-
selectModel: () => selectModel,
|
|
1753
|
-
selectSkillSections: () => selectSkillSections,
|
|
1754
2139
|
syncCommand: () => syncCommand,
|
|
1755
2140
|
updateCommandDef: () => updateCommandDef
|
|
1756
2141
|
});
|
|
@@ -1764,59 +2149,6 @@ function showResolveAttempts(attempts) {
|
|
|
1764
2149
|
p.log.message(` ${icon} ${source}${msg}`);
|
|
1765
2150
|
}
|
|
1766
2151
|
}
|
|
1767
|
-
async function ensureGitignore(skillsDir, cwd, isGlobal) {
|
|
1768
|
-
if (isGlobal) return;
|
|
1769
|
-
const gitignorePath = join(cwd, ".gitignore");
|
|
1770
|
-
const pattern = ".skilld";
|
|
1771
|
-
if (existsSync(gitignorePath)) {
|
|
1772
|
-
if (readFileSync(gitignorePath, "utf-8").split("\n").some((line) => line.trim() === pattern)) return;
|
|
1773
|
-
}
|
|
1774
|
-
if (!isInteractive()) {
|
|
1775
|
-
const entry = `\n# Skilld references (recreated by \`skilld install\`)\n${pattern}\n`;
|
|
1776
|
-
if (existsSync(gitignorePath)) appendFileSync(gitignorePath, `${readFileSync(gitignorePath, "utf-8").endsWith("\n") ? "" : "\n"}${entry}`);
|
|
1777
|
-
else writeFileSync(gitignorePath, entry);
|
|
1778
|
-
return;
|
|
1779
|
-
}
|
|
1780
|
-
p.log.info(`\x1B[1mGit guidance:\x1B[0m\n \x1B[32m✓\x1B[0m Commit: \x1B[36m${skillsDir}/*/SKILL.md\x1B[0m\n \x1B[32m✓\x1B[0m Commit: \x1B[36m${skillsDir}/skilld-lock.yaml\x1B[0m\n \x1B[31m✗\x1B[0m Ignore: \x1B[36m${pattern}\x1B[0m \x1B[90m(recreated by \`skilld install\`)\x1B[0m`);
|
|
1781
|
-
const add = await p.confirm({
|
|
1782
|
-
message: `Add \`${pattern}\` to .gitignore?`,
|
|
1783
|
-
initialValue: true
|
|
1784
|
-
});
|
|
1785
|
-
if (p.isCancel(add) || !add) return;
|
|
1786
|
-
const entry = `\n# Skilld references (recreated by \`skilld install\`)\n${pattern}\n`;
|
|
1787
|
-
if (existsSync(gitignorePath)) appendFileSync(gitignorePath, `${readFileSync(gitignorePath, "utf-8").endsWith("\n") ? "" : "\n"}${entry}`);
|
|
1788
|
-
else writeFileSync(gitignorePath, entry);
|
|
1789
|
-
p.log.success("Updated .gitignore");
|
|
1790
|
-
}
|
|
1791
|
-
const SKILLD_MARKER_START = "<!-- skilld -->";
|
|
1792
|
-
const SKILLD_MARKER_END = "<!-- /skilld -->";
|
|
1793
|
-
const SKILLD_INSTRUCTIONS = `${SKILLD_MARKER_START}
|
|
1794
|
-
Before modifying code, evaluate each installed skill against the current task.
|
|
1795
|
-
For each skill, determine YES/NO relevance and invoke all YES skills before proceeding.
|
|
1796
|
-
${SKILLD_MARKER_END}`;
|
|
1797
|
-
async function ensureAgentInstructions(agent, cwd, isGlobal) {
|
|
1798
|
-
if (isGlobal) return;
|
|
1799
|
-
const agentConfig = targets[agent];
|
|
1800
|
-
if (!agentConfig.instructionFile) return;
|
|
1801
|
-
const filePath = join(cwd, agentConfig.instructionFile);
|
|
1802
|
-
if (existsSync(filePath)) {
|
|
1803
|
-
if (readFileSync(filePath, "utf-8").includes(SKILLD_MARKER_START)) return;
|
|
1804
|
-
}
|
|
1805
|
-
if (!isInteractive()) {
|
|
1806
|
-
if (existsSync(filePath)) appendFileSync(filePath, `${readFileSync(filePath, "utf-8").endsWith("\n") ? "" : "\n"}\n${SKILLD_INSTRUCTIONS}\n`);
|
|
1807
|
-
else writeFileSync(filePath, `${SKILLD_INSTRUCTIONS}\n`);
|
|
1808
|
-
return;
|
|
1809
|
-
}
|
|
1810
|
-
p.note(SKILLD_INSTRUCTIONS, `Will be added to ${agentConfig.instructionFile}`);
|
|
1811
|
-
const add = await p.confirm({
|
|
1812
|
-
message: `Add skill activation instructions to ${agentConfig.instructionFile}?`,
|
|
1813
|
-
initialValue: true
|
|
1814
|
-
});
|
|
1815
|
-
if (p.isCancel(add) || !add) return;
|
|
1816
|
-
if (existsSync(filePath)) appendFileSync(filePath, `${readFileSync(filePath, "utf-8").endsWith("\n") ? "" : "\n"}\n${SKILLD_INSTRUCTIONS}\n`);
|
|
1817
|
-
else writeFileSync(filePath, `${SKILLD_INSTRUCTIONS}\n`);
|
|
1818
|
-
p.log.success(`Updated ${agentConfig.instructionFile}`);
|
|
1819
|
-
}
|
|
1820
2152
|
async function syncCommand(state, opts) {
|
|
1821
2153
|
if (opts.packages && opts.packages.length > 0) {
|
|
1822
2154
|
if (opts.packages.length > 1) return syncPackagesParallel({
|
|
@@ -1905,148 +2237,13 @@ async function pickFromList(packages, state) {
|
|
|
1905
2237
|
}
|
|
1906
2238
|
return selected;
|
|
1907
2239
|
}
|
|
1908
|
-
async function
|
|
1909
|
-
const
|
|
1910
|
-
const available = await getAvailableModels();
|
|
1911
|
-
if (available.length === 0) {
|
|
1912
|
-
p.log.warn("No LLM CLIs found (claude, gemini, codex)");
|
|
1913
|
-
return null;
|
|
1914
|
-
}
|
|
1915
|
-
if (config.model && available.some((m) => m.id === config.model)) return config.model;
|
|
1916
|
-
if (skipPrompt) return available.find((m) => m.recommended)?.id ?? available[0].id;
|
|
1917
|
-
const modelChoice = await p.select({
|
|
1918
|
-
message: "Model for SKILL.md generation",
|
|
1919
|
-
options: available.map((m) => ({
|
|
1920
|
-
label: m.recommended ? `${m.name} (Recommended)` : m.name,
|
|
1921
|
-
value: m.id,
|
|
1922
|
-
hint: `${m.agentName} · ${m.hint}`
|
|
1923
|
-
})),
|
|
1924
|
-
initialValue: available.find((m) => m.recommended)?.id ?? available[0].id
|
|
1925
|
-
});
|
|
1926
|
-
if (p.isCancel(modelChoice)) {
|
|
1927
|
-
p.cancel("Cancelled");
|
|
1928
|
-
return null;
|
|
1929
|
-
}
|
|
1930
|
-
updateConfig({ model: modelChoice });
|
|
1931
|
-
return modelChoice;
|
|
1932
|
-
}
|
|
1933
|
-
const DEFAULT_SECTIONS = ["best-practices", "api-changes"];
|
|
1934
|
-
async function selectSkillSections(message = "Generate SKILL.md with LLM") {
|
|
1935
|
-
p.log.info("More sections = less budget each. Fewer sections = deeper coverage.");
|
|
1936
|
-
const selected = await p.multiselect({
|
|
1937
|
-
message,
|
|
1938
|
-
options: [
|
|
1939
|
-
{
|
|
1940
|
-
label: "API changes",
|
|
1941
|
-
value: "api-changes",
|
|
1942
|
-
hint: "new/deprecated APIs from version history"
|
|
1943
|
-
},
|
|
1944
|
-
{
|
|
1945
|
-
label: "Best practices",
|
|
1946
|
-
value: "best-practices",
|
|
1947
|
-
hint: "gotchas, pitfalls, patterns"
|
|
1948
|
-
},
|
|
1949
|
-
{
|
|
1950
|
-
label: "Doc map",
|
|
1951
|
-
value: "api",
|
|
1952
|
-
hint: "compact index of exports linked to source files"
|
|
1953
|
-
},
|
|
1954
|
-
{
|
|
1955
|
-
label: "Custom section",
|
|
1956
|
-
value: "custom",
|
|
1957
|
-
hint: "add your own section"
|
|
1958
|
-
}
|
|
1959
|
-
],
|
|
1960
|
-
initialValues: DEFAULT_SECTIONS,
|
|
1961
|
-
required: false
|
|
1962
|
-
});
|
|
1963
|
-
if (p.isCancel(selected)) return {
|
|
1964
|
-
sections: [],
|
|
1965
|
-
cancelled: true
|
|
1966
|
-
};
|
|
1967
|
-
const sections = selected;
|
|
1968
|
-
if (sections.length === 0) return {
|
|
1969
|
-
sections: [],
|
|
1970
|
-
cancelled: false
|
|
1971
|
-
};
|
|
1972
|
-
if (sections.length > 1) {
|
|
1973
|
-
const n = sections.length;
|
|
1974
|
-
const budgetLines = [];
|
|
1975
|
-
for (const s of sections) switch (s) {
|
|
1976
|
-
case "api-changes":
|
|
1977
|
-
budgetLines.push(` API changes ≤${maxLines(50, 80, n)} lines, ${maxItems(6, 12, n)} items`);
|
|
1978
|
-
break;
|
|
1979
|
-
case "best-practices":
|
|
1980
|
-
budgetLines.push(` Best practices ≤${maxLines(80, 150, n)} lines, ${maxItems(4, 10, n)} items`);
|
|
1981
|
-
break;
|
|
1982
|
-
case "api":
|
|
1983
|
-
budgetLines.push(` Doc map ≤${maxLines(15, 25, n)} lines`);
|
|
1984
|
-
break;
|
|
1985
|
-
case "custom":
|
|
1986
|
-
budgetLines.push(` Custom ≤${maxLines(50, 80, n)} lines`);
|
|
1987
|
-
break;
|
|
1988
|
-
}
|
|
1989
|
-
p.log.info(`Budget (${n} sections):\n${budgetLines.join("\n")}`);
|
|
1990
|
-
}
|
|
1991
|
-
let customPrompt;
|
|
1992
|
-
if (sections.includes("custom")) {
|
|
1993
|
-
const heading = await p.text({
|
|
1994
|
-
message: "Section heading",
|
|
1995
|
-
placeholder: "e.g. \"Migration from v2\" or \"SSR Patterns\""
|
|
1996
|
-
});
|
|
1997
|
-
if (p.isCancel(heading)) return {
|
|
1998
|
-
sections: [],
|
|
1999
|
-
cancelled: true
|
|
2000
|
-
};
|
|
2001
|
-
const body = await p.text({
|
|
2002
|
-
message: "Instructions for this section",
|
|
2003
|
-
placeholder: "e.g. \"Document breaking changes and migration steps from v2 to v3\""
|
|
2004
|
-
});
|
|
2005
|
-
if (p.isCancel(body)) return {
|
|
2006
|
-
sections: [],
|
|
2007
|
-
cancelled: true
|
|
2008
|
-
};
|
|
2009
|
-
customPrompt = {
|
|
2010
|
-
heading,
|
|
2011
|
-
body
|
|
2012
|
-
};
|
|
2013
|
-
}
|
|
2014
|
-
return {
|
|
2015
|
-
sections,
|
|
2016
|
-
customPrompt,
|
|
2017
|
-
cancelled: false
|
|
2018
|
-
};
|
|
2019
|
-
}
|
|
2020
|
-
async function selectLlmConfig(presetModel, message) {
|
|
2021
|
-
if (presetModel) return {
|
|
2022
|
-
model: presetModel,
|
|
2023
|
-
sections: DEFAULT_SECTIONS
|
|
2024
|
-
};
|
|
2025
|
-
if (!isInteractive()) {
|
|
2026
|
-
const model = await selectModel(true);
|
|
2027
|
-
if (!model) return null;
|
|
2028
|
-
return {
|
|
2029
|
-
model,
|
|
2030
|
-
sections: DEFAULT_SECTIONS
|
|
2031
|
-
};
|
|
2032
|
-
}
|
|
2033
|
-
const model = await selectModel(false);
|
|
2034
|
-
if (!model) return null;
|
|
2035
|
-
const modelName = getModelName(model);
|
|
2036
|
-
const { sections, customPrompt, cancelled } = await selectSkillSections(message ? `${message} (${modelName})` : `Generate SKILL.md with ${modelName}`);
|
|
2037
|
-
if (cancelled || sections.length === 0) return null;
|
|
2038
|
-
return {
|
|
2039
|
-
model,
|
|
2040
|
-
sections,
|
|
2041
|
-
customPrompt
|
|
2042
|
-
};
|
|
2043
|
-
}
|
|
2044
|
-
async function syncSinglePackage(packageName, config) {
|
|
2240
|
+
async function syncSinglePackage(packageSpec, config) {
|
|
2241
|
+
const { name: packageName, tag: requestedTag } = parsePackageSpec(packageSpec);
|
|
2045
2242
|
const spin = timedSpinner();
|
|
2046
|
-
spin.start(`Resolving ${
|
|
2243
|
+
spin.start(`Resolving ${packageSpec}`);
|
|
2047
2244
|
const cwd = process.cwd();
|
|
2048
2245
|
const localVersion = (await readLocalDependencies(cwd).catch(() => [])).find((d) => d.name === packageName)?.version;
|
|
2049
|
-
const resolveResult = await resolvePackageDocsWithAttempts(packageName, {
|
|
2246
|
+
const resolveResult = await resolvePackageDocsWithAttempts(requestedTag ? packageSpec : packageName, {
|
|
2050
2247
|
version: localVersion,
|
|
2051
2248
|
cwd,
|
|
2052
2249
|
onProgress: (step) => spin.message(`${packageName}: ${RESOLVE_STEP_LABELS[step]}`)
|
|
@@ -2102,7 +2299,7 @@ async function syncSinglePackage(packageName, config) {
|
|
|
2102
2299
|
ensureCacheDir();
|
|
2103
2300
|
const baseDir = resolveBaseDir(cwd, config.agent, config.global);
|
|
2104
2301
|
const skillDirName = config.name ? sanitizeName(config.name) : computeSkillDirName(packageName, resolved.repoUrl);
|
|
2105
|
-
const skillDir = config.eject ? typeof config.eject === "string" ? resolve(cwd, config.eject) : join(cwd, "skills", skillDirName) : join(baseDir, skillDirName);
|
|
2302
|
+
const skillDir = config.eject ? typeof config.eject === "string" ? join(resolve(cwd, config.eject), skillDirName) : join(cwd, "skills", skillDirName) : join(baseDir, skillDirName);
|
|
2106
2303
|
mkdirSync(skillDir, { recursive: true });
|
|
2107
2304
|
const existingLock = config.eject ? void 0 : readLock(baseDir)?.skills[skillDirName];
|
|
2108
2305
|
if (existingLock && existingLock.packageName !== packageName) {
|
|
@@ -2267,68 +2464,6 @@ async function syncSinglePackage(packageName, config) {
|
|
|
2267
2464
|
const ejectMsg = isEject ? " (ejected)" : "";
|
|
2268
2465
|
p.outro(config.mode === "update" ? `Updated ${packageName}${ejectMsg}` : `Synced ${packageName} to ${relative(cwd, skillDir)}${ejectMsg}`);
|
|
2269
2466
|
}
|
|
2270
|
-
async function enhanceSkillWithLLM(opts) {
|
|
2271
|
-
const { packageName, version, skillDir, dirName, model, resolved, relatedSkills, hasIssues, hasDiscussions, hasReleases, hasChangelog, docsType, hasShippedDocs: shippedDocs, pkgFiles, force, debug, sections, customPrompt, packages, features, eject } = opts;
|
|
2272
|
-
const effectiveFeatures = eject && features ? {
|
|
2273
|
-
...features,
|
|
2274
|
-
search: false
|
|
2275
|
-
} : features;
|
|
2276
|
-
const llmLog = p.taskLog({ title: `Agent exploring ${packageName}` });
|
|
2277
|
-
const docFiles = listReferenceFiles(skillDir);
|
|
2278
|
-
const { optimized, wasOptimized, usage, cost, warnings, debugLogsDir } = await optimizeDocs({
|
|
2279
|
-
packageName,
|
|
2280
|
-
skillDir,
|
|
2281
|
-
model,
|
|
2282
|
-
version,
|
|
2283
|
-
hasGithub: hasIssues || hasDiscussions,
|
|
2284
|
-
hasReleases,
|
|
2285
|
-
hasChangelog,
|
|
2286
|
-
docFiles,
|
|
2287
|
-
docsType,
|
|
2288
|
-
hasShippedDocs: shippedDocs,
|
|
2289
|
-
noCache: force,
|
|
2290
|
-
debug,
|
|
2291
|
-
sections,
|
|
2292
|
-
customPrompt,
|
|
2293
|
-
features: effectiveFeatures,
|
|
2294
|
-
onProgress: createToolProgress(llmLog)
|
|
2295
|
-
});
|
|
2296
|
-
if (wasOptimized) {
|
|
2297
|
-
const costParts = [];
|
|
2298
|
-
if (usage) {
|
|
2299
|
-
const totalK = Math.round(usage.totalTokens / 1e3);
|
|
2300
|
-
costParts.push(`${totalK}k tokens`);
|
|
2301
|
-
}
|
|
2302
|
-
if (cost) costParts.push(`$${cost.toFixed(2)}`);
|
|
2303
|
-
const costSuffix = costParts.length > 0 ? ` (${costParts.join(", ")})` : "";
|
|
2304
|
-
llmLog.success(`Generated best practices${costSuffix}`);
|
|
2305
|
-
if (debugLogsDir) p.log.info(`Debug logs: ${debugLogsDir}`);
|
|
2306
|
-
if (warnings?.length) for (const w of warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
|
|
2307
|
-
const skillMd = generateSkillMd({
|
|
2308
|
-
name: packageName,
|
|
2309
|
-
version,
|
|
2310
|
-
releasedAt: resolved.releasedAt,
|
|
2311
|
-
dependencies: resolved.dependencies,
|
|
2312
|
-
distTags: resolved.distTags,
|
|
2313
|
-
body: optimized,
|
|
2314
|
-
relatedSkills,
|
|
2315
|
-
hasIssues,
|
|
2316
|
-
hasDiscussions,
|
|
2317
|
-
hasReleases,
|
|
2318
|
-
hasChangelog,
|
|
2319
|
-
docsType,
|
|
2320
|
-
hasShippedDocs: shippedDocs,
|
|
2321
|
-
pkgFiles,
|
|
2322
|
-
generatedBy: getModelLabel(model),
|
|
2323
|
-
dirName,
|
|
2324
|
-
packages,
|
|
2325
|
-
repoUrl: resolved.repoUrl,
|
|
2326
|
-
features,
|
|
2327
|
-
eject
|
|
2328
|
-
});
|
|
2329
|
-
writeFileSync(join(skillDir, "SKILL.md"), skillMd);
|
|
2330
|
-
} else llmLog.error("LLM optimization failed");
|
|
2331
|
-
}
|
|
2332
2467
|
const addCommandDef = defineCommand({
|
|
2333
2468
|
meta: {
|
|
2334
2469
|
name: "add",
|
|
@@ -2362,7 +2497,10 @@ const addCommandDef = defineCommand({
|
|
|
2362
2497
|
source,
|
|
2363
2498
|
global: args.global,
|
|
2364
2499
|
agent,
|
|
2365
|
-
yes: args.yes
|
|
2500
|
+
yes: args.yes,
|
|
2501
|
+
model: args.model,
|
|
2502
|
+
force: args.force,
|
|
2503
|
+
debug: args.debug
|
|
2366
2504
|
});
|
|
2367
2505
|
if (npmTokens.length > 0) {
|
|
2368
2506
|
const packages = [...new Set(npmTokens.flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean))];
|
|
@@ -2886,6 +3024,7 @@ async function enhanceRegenerated(pkgName, version, skillDir, model, sections, c
|
|
|
2886
3024
|
sections,
|
|
2887
3025
|
customPrompt,
|
|
2888
3026
|
features,
|
|
3027
|
+
pkgFiles: getPkgKeyFiles(pkgName, process.cwd(), version),
|
|
2889
3028
|
onProgress: createToolProgress(llmLog)
|
|
2890
3029
|
});
|
|
2891
3030
|
if (wasOptimized) {
|