skilld 1.2.2 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -20
- package/dist/_chunks/agent.mjs +471 -17
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/assemble.mjs +2 -2
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +8 -2
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +2 -2
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/cli-helpers.mjs +421 -0
- package/dist/_chunks/cli-helpers.mjs.map +1 -0
- package/dist/_chunks/detect.mjs +51 -22
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/detect2.mjs +2 -0
- package/dist/_chunks/embedding-cache.mjs +13 -4
- package/dist/_chunks/embedding-cache.mjs.map +1 -1
- package/dist/_chunks/formatting.mjs +1 -286
- package/dist/_chunks/formatting.mjs.map +1 -1
- package/dist/_chunks/index.d.mts.map +1 -1
- package/dist/_chunks/index2.d.mts.map +1 -1
- package/dist/_chunks/install.mjs +6 -4
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/list.mjs +3 -2
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/pool.mjs +3 -2
- package/dist/_chunks/pool.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +38 -4
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/sanitize.mjs +7 -0
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +3 -2
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +4 -3
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/setup.mjs +27 -0
- package/dist/_chunks/setup.mjs.map +1 -0
- package/dist/_chunks/shared.mjs +6 -2
- package/dist/_chunks/shared.mjs.map +1 -1
- package/dist/_chunks/skills.mjs +1 -1
- package/dist/_chunks/sources.mjs +8 -8
- package/dist/_chunks/sources.mjs.map +1 -1
- package/dist/_chunks/sync.mjs +390 -108
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/uninstall.mjs +16 -2
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/agent/index.d.mts +22 -4
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +3 -3
- package/dist/cli.mjs +619 -328
- package/dist/cli.mjs.map +1 -1
- package/dist/retriv/index.d.mts +18 -3
- package/dist/retriv/index.d.mts.map +1 -1
- package/dist/retriv/index.mjs +30 -1
- package/dist/retriv/index.mjs.map +1 -1
- package/dist/retriv/worker.d.mts +2 -0
- package/dist/retriv/worker.d.mts.map +1 -1
- package/dist/retriv/worker.mjs +1 -0
- package/dist/retriv/worker.mjs.map +1 -1
- package/dist/sources/index.mjs +1 -1
- package/package.json +9 -8
- package/dist/_chunks/chunk.mjs +0 -15
package/dist/_chunks/sync.mjs
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
+
import { a as getModelLabel, i as getAvailableModels, o as getModelName, r as createToolProgress, s as optimizeDocs, t as detectImportedPackages } from "./agent.mjs";
|
|
1
2
|
import { a as getRepoCacheDir, c as getVersionKey, i as getPackageDbPath, o as getCacheDir, t as CACHE_DIR } from "./config.mjs";
|
|
2
3
|
import { n as sanitizeMarkdown } from "./sanitize.mjs";
|
|
3
|
-
import { _ as resolvePkgDir, a as getShippedSkills, b as writeToRepoCache, c as linkCachedDir, d as linkRepoCachedDir, f as linkShippedSkill, h as readCachedDocs, i as getPkgKeyFiles, l as linkPkg, m as listReferenceFiles, n as clearCache, o as hasShippedDocs, r as ensureCacheDir, s as isCached, u as linkPkgNamed, y as writeToCache } from "./cache.mjs";
|
|
4
|
+
import { _ as resolvePkgDir, a as getShippedSkills, b as writeToRepoCache, c as linkCachedDir, d as linkRepoCachedDir, f as linkShippedSkill, g as readCachedSection, h as readCachedDocs, i as getPkgKeyFiles, l as linkPkg, m as listReferenceFiles, n as clearCache, o as hasShippedDocs, r as ensureCacheDir, s as isCached, u as linkPkgNamed, y as writeToCache } from "./cache.mjs";
|
|
4
5
|
import "./yaml.mjs";
|
|
5
6
|
import { i as parseFrontmatter } from "./markdown.mjs";
|
|
6
|
-
import { SearchDepsUnavailableError, createIndex } from "../retriv/index.mjs";
|
|
7
|
-
import {
|
|
7
|
+
import { SearchDepsUnavailableError, createIndex, listIndexIds } from "../retriv/index.mjs";
|
|
8
|
+
import { a as semverDiff, c as getBlogPreset, n as getSharedSkillsDir, p as getPrereleaseChangelogRef, t as SHARED_SKILLS_DIR } from "./shared.mjs";
|
|
8
9
|
import { A as parseGitSkillInput, B as isGhAvailable, C as downloadLlmsDocs, D as normalizeLlmsLinks, F as formatDiscussionAsMarkdown, G as fetchReleaseNotes, H as toCrawlPattern, I as generateDiscussionIndex, K as generateReleaseIndex, L as fetchGitHubIssues, M as resolveEntryFiles, N as generateDocsIndex, P as fetchGitHubDiscussions, R as formatIssueAsMarkdown, T as fetchLlmsTxt, U as fetchBlogReleases, V as fetchCrawledDocs, Z as fetchGitHubRaw, b as isShallowGitDocs, f as resolvePackageDocsWithAttempts, h as fetchGitDocs, i as fetchPkgDist, k as fetchGitSkills, n as fetchNpmPackage, nt as parsePackageSpec, p as searchNpmPackages, q as isPrerelease, s as readLocalDependencies, tt as parseGitHubUrl, u as resolveLocalPackageDocs, v as fetchReadmeContent, x as resolveGitHubRepo, y as filterFrameworkDocs, z as generateIssueIndex } from "./sources.mjs";
|
|
9
10
|
import { a as targets } from "./detect.mjs";
|
|
10
|
-
import { a as sanitizeName, c as SECTION_OUTPUT_FILES, g as maxLines, h as maxItems, i as linkSkillToAgents, l as buildAllSectionPrompts, n as computeSkillDirName, p as portabilizePrompt, t as generateSkillMd } from "./prompts.mjs";
|
|
11
|
-
import {
|
|
12
|
-
import { C as hasCompletedWizard, E as registerProject, O as updateConfig, T as readConfig, d as getInstalledGenerators, h as promptForAgent, l as timedSpinner, m as isInteractive, n as formatDuration, p as introLine, v as resolveAgent, x as defaultFeatures, y as sharedArgs } from "./formatting.mjs";
|
|
11
|
+
import { a as sanitizeName, c as SECTION_OUTPUT_FILES, g as maxLines, h as maxItems, i as linkSkillToAgents, l as buildAllSectionPrompts, m as wrapSection, n as computeSkillDirName, p as portabilizePrompt, s as SECTION_MERGE_ORDER, t as generateSkillMd } from "./prompts.mjs";
|
|
12
|
+
import { C as registerProject, S as readConfig, T as updateConfig, b as hasCompletedWizard, c as isInteractive, d as pickModel, f as promptForAgent, g as sharedArgs, h as resolveAgent, i as getInstalledGenerators, s as introLine, t as NO_MODELS_MESSAGE, v as defaultFeatures } from "./cli-helpers.mjs";
|
|
13
13
|
import { o as parsePackages, s as readLock, t as getProjectState, u as writeLock } from "./skills.mjs";
|
|
14
|
+
import { l as timedSpinner, n as formatDuration } from "./formatting.mjs";
|
|
14
15
|
import { t as runWizard } from "../cli.mjs";
|
|
15
16
|
import { n as shutdownWorker } from "./pool.mjs";
|
|
16
17
|
import { dirname, join, relative, resolve } from "pathe";
|
|
@@ -121,9 +122,7 @@ function detectDocsType(packageName, version, repoUrl, llmsUrl) {
|
|
|
121
122
|
function handleShippedSkills(packageName, version, cwd, agent, global) {
|
|
122
123
|
const shippedSkills = getShippedSkills(packageName, cwd, version);
|
|
123
124
|
if (shippedSkills.length === 0) return null;
|
|
124
|
-
const
|
|
125
|
-
const agentConfig = targets[agent];
|
|
126
|
-
const baseDir = global ? join(CACHE_DIR, "skills") : shared || join(cwd, agentConfig.skillsDir);
|
|
125
|
+
const baseDir = resolveBaseDir(cwd, agent, global);
|
|
127
126
|
mkdirSync(baseDir, { recursive: true });
|
|
128
127
|
for (const shipped of shippedSkills) {
|
|
129
128
|
linkShippedSkill(baseDir, shipped.skillName, shipped.skillDir);
|
|
@@ -143,7 +142,7 @@ function handleShippedSkills(packageName, version, cwd, agent, global) {
|
|
|
143
142
|
}
|
|
144
143
|
/** Resolve the base skills directory for an agent */
|
|
145
144
|
function resolveBaseDir(cwd, agent, global) {
|
|
146
|
-
if (global) return
|
|
145
|
+
if (global) return targets[agent].globalSkillsDir;
|
|
147
146
|
const shared = getSharedSkillsDir(cwd);
|
|
148
147
|
if (shared) return shared;
|
|
149
148
|
const agentConfig = targets[agent];
|
|
@@ -321,6 +320,7 @@ async function fetchAndCacheResources(opts) {
|
|
|
321
320
|
}
|
|
322
321
|
});
|
|
323
322
|
}
|
|
323
|
+
if (docs.length > 0) docsType = "docs";
|
|
324
324
|
}
|
|
325
325
|
writeToCache(packageName, version, cachedDocs);
|
|
326
326
|
}
|
|
@@ -541,13 +541,41 @@ async function fetchAndCacheResources(opts) {
|
|
|
541
541
|
usedCache: useCache
|
|
542
542
|
};
|
|
543
543
|
}
|
|
544
|
-
/**
|
|
544
|
+
/**
|
|
545
|
+
* Extract the parent document ID from a chunk ID.
|
|
546
|
+
* Chunk IDs have the form "docId#chunk-N"; non-chunk IDs return as-is.
|
|
547
|
+
*/
|
|
548
|
+
function parentDocId(id) {
|
|
549
|
+
const idx = id.indexOf("#chunk-");
|
|
550
|
+
return idx === -1 ? id : id.slice(0, idx);
|
|
551
|
+
}
|
|
552
|
+
/** Cap and sort docs by type priority, mutates and truncates allDocs in place */
|
|
553
|
+
function capDocs(allDocs, max, onProgress) {
|
|
554
|
+
if (allDocs.length <= max) return;
|
|
555
|
+
const TYPE_PRIORITY = {
|
|
556
|
+
doc: 0,
|
|
557
|
+
issue: 1,
|
|
558
|
+
discussion: 2,
|
|
559
|
+
release: 3,
|
|
560
|
+
source: 4,
|
|
561
|
+
types: 5
|
|
562
|
+
};
|
|
563
|
+
allDocs.sort((a, b) => {
|
|
564
|
+
const ta = TYPE_PRIORITY[a.metadata?.type || "doc"] ?? 3;
|
|
565
|
+
const tb = TYPE_PRIORITY[b.metadata?.type || "doc"] ?? 3;
|
|
566
|
+
if (ta !== tb) return ta - tb;
|
|
567
|
+
return a.id.localeCompare(b.id);
|
|
568
|
+
});
|
|
569
|
+
onProgress(`Indexing capped at ${max}/${allDocs.length} docs (prioritized by type)`);
|
|
570
|
+
allDocs.length = max;
|
|
571
|
+
}
|
|
572
|
+
/** Index all resources into the search database, with incremental support */
|
|
545
573
|
async function indexResources(opts) {
|
|
546
574
|
const { packageName, version, cwd, onProgress } = opts;
|
|
547
575
|
const features = opts.features ?? readConfig().features ?? defaultFeatures;
|
|
548
576
|
if (!features.search) return;
|
|
549
577
|
const dbPath = getPackageDbPath(packageName, version);
|
|
550
|
-
|
|
578
|
+
const dbExists = existsSync(dbPath);
|
|
551
579
|
const allDocs = [...opts.docsToIndex];
|
|
552
580
|
const pkgDir = resolvePkgDir(packageName, cwd, version);
|
|
553
581
|
if (features.search && pkgDir) {
|
|
@@ -564,31 +592,54 @@ async function indexResources(opts) {
|
|
|
564
592
|
});
|
|
565
593
|
}
|
|
566
594
|
if (allDocs.length === 0) return;
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
595
|
+
capDocs(allDocs, MAX_INDEX_DOCS, onProgress);
|
|
596
|
+
if (!dbExists) {
|
|
597
|
+
onProgress(`Building search index (${allDocs.length} docs)`);
|
|
598
|
+
try {
|
|
599
|
+
await createIndex(allDocs, {
|
|
600
|
+
dbPath,
|
|
601
|
+
onProgress: ({ phase, current, total }) => {
|
|
602
|
+
if (phase === "storing") {
|
|
603
|
+
const d = allDocs[current - 1];
|
|
604
|
+
onProgress(`Storing ${d?.metadata?.type === "source" || d?.metadata?.type === "types" ? "code" : d?.metadata?.type || "doc"} (${current}/${total})`);
|
|
605
|
+
} else if (phase === "embedding") onProgress(`Creating embeddings (${current}/${total})`);
|
|
606
|
+
}
|
|
607
|
+
});
|
|
608
|
+
} catch (err) {
|
|
609
|
+
if (err instanceof SearchDepsUnavailableError) onProgress("Search indexing skipped (native deps unavailable)");
|
|
610
|
+
else throw err;
|
|
611
|
+
}
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
let existingIds;
|
|
615
|
+
try {
|
|
616
|
+
existingIds = await listIndexIds({ dbPath });
|
|
617
|
+
} catch (err) {
|
|
618
|
+
if (err instanceof SearchDepsUnavailableError) {
|
|
619
|
+
onProgress("Search indexing skipped (native deps unavailable)");
|
|
620
|
+
return;
|
|
621
|
+
}
|
|
622
|
+
throw err;
|
|
623
|
+
}
|
|
624
|
+
const existingParentIds = new Set(existingIds.map(parentDocId));
|
|
625
|
+
const incomingIds = new Set(allDocs.map((d) => d.id));
|
|
626
|
+
const newDocs = allDocs.filter((d) => !existingParentIds.has(d.id));
|
|
627
|
+
const removeIds = existingIds.filter((id) => !incomingIds.has(parentDocId(id)));
|
|
628
|
+
if (newDocs.length === 0 && removeIds.length === 0) {
|
|
629
|
+
onProgress("Search index up to date");
|
|
630
|
+
return;
|
|
584
631
|
}
|
|
585
|
-
|
|
632
|
+
const parts = [];
|
|
633
|
+
if (newDocs.length > 0) parts.push(`+${newDocs.length} new`);
|
|
634
|
+
if (removeIds.length > 0) parts.push(`-${removeIds.length} stale`);
|
|
635
|
+
onProgress(`Updating search index (${parts.join(", ")})`);
|
|
586
636
|
try {
|
|
587
|
-
await createIndex(
|
|
637
|
+
await createIndex(newDocs, {
|
|
588
638
|
dbPath,
|
|
639
|
+
removeIds,
|
|
589
640
|
onProgress: ({ phase, current, total }) => {
|
|
590
641
|
if (phase === "storing") {
|
|
591
|
-
const d =
|
|
642
|
+
const d = newDocs[current - 1];
|
|
592
643
|
onProgress(`Storing ${d?.metadata?.type === "source" || d?.metadata?.type === "types" ? "code" : d?.metadata?.type || "doc"} (${current}/${total})`);
|
|
593
644
|
} else if (phase === "embedding") onProgress(`Creating embeddings (${current}/${total})`);
|
|
594
645
|
}
|
|
@@ -662,10 +713,13 @@ async function ensureGitignore(skillsDir, cwd, isGlobal) {
|
|
|
662
713
|
}
|
|
663
714
|
const SKILLD_MARKER_START = "<!-- skilld -->";
|
|
664
715
|
const SKILLD_MARKER_END = "<!-- /skilld -->";
|
|
665
|
-
const
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
716
|
+
const DEFAULT_SKILL_HINT = "Before modifying code, evaluate each installed skill against the current task.\nFor each skill, determine YES/NO relevance and invoke all YES skills before proceeding.";
|
|
717
|
+
function getSkillInstructions(agent) {
|
|
718
|
+
return `${SKILLD_MARKER_START}\n${targets[agent].skillActivationHint || DEFAULT_SKILL_HINT}\n${SKILLD_MARKER_END}`;
|
|
719
|
+
}
|
|
720
|
+
function getMdcSkillInstructions(agent) {
|
|
721
|
+
return `---\ndescription: "Activates installed skilld skills before code changes"\nalwaysApply: true\n---\n\n${targets[agent].skillActivationHint || DEFAULT_SKILL_HINT}`;
|
|
722
|
+
}
|
|
669
723
|
/**
|
|
670
724
|
* Check if agent instruction file has skilld skill-activation snippet.
|
|
671
725
|
* If missing, prompt to add it. Skipped for global installs or agents without an instructionFile.
|
|
@@ -675,55 +729,55 @@ async function ensureAgentInstructions(agent, cwd, isGlobal) {
|
|
|
675
729
|
const agentConfig = targets[agent];
|
|
676
730
|
if (!agentConfig.instructionFile) return;
|
|
677
731
|
const filePath = join(cwd, agentConfig.instructionFile);
|
|
732
|
+
if (agentConfig.instructionFile.endsWith(".mdc")) {
|
|
733
|
+
if (existsSync(filePath)) return;
|
|
734
|
+
const content = `${getMdcSkillInstructions(agent)}\n`;
|
|
735
|
+
if (!isInteractive()) {
|
|
736
|
+
mkdirSync(join(filePath, ".."), { recursive: true });
|
|
737
|
+
writeFileSync(filePath, content);
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
p.note(`This tells your agent to check installed skills before making
|
|
741
|
+
code changes. Without it, skills are available but may not
|
|
742
|
+
activate automatically.
|
|
743
|
+
|
|
744
|
+
\x1B[90m${getMdcSkillInstructions(agent)}\x1B[0m`, `Create ${agentConfig.instructionFile}`);
|
|
745
|
+
const add = await p.confirm({
|
|
746
|
+
message: `Create ${agentConfig.instructionFile} with skill activation instructions?`,
|
|
747
|
+
initialValue: true
|
|
748
|
+
});
|
|
749
|
+
if (p.isCancel(add) || !add) return;
|
|
750
|
+
mkdirSync(join(filePath, ".."), { recursive: true });
|
|
751
|
+
writeFileSync(filePath, content);
|
|
752
|
+
p.log.success(`Created ${agentConfig.instructionFile}`);
|
|
753
|
+
return;
|
|
754
|
+
}
|
|
678
755
|
if (existsSync(filePath)) {
|
|
679
756
|
if (readFileSync(filePath, "utf-8").includes("<!-- skilld -->")) return;
|
|
680
757
|
}
|
|
681
758
|
if (!isInteractive()) {
|
|
682
|
-
if (existsSync(filePath)) appendFileSync(filePath, `${readFileSync(filePath, "utf-8").endsWith("\n") ? "" : "\n"}\n${
|
|
683
|
-
else writeFileSync(filePath, `${
|
|
759
|
+
if (existsSync(filePath)) appendFileSync(filePath, `${readFileSync(filePath, "utf-8").endsWith("\n") ? "" : "\n"}\n${getSkillInstructions(agent)}\n`);
|
|
760
|
+
else writeFileSync(filePath, `${getSkillInstructions(agent)}\n`);
|
|
684
761
|
return;
|
|
685
762
|
}
|
|
686
|
-
|
|
763
|
+
const action = existsSync(filePath) ? "Append to" : "Create";
|
|
764
|
+
p.note(`This tells your agent to check installed skills before making
|
|
765
|
+
code changes. Without it, skills are available but may not
|
|
766
|
+
activate automatically.
|
|
767
|
+
|
|
768
|
+
\x1B[90m${getSkillInstructions(agent).replace(/\n/g, "\n")}\x1B[0m`, `${action} ${agentConfig.instructionFile}`);
|
|
687
769
|
const add = await p.confirm({
|
|
688
|
-
message:
|
|
770
|
+
message: `${action} ${agentConfig.instructionFile} with skill activation instructions?`,
|
|
689
771
|
initialValue: true
|
|
690
772
|
});
|
|
691
773
|
if (p.isCancel(add) || !add) return;
|
|
692
|
-
if (existsSync(filePath)) appendFileSync(filePath, `${readFileSync(filePath, "utf-8").endsWith("\n") ? "" : "\n"}\n${
|
|
693
|
-
else writeFileSync(filePath, `${
|
|
774
|
+
if (existsSync(filePath)) appendFileSync(filePath, `${readFileSync(filePath, "utf-8").endsWith("\n") ? "" : "\n"}\n${getSkillInstructions(agent)}\n`);
|
|
775
|
+
else writeFileSync(filePath, `${getSkillInstructions(agent)}\n`);
|
|
694
776
|
p.log.success(`Updated ${agentConfig.instructionFile}`);
|
|
695
777
|
}
|
|
696
|
-
/** Select LLM model for SKILL.md generation (independent of target agent) */
|
|
697
|
-
async function selectModel(skipPrompt) {
|
|
698
|
-
const config = readConfig();
|
|
699
|
-
const available = await getAvailableModels();
|
|
700
|
-
if (available.length === 0) {
|
|
701
|
-
p.log.warn("No LLM CLIs found (claude, gemini, codex)");
|
|
702
|
-
return null;
|
|
703
|
-
}
|
|
704
|
-
if (skipPrompt) {
|
|
705
|
-
if (config.model && available.some((m) => m.id === config.model)) return config.model;
|
|
706
|
-
return available.find((m) => m.recommended)?.id ?? available[0].id;
|
|
707
|
-
}
|
|
708
|
-
const modelChoice = await p.select({
|
|
709
|
-
message: "Model for SKILL.md generation",
|
|
710
|
-
options: available.map((m) => ({
|
|
711
|
-
label: m.recommended ? `${m.name} (Recommended)` : m.name,
|
|
712
|
-
value: m.id,
|
|
713
|
-
hint: `${m.agentName} · ${m.hint}`
|
|
714
|
-
})),
|
|
715
|
-
initialValue: available.find((m) => m.recommended)?.id ?? available[0].id
|
|
716
|
-
});
|
|
717
|
-
if (p.isCancel(modelChoice)) {
|
|
718
|
-
p.cancel("Cancelled");
|
|
719
|
-
return null;
|
|
720
|
-
}
|
|
721
|
-
updateConfig({ model: modelChoice });
|
|
722
|
-
return modelChoice;
|
|
723
|
-
}
|
|
724
778
|
/** Default sections when model is pre-set (non-interactive) */
|
|
725
779
|
const DEFAULT_SECTIONS = ["best-practices", "api-changes"];
|
|
726
|
-
async function selectSkillSections(message = "
|
|
780
|
+
async function selectSkillSections(message = "Enhance SKILL.md") {
|
|
727
781
|
p.log.info("Budgets adapt to package release density.");
|
|
728
782
|
const selected = await p.multiselect({
|
|
729
783
|
message,
|
|
@@ -806,27 +860,62 @@ async function selectSkillSections(message = "Generate SKILL.md with LLM") {
|
|
|
806
860
|
* If presetModel is provided, uses DEFAULT_SECTIONS without prompting.
|
|
807
861
|
* Returns null if cancelled or no sections/model selected.
|
|
808
862
|
*/
|
|
809
|
-
async function selectLlmConfig(presetModel, message) {
|
|
810
|
-
if (presetModel)
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
863
|
+
async function selectLlmConfig(presetModel, message, updateCtx) {
|
|
864
|
+
if (presetModel) {
|
|
865
|
+
if ((await getAvailableModels()).some((m) => m.id === presetModel)) return {
|
|
866
|
+
model: presetModel,
|
|
867
|
+
sections: DEFAULT_SECTIONS
|
|
868
|
+
};
|
|
869
|
+
if (!isInteractive()) return null;
|
|
870
|
+
}
|
|
814
871
|
if (!isInteractive()) return null;
|
|
815
|
-
const
|
|
816
|
-
|
|
872
|
+
const config = readConfig();
|
|
873
|
+
const available = await getAvailableModels();
|
|
874
|
+
if (available.length === 0) {
|
|
875
|
+
p.log.warn(NO_MODELS_MESSAGE);
|
|
876
|
+
return null;
|
|
877
|
+
}
|
|
878
|
+
let defaultModel;
|
|
879
|
+
if (config.model && available.some((m) => m.id === config.model)) defaultModel = config.model;
|
|
880
|
+
else {
|
|
881
|
+
if (config.model) p.log.warn(`Configured model \x1B[36m${config.model}\x1B[0m is unavailable — using auto-selected fallback`);
|
|
882
|
+
defaultModel = available.find((m) => m.recommended)?.id ?? available[0].id;
|
|
883
|
+
}
|
|
817
884
|
const defaultModelName = getModelName(defaultModel);
|
|
885
|
+
const providerHint = available.find((m) => m.id === defaultModel)?.providerName ?? "";
|
|
886
|
+
const sourceHint = config.model === defaultModel ? "configured" : "recommended";
|
|
887
|
+
const defaultHint = providerHint ? `${providerHint} · ${sourceHint}` : sourceHint;
|
|
888
|
+
let enhanceMessage = "Enhance SKILL.md?";
|
|
889
|
+
let defaultToSkip = false;
|
|
890
|
+
if (updateCtx) {
|
|
891
|
+
const diff = updateCtx.bumpType ?? (updateCtx.oldVersion && updateCtx.newVersion ? semverDiff(updateCtx.oldVersion, updateCtx.newVersion) : null);
|
|
892
|
+
const isSmallBump = diff === "patch" || diff === "prerelease" || diff === "prepatch" || diff === "preminor" || diff === "premajor";
|
|
893
|
+
const ageParts = [];
|
|
894
|
+
if (diff) ageParts.push(diff);
|
|
895
|
+
if (updateCtx.syncedAt) {
|
|
896
|
+
const syncedAtMs = new Date(updateCtx.syncedAt).getTime();
|
|
897
|
+
if (Number.isFinite(syncedAtMs)) {
|
|
898
|
+
const days = Math.floor((Date.now() - syncedAtMs) / 864e5);
|
|
899
|
+
ageParts.push(days === 0 ? "today" : days === 1 ? "1d ago" : `${days}d ago`);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
if (updateCtx.wasEnhanced) ageParts.push("LLM-enhanced");
|
|
903
|
+
const hint = [updateCtx.oldVersion && updateCtx.newVersion ? `${updateCtx.oldVersion} → ${updateCtx.newVersion}` : null, ...ageParts].filter(Boolean).join(" · ");
|
|
904
|
+
if (hint) enhanceMessage = `Enhance SKILL.md? \x1B[90m(${hint})\x1B[0m`;
|
|
905
|
+
if (updateCtx.wasEnhanced && isSmallBump) defaultToSkip = true;
|
|
906
|
+
}
|
|
818
907
|
const choice = await p.select({
|
|
819
|
-
message:
|
|
908
|
+
message: enhanceMessage,
|
|
820
909
|
options: [
|
|
821
910
|
{
|
|
822
911
|
label: defaultModelName,
|
|
823
912
|
value: "default",
|
|
824
|
-
hint:
|
|
913
|
+
hint: defaultHint
|
|
825
914
|
},
|
|
826
915
|
{
|
|
827
916
|
label: "Different model",
|
|
828
917
|
value: "pick",
|
|
829
|
-
hint: "choose another model"
|
|
918
|
+
hint: "choose another enhancement model"
|
|
830
919
|
},
|
|
831
920
|
{
|
|
832
921
|
label: "Prompt only",
|
|
@@ -836,9 +925,10 @@ async function selectLlmConfig(presetModel, message) {
|
|
|
836
925
|
{
|
|
837
926
|
label: "Skip",
|
|
838
927
|
value: "skip",
|
|
839
|
-
hint: "base skill
|
|
928
|
+
hint: "base skill with docs, issues, and types"
|
|
840
929
|
}
|
|
841
|
-
]
|
|
930
|
+
],
|
|
931
|
+
...defaultToSkip ? { initialValue: "skip" } : {}
|
|
842
932
|
});
|
|
843
933
|
if (p.isCancel(choice)) return null;
|
|
844
934
|
if (choice === "skip") return null;
|
|
@@ -852,10 +942,16 @@ async function selectLlmConfig(presetModel, message) {
|
|
|
852
942
|
promptOnly: true
|
|
853
943
|
};
|
|
854
944
|
}
|
|
855
|
-
|
|
945
|
+
let model;
|
|
946
|
+
if (choice === "pick") {
|
|
947
|
+
const picked = await pickModel(available);
|
|
948
|
+
if (!picked) return null;
|
|
949
|
+
updateConfig({ model: picked });
|
|
950
|
+
model = picked;
|
|
951
|
+
} else model = defaultModel;
|
|
856
952
|
if (!model) return null;
|
|
857
953
|
const modelName = getModelName(model);
|
|
858
|
-
const { sections, customPrompt, cancelled } = await selectSkillSections(message ? `${message} (${modelName})` : `
|
|
954
|
+
const { sections, customPrompt, cancelled } = await selectSkillSections(message ? `${message} (${modelName})` : `Enhance SKILL.md with ${modelName}`);
|
|
859
955
|
if (cancelled || sections.length === 0) return null;
|
|
860
956
|
return {
|
|
861
957
|
model,
|
|
@@ -922,7 +1018,7 @@ async function enhanceSkillWithLLM(opts) {
|
|
|
922
1018
|
eject
|
|
923
1019
|
});
|
|
924
1020
|
writeFileSync(join(skillDir, "SKILL.md"), skillMd);
|
|
925
|
-
} else llmLog.error(`
|
|
1021
|
+
} else llmLog.error(`Enhancement failed${error ? `: ${error}` : ""}`);
|
|
926
1022
|
}
|
|
927
1023
|
/**
|
|
928
1024
|
* Build and write PROMPT_*.md files for manual LLM use.
|
|
@@ -1302,10 +1398,93 @@ async function syncPackagesParallel(config) {
|
|
|
1302
1398
|
p.log.success(skillMsg);
|
|
1303
1399
|
for (const [, data] of skillData) for (const w of data.warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
|
|
1304
1400
|
if (errors.length > 0) for (const { pkg, reason } of errors) p.log.error(` ${pkg}: ${reason}`);
|
|
1401
|
+
const cachedPkgs = [];
|
|
1402
|
+
if (!config.force) for (const pkg of successfulPkgs) {
|
|
1403
|
+
const data = skillData.get(pkg);
|
|
1404
|
+
const resolvedName = data.resolved.name;
|
|
1405
|
+
if (DEFAULT_SECTIONS.every((s) => {
|
|
1406
|
+
const outputFile = SECTION_OUTPUT_FILES[s];
|
|
1407
|
+
return readCachedSection(resolvedName, data.version, outputFile) !== null;
|
|
1408
|
+
})) {
|
|
1409
|
+
const skillDir = join(resolveBaseDir(cwd, config.agent, config.global), data.skillDirName);
|
|
1410
|
+
const cachedParts = [];
|
|
1411
|
+
for (const s of SECTION_MERGE_ORDER) {
|
|
1412
|
+
if (!DEFAULT_SECTIONS.includes(s)) continue;
|
|
1413
|
+
const outputFile = SECTION_OUTPUT_FILES[s];
|
|
1414
|
+
const content = readCachedSection(resolvedName, data.version, outputFile);
|
|
1415
|
+
if (content) cachedParts.push(wrapSection(s, content));
|
|
1416
|
+
}
|
|
1417
|
+
const cachedBody = cachedParts.join("\n\n");
|
|
1418
|
+
const skillMd = generateSkillMd({
|
|
1419
|
+
name: resolvedName,
|
|
1420
|
+
version: data.version,
|
|
1421
|
+
releasedAt: data.resolved.releasedAt,
|
|
1422
|
+
dependencies: data.resolved.dependencies,
|
|
1423
|
+
distTags: data.resolved.distTags,
|
|
1424
|
+
body: cachedBody,
|
|
1425
|
+
relatedSkills: data.relatedSkills,
|
|
1426
|
+
hasIssues: data.hasIssues,
|
|
1427
|
+
hasDiscussions: data.hasDiscussions,
|
|
1428
|
+
hasReleases: data.hasReleases,
|
|
1429
|
+
hasChangelog: data.hasChangelog,
|
|
1430
|
+
docsType: data.docsType,
|
|
1431
|
+
hasShippedDocs: data.shippedDocs,
|
|
1432
|
+
pkgFiles: data.pkgFiles,
|
|
1433
|
+
generatedBy: "cached",
|
|
1434
|
+
dirName: data.skillDirName,
|
|
1435
|
+
packages: data.packages,
|
|
1436
|
+
repoUrl: data.resolved.repoUrl,
|
|
1437
|
+
features: data.features
|
|
1438
|
+
});
|
|
1439
|
+
writeFileSync(join(skillDir, "SKILL.md"), skillMd);
|
|
1440
|
+
cachedPkgs.push(pkg);
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
const uncachedPkgs = successfulPkgs.filter((pkg) => !cachedPkgs.includes(pkg));
|
|
1444
|
+
if (cachedPkgs.length > 0) p.log.success(`Applied cached SKILL.md sections for ${cachedPkgs.join(", ")}`);
|
|
1305
1445
|
const globalConfig = readConfig();
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1446
|
+
let resolvedModel = config.model || (config.yes && !globalConfig.skipLlm ? globalConfig.model : void 0);
|
|
1447
|
+
if (!resolvedModel && config.yes && !globalConfig.skipLlm) {
|
|
1448
|
+
const { getAvailableModels } = await import("../agent/index.mjs");
|
|
1449
|
+
const available = await getAvailableModels();
|
|
1450
|
+
const auto = available.find((m) => m.recommended)?.id ?? available[0]?.id;
|
|
1451
|
+
if (auto) resolvedModel = auto;
|
|
1452
|
+
}
|
|
1453
|
+
if (uncachedPkgs.length > 0 && !globalConfig.skipLlm && !(config.yes && !resolvedModel)) {
|
|
1454
|
+
const DIFF_RANK = {
|
|
1455
|
+
major: 5,
|
|
1456
|
+
premajor: 4,
|
|
1457
|
+
minor: 3,
|
|
1458
|
+
preminor: 2,
|
|
1459
|
+
patch: 1,
|
|
1460
|
+
prepatch: 1,
|
|
1461
|
+
prerelease: 0
|
|
1462
|
+
};
|
|
1463
|
+
let parallelUpdateCtx;
|
|
1464
|
+
if (config.mode === "update") {
|
|
1465
|
+
let maxDiff = "";
|
|
1466
|
+
let allEnhanced = true;
|
|
1467
|
+
let anySyncedAt;
|
|
1468
|
+
for (const pkg of successfulPkgs) {
|
|
1469
|
+
const data = skillData.get(pkg);
|
|
1470
|
+
if (!data.wasEnhanced) allEnhanced = false;
|
|
1471
|
+
if (data.oldSyncedAt && (!anySyncedAt || data.oldSyncedAt < anySyncedAt)) anySyncedAt = data.oldSyncedAt;
|
|
1472
|
+
if (data.oldVersion) {
|
|
1473
|
+
const diff = semverDiff(data.oldVersion, data.version);
|
|
1474
|
+
if (diff && (DIFF_RANK[diff] ?? 0) > (DIFF_RANK[maxDiff] ?? -1)) maxDiff = diff;
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
const first = skillData.get(successfulPkgs[0]);
|
|
1478
|
+
parallelUpdateCtx = {
|
|
1479
|
+
oldVersion: successfulPkgs.length === 1 ? first.oldVersion : void 0,
|
|
1480
|
+
newVersion: successfulPkgs.length === 1 ? first.version : void 0,
|
|
1481
|
+
syncedAt: anySyncedAt,
|
|
1482
|
+
wasEnhanced: allEnhanced,
|
|
1483
|
+
bumpType: maxDiff || void 0
|
|
1484
|
+
};
|
|
1485
|
+
}
|
|
1486
|
+
const llmConfig = await selectLlmConfig(resolvedModel, void 0, parallelUpdateCtx);
|
|
1487
|
+
if (llmConfig?.promptOnly) for (const pkg of uncachedPkgs) {
|
|
1309
1488
|
const data = skillData.get(pkg);
|
|
1310
1489
|
writePromptFiles({
|
|
1311
1490
|
packageName: pkg,
|
|
@@ -1325,19 +1504,19 @@ async function syncPackagesParallel(config) {
|
|
|
1325
1504
|
}
|
|
1326
1505
|
else if (llmConfig) {
|
|
1327
1506
|
p.log.step(getModelLabel(llmConfig.model));
|
|
1328
|
-
for (const pkg of
|
|
1507
|
+
for (const pkg of uncachedPkgs) states.set(pkg, {
|
|
1329
1508
|
name: pkg,
|
|
1330
1509
|
status: "pending",
|
|
1331
1510
|
message: "Waiting..."
|
|
1332
1511
|
});
|
|
1333
1512
|
render();
|
|
1334
|
-
const llmResults = await Promise.allSettled(
|
|
1513
|
+
const llmResults = await Promise.allSettled(uncachedPkgs.map((pkg) => limit(() => enhanceWithLLM(pkg, skillData.get(pkg), {
|
|
1335
1514
|
...config,
|
|
1336
1515
|
model: llmConfig.model
|
|
1337
1516
|
}, cwd, update, llmConfig.sections, llmConfig.customPrompt))));
|
|
1338
1517
|
logUpdate.done();
|
|
1339
1518
|
const llmSucceeded = llmResults.filter((r) => r.status === "fulfilled").length;
|
|
1340
|
-
p.log.success(`Enhanced ${llmSucceeded}/${
|
|
1519
|
+
p.log.success(`Enhanced ${llmSucceeded}/${uncachedPkgs.length} skills with LLM`);
|
|
1341
1520
|
}
|
|
1342
1521
|
}
|
|
1343
1522
|
await ensureGitignore(getSharedSkillsDir(cwd) ? SHARED_SKILLS_DIR : agent.skillsDir, cwd, config.global);
|
|
@@ -1388,9 +1567,25 @@ async function syncBaseSkill(packageSpec, config, cwd, update) {
|
|
|
1388
1567
|
if (useCache) update(packageName, "downloading", "Using cache", versionKey);
|
|
1389
1568
|
else update(packageName, "downloading", config.force ? "Re-fetching docs..." : "Fetching docs...", versionKey);
|
|
1390
1569
|
const baseDir = resolveBaseDir(cwd, config.agent, config.global);
|
|
1391
|
-
|
|
1570
|
+
let skillDirName = computeSkillDirName(packageName);
|
|
1571
|
+
if (config.mode === "update") {
|
|
1572
|
+
const lock = readLock(baseDir);
|
|
1573
|
+
if (lock) {
|
|
1574
|
+
for (const [name, info] of Object.entries(lock.skills)) if (info.packageName === packageName || parsePackages(info.packages).some((p) => p.name === packageName)) {
|
|
1575
|
+
skillDirName = name;
|
|
1576
|
+
break;
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
}
|
|
1392
1580
|
const skillDir = join(baseDir, skillDirName);
|
|
1393
1581
|
mkdirSync(skillDir, { recursive: true });
|
|
1582
|
+
const preLock = config.mode === "update" ? readLock(baseDir)?.skills[skillDirName] : void 0;
|
|
1583
|
+
const preEnhanced = (() => {
|
|
1584
|
+
if (!preLock) return false;
|
|
1585
|
+
const skillMdPath = join(skillDir, "SKILL.md");
|
|
1586
|
+
if (!existsSync(skillMdPath)) return false;
|
|
1587
|
+
return !!parseFrontmatter(readFileSync(skillMdPath, "utf-8")).generated_by;
|
|
1588
|
+
})();
|
|
1394
1589
|
const features = readConfig().features ?? defaultFeatures;
|
|
1395
1590
|
const resources = await fetchAndCacheResources({
|
|
1396
1591
|
packageName,
|
|
@@ -1469,7 +1664,10 @@ async function syncBaseSkill(packageSpec, config, cwd, update) {
|
|
|
1469
1664
|
packages: allPackages.length > 1 ? allPackages : void 0,
|
|
1470
1665
|
warnings: resources.warnings,
|
|
1471
1666
|
features,
|
|
1472
|
-
usedCache: resources.usedCache
|
|
1667
|
+
usedCache: resources.usedCache,
|
|
1668
|
+
oldVersion: preLock?.version,
|
|
1669
|
+
oldSyncedAt: preLock?.syncedAt,
|
|
1670
|
+
wasEnhanced: preEnhanced
|
|
1473
1671
|
};
|
|
1474
1672
|
}
|
|
1475
1673
|
/** Phase 2: Enhance skill with LLM */
|
|
@@ -1533,13 +1731,23 @@ async function enhanceWithLLM(packageName, data, config, cwd, update, sections,
|
|
|
1533
1731
|
}
|
|
1534
1732
|
//#endregion
|
|
1535
1733
|
//#region src/commands/sync.ts
|
|
1734
|
+
const RESOLVE_SOURCE_LABELS = {
|
|
1735
|
+
"npm": "npm registry",
|
|
1736
|
+
"github-docs": "GitHub versioned docs",
|
|
1737
|
+
"github-meta": "GitHub metadata",
|
|
1738
|
+
"github-search": "GitHub search",
|
|
1739
|
+
"readme": "README fallback",
|
|
1740
|
+
"llms.txt": "llms.txt convention",
|
|
1741
|
+
"crawl": "website crawl",
|
|
1742
|
+
"local": "local node_modules"
|
|
1743
|
+
};
|
|
1536
1744
|
function showResolveAttempts(attempts) {
|
|
1537
1745
|
if (attempts.length === 0) return;
|
|
1538
|
-
p.log.message("\x1B[
|
|
1746
|
+
p.log.message("\x1B[90mDoc resolution:\x1B[0m");
|
|
1539
1747
|
for (const attempt of attempts) {
|
|
1540
1748
|
const icon = attempt.status === "success" ? "\x1B[32m✓\x1B[0m" : "\x1B[90m✗\x1B[0m";
|
|
1541
|
-
const source = `\x1B[90m${attempt.source}\x1B[0m`;
|
|
1542
|
-
const msg = attempt.message ? `
|
|
1749
|
+
const source = `\x1B[90m${RESOLVE_SOURCE_LABELS[attempt.source] ?? attempt.source}\x1B[0m`;
|
|
1750
|
+
const msg = attempt.message ? ` \x1B[90m— ${attempt.message}\x1B[0m` : "";
|
|
1543
1751
|
p.log.message(` ${icon} ${source}${msg}`);
|
|
1544
1752
|
}
|
|
1545
1753
|
}
|
|
@@ -1696,11 +1904,31 @@ async function syncSinglePackage(packageSpec, config) {
|
|
|
1696
1904
|
}
|
|
1697
1905
|
ensureCacheDir();
|
|
1698
1906
|
const baseDir = resolveBaseDir(cwd, config.agent, config.global);
|
|
1699
|
-
|
|
1907
|
+
let skillDirName = config.name ? sanitizeName(config.name) : computeSkillDirName(packageName);
|
|
1908
|
+
if (config.mode === "update" && !config.name) {
|
|
1909
|
+
const lock = readLock(baseDir);
|
|
1910
|
+
if (lock) {
|
|
1911
|
+
for (const [name, info] of Object.entries(lock.skills)) if (info.packageName === packageName || parsePackages(info.packages).some((p) => p.name === packageName)) {
|
|
1912
|
+
skillDirName = name;
|
|
1913
|
+
break;
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
}
|
|
1700
1917
|
const skillDir = config.eject ? typeof config.eject === "string" ? join(resolve(cwd, config.eject), skillDirName) : join(cwd, "skills", skillDirName) : join(baseDir, skillDirName);
|
|
1701
1918
|
mkdirSync(skillDir, { recursive: true });
|
|
1702
1919
|
const existingLock = config.eject ? void 0 : readLock(baseDir)?.skills[skillDirName];
|
|
1703
|
-
|
|
1920
|
+
const isMerge = existingLock && existingLock.packageName && existingLock.packageName !== packageName;
|
|
1921
|
+
const updateCtx = config.mode === "update" && existingLock ? {
|
|
1922
|
+
oldVersion: existingLock.version,
|
|
1923
|
+
newVersion: version,
|
|
1924
|
+
syncedAt: existingLock.syncedAt,
|
|
1925
|
+
wasEnhanced: (() => {
|
|
1926
|
+
const skillMdPath = join(skillDir, "SKILL.md");
|
|
1927
|
+
if (!existsSync(skillMdPath)) return false;
|
|
1928
|
+
return !!parseFrontmatter(readFileSync(skillMdPath, "utf-8")).generated_by;
|
|
1929
|
+
})()
|
|
1930
|
+
} : void 0;
|
|
1931
|
+
if (isMerge) {
|
|
1704
1932
|
spin.stop(`Merging ${packageName} into ${skillDirName}`);
|
|
1705
1933
|
linkPkgNamed(skillDir, packageName, cwd, version);
|
|
1706
1934
|
const repoSlug = resolved.repoUrl?.match(/github\.com\/([^/]+\/[^/]+?)(?:\.git)?(?:[/#]|$)/)?.[1];
|
|
@@ -1815,8 +2043,54 @@ async function syncSinglePackage(packageSpec, config) {
|
|
|
1815
2043
|
});
|
|
1816
2044
|
writeFileSync(join(skillDir, "SKILL.md"), baseSkillMd);
|
|
1817
2045
|
p.log.success(config.mode === "update" ? `Updated skill: ${relative(cwd, skillDir)}` : `Created base skill: ${relative(cwd, skillDir)}`);
|
|
1818
|
-
|
|
1819
|
-
const
|
|
2046
|
+
const allSectionsCached = !config.force && DEFAULT_SECTIONS.every((s) => {
|
|
2047
|
+
const outputFile = SECTION_OUTPUT_FILES[s];
|
|
2048
|
+
return readCachedSection(packageName, version, outputFile) !== null;
|
|
2049
|
+
});
|
|
2050
|
+
if (allSectionsCached) {
|
|
2051
|
+
const cachedParts = [];
|
|
2052
|
+
for (const s of SECTION_MERGE_ORDER) {
|
|
2053
|
+
if (!DEFAULT_SECTIONS.includes(s)) continue;
|
|
2054
|
+
const outputFile = SECTION_OUTPUT_FILES[s];
|
|
2055
|
+
const content = readCachedSection(packageName, version, outputFile);
|
|
2056
|
+
if (content) cachedParts.push(wrapSection(s, content));
|
|
2057
|
+
}
|
|
2058
|
+
const cachedBody = cachedParts.join("\n\n");
|
|
2059
|
+
const skillMd = generateSkillMd({
|
|
2060
|
+
name: packageName,
|
|
2061
|
+
version,
|
|
2062
|
+
releasedAt: resolved.releasedAt,
|
|
2063
|
+
description: resolved.description,
|
|
2064
|
+
dependencies: resolved.dependencies,
|
|
2065
|
+
distTags: resolved.distTags,
|
|
2066
|
+
body: cachedBody,
|
|
2067
|
+
relatedSkills,
|
|
2068
|
+
hasIssues: resources.hasIssues,
|
|
2069
|
+
hasDiscussions: resources.hasDiscussions,
|
|
2070
|
+
hasReleases: resources.hasReleases,
|
|
2071
|
+
hasChangelog,
|
|
2072
|
+
docsType: resources.docsType,
|
|
2073
|
+
hasShippedDocs: shippedDocs,
|
|
2074
|
+
pkgFiles,
|
|
2075
|
+
generatedBy: "cached",
|
|
2076
|
+
dirName: skillDirName,
|
|
2077
|
+
packages: allPackages.length > 1 ? allPackages : void 0,
|
|
2078
|
+
repoUrl: resolved.repoUrl,
|
|
2079
|
+
features,
|
|
2080
|
+
eject: isEject
|
|
2081
|
+
});
|
|
2082
|
+
writeFileSync(join(skillDir, "SKILL.md"), skillMd);
|
|
2083
|
+
p.log.success("Applied cached SKILL.md sections");
|
|
2084
|
+
}
|
|
2085
|
+
const globalConfig = readConfig();
|
|
2086
|
+
let resolvedModel = config.model || (config.yes && !globalConfig.skipLlm ? globalConfig.model : void 0);
|
|
2087
|
+
if (!resolvedModel && config.yes && !globalConfig.skipLlm) {
|
|
2088
|
+
const available = await getAvailableModels();
|
|
2089
|
+
const auto = available.find((m) => m.recommended)?.id ?? available[0]?.id;
|
|
2090
|
+
if (auto) resolvedModel = auto;
|
|
2091
|
+
}
|
|
2092
|
+
if (!allSectionsCached && !globalConfig.skipLlm && !(config.yes && !resolvedModel)) {
|
|
2093
|
+
const llmConfig = await selectLlmConfig(resolvedModel, void 0, updateCtx);
|
|
1820
2094
|
if (llmConfig?.promptOnly) writePromptFiles({
|
|
1821
2095
|
packageName,
|
|
1822
2096
|
skillDir,
|
|
@@ -1876,7 +2150,8 @@ async function syncSinglePackage(packageSpec, config) {
|
|
|
1876
2150
|
}
|
|
1877
2151
|
await shutdownWorker();
|
|
1878
2152
|
const ejectMsg = isEject ? " (ejected)" : "";
|
|
1879
|
-
|
|
2153
|
+
const relDir = relative(cwd, skillDir);
|
|
2154
|
+
p.outro(config.mode === "update" ? `Updated ${packageName}${ejectMsg}` : `Synced ${packageName} → ${relDir}${ejectMsg}`);
|
|
1880
2155
|
}
|
|
1881
2156
|
const addCommandDef = defineCommand({
|
|
1882
2157
|
meta: {
|
|
@@ -1913,7 +2188,7 @@ const addCommandDef = defineCommand({
|
|
|
1913
2188
|
});
|
|
1914
2189
|
return;
|
|
1915
2190
|
}
|
|
1916
|
-
if (!hasCompletedWizard()) await runWizard();
|
|
2191
|
+
if (!hasCompletedWizard()) await runWizard({ agent });
|
|
1917
2192
|
const gitSources = [];
|
|
1918
2193
|
const npmTokens = [];
|
|
1919
2194
|
for (const input of rawInputs) {
|
|
@@ -1937,7 +2212,10 @@ const addCommandDef = defineCommand({
|
|
|
1937
2212
|
if (npmTokens.length > 0) {
|
|
1938
2213
|
const packages = [...new Set(npmTokens.flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean))];
|
|
1939
2214
|
const state = await getProjectState(cwd);
|
|
1940
|
-
p.intro(introLine({
|
|
2215
|
+
p.intro(introLine({
|
|
2216
|
+
state,
|
|
2217
|
+
agentId: agent || void 0
|
|
2218
|
+
}));
|
|
1941
2219
|
return syncCommand(state, {
|
|
1942
2220
|
packages,
|
|
1943
2221
|
global: args.global,
|
|
@@ -1986,9 +2264,12 @@ const ejectCommandDef = defineCommand({
|
|
|
1986
2264
|
const cwd = process.cwd();
|
|
1987
2265
|
const resolved = resolveAgent(args.agent);
|
|
1988
2266
|
const agent = resolved && resolved !== "none" ? resolved : "claude-code";
|
|
1989
|
-
if (!hasCompletedWizard()) await runWizard();
|
|
2267
|
+
if (!hasCompletedWizard()) await runWizard({ agent });
|
|
1990
2268
|
const state = await getProjectState(cwd);
|
|
1991
|
-
p.intro(introLine({
|
|
2269
|
+
p.intro(introLine({
|
|
2270
|
+
state,
|
|
2271
|
+
agentId: agent || void 0
|
|
2272
|
+
}));
|
|
1992
2273
|
return syncCommand(state, {
|
|
1993
2274
|
packages: [args.package],
|
|
1994
2275
|
global: args.global,
|
|
@@ -2066,7 +2347,8 @@ const updateCommandDef = defineCommand({
|
|
|
2066
2347
|
p.intro(introLine({
|
|
2067
2348
|
state,
|
|
2068
2349
|
generators,
|
|
2069
|
-
modelId: config.model
|
|
2350
|
+
modelId: config.model,
|
|
2351
|
+
agentId: config.agent || agent || void 0
|
|
2070
2352
|
}));
|
|
2071
2353
|
}
|
|
2072
2354
|
if (args.package) return syncCommand(state, {
|
|
@@ -2126,7 +2408,7 @@ async function exportPortablePrompts(packageSpec, opts) {
|
|
|
2126
2408
|
ensureCacheDir();
|
|
2127
2409
|
const skillDirName = computeSkillDirName(packageName);
|
|
2128
2410
|
const features = readConfig().features ?? defaultFeatures;
|
|
2129
|
-
const agent = opts.agent === "none" ? null : opts.agent ?? await import("./
|
|
2411
|
+
const agent = opts.agent === "none" ? null : opts.agent ?? await import("./detect2.mjs").then((m) => m.detectTargetAgent());
|
|
2130
2412
|
const baseDir = agent ? resolveBaseDir(cwd, agent, false) : join(cwd, ".claude", "skills");
|
|
2131
2413
|
const skillDir = opts.out ? resolve(cwd, opts.out) : join(baseDir, skillDirName);
|
|
2132
2414
|
if (existsSync(skillDir) && !opts.force) {
|