skilld 1.2.3 → 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/install.mjs +4 -3
- 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/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 +1 -1
- package/dist/_chunks/sync.mjs +389 -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 +3 -2
- 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];
|
|
@@ -542,13 +541,41 @@ async function fetchAndCacheResources(opts) {
|
|
|
542
541
|
usedCache: useCache
|
|
543
542
|
};
|
|
544
543
|
}
|
|
545
|
-
/**
|
|
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 */
|
|
546
573
|
async function indexResources(opts) {
|
|
547
574
|
const { packageName, version, cwd, onProgress } = opts;
|
|
548
575
|
const features = opts.features ?? readConfig().features ?? defaultFeatures;
|
|
549
576
|
if (!features.search) return;
|
|
550
577
|
const dbPath = getPackageDbPath(packageName, version);
|
|
551
|
-
|
|
578
|
+
const dbExists = existsSync(dbPath);
|
|
552
579
|
const allDocs = [...opts.docsToIndex];
|
|
553
580
|
const pkgDir = resolvePkgDir(packageName, cwd, version);
|
|
554
581
|
if (features.search && pkgDir) {
|
|
@@ -565,31 +592,54 @@ async function indexResources(opts) {
|
|
|
565
592
|
});
|
|
566
593
|
}
|
|
567
594
|
if (allDocs.length === 0) return;
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
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;
|
|
585
631
|
}
|
|
586
|
-
|
|
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(", ")})`);
|
|
587
636
|
try {
|
|
588
|
-
await createIndex(
|
|
637
|
+
await createIndex(newDocs, {
|
|
589
638
|
dbPath,
|
|
639
|
+
removeIds,
|
|
590
640
|
onProgress: ({ phase, current, total }) => {
|
|
591
641
|
if (phase === "storing") {
|
|
592
|
-
const d =
|
|
642
|
+
const d = newDocs[current - 1];
|
|
593
643
|
onProgress(`Storing ${d?.metadata?.type === "source" || d?.metadata?.type === "types" ? "code" : d?.metadata?.type || "doc"} (${current}/${total})`);
|
|
594
644
|
} else if (phase === "embedding") onProgress(`Creating embeddings (${current}/${total})`);
|
|
595
645
|
}
|
|
@@ -663,10 +713,13 @@ async function ensureGitignore(skillsDir, cwd, isGlobal) {
|
|
|
663
713
|
}
|
|
664
714
|
const SKILLD_MARKER_START = "<!-- skilld -->";
|
|
665
715
|
const SKILLD_MARKER_END = "<!-- /skilld -->";
|
|
666
|
-
const
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
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
|
+
}
|
|
670
723
|
/**
|
|
671
724
|
* Check if agent instruction file has skilld skill-activation snippet.
|
|
672
725
|
* If missing, prompt to add it. Skipped for global installs or agents without an instructionFile.
|
|
@@ -676,55 +729,55 @@ async function ensureAgentInstructions(agent, cwd, isGlobal) {
|
|
|
676
729
|
const agentConfig = targets[agent];
|
|
677
730
|
if (!agentConfig.instructionFile) return;
|
|
678
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
|
+
}
|
|
679
755
|
if (existsSync(filePath)) {
|
|
680
756
|
if (readFileSync(filePath, "utf-8").includes("<!-- skilld -->")) return;
|
|
681
757
|
}
|
|
682
758
|
if (!isInteractive()) {
|
|
683
|
-
if (existsSync(filePath)) appendFileSync(filePath, `${readFileSync(filePath, "utf-8").endsWith("\n") ? "" : "\n"}\n${
|
|
684
|
-
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`);
|
|
685
761
|
return;
|
|
686
762
|
}
|
|
687
|
-
|
|
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}`);
|
|
688
769
|
const add = await p.confirm({
|
|
689
|
-
message:
|
|
770
|
+
message: `${action} ${agentConfig.instructionFile} with skill activation instructions?`,
|
|
690
771
|
initialValue: true
|
|
691
772
|
});
|
|
692
773
|
if (p.isCancel(add) || !add) return;
|
|
693
|
-
if (existsSync(filePath)) appendFileSync(filePath, `${readFileSync(filePath, "utf-8").endsWith("\n") ? "" : "\n"}\n${
|
|
694
|
-
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`);
|
|
695
776
|
p.log.success(`Updated ${agentConfig.instructionFile}`);
|
|
696
777
|
}
|
|
697
|
-
/** Select LLM model for SKILL.md generation (independent of target agent) */
|
|
698
|
-
async function selectModel(skipPrompt) {
|
|
699
|
-
const config = readConfig();
|
|
700
|
-
const available = await getAvailableModels();
|
|
701
|
-
if (available.length === 0) {
|
|
702
|
-
p.log.warn("No LLM CLIs found (claude, gemini, codex)");
|
|
703
|
-
return null;
|
|
704
|
-
}
|
|
705
|
-
if (skipPrompt) {
|
|
706
|
-
if (config.model && available.some((m) => m.id === config.model)) return config.model;
|
|
707
|
-
return available.find((m) => m.recommended)?.id ?? available[0].id;
|
|
708
|
-
}
|
|
709
|
-
const modelChoice = await p.select({
|
|
710
|
-
message: "Model for SKILL.md generation",
|
|
711
|
-
options: available.map((m) => ({
|
|
712
|
-
label: m.recommended ? `${m.name} (Recommended)` : m.name,
|
|
713
|
-
value: m.id,
|
|
714
|
-
hint: `${m.agentName} · ${m.hint}`
|
|
715
|
-
})),
|
|
716
|
-
initialValue: available.find((m) => m.recommended)?.id ?? available[0].id
|
|
717
|
-
});
|
|
718
|
-
if (p.isCancel(modelChoice)) {
|
|
719
|
-
p.cancel("Cancelled");
|
|
720
|
-
return null;
|
|
721
|
-
}
|
|
722
|
-
updateConfig({ model: modelChoice });
|
|
723
|
-
return modelChoice;
|
|
724
|
-
}
|
|
725
778
|
/** Default sections when model is pre-set (non-interactive) */
|
|
726
779
|
const DEFAULT_SECTIONS = ["best-practices", "api-changes"];
|
|
727
|
-
async function selectSkillSections(message = "
|
|
780
|
+
async function selectSkillSections(message = "Enhance SKILL.md") {
|
|
728
781
|
p.log.info("Budgets adapt to package release density.");
|
|
729
782
|
const selected = await p.multiselect({
|
|
730
783
|
message,
|
|
@@ -807,27 +860,62 @@ async function selectSkillSections(message = "Generate SKILL.md with LLM") {
|
|
|
807
860
|
* If presetModel is provided, uses DEFAULT_SECTIONS without prompting.
|
|
808
861
|
* Returns null if cancelled or no sections/model selected.
|
|
809
862
|
*/
|
|
810
|
-
async function selectLlmConfig(presetModel, message) {
|
|
811
|
-
if (presetModel)
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
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
|
+
}
|
|
815
871
|
if (!isInteractive()) return null;
|
|
816
|
-
const
|
|
817
|
-
|
|
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
|
+
}
|
|
818
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
|
+
}
|
|
819
907
|
const choice = await p.select({
|
|
820
|
-
message:
|
|
908
|
+
message: enhanceMessage,
|
|
821
909
|
options: [
|
|
822
910
|
{
|
|
823
911
|
label: defaultModelName,
|
|
824
912
|
value: "default",
|
|
825
|
-
hint:
|
|
913
|
+
hint: defaultHint
|
|
826
914
|
},
|
|
827
915
|
{
|
|
828
916
|
label: "Different model",
|
|
829
917
|
value: "pick",
|
|
830
|
-
hint: "choose another model"
|
|
918
|
+
hint: "choose another enhancement model"
|
|
831
919
|
},
|
|
832
920
|
{
|
|
833
921
|
label: "Prompt only",
|
|
@@ -837,9 +925,10 @@ async function selectLlmConfig(presetModel, message) {
|
|
|
837
925
|
{
|
|
838
926
|
label: "Skip",
|
|
839
927
|
value: "skip",
|
|
840
|
-
hint: "base skill
|
|
928
|
+
hint: "base skill with docs, issues, and types"
|
|
841
929
|
}
|
|
842
|
-
]
|
|
930
|
+
],
|
|
931
|
+
...defaultToSkip ? { initialValue: "skip" } : {}
|
|
843
932
|
});
|
|
844
933
|
if (p.isCancel(choice)) return null;
|
|
845
934
|
if (choice === "skip") return null;
|
|
@@ -853,10 +942,16 @@ async function selectLlmConfig(presetModel, message) {
|
|
|
853
942
|
promptOnly: true
|
|
854
943
|
};
|
|
855
944
|
}
|
|
856
|
-
|
|
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;
|
|
857
952
|
if (!model) return null;
|
|
858
953
|
const modelName = getModelName(model);
|
|
859
|
-
const { sections, customPrompt, cancelled } = await selectSkillSections(message ? `${message} (${modelName})` : `
|
|
954
|
+
const { sections, customPrompt, cancelled } = await selectSkillSections(message ? `${message} (${modelName})` : `Enhance SKILL.md with ${modelName}`);
|
|
860
955
|
if (cancelled || sections.length === 0) return null;
|
|
861
956
|
return {
|
|
862
957
|
model,
|
|
@@ -923,7 +1018,7 @@ async function enhanceSkillWithLLM(opts) {
|
|
|
923
1018
|
eject
|
|
924
1019
|
});
|
|
925
1020
|
writeFileSync(join(skillDir, "SKILL.md"), skillMd);
|
|
926
|
-
} else llmLog.error(`
|
|
1021
|
+
} else llmLog.error(`Enhancement failed${error ? `: ${error}` : ""}`);
|
|
927
1022
|
}
|
|
928
1023
|
/**
|
|
929
1024
|
* Build and write PROMPT_*.md files for manual LLM use.
|
|
@@ -1303,10 +1398,93 @@ async function syncPackagesParallel(config) {
|
|
|
1303
1398
|
p.log.success(skillMsg);
|
|
1304
1399
|
for (const [, data] of skillData) for (const w of data.warnings) p.log.warn(`\x1B[33m${w}\x1B[0m`);
|
|
1305
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(", ")}`);
|
|
1306
1445
|
const globalConfig = readConfig();
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
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) {
|
|
1310
1488
|
const data = skillData.get(pkg);
|
|
1311
1489
|
writePromptFiles({
|
|
1312
1490
|
packageName: pkg,
|
|
@@ -1326,19 +1504,19 @@ async function syncPackagesParallel(config) {
|
|
|
1326
1504
|
}
|
|
1327
1505
|
else if (llmConfig) {
|
|
1328
1506
|
p.log.step(getModelLabel(llmConfig.model));
|
|
1329
|
-
for (const pkg of
|
|
1507
|
+
for (const pkg of uncachedPkgs) states.set(pkg, {
|
|
1330
1508
|
name: pkg,
|
|
1331
1509
|
status: "pending",
|
|
1332
1510
|
message: "Waiting..."
|
|
1333
1511
|
});
|
|
1334
1512
|
render();
|
|
1335
|
-
const llmResults = await Promise.allSettled(
|
|
1513
|
+
const llmResults = await Promise.allSettled(uncachedPkgs.map((pkg) => limit(() => enhanceWithLLM(pkg, skillData.get(pkg), {
|
|
1336
1514
|
...config,
|
|
1337
1515
|
model: llmConfig.model
|
|
1338
1516
|
}, cwd, update, llmConfig.sections, llmConfig.customPrompt))));
|
|
1339
1517
|
logUpdate.done();
|
|
1340
1518
|
const llmSucceeded = llmResults.filter((r) => r.status === "fulfilled").length;
|
|
1341
|
-
p.log.success(`Enhanced ${llmSucceeded}/${
|
|
1519
|
+
p.log.success(`Enhanced ${llmSucceeded}/${uncachedPkgs.length} skills with LLM`);
|
|
1342
1520
|
}
|
|
1343
1521
|
}
|
|
1344
1522
|
await ensureGitignore(getSharedSkillsDir(cwd) ? SHARED_SKILLS_DIR : agent.skillsDir, cwd, config.global);
|
|
@@ -1389,9 +1567,25 @@ async function syncBaseSkill(packageSpec, config, cwd, update) {
|
|
|
1389
1567
|
if (useCache) update(packageName, "downloading", "Using cache", versionKey);
|
|
1390
1568
|
else update(packageName, "downloading", config.force ? "Re-fetching docs..." : "Fetching docs...", versionKey);
|
|
1391
1569
|
const baseDir = resolveBaseDir(cwd, config.agent, config.global);
|
|
1392
|
-
|
|
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
|
+
}
|
|
1393
1580
|
const skillDir = join(baseDir, skillDirName);
|
|
1394
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
|
+
})();
|
|
1395
1589
|
const features = readConfig().features ?? defaultFeatures;
|
|
1396
1590
|
const resources = await fetchAndCacheResources({
|
|
1397
1591
|
packageName,
|
|
@@ -1470,7 +1664,10 @@ async function syncBaseSkill(packageSpec, config, cwd, update) {
|
|
|
1470
1664
|
packages: allPackages.length > 1 ? allPackages : void 0,
|
|
1471
1665
|
warnings: resources.warnings,
|
|
1472
1666
|
features,
|
|
1473
|
-
usedCache: resources.usedCache
|
|
1667
|
+
usedCache: resources.usedCache,
|
|
1668
|
+
oldVersion: preLock?.version,
|
|
1669
|
+
oldSyncedAt: preLock?.syncedAt,
|
|
1670
|
+
wasEnhanced: preEnhanced
|
|
1474
1671
|
};
|
|
1475
1672
|
}
|
|
1476
1673
|
/** Phase 2: Enhance skill with LLM */
|
|
@@ -1534,13 +1731,23 @@ async function enhanceWithLLM(packageName, data, config, cwd, update, sections,
|
|
|
1534
1731
|
}
|
|
1535
1732
|
//#endregion
|
|
1536
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
|
+
};
|
|
1537
1744
|
function showResolveAttempts(attempts) {
|
|
1538
1745
|
if (attempts.length === 0) return;
|
|
1539
|
-
p.log.message("\x1B[
|
|
1746
|
+
p.log.message("\x1B[90mDoc resolution:\x1B[0m");
|
|
1540
1747
|
for (const attempt of attempts) {
|
|
1541
1748
|
const icon = attempt.status === "success" ? "\x1B[32m✓\x1B[0m" : "\x1B[90m✗\x1B[0m";
|
|
1542
|
-
const source = `\x1B[90m${attempt.source}\x1B[0m`;
|
|
1543
|
-
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` : "";
|
|
1544
1751
|
p.log.message(` ${icon} ${source}${msg}`);
|
|
1545
1752
|
}
|
|
1546
1753
|
}
|
|
@@ -1697,11 +1904,31 @@ async function syncSinglePackage(packageSpec, config) {
|
|
|
1697
1904
|
}
|
|
1698
1905
|
ensureCacheDir();
|
|
1699
1906
|
const baseDir = resolveBaseDir(cwd, config.agent, config.global);
|
|
1700
|
-
|
|
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
|
+
}
|
|
1701
1917
|
const skillDir = config.eject ? typeof config.eject === "string" ? join(resolve(cwd, config.eject), skillDirName) : join(cwd, "skills", skillDirName) : join(baseDir, skillDirName);
|
|
1702
1918
|
mkdirSync(skillDir, { recursive: true });
|
|
1703
1919
|
const existingLock = config.eject ? void 0 : readLock(baseDir)?.skills[skillDirName];
|
|
1704
|
-
|
|
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) {
|
|
1705
1932
|
spin.stop(`Merging ${packageName} into ${skillDirName}`);
|
|
1706
1933
|
linkPkgNamed(skillDir, packageName, cwd, version);
|
|
1707
1934
|
const repoSlug = resolved.repoUrl?.match(/github\.com\/([^/]+\/[^/]+?)(?:\.git)?(?:[/#]|$)/)?.[1];
|
|
@@ -1816,8 +2043,54 @@ async function syncSinglePackage(packageSpec, config) {
|
|
|
1816
2043
|
});
|
|
1817
2044
|
writeFileSync(join(skillDir, "SKILL.md"), baseSkillMd);
|
|
1818
2045
|
p.log.success(config.mode === "update" ? `Updated skill: ${relative(cwd, skillDir)}` : `Created base skill: ${relative(cwd, skillDir)}`);
|
|
1819
|
-
|
|
1820
|
-
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);
|
|
1821
2094
|
if (llmConfig?.promptOnly) writePromptFiles({
|
|
1822
2095
|
packageName,
|
|
1823
2096
|
skillDir,
|
|
@@ -1877,7 +2150,8 @@ async function syncSinglePackage(packageSpec, config) {
|
|
|
1877
2150
|
}
|
|
1878
2151
|
await shutdownWorker();
|
|
1879
2152
|
const ejectMsg = isEject ? " (ejected)" : "";
|
|
1880
|
-
|
|
2153
|
+
const relDir = relative(cwd, skillDir);
|
|
2154
|
+
p.outro(config.mode === "update" ? `Updated ${packageName}${ejectMsg}` : `Synced ${packageName} → ${relDir}${ejectMsg}`);
|
|
1881
2155
|
}
|
|
1882
2156
|
const addCommandDef = defineCommand({
|
|
1883
2157
|
meta: {
|
|
@@ -1914,7 +2188,7 @@ const addCommandDef = defineCommand({
|
|
|
1914
2188
|
});
|
|
1915
2189
|
return;
|
|
1916
2190
|
}
|
|
1917
|
-
if (!hasCompletedWizard()) await runWizard();
|
|
2191
|
+
if (!hasCompletedWizard()) await runWizard({ agent });
|
|
1918
2192
|
const gitSources = [];
|
|
1919
2193
|
const npmTokens = [];
|
|
1920
2194
|
for (const input of rawInputs) {
|
|
@@ -1938,7 +2212,10 @@ const addCommandDef = defineCommand({
|
|
|
1938
2212
|
if (npmTokens.length > 0) {
|
|
1939
2213
|
const packages = [...new Set(npmTokens.flatMap((s) => s.split(/[,\s]+/)).map((s) => s.trim()).filter(Boolean))];
|
|
1940
2214
|
const state = await getProjectState(cwd);
|
|
1941
|
-
p.intro(introLine({
|
|
2215
|
+
p.intro(introLine({
|
|
2216
|
+
state,
|
|
2217
|
+
agentId: agent || void 0
|
|
2218
|
+
}));
|
|
1942
2219
|
return syncCommand(state, {
|
|
1943
2220
|
packages,
|
|
1944
2221
|
global: args.global,
|
|
@@ -1987,9 +2264,12 @@ const ejectCommandDef = defineCommand({
|
|
|
1987
2264
|
const cwd = process.cwd();
|
|
1988
2265
|
const resolved = resolveAgent(args.agent);
|
|
1989
2266
|
const agent = resolved && resolved !== "none" ? resolved : "claude-code";
|
|
1990
|
-
if (!hasCompletedWizard()) await runWizard();
|
|
2267
|
+
if (!hasCompletedWizard()) await runWizard({ agent });
|
|
1991
2268
|
const state = await getProjectState(cwd);
|
|
1992
|
-
p.intro(introLine({
|
|
2269
|
+
p.intro(introLine({
|
|
2270
|
+
state,
|
|
2271
|
+
agentId: agent || void 0
|
|
2272
|
+
}));
|
|
1993
2273
|
return syncCommand(state, {
|
|
1994
2274
|
packages: [args.package],
|
|
1995
2275
|
global: args.global,
|
|
@@ -2067,7 +2347,8 @@ const updateCommandDef = defineCommand({
|
|
|
2067
2347
|
p.intro(introLine({
|
|
2068
2348
|
state,
|
|
2069
2349
|
generators,
|
|
2070
|
-
modelId: config.model
|
|
2350
|
+
modelId: config.model,
|
|
2351
|
+
agentId: config.agent || agent || void 0
|
|
2071
2352
|
}));
|
|
2072
2353
|
}
|
|
2073
2354
|
if (args.package) return syncCommand(state, {
|
|
@@ -2127,7 +2408,7 @@ async function exportPortablePrompts(packageSpec, opts) {
|
|
|
2127
2408
|
ensureCacheDir();
|
|
2128
2409
|
const skillDirName = computeSkillDirName(packageName);
|
|
2129
2410
|
const features = readConfig().features ?? defaultFeatures;
|
|
2130
|
-
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());
|
|
2131
2412
|
const baseDir = agent ? resolveBaseDir(cwd, agent, false) : join(cwd, ".claude", "skills");
|
|
2132
2413
|
const skillDir = opts.out ? resolve(cwd, opts.out) : join(baseDir, skillDirName);
|
|
2133
2414
|
if (existsSync(skillDir) && !opts.force) {
|