skilld 1.5.0 → 1.5.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/agent.mjs +2 -2
- package/dist/_chunks/assemble.mjs +1 -0
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author.mjs +4 -2
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +2 -39
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +2 -1
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/cli-helpers.mjs +6 -28
- package/dist/_chunks/cli-helpers.mjs.map +1 -1
- package/dist/_chunks/cli-helpers2.mjs +11 -0
- package/dist/_chunks/core.mjs +1 -0
- package/dist/_chunks/embedding-cache.mjs +3 -60
- package/dist/_chunks/embedding-cache2.mjs +61 -0
- package/dist/_chunks/embedding-cache2.mjs.map +1 -0
- package/dist/_chunks/index.d.mts +13 -21
- package/dist/_chunks/index.d.mts.map +1 -1
- package/dist/_chunks/index2.d.mts +32 -600
- package/dist/_chunks/index2.d.mts.map +1 -1
- package/dist/_chunks/index3.d.mts +615 -0
- package/dist/_chunks/index3.d.mts.map +1 -0
- package/dist/_chunks/install.mjs +6 -4
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/list.mjs +2 -1
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/pool.mjs +2 -123
- package/dist/_chunks/pool2.mjs +118 -0
- package/dist/_chunks/pool2.mjs.map +1 -0
- package/dist/_chunks/prepare.mjs +34 -78
- package/dist/_chunks/prepare.mjs.map +1 -1
- package/dist/_chunks/prepare2.mjs +93 -0
- package/dist/_chunks/prepare2.mjs.map +1 -0
- package/dist/_chunks/retriv.mjs +172 -0
- package/dist/_chunks/retriv.mjs.map +1 -0
- package/dist/_chunks/search-interactive.mjs +4 -3
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +12 -320
- package/dist/_chunks/search2.mjs +319 -0
- package/dist/_chunks/search2.mjs.map +1 -0
- package/dist/_chunks/setup.mjs +3 -2
- package/dist/_chunks/setup.mjs.map +1 -1
- package/dist/_chunks/skills.mjs +1 -1
- package/dist/_chunks/sync-shared.mjs +2 -0
- package/dist/_chunks/sync-shared2.mjs +4 -3
- package/dist/_chunks/sync-shared2.mjs.map +1 -1
- package/dist/_chunks/sync.mjs +7 -7
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +21 -0
- package/dist/_chunks/uninstall.mjs +5 -2
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/wizard.mjs +186 -0
- package/dist/_chunks/wizard.mjs.map +1 -0
- package/dist/agent/index.mjs +1 -0
- package/dist/cache/index.d.mts +1 -1
- package/dist/cache/index.mjs +2 -1
- package/dist/cli-entry.d.mts +1 -0
- package/dist/cli-entry.mjs +11 -0
- package/dist/cli-entry.mjs.map +1 -0
- package/dist/cli.mjs +12 -188
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -2
- package/dist/prepare.d.mts +1 -0
- package/dist/prepare.mjs +93 -0
- package/dist/prepare.mjs.map +1 -0
- package/dist/retriv/index.d.mts +2 -46
- package/dist/retriv/index.mjs +2 -171
- package/dist/sources/index.d.mts +1 -1
- package/dist/types.d.mts +1 -1
- package/package.json +1 -1
- package/dist/_chunks/embedding-cache.mjs.map +0 -1
- package/dist/_chunks/pool.mjs.map +0 -1
- package/dist/_chunks/search.mjs.map +0 -1
- package/dist/retriv/index.d.mts.map +0 -1
- package/dist/retriv/index.mjs.map +0 -1
package/dist/_chunks/agent.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as sanitizeMarkdown } from "./sanitize.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { h as writeSections, m as readCachedSection } from "./cache.mjs";
|
|
3
3
|
import { i as resolveSkilldCommand } from "./shared.mjs";
|
|
4
4
|
import { a as targets, t as detectInstalledAgents } from "./detect.mjs";
|
|
5
5
|
import { c as SECTION_OUTPUT_FILES, f as getSectionValidator, l as buildAllSectionPrompts, m as wrapSection, p as portabilizePrompt, s as SECTION_MERGE_ORDER } from "./prompts.mjs";
|
|
@@ -1445,6 +1445,6 @@ function isNodeBuiltin(pkg) {
|
|
|
1445
1445
|
return NODE_BUILTINS.has(base.split("/")[0]);
|
|
1446
1446
|
}
|
|
1447
1447
|
//#endregion
|
|
1448
|
-
export { getModelLabel as a, getOAuthProviderList as c,
|
|
1448
|
+
export { getModelLabel as a, getOAuthProviderList as c, getAvailableModels as i, loginOAuthProvider as l, cleanSectionOutput as n, getModelName as o, createToolProgress as r, optimizeDocs as s, detectImportedPackages as t, logoutOAuthProvider as u };
|
|
1449
1449
|
|
|
1450
1450
|
//# sourceMappingURL=agent.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assemble.mjs","names":[],"sources":["../../src/commands/assemble.ts"],"sourcesContent":["/**\n * `skilld assemble` — merge pasted LLM output back into SKILL.md\n *\n * Auto-discovers skill directories with pending output files when run without arguments.\n */\n\nimport type { SkillSection } from '../agent/index.ts'\nimport { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join, relative, resolve } from 'pathe'\nimport { cleanSectionOutput } from '../agent/clis/index.ts'\nimport {\n extractMarkedSections,\n getSectionValidator,\n SECTION_MERGE_ORDER,\n SECTION_OUTPUT_FILES,\n wrapSection,\n} from '../agent/index.ts'\nimport { iterateSkills } from '../core/skills.ts'\n\nconst OUTPUT_FILE_SET = new Set(Object.values(SECTION_OUTPUT_FILES))\n\n/**\n * Find installed skill dirs that have pending section output files.\n */\nfunction discoverSkillDirsWithOutputs(): string[] {\n const dirs: string[] = []\n for (const skill of iterateSkills({})) {\n if (readdirSync(skill.dir).some(f => OUTPUT_FILE_SET.has(f)))\n dirs.push(skill.dir)\n }\n return dirs\n}\n\nexport async function assembleCommand(dir: string | undefined): Promise<void> {\n const cwd = process.cwd()\n\n let dirs: string[]\n if (dir) {\n dirs = [resolve(cwd, dir)]\n }\n else {\n // Check cwd first — if it has SKILL.md + output files, use it\n if (existsSync(join(cwd, 'SKILL.md'))\n && readdirSync(cwd).some(f => OUTPUT_FILE_SET.has(f))) {\n dirs = [cwd]\n }\n else {\n dirs = discoverSkillDirsWithOutputs()\n if (dirs.length === 0) {\n p.log.error('No skill directories with output files found. Run `skilld add` first.')\n return\n }\n }\n }\n\n for (const targetDir of dirs)\n assembleDir(targetDir, cwd)\n}\n\nfunction assembleDir(targetDir: string, cwd: string): void {\n if (!existsSync(targetDir)) {\n p.log.error(`Directory not found: ${targetDir}`)\n return\n }\n\n const skillMdPath = join(targetDir, 'SKILL.md')\n if (!existsSync(skillMdPath)) {\n p.log.error(`No SKILL.md found in ${targetDir}`)\n return\n }\n\n const existingSkillMd = readFileSync(skillMdPath, 'utf-8')\n\n // Find and read section output files\n const sections: Array<{ section: SkillSection, content: string }> = []\n const warnings: string[] = []\n\n for (const [section, outputFile] of Object.entries(SECTION_OUTPUT_FILES) as Array<[SkillSection, string]>) {\n const filePath = join(targetDir, outputFile)\n if (!existsSync(filePath))\n continue\n\n const raw = readFileSync(filePath, 'utf-8').trim()\n if (!raw) {\n p.log.warn(`Empty file: ${outputFile}`)\n continue\n }\n\n const cleaned = cleanSectionOutput(raw)\n if (!cleaned) {\n const missing: string[] = []\n if (!/^##\\s/m.test(raw))\n missing.push('h2 heading (## ...)')\n if (!/^- (?:BREAKING|DEPRECATED|NEW): /m.test(raw))\n missing.push('change label (- BREAKING/DEPRECATED/NEW: ...)')\n if (!/\\[source\\]/.test(raw))\n missing.push('[source] link')\n p.log.warn(`${outputFile}: content rejected — missing ${missing.join(', ')}`)\n continue\n }\n\n const validator = getSectionValidator(section)\n if (validator) {\n for (const w of validator(cleaned))\n warnings.push(`${section}: ${w.warning}`)\n }\n\n sections.push({ section, content: cleaned })\n p.log.success(`Loaded ${outputFile}`)\n }\n\n if (sections.length === 0) {\n p.log.warn(`No section output files in ${relative(cwd, targetDir)}. Expected: ${Object.values(SECTION_OUTPUT_FILES).join(', ')}`)\n return\n }\n\n for (const w of warnings)\n p.log.warn(`\\x1B[33m${w}\\x1B[0m`)\n\n // Wrap each section with comment markers\n const wrappedSections: Array<{ section: SkillSection, wrapped: string }> = []\n for (const section of SECTION_MERGE_ORDER) {\n const result = sections.find(s => s.section === section)\n if (result)\n wrappedSections.push({ section, wrapped: wrapSection(section, result.content) })\n }\n\n // Try marker-based replacement first (re-assembly of previously assembled SKILL.md)\n const existingMarkers = extractMarkedSections(existingSkillMd)\n let newSkillMd: string\n\n if (existingMarkers.size > 0) {\n // Replace existing marked sections in-place, append new ones at the end\n newSkillMd = existingSkillMd\n // Process in reverse offset order to preserve indices\n const replacements = wrappedSections\n .filter(s => existingMarkers.has(s.section))\n .sort((a, b) => existingMarkers.get(b.section)!.start - existingMarkers.get(a.section)!.start)\n for (const { section, wrapped } of replacements) {\n const { start, end } = existingMarkers.get(section)!\n newSkillMd = newSkillMd.slice(0, start) + wrapped + newSkillMd.slice(end)\n }\n // Append sections that don't have existing markers\n const newSections = wrappedSections.filter(s => !existingMarkers.has(s.section))\n if (newSections.length > 0)\n newSkillMd = `${newSkillMd.trimEnd()}\\n\\n${newSections.map(s => s.wrapped).join('\\n\\n')}\\n`\n }\n else {\n // First assembly — find header boundary and append all sections\n const body = wrappedSections.map(s => s.wrapped).join('\\n\\n')\n const fmEnd = existingSkillMd.indexOf('\\n---\\n', 4)\n const afterFm = fmEnd !== -1 ? existingSkillMd.slice(fmEnd + 5) : existingSkillMd\n\n const firstLlmHeading = body.match(/^## .+$/m)?.[0]\n let headerPart = afterFm\n if (firstLlmHeading) {\n const idx = afterFm.indexOf(firstLlmHeading)\n if (idx !== -1)\n headerPart = afterFm.slice(0, idx)\n }\n\n const fmPart = fmEnd !== -1 ? existingSkillMd.slice(0, fmEnd + 5) : ''\n const cleanHeader = headerPart.trimEnd()\n newSkillMd = fmPart\n ? `${fmPart}${cleanHeader}\\n\\n${body}\\n`\n : `${cleanHeader}\\n\\n${body}\\n`\n }\n\n writeFileSync(skillMdPath, newSkillMd)\n p.log.success(`Updated ${relative(cwd, skillMdPath)} with ${sections.length} section(s)`)\n}\n\nexport const assembleCommandDef = defineCommand({\n meta: { name: 'assemble', description: 'Merge enhancement output files into SKILL.md' },\n args: {\n dir: {\n type: 'positional',\n description: 'Skill directory with output files (auto-discovers installed skills)',\n required: false,\n },\n },\n async run({ args }) {\n await assembleCommand(args.dir)\n },\n})\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"assemble.mjs","names":[],"sources":["../../src/commands/assemble.ts"],"sourcesContent":["/**\n * `skilld assemble` — merge pasted LLM output back into SKILL.md\n *\n * Auto-discovers skill directories with pending output files when run without arguments.\n */\n\nimport type { SkillSection } from '../agent/index.ts'\nimport { existsSync, readdirSync, readFileSync, writeFileSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join, relative, resolve } from 'pathe'\nimport { cleanSectionOutput } from '../agent/clis/index.ts'\nimport {\n extractMarkedSections,\n getSectionValidator,\n SECTION_MERGE_ORDER,\n SECTION_OUTPUT_FILES,\n wrapSection,\n} from '../agent/index.ts'\nimport { iterateSkills } from '../core/skills.ts'\n\nconst OUTPUT_FILE_SET = new Set(Object.values(SECTION_OUTPUT_FILES))\n\n/**\n * Find installed skill dirs that have pending section output files.\n */\nfunction discoverSkillDirsWithOutputs(): string[] {\n const dirs: string[] = []\n for (const skill of iterateSkills({})) {\n if (readdirSync(skill.dir).some(f => OUTPUT_FILE_SET.has(f)))\n dirs.push(skill.dir)\n }\n return dirs\n}\n\nexport async function assembleCommand(dir: string | undefined): Promise<void> {\n const cwd = process.cwd()\n\n let dirs: string[]\n if (dir) {\n dirs = [resolve(cwd, dir)]\n }\n else {\n // Check cwd first — if it has SKILL.md + output files, use it\n if (existsSync(join(cwd, 'SKILL.md'))\n && readdirSync(cwd).some(f => OUTPUT_FILE_SET.has(f))) {\n dirs = [cwd]\n }\n else {\n dirs = discoverSkillDirsWithOutputs()\n if (dirs.length === 0) {\n p.log.error('No skill directories with output files found. Run `skilld add` first.')\n return\n }\n }\n }\n\n for (const targetDir of dirs)\n assembleDir(targetDir, cwd)\n}\n\nfunction assembleDir(targetDir: string, cwd: string): void {\n if (!existsSync(targetDir)) {\n p.log.error(`Directory not found: ${targetDir}`)\n return\n }\n\n const skillMdPath = join(targetDir, 'SKILL.md')\n if (!existsSync(skillMdPath)) {\n p.log.error(`No SKILL.md found in ${targetDir}`)\n return\n }\n\n const existingSkillMd = readFileSync(skillMdPath, 'utf-8')\n\n // Find and read section output files\n const sections: Array<{ section: SkillSection, content: string }> = []\n const warnings: string[] = []\n\n for (const [section, outputFile] of Object.entries(SECTION_OUTPUT_FILES) as Array<[SkillSection, string]>) {\n const filePath = join(targetDir, outputFile)\n if (!existsSync(filePath))\n continue\n\n const raw = readFileSync(filePath, 'utf-8').trim()\n if (!raw) {\n p.log.warn(`Empty file: ${outputFile}`)\n continue\n }\n\n const cleaned = cleanSectionOutput(raw)\n if (!cleaned) {\n const missing: string[] = []\n if (!/^##\\s/m.test(raw))\n missing.push('h2 heading (## ...)')\n if (!/^- (?:BREAKING|DEPRECATED|NEW): /m.test(raw))\n missing.push('change label (- BREAKING/DEPRECATED/NEW: ...)')\n if (!/\\[source\\]/.test(raw))\n missing.push('[source] link')\n p.log.warn(`${outputFile}: content rejected — missing ${missing.join(', ')}`)\n continue\n }\n\n const validator = getSectionValidator(section)\n if (validator) {\n for (const w of validator(cleaned))\n warnings.push(`${section}: ${w.warning}`)\n }\n\n sections.push({ section, content: cleaned })\n p.log.success(`Loaded ${outputFile}`)\n }\n\n if (sections.length === 0) {\n p.log.warn(`No section output files in ${relative(cwd, targetDir)}. Expected: ${Object.values(SECTION_OUTPUT_FILES).join(', ')}`)\n return\n }\n\n for (const w of warnings)\n p.log.warn(`\\x1B[33m${w}\\x1B[0m`)\n\n // Wrap each section with comment markers\n const wrappedSections: Array<{ section: SkillSection, wrapped: string }> = []\n for (const section of SECTION_MERGE_ORDER) {\n const result = sections.find(s => s.section === section)\n if (result)\n wrappedSections.push({ section, wrapped: wrapSection(section, result.content) })\n }\n\n // Try marker-based replacement first (re-assembly of previously assembled SKILL.md)\n const existingMarkers = extractMarkedSections(existingSkillMd)\n let newSkillMd: string\n\n if (existingMarkers.size > 0) {\n // Replace existing marked sections in-place, append new ones at the end\n newSkillMd = existingSkillMd\n // Process in reverse offset order to preserve indices\n const replacements = wrappedSections\n .filter(s => existingMarkers.has(s.section))\n .sort((a, b) => existingMarkers.get(b.section)!.start - existingMarkers.get(a.section)!.start)\n for (const { section, wrapped } of replacements) {\n const { start, end } = existingMarkers.get(section)!\n newSkillMd = newSkillMd.slice(0, start) + wrapped + newSkillMd.slice(end)\n }\n // Append sections that don't have existing markers\n const newSections = wrappedSections.filter(s => !existingMarkers.has(s.section))\n if (newSections.length > 0)\n newSkillMd = `${newSkillMd.trimEnd()}\\n\\n${newSections.map(s => s.wrapped).join('\\n\\n')}\\n`\n }\n else {\n // First assembly — find header boundary and append all sections\n const body = wrappedSections.map(s => s.wrapped).join('\\n\\n')\n const fmEnd = existingSkillMd.indexOf('\\n---\\n', 4)\n const afterFm = fmEnd !== -1 ? existingSkillMd.slice(fmEnd + 5) : existingSkillMd\n\n const firstLlmHeading = body.match(/^## .+$/m)?.[0]\n let headerPart = afterFm\n if (firstLlmHeading) {\n const idx = afterFm.indexOf(firstLlmHeading)\n if (idx !== -1)\n headerPart = afterFm.slice(0, idx)\n }\n\n const fmPart = fmEnd !== -1 ? existingSkillMd.slice(0, fmEnd + 5) : ''\n const cleanHeader = headerPart.trimEnd()\n newSkillMd = fmPart\n ? `${fmPart}${cleanHeader}\\n\\n${body}\\n`\n : `${cleanHeader}\\n\\n${body}\\n`\n }\n\n writeFileSync(skillMdPath, newSkillMd)\n p.log.success(`Updated ${relative(cwd, skillMdPath)} with ${sections.length} section(s)`)\n}\n\nexport const assembleCommandDef = defineCommand({\n meta: { name: 'assemble', description: 'Merge enhancement output files into SKILL.md' },\n args: {\n dir: {\n type: 'positional',\n description: 'Skill directory with output files (auto-discovers installed skills)',\n required: false,\n },\n },\n async run({ args }) {\n await assembleCommand(args.dir)\n },\n})\n"],"mappings":"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"}
|
package/dist/_chunks/author.mjs
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { a as getModelLabel } from "./agent.mjs";
|
|
2
2
|
import { o as getCacheDir } from "./config.mjs";
|
|
3
|
+
import "./prepare.mjs";
|
|
3
4
|
import { n as sanitizeMarkdown } from "./sanitize.mjs";
|
|
4
|
-
import {
|
|
5
|
+
import { g as writeToCache, r as ensureCacheDir } from "./cache.mjs";
|
|
5
6
|
import "./yaml.mjs";
|
|
6
7
|
import "./markdown.mjs";
|
|
8
|
+
import "./retriv.mjs";
|
|
7
9
|
import "./shared.mjs";
|
|
8
10
|
import { B as isGhAvailable, F as formatDiscussionAsMarkdown, I as generateDiscussionIndex, L as fetchGitHubIssues, P as fetchGitHubDiscussions, R as formatIssueAsMarkdown, c as readLocalPackageInfo, tt as parseGitHubUrl, z as generateIssueIndex } from "./sources.mjs";
|
|
9
11
|
import "./detect.mjs";
|
|
10
12
|
import { n as computeSkillDirName, t as generateSkillMd } from "./prompts.mjs";
|
|
11
|
-
import {
|
|
13
|
+
import { C as appendToJsonArray, T as defaultFeatures, k as readConfig, u as guard, w as patchPackageJson } from "./cli-helpers.mjs";
|
|
12
14
|
import "./lockfile.mjs";
|
|
13
15
|
import { l as timedSpinner } from "./formatting.mjs";
|
|
14
16
|
import { S as writePromptFiles, _ as linkAllReferences, b as selectLlmConfig, c as ejectReferences, l as enhanceSkillWithLLM, m as forceClearCache, o as detectChangelog } from "./sync-shared2.mjs";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"author.mjs","names":[],"sources":["../../src/commands/author.ts"],"sourcesContent":["import type { OptimizeModel } from '../agent/index.ts'\nimport type { FeaturesConfig } from '../core/config.ts'\nimport type { LlmConfig } from './sync-shared.ts'\nimport { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join, relative, resolve } from 'pathe'\nimport {\n computeSkillDirName,\n generateSkillMd,\n getModelLabel,\n} from '../agent/index.ts'\nimport {\n ensureCacheDir,\n getCacheDir,\n writeToCache,\n} from '../cache/index.ts'\nimport { guard } from '../cli-helpers.ts'\nimport { defaultFeatures, readConfig } from '../core/config.ts'\nimport { timedSpinner } from '../core/formatting.ts'\nimport { appendToJsonArray, patchPackageJson } from '../core/package-json.ts'\nimport { sanitizeMarkdown } from '../core/sanitize.ts'\nimport {\n fetchGitHubDiscussions,\n fetchGitHubIssues,\n formatDiscussionAsMarkdown,\n formatIssueAsMarkdown,\n generateDiscussionIndex,\n generateIssueIndex,\n isGhAvailable,\n parseGitHubUrl,\n readLocalPackageInfo,\n} from '../sources/index.ts'\nimport {\n detectChangelog,\n ejectReferences,\n enhanceSkillWithLLM,\n forceClearCache,\n linkAllReferences,\n selectLlmConfig,\n writePromptFiles,\n} from './sync-shared.ts'\n\nconst QUOTE_PREFIX_RE = /^['\"]/\nconst QUOTE_SUFFIX_RE = /['\"]$/\n\n// ── Monorepo detection ──\n\nexport interface MonorepoPackage {\n name: string\n version: string\n description?: string\n repoUrl?: string\n dir: string\n}\n\nexport function detectMonorepoPackages(cwd: string): MonorepoPackage[] | null {\n const pkgPath = join(cwd, 'package.json')\n if (!existsSync(pkgPath))\n return null\n\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))\n\n // Must be private (monorepo root) with workspaces or pnpm-workspace.yaml\n if (!pkg.private)\n return null\n\n let patterns: string[] = []\n\n if (Array.isArray(pkg.workspaces)) {\n patterns = pkg.workspaces\n }\n else if (pkg.workspaces?.packages) {\n patterns = pkg.workspaces.packages\n }\n\n // Check pnpm-workspace.yaml\n if (patterns.length === 0) {\n const pnpmWs = join(cwd, 'pnpm-workspace.yaml')\n if (existsSync(pnpmWs)) {\n const lines = readFileSync(pnpmWs, 'utf-8').split('\\n')\n for (const line of lines) {\n const trimmed = line.trim()\n if (!trimmed.startsWith('-'))\n continue\n const value = trimmed.slice(1).trim().replace(QUOTE_PREFIX_RE, '').replace(QUOTE_SUFFIX_RE, '')\n if (value)\n patterns.push(value)\n }\n }\n }\n\n if (patterns.length === 0)\n return null\n\n const packages: MonorepoPackage[] = []\n\n for (const pattern of patterns) {\n // Expand simple glob: \"packages/*\" → scan packages/*/package.json\n const base = pattern.replace(/\\/?\\*+$/, '')\n const scanDir = resolve(cwd, base)\n if (!existsSync(scanDir))\n continue\n\n for (const entry of readdirSync(scanDir, { withFileTypes: true })) {\n if (!entry.isDirectory())\n continue\n const pkgJsonPath = join(scanDir, entry.name, 'package.json')\n if (!existsSync(pkgJsonPath))\n continue\n\n const childPkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'))\n if (childPkg.private)\n continue\n if (!childPkg.name)\n continue\n\n const repoUrl = typeof childPkg.repository === 'string'\n ? childPkg.repository\n : childPkg.repository?.url?.replace(/^git\\+/, '').replace(/\\.git$/, '')\n\n packages.push({\n name: childPkg.name,\n version: childPkg.version || '0.0.0',\n description: childPkg.description,\n repoUrl,\n dir: join(scanDir, entry.name),\n })\n }\n }\n\n return packages.length > 0 ? packages : null\n}\n\n// ── Docs resolution ──\n\nfunction walkMarkdownFiles(dir: string, base = ''): Array<{ path: string, content: string }> {\n const results: Array<{ path: string, content: string }> = []\n if (!existsSync(dir))\n return results\n\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const rel = base ? `${base}/${entry.name}` : entry.name\n const full = join(dir, entry.name)\n if (entry.isDirectory()) {\n results.push(...walkMarkdownFiles(full, rel))\n }\n else if (/\\.mdx?$/.test(entry.name)) {\n results.push({ path: rel, content: readFileSync(full, 'utf-8') })\n }\n }\n return results\n}\n\n/**\n * Resolve docs from local filesystem. Cascade:\n * 1. Package-level docs/ directory\n * 2. Monorepo-root docs/ directory (if monorepoRoot provided)\n * 3. Monorepo-root docs/content/ (Nuxt Content convention)\n * 4. llms.txt in package dir\n * 5. README.md in package dir\n */\nfunction resolveLocalDocs(\n packageDir: string,\n packageName: string,\n version: string,\n monorepoRoot?: string,\n): { docsType: 'docs' | 'llms.txt' | 'readme', docSource: string } {\n const cachedDocs: Array<{ path: string, content: string }> = []\n\n const cacheChangelog = () => cacheLocalChangelog(packageDir, packageName, version, monorepoRoot)\n\n // 1. Package-level docs/\n const docsDir = join(packageDir, 'docs')\n if (existsSync(docsDir)) {\n const mdFiles = walkMarkdownFiles(docsDir)\n if (mdFiles.length > 0) {\n for (const f of mdFiles)\n cachedDocs.push({ path: `docs/${f.path}`, content: sanitizeMarkdown(f.content) })\n writeToCache(packageName, version, cachedDocs)\n cacheChangelog()\n return { docsType: 'docs', docSource: `local docs/ (${mdFiles.length} files)` }\n }\n }\n\n // 2. Monorepo-root docs/ or docs/content/\n if (monorepoRoot) {\n for (const candidate of ['docs/content', 'docs']) {\n const rootDocsDir = join(monorepoRoot, candidate)\n if (existsSync(rootDocsDir)) {\n const mdFiles = walkMarkdownFiles(rootDocsDir)\n if (mdFiles.length > 0) {\n for (const f of mdFiles)\n cachedDocs.push({ path: `docs/${f.path}`, content: sanitizeMarkdown(f.content) })\n writeToCache(packageName, version, cachedDocs)\n cacheChangelog()\n return { docsType: 'docs', docSource: `monorepo ${candidate}/ (${mdFiles.length} files)` }\n }\n }\n }\n }\n\n // 3. llms.txt (package dir, then monorepo root)\n for (const dir of [packageDir, monorepoRoot].filter(Boolean) as string[]) {\n const llmsPath = join(dir, 'llms.txt')\n if (existsSync(llmsPath)) {\n cachedDocs.push({ path: 'llms.txt', content: sanitizeMarkdown(readFileSync(llmsPath, 'utf-8')) })\n writeToCache(packageName, version, cachedDocs)\n cacheChangelog()\n const source = dir === packageDir ? 'local llms.txt' : 'monorepo llms.txt'\n return { docsType: 'llms.txt', docSource: source }\n }\n }\n\n // 4. README.md (package dir, then monorepo root)\n for (const dir of [packageDir, monorepoRoot].filter(Boolean) as string[]) {\n const readmeFile = readdirSync(dir).find(f => /^readme\\.md$/i.test(f))\n if (readmeFile) {\n cachedDocs.push({ path: 'docs/README.md', content: sanitizeMarkdown(readFileSync(join(dir, readmeFile), 'utf-8')) })\n writeToCache(packageName, version, cachedDocs)\n cacheChangelog()\n const source = dir === packageDir ? 'local README.md' : 'monorepo README.md'\n return { docsType: 'readme', docSource: source }\n }\n }\n\n cacheChangelog()\n return { docsType: 'readme', docSource: 'none' }\n}\n\nfunction cacheLocalChangelog(dir: string, packageName: string, version: string, monorepoRoot?: string): void {\n const candidates = ['CHANGELOG.md', 'changelog.md']\n const changelogFile = candidates.find(f => existsSync(join(dir, f)))\n || (monorepoRoot ? candidates.find(f => existsSync(join(monorepoRoot, f))) : undefined)\n const changelogDir = changelogFile && existsSync(join(dir, changelogFile)) ? dir : monorepoRoot\n if (changelogFile && changelogDir) {\n writeToCache(packageName, version, [{\n path: `releases/${changelogFile}`,\n content: sanitizeMarkdown(readFileSync(join(changelogDir, changelogFile), 'utf-8')),\n }])\n }\n}\n\n// ── Remote supplements ──\n\nasync function fetchRemoteSupplements(opts: {\n packageName: string\n version: string\n repoUrl?: string\n features: FeaturesConfig\n onProgress: (msg: string) => void\n}): Promise<{ hasIssues: boolean, hasDiscussions: boolean }> {\n const { packageName, version, repoUrl, features, onProgress } = opts\n\n if (!repoUrl || !isGhAvailable())\n return { hasIssues: false, hasDiscussions: false }\n\n const gh = parseGitHubUrl(repoUrl)\n if (!gh)\n return { hasIssues: false, hasDiscussions: false }\n\n const cacheDir = getCacheDir(packageName, version)\n\n let hasIssues = false\n const issuesDir = join(cacheDir, 'issues')\n if (features.issues && !existsSync(issuesDir)) {\n onProgress('Fetching issues via GitHub API')\n const issues = await fetchGitHubIssues(gh.owner, gh.repo, 30).catch(() => [])\n if (issues.length > 0) {\n onProgress(`Caching ${issues.length} issues`)\n writeToCache(packageName, version, issues.map(issue => ({\n path: `issues/issue-${issue.number}.md`,\n content: formatIssueAsMarkdown(issue),\n })))\n writeToCache(packageName, version, [{\n path: 'issues/_INDEX.md',\n content: generateIssueIndex(issues),\n }])\n hasIssues = true\n }\n }\n else {\n hasIssues = features.issues && existsSync(issuesDir)\n }\n\n let hasDiscussions = false\n const discussionsDir = join(cacheDir, 'discussions')\n if (features.discussions && !existsSync(discussionsDir)) {\n onProgress('Fetching discussions via GitHub API')\n const discussions = await fetchGitHubDiscussions(gh.owner, gh.repo, 20).catch(() => [])\n if (discussions.length > 0) {\n onProgress(`Caching ${discussions.length} discussions`)\n writeToCache(packageName, version, discussions.map(d => ({\n path: `discussions/discussion-${d.number}.md`,\n content: formatDiscussionAsMarkdown(d),\n })))\n writeToCache(packageName, version, [{\n path: 'discussions/_INDEX.md',\n content: generateDiscussionIndex(discussions),\n }])\n hasDiscussions = true\n }\n }\n else {\n hasDiscussions = features.discussions && existsSync(discussionsDir)\n }\n\n return { hasIssues, hasDiscussions }\n}\n\n// ── package.json patching ──\n\nexport function patchPackageJsonFiles(packageDir: string): void {\n const pkgPath = join(packageDir, 'package.json')\n if (!existsSync(pkgPath))\n return\n\n const wrote = patchPackageJson(pkgPath, (raw, pkg) => {\n if (!Array.isArray(pkg.files)) {\n p.log.warn('No `files` array in package.json. Add `\"skills\"` to your files array manually.')\n return null\n }\n\n if ((pkg.files as string[]).some((f: string) => f === 'skills' || f === 'skills/' || f === 'skills/**'))\n return null\n\n return appendToJsonArray(raw, ['files'], 'skills')\n })\n\n if (wrote)\n p.log.success('Added `\"skills\"` to package.json files array')\n}\n\n// ── Core author flow for a single package ──\n\nasync function authorSinglePackage(opts: {\n packageDir: string\n packageName: string\n version: string\n description?: string\n repoUrl?: string\n monorepoRoot?: string\n out?: string\n llmConfig?: LlmConfig | null\n force?: boolean\n debug?: boolean\n}): Promise<string | null> {\n const { packageDir, packageName, version } = opts\n const spin = timedSpinner()\n\n const sanitizedName = computeSkillDirName(packageName)\n const outDir = opts.out ? resolve(packageDir, opts.out) : join(packageDir, 'skills', sanitizedName)\n\n // Validate --out doesn't point at the package root or a parent\n if (opts.out) {\n const rel = relative(packageDir, outDir)\n if (!rel || rel === '.' || rel.startsWith('..')) {\n p.log.error('--out must point to a child directory, not the package root or a parent')\n return null\n }\n }\n\n if (existsSync(outDir))\n rmSync(outDir, { recursive: true, force: true })\n mkdirSync(outDir, { recursive: true })\n\n if (opts.force) {\n forceClearCache(packageName, version)\n }\n\n ensureCacheDir()\n const features = readConfig().features ?? defaultFeatures\n\n // Resolve local docs\n spin.start('Resolving local docs')\n const { docsType, docSource } = resolveLocalDocs(packageDir, packageName, version, opts.monorepoRoot)\n spin.stop(`Resolved docs: ${docSource}`)\n\n // Fetch remote supplements (issues/discussions)\n const supSpin = timedSpinner()\n supSpin.start('Checking remote supplements')\n const { hasIssues, hasDiscussions } = await fetchRemoteSupplements({\n packageName,\n version,\n repoUrl: opts.repoUrl,\n features,\n onProgress: msg => supSpin.message(msg),\n })\n const supParts: string[] = []\n if (hasIssues)\n supParts.push('issues')\n if (hasDiscussions)\n supParts.push('discussions')\n supSpin.stop(supParts.length > 0 ? `Fetched ${supParts.join(', ')}` : 'No remote supplements')\n\n // Create temporary .skilld/ symlinks (LLM needs these to read docs)\n linkAllReferences(outDir, packageName, packageDir, version, docsType, undefined, features)\n\n // Detect changelog + releases\n const cacheDir = getCacheDir(packageName, version)\n const hasChangelog = detectChangelog(packageDir, cacheDir)\n const hasReleases = existsSync(join(cacheDir, 'releases'))\n\n // Generate base SKILL.md\n const baseSkillMd = generateSkillMd({\n name: packageName,\n version,\n description: opts.description,\n relatedSkills: [],\n hasIssues,\n hasDiscussions,\n hasReleases,\n hasChangelog,\n docsType,\n hasShippedDocs: false,\n pkgFiles: [],\n dirName: sanitizedName,\n repoUrl: opts.repoUrl,\n features,\n eject: true,\n })\n writeFileSync(join(outDir, 'SKILL.md'), baseSkillMd)\n p.log.success(`Created base skill: ${relative(packageDir, outDir)}`)\n\n // LLM enhancement (config resolved by caller)\n const skilldDir = join(outDir, '.skilld')\n try {\n const llmConfig = opts.llmConfig\n if (llmConfig?.promptOnly) {\n writePromptFiles({\n packageName,\n skillDir: outDir,\n version,\n hasIssues,\n hasDiscussions,\n hasReleases,\n hasChangelog,\n docsType,\n hasShippedDocs: false,\n pkgFiles: [],\n sections: llmConfig.sections,\n customPrompt: llmConfig.customPrompt,\n features,\n })\n }\n else if (llmConfig) {\n p.log.step(getModelLabel(llmConfig.model))\n await enhanceSkillWithLLM({\n packageName,\n version,\n skillDir: outDir,\n dirName: sanitizedName,\n model: llmConfig.model,\n resolved: { repoUrl: opts.repoUrl },\n relatedSkills: [],\n hasIssues,\n hasDiscussions,\n hasReleases,\n hasChangelog,\n docsType,\n hasShippedDocs: false,\n pkgFiles: [],\n force: opts.force,\n debug: opts.debug,\n sections: llmConfig.sections,\n customPrompt: llmConfig.customPrompt,\n features,\n eject: true,\n })\n }\n\n ejectReferences(outDir, packageName, packageDir, version, docsType, features)\n }\n finally {\n // Always clean up .skilld/ symlinks, even if LLM enhancement fails\n if (existsSync(skilldDir))\n rmSync(skilldDir, { recursive: true, force: true })\n }\n\n // Only patch package.json when output is under skills/\n const relOut = relative(packageDir, outDir)\n if (relOut === 'skills' || relOut.startsWith('skills/'))\n patchPackageJsonFiles(packageDir)\n else if (opts.out)\n p.log.info('Output is outside skills/, skipping package.json patch. Add the path to \"files\" manually if publishing.')\n\n return outDir\n}\n\n// ── Main command ──\n\nasync function resolveLlmConfig(model?: OptimizeModel, yes?: boolean): Promise<LlmConfig | null | undefined> {\n const globalConfig = readConfig()\n if (globalConfig.skipLlm || (yes && !model))\n return undefined\n return selectLlmConfig(model)\n}\n\nasync function authorCommand(opts: {\n out?: string\n model?: OptimizeModel\n yes?: boolean\n force?: boolean\n debug?: boolean\n}): Promise<void> {\n const cwd = process.cwd()\n\n // Check for monorepo\n const monoPackages = detectMonorepoPackages(cwd)\n\n if (monoPackages && monoPackages.length > 0) {\n p.intro(`\\x1B[1m\\x1B[35mskilld\\x1B[0m author \\x1B[90m(monorepo: ${monoPackages.length} packages)\\x1B[0m`)\n\n if (opts.out) {\n p.log.error('--out is not supported in monorepo mode (each package gets its own skills/ directory)')\n return\n }\n\n const selected = guard(await p.multiselect({\n message: 'Which packages should ship skills?',\n options: monoPackages.map(pkg => ({\n label: pkg.name,\n value: pkg,\n hint: pkg.description,\n })),\n }))\n\n if (selected.length === 0)\n return\n\n // Resolve LLM config once for all packages\n const llmConfig = await resolveLlmConfig(opts.model, opts.yes)\n\n // Resolve monorepo-level repoUrl for packages that lack their own\n const rootPkgPath = join(cwd, 'package.json')\n const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'))\n const rootRepoUrl = typeof rootPkg.repository === 'string'\n ? rootPkg.repository\n : rootPkg.repository?.url?.replace(/^git\\+/, '').replace(/\\.git$/, '')\n\n const results: Array<{ name: string, outDir: string }> = []\n\n for (const pkg of selected) {\n p.log.step(`\\x1B[36m${pkg.name}\\x1B[0m@${pkg.version}`)\n const outDir = await authorSinglePackage({\n packageDir: pkg.dir,\n packageName: pkg.name,\n version: pkg.version,\n description: pkg.description,\n repoUrl: pkg.repoUrl || rootRepoUrl,\n monorepoRoot: cwd,\n llmConfig,\n force: opts.force,\n debug: opts.debug,\n })\n if (outDir)\n results.push({ name: pkg.name, outDir })\n }\n\n if (results.length > 0) {\n p.log.message('')\n for (const { name, outDir } of results)\n p.log.success(`${name} → ${relative(cwd, outDir)}`)\n\n printConsumerGuidance(results.map(r => r.name))\n }\n\n p.outro('Done')\n return\n }\n\n // Single package mode\n const pkgInfo = readLocalPackageInfo(cwd)\n if (!pkgInfo) {\n p.log.error('No package.json found in current directory')\n return\n }\n\n const { name: packageName, version, repoUrl } = pkgInfo\n\n p.intro(`\\x1B[1m\\x1B[35mskilld\\x1B[0m author \\x1B[36m${packageName}\\x1B[0m@${version}`)\n\n const llmConfig = await resolveLlmConfig(opts.model, opts.yes)\n\n const outDir = await authorSinglePackage({\n packageDir: cwd,\n packageName,\n version,\n description: pkgInfo.description,\n repoUrl,\n out: opts.out,\n llmConfig,\n force: opts.force,\n debug: opts.debug,\n })\n\n if (outDir) {\n printConsumerGuidance([packageName])\n p.outro(`Authored skill to ${relative(cwd, outDir)}`)\n }\n}\n\nfunction printConsumerGuidance(packageNames: string[]): void {\n const names = packageNames.join(', ')\n p.log.info(\n `\\x1B[90mConsumers get ${packageNames.length > 1 ? 'these skills' : 'this skill'} automatically:\\x1B[0m\\n`\n + ` \\x1B[90m1. Install ${names} as a dependency\\x1B[0m\\n`\n + ` \\x1B[90m2. Run \\x1B[36mskilld prepare\\x1B[90m (or add to package.json: \\x1B[36m\"prepare\": \"skilld prepare\"\\x1B[90m)\\x1B[0m`,\n )\n}\n\nexport const authorCommandDef = defineCommand({\n meta: { name: 'author', description: 'Generate portable skill for npm publishing' },\n args: {\n out: {\n type: 'string',\n alias: 'o',\n description: 'Output directory (default: ./skills/<name>/)',\n },\n model: {\n type: 'string',\n alias: 'm',\n description: 'Enhancement model for SKILL.md generation',\n valueHint: 'id',\n },\n yes: {\n type: 'boolean',\n alias: 'y',\n description: 'Skip prompts, use defaults',\n default: false,\n },\n force: {\n type: 'boolean',\n alias: 'f',\n description: 'Clear cache and regenerate',\n default: false,\n },\n debug: {\n type: 'boolean',\n description: 'Save raw enhancement output to logs/',\n default: false,\n },\n },\n async run({ args }) {\n await authorCommand({\n out: args.out,\n model: args.model as OptimizeModel | undefined,\n yes: args.yes,\n force: args.force,\n debug: args.debug,\n })\n },\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"author.mjs","names":[],"sources":["../../src/commands/author.ts"],"sourcesContent":["import type { OptimizeModel } from '../agent/index.ts'\nimport type { FeaturesConfig } from '../core/config.ts'\nimport type { LlmConfig } from './sync-shared.ts'\nimport { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join, relative, resolve } from 'pathe'\nimport {\n computeSkillDirName,\n generateSkillMd,\n getModelLabel,\n} from '../agent/index.ts'\nimport {\n ensureCacheDir,\n getCacheDir,\n writeToCache,\n} from '../cache/index.ts'\nimport { guard } from '../cli-helpers.ts'\nimport { defaultFeatures, readConfig } from '../core/config.ts'\nimport { timedSpinner } from '../core/formatting.ts'\nimport { appendToJsonArray, patchPackageJson } from '../core/package-json.ts'\nimport { sanitizeMarkdown } from '../core/sanitize.ts'\nimport {\n fetchGitHubDiscussions,\n fetchGitHubIssues,\n formatDiscussionAsMarkdown,\n formatIssueAsMarkdown,\n generateDiscussionIndex,\n generateIssueIndex,\n isGhAvailable,\n parseGitHubUrl,\n readLocalPackageInfo,\n} from '../sources/index.ts'\nimport {\n detectChangelog,\n ejectReferences,\n enhanceSkillWithLLM,\n forceClearCache,\n linkAllReferences,\n selectLlmConfig,\n writePromptFiles,\n} from './sync-shared.ts'\n\nconst QUOTE_PREFIX_RE = /^['\"]/\nconst QUOTE_SUFFIX_RE = /['\"]$/\n\n// ── Monorepo detection ──\n\nexport interface MonorepoPackage {\n name: string\n version: string\n description?: string\n repoUrl?: string\n dir: string\n}\n\nexport function detectMonorepoPackages(cwd: string): MonorepoPackage[] | null {\n const pkgPath = join(cwd, 'package.json')\n if (!existsSync(pkgPath))\n return null\n\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'))\n\n // Must be private (monorepo root) with workspaces or pnpm-workspace.yaml\n if (!pkg.private)\n return null\n\n let patterns: string[] = []\n\n if (Array.isArray(pkg.workspaces)) {\n patterns = pkg.workspaces\n }\n else if (pkg.workspaces?.packages) {\n patterns = pkg.workspaces.packages\n }\n\n // Check pnpm-workspace.yaml\n if (patterns.length === 0) {\n const pnpmWs = join(cwd, 'pnpm-workspace.yaml')\n if (existsSync(pnpmWs)) {\n const lines = readFileSync(pnpmWs, 'utf-8').split('\\n')\n for (const line of lines) {\n const trimmed = line.trim()\n if (!trimmed.startsWith('-'))\n continue\n const value = trimmed.slice(1).trim().replace(QUOTE_PREFIX_RE, '').replace(QUOTE_SUFFIX_RE, '')\n if (value)\n patterns.push(value)\n }\n }\n }\n\n if (patterns.length === 0)\n return null\n\n const packages: MonorepoPackage[] = []\n\n for (const pattern of patterns) {\n // Expand simple glob: \"packages/*\" → scan packages/*/package.json\n const base = pattern.replace(/\\/?\\*+$/, '')\n const scanDir = resolve(cwd, base)\n if (!existsSync(scanDir))\n continue\n\n for (const entry of readdirSync(scanDir, { withFileTypes: true })) {\n if (!entry.isDirectory())\n continue\n const pkgJsonPath = join(scanDir, entry.name, 'package.json')\n if (!existsSync(pkgJsonPath))\n continue\n\n const childPkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'))\n if (childPkg.private)\n continue\n if (!childPkg.name)\n continue\n\n const repoUrl = typeof childPkg.repository === 'string'\n ? childPkg.repository\n : childPkg.repository?.url?.replace(/^git\\+/, '').replace(/\\.git$/, '')\n\n packages.push({\n name: childPkg.name,\n version: childPkg.version || '0.0.0',\n description: childPkg.description,\n repoUrl,\n dir: join(scanDir, entry.name),\n })\n }\n }\n\n return packages.length > 0 ? packages : null\n}\n\n// ── Docs resolution ──\n\nfunction walkMarkdownFiles(dir: string, base = ''): Array<{ path: string, content: string }> {\n const results: Array<{ path: string, content: string }> = []\n if (!existsSync(dir))\n return results\n\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const rel = base ? `${base}/${entry.name}` : entry.name\n const full = join(dir, entry.name)\n if (entry.isDirectory()) {\n results.push(...walkMarkdownFiles(full, rel))\n }\n else if (/\\.mdx?$/.test(entry.name)) {\n results.push({ path: rel, content: readFileSync(full, 'utf-8') })\n }\n }\n return results\n}\n\n/**\n * Resolve docs from local filesystem. Cascade:\n * 1. Package-level docs/ directory\n * 2. Monorepo-root docs/ directory (if monorepoRoot provided)\n * 3. Monorepo-root docs/content/ (Nuxt Content convention)\n * 4. llms.txt in package dir\n * 5. README.md in package dir\n */\nfunction resolveLocalDocs(\n packageDir: string,\n packageName: string,\n version: string,\n monorepoRoot?: string,\n): { docsType: 'docs' | 'llms.txt' | 'readme', docSource: string } {\n const cachedDocs: Array<{ path: string, content: string }> = []\n\n const cacheChangelog = () => cacheLocalChangelog(packageDir, packageName, version, monorepoRoot)\n\n // 1. Package-level docs/\n const docsDir = join(packageDir, 'docs')\n if (existsSync(docsDir)) {\n const mdFiles = walkMarkdownFiles(docsDir)\n if (mdFiles.length > 0) {\n for (const f of mdFiles)\n cachedDocs.push({ path: `docs/${f.path}`, content: sanitizeMarkdown(f.content) })\n writeToCache(packageName, version, cachedDocs)\n cacheChangelog()\n return { docsType: 'docs', docSource: `local docs/ (${mdFiles.length} files)` }\n }\n }\n\n // 2. Monorepo-root docs/ or docs/content/\n if (monorepoRoot) {\n for (const candidate of ['docs/content', 'docs']) {\n const rootDocsDir = join(monorepoRoot, candidate)\n if (existsSync(rootDocsDir)) {\n const mdFiles = walkMarkdownFiles(rootDocsDir)\n if (mdFiles.length > 0) {\n for (const f of mdFiles)\n cachedDocs.push({ path: `docs/${f.path}`, content: sanitizeMarkdown(f.content) })\n writeToCache(packageName, version, cachedDocs)\n cacheChangelog()\n return { docsType: 'docs', docSource: `monorepo ${candidate}/ (${mdFiles.length} files)` }\n }\n }\n }\n }\n\n // 3. llms.txt (package dir, then monorepo root)\n for (const dir of [packageDir, monorepoRoot].filter(Boolean) as string[]) {\n const llmsPath = join(dir, 'llms.txt')\n if (existsSync(llmsPath)) {\n cachedDocs.push({ path: 'llms.txt', content: sanitizeMarkdown(readFileSync(llmsPath, 'utf-8')) })\n writeToCache(packageName, version, cachedDocs)\n cacheChangelog()\n const source = dir === packageDir ? 'local llms.txt' : 'monorepo llms.txt'\n return { docsType: 'llms.txt', docSource: source }\n }\n }\n\n // 4. README.md (package dir, then monorepo root)\n for (const dir of [packageDir, monorepoRoot].filter(Boolean) as string[]) {\n const readmeFile = readdirSync(dir).find(f => /^readme\\.md$/i.test(f))\n if (readmeFile) {\n cachedDocs.push({ path: 'docs/README.md', content: sanitizeMarkdown(readFileSync(join(dir, readmeFile), 'utf-8')) })\n writeToCache(packageName, version, cachedDocs)\n cacheChangelog()\n const source = dir === packageDir ? 'local README.md' : 'monorepo README.md'\n return { docsType: 'readme', docSource: source }\n }\n }\n\n cacheChangelog()\n return { docsType: 'readme', docSource: 'none' }\n}\n\nfunction cacheLocalChangelog(dir: string, packageName: string, version: string, monorepoRoot?: string): void {\n const candidates = ['CHANGELOG.md', 'changelog.md']\n const changelogFile = candidates.find(f => existsSync(join(dir, f)))\n || (monorepoRoot ? candidates.find(f => existsSync(join(monorepoRoot, f))) : undefined)\n const changelogDir = changelogFile && existsSync(join(dir, changelogFile)) ? dir : monorepoRoot\n if (changelogFile && changelogDir) {\n writeToCache(packageName, version, [{\n path: `releases/${changelogFile}`,\n content: sanitizeMarkdown(readFileSync(join(changelogDir, changelogFile), 'utf-8')),\n }])\n }\n}\n\n// ── Remote supplements ──\n\nasync function fetchRemoteSupplements(opts: {\n packageName: string\n version: string\n repoUrl?: string\n features: FeaturesConfig\n onProgress: (msg: string) => void\n}): Promise<{ hasIssues: boolean, hasDiscussions: boolean }> {\n const { packageName, version, repoUrl, features, onProgress } = opts\n\n if (!repoUrl || !isGhAvailable())\n return { hasIssues: false, hasDiscussions: false }\n\n const gh = parseGitHubUrl(repoUrl)\n if (!gh)\n return { hasIssues: false, hasDiscussions: false }\n\n const cacheDir = getCacheDir(packageName, version)\n\n let hasIssues = false\n const issuesDir = join(cacheDir, 'issues')\n if (features.issues && !existsSync(issuesDir)) {\n onProgress('Fetching issues via GitHub API')\n const issues = await fetchGitHubIssues(gh.owner, gh.repo, 30).catch(() => [])\n if (issues.length > 0) {\n onProgress(`Caching ${issues.length} issues`)\n writeToCache(packageName, version, issues.map(issue => ({\n path: `issues/issue-${issue.number}.md`,\n content: formatIssueAsMarkdown(issue),\n })))\n writeToCache(packageName, version, [{\n path: 'issues/_INDEX.md',\n content: generateIssueIndex(issues),\n }])\n hasIssues = true\n }\n }\n else {\n hasIssues = features.issues && existsSync(issuesDir)\n }\n\n let hasDiscussions = false\n const discussionsDir = join(cacheDir, 'discussions')\n if (features.discussions && !existsSync(discussionsDir)) {\n onProgress('Fetching discussions via GitHub API')\n const discussions = await fetchGitHubDiscussions(gh.owner, gh.repo, 20).catch(() => [])\n if (discussions.length > 0) {\n onProgress(`Caching ${discussions.length} discussions`)\n writeToCache(packageName, version, discussions.map(d => ({\n path: `discussions/discussion-${d.number}.md`,\n content: formatDiscussionAsMarkdown(d),\n })))\n writeToCache(packageName, version, [{\n path: 'discussions/_INDEX.md',\n content: generateDiscussionIndex(discussions),\n }])\n hasDiscussions = true\n }\n }\n else {\n hasDiscussions = features.discussions && existsSync(discussionsDir)\n }\n\n return { hasIssues, hasDiscussions }\n}\n\n// ── package.json patching ──\n\nexport function patchPackageJsonFiles(packageDir: string): void {\n const pkgPath = join(packageDir, 'package.json')\n if (!existsSync(pkgPath))\n return\n\n const wrote = patchPackageJson(pkgPath, (raw, pkg) => {\n if (!Array.isArray(pkg.files)) {\n p.log.warn('No `files` array in package.json. Add `\"skills\"` to your files array manually.')\n return null\n }\n\n if ((pkg.files as string[]).some((f: string) => f === 'skills' || f === 'skills/' || f === 'skills/**'))\n return null\n\n return appendToJsonArray(raw, ['files'], 'skills')\n })\n\n if (wrote)\n p.log.success('Added `\"skills\"` to package.json files array')\n}\n\n// ── Core author flow for a single package ──\n\nasync function authorSinglePackage(opts: {\n packageDir: string\n packageName: string\n version: string\n description?: string\n repoUrl?: string\n monorepoRoot?: string\n out?: string\n llmConfig?: LlmConfig | null\n force?: boolean\n debug?: boolean\n}): Promise<string | null> {\n const { packageDir, packageName, version } = opts\n const spin = timedSpinner()\n\n const sanitizedName = computeSkillDirName(packageName)\n const outDir = opts.out ? resolve(packageDir, opts.out) : join(packageDir, 'skills', sanitizedName)\n\n // Validate --out doesn't point at the package root or a parent\n if (opts.out) {\n const rel = relative(packageDir, outDir)\n if (!rel || rel === '.' || rel.startsWith('..')) {\n p.log.error('--out must point to a child directory, not the package root or a parent')\n return null\n }\n }\n\n if (existsSync(outDir))\n rmSync(outDir, { recursive: true, force: true })\n mkdirSync(outDir, { recursive: true })\n\n if (opts.force) {\n forceClearCache(packageName, version)\n }\n\n ensureCacheDir()\n const features = readConfig().features ?? defaultFeatures\n\n // Resolve local docs\n spin.start('Resolving local docs')\n const { docsType, docSource } = resolveLocalDocs(packageDir, packageName, version, opts.monorepoRoot)\n spin.stop(`Resolved docs: ${docSource}`)\n\n // Fetch remote supplements (issues/discussions)\n const supSpin = timedSpinner()\n supSpin.start('Checking remote supplements')\n const { hasIssues, hasDiscussions } = await fetchRemoteSupplements({\n packageName,\n version,\n repoUrl: opts.repoUrl,\n features,\n onProgress: msg => supSpin.message(msg),\n })\n const supParts: string[] = []\n if (hasIssues)\n supParts.push('issues')\n if (hasDiscussions)\n supParts.push('discussions')\n supSpin.stop(supParts.length > 0 ? `Fetched ${supParts.join(', ')}` : 'No remote supplements')\n\n // Create temporary .skilld/ symlinks (LLM needs these to read docs)\n linkAllReferences(outDir, packageName, packageDir, version, docsType, undefined, features)\n\n // Detect changelog + releases\n const cacheDir = getCacheDir(packageName, version)\n const hasChangelog = detectChangelog(packageDir, cacheDir)\n const hasReleases = existsSync(join(cacheDir, 'releases'))\n\n // Generate base SKILL.md\n const baseSkillMd = generateSkillMd({\n name: packageName,\n version,\n description: opts.description,\n relatedSkills: [],\n hasIssues,\n hasDiscussions,\n hasReleases,\n hasChangelog,\n docsType,\n hasShippedDocs: false,\n pkgFiles: [],\n dirName: sanitizedName,\n repoUrl: opts.repoUrl,\n features,\n eject: true,\n })\n writeFileSync(join(outDir, 'SKILL.md'), baseSkillMd)\n p.log.success(`Created base skill: ${relative(packageDir, outDir)}`)\n\n // LLM enhancement (config resolved by caller)\n const skilldDir = join(outDir, '.skilld')\n try {\n const llmConfig = opts.llmConfig\n if (llmConfig?.promptOnly) {\n writePromptFiles({\n packageName,\n skillDir: outDir,\n version,\n hasIssues,\n hasDiscussions,\n hasReleases,\n hasChangelog,\n docsType,\n hasShippedDocs: false,\n pkgFiles: [],\n sections: llmConfig.sections,\n customPrompt: llmConfig.customPrompt,\n features,\n })\n }\n else if (llmConfig) {\n p.log.step(getModelLabel(llmConfig.model))\n await enhanceSkillWithLLM({\n packageName,\n version,\n skillDir: outDir,\n dirName: sanitizedName,\n model: llmConfig.model,\n resolved: { repoUrl: opts.repoUrl },\n relatedSkills: [],\n hasIssues,\n hasDiscussions,\n hasReleases,\n hasChangelog,\n docsType,\n hasShippedDocs: false,\n pkgFiles: [],\n force: opts.force,\n debug: opts.debug,\n sections: llmConfig.sections,\n customPrompt: llmConfig.customPrompt,\n features,\n eject: true,\n })\n }\n\n ejectReferences(outDir, packageName, packageDir, version, docsType, features)\n }\n finally {\n // Always clean up .skilld/ symlinks, even if LLM enhancement fails\n if (existsSync(skilldDir))\n rmSync(skilldDir, { recursive: true, force: true })\n }\n\n // Only patch package.json when output is under skills/\n const relOut = relative(packageDir, outDir)\n if (relOut === 'skills' || relOut.startsWith('skills/'))\n patchPackageJsonFiles(packageDir)\n else if (opts.out)\n p.log.info('Output is outside skills/, skipping package.json patch. Add the path to \"files\" manually if publishing.')\n\n return outDir\n}\n\n// ── Main command ──\n\nasync function resolveLlmConfig(model?: OptimizeModel, yes?: boolean): Promise<LlmConfig | null | undefined> {\n const globalConfig = readConfig()\n if (globalConfig.skipLlm || (yes && !model))\n return undefined\n return selectLlmConfig(model)\n}\n\nasync function authorCommand(opts: {\n out?: string\n model?: OptimizeModel\n yes?: boolean\n force?: boolean\n debug?: boolean\n}): Promise<void> {\n const cwd = process.cwd()\n\n // Check for monorepo\n const monoPackages = detectMonorepoPackages(cwd)\n\n if (monoPackages && monoPackages.length > 0) {\n p.intro(`\\x1B[1m\\x1B[35mskilld\\x1B[0m author \\x1B[90m(monorepo: ${monoPackages.length} packages)\\x1B[0m`)\n\n if (opts.out) {\n p.log.error('--out is not supported in monorepo mode (each package gets its own skills/ directory)')\n return\n }\n\n const selected = guard(await p.multiselect({\n message: 'Which packages should ship skills?',\n options: monoPackages.map(pkg => ({\n label: pkg.name,\n value: pkg,\n hint: pkg.description,\n })),\n }))\n\n if (selected.length === 0)\n return\n\n // Resolve LLM config once for all packages\n const llmConfig = await resolveLlmConfig(opts.model, opts.yes)\n\n // Resolve monorepo-level repoUrl for packages that lack their own\n const rootPkgPath = join(cwd, 'package.json')\n const rootPkg = JSON.parse(readFileSync(rootPkgPath, 'utf-8'))\n const rootRepoUrl = typeof rootPkg.repository === 'string'\n ? rootPkg.repository\n : rootPkg.repository?.url?.replace(/^git\\+/, '').replace(/\\.git$/, '')\n\n const results: Array<{ name: string, outDir: string }> = []\n\n for (const pkg of selected) {\n p.log.step(`\\x1B[36m${pkg.name}\\x1B[0m@${pkg.version}`)\n const outDir = await authorSinglePackage({\n packageDir: pkg.dir,\n packageName: pkg.name,\n version: pkg.version,\n description: pkg.description,\n repoUrl: pkg.repoUrl || rootRepoUrl,\n monorepoRoot: cwd,\n llmConfig,\n force: opts.force,\n debug: opts.debug,\n })\n if (outDir)\n results.push({ name: pkg.name, outDir })\n }\n\n if (results.length > 0) {\n p.log.message('')\n for (const { name, outDir } of results)\n p.log.success(`${name} → ${relative(cwd, outDir)}`)\n\n printConsumerGuidance(results.map(r => r.name))\n }\n\n p.outro('Done')\n return\n }\n\n // Single package mode\n const pkgInfo = readLocalPackageInfo(cwd)\n if (!pkgInfo) {\n p.log.error('No package.json found in current directory')\n return\n }\n\n const { name: packageName, version, repoUrl } = pkgInfo\n\n p.intro(`\\x1B[1m\\x1B[35mskilld\\x1B[0m author \\x1B[36m${packageName}\\x1B[0m@${version}`)\n\n const llmConfig = await resolveLlmConfig(opts.model, opts.yes)\n\n const outDir = await authorSinglePackage({\n packageDir: cwd,\n packageName,\n version,\n description: pkgInfo.description,\n repoUrl,\n out: opts.out,\n llmConfig,\n force: opts.force,\n debug: opts.debug,\n })\n\n if (outDir) {\n printConsumerGuidance([packageName])\n p.outro(`Authored skill to ${relative(cwd, outDir)}`)\n }\n}\n\nfunction printConsumerGuidance(packageNames: string[]): void {\n const names = packageNames.join(', ')\n p.log.info(\n `\\x1B[90mConsumers get ${packageNames.length > 1 ? 'these skills' : 'this skill'} automatically:\\x1B[0m\\n`\n + ` \\x1B[90m1. Install ${names} as a dependency\\x1B[0m\\n`\n + ` \\x1B[90m2. Run \\x1B[36mskilld prepare\\x1B[90m (or add to package.json: \\x1B[36m\"prepare\": \"skilld prepare\"\\x1B[90m)\\x1B[0m`,\n )\n}\n\nexport const authorCommandDef = defineCommand({\n meta: { name: 'author', description: 'Generate portable skill for npm publishing' },\n args: {\n out: {\n type: 'string',\n alias: 'o',\n description: 'Output directory (default: ./skills/<name>/)',\n },\n model: {\n type: 'string',\n alias: 'm',\n description: 'Enhancement model for SKILL.md generation',\n valueHint: 'id',\n },\n yes: {\n type: 'boolean',\n alias: 'y',\n description: 'Skip prompts, use defaults',\n default: false,\n },\n force: {\n type: 'boolean',\n alias: 'f',\n description: 'Clear cache and regenerate',\n default: false,\n },\n debug: {\n type: 'boolean',\n description: 'Save raw enhancement output to logs/',\n default: false,\n },\n },\n async run({ args }) {\n await authorCommand({\n out: args.out,\n model: args.model as OptimizeModel | undefined,\n yes: args.yes,\n force: args.force,\n debug: args.debug,\n })\n },\n})\n"],"mappings":"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"}
|
package/dist/_chunks/cache.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { a as getRepoCacheDir, n as REFERENCES_DIR, o as getCacheDir, r as REPOS_DIR } from "./config.mjs";
|
|
2
|
+
import { r as resolvePkgDir } from "./prepare.mjs";
|
|
2
3
|
import { n as sanitizeMarkdown } from "./sanitize.mjs";
|
|
3
4
|
import { basename, join, resolve } from "pathe";
|
|
4
5
|
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
@@ -100,19 +101,6 @@ function linkCachedDir(skillDir, name, version, subdir) {
|
|
|
100
101
|
if (existsSync(cachedPath)) safeSymlink(cachedPath, linkPath);
|
|
101
102
|
}
|
|
102
103
|
/**
|
|
103
|
-
* Resolve the package directory: node_modules first, then cached dist fallback.
|
|
104
|
-
* Returns the path if found, null otherwise.
|
|
105
|
-
*/
|
|
106
|
-
function resolvePkgDir(name, cwd, version) {
|
|
107
|
-
const nodeModulesPath = join(cwd, "node_modules", name);
|
|
108
|
-
if (existsSync(nodeModulesPath)) return nodeModulesPath;
|
|
109
|
-
if (version) {
|
|
110
|
-
const cachedPkgDir = join(getCacheDir(name, version), "pkg");
|
|
111
|
-
if (existsSync(join(cachedPkgDir, "package.json"))) return cachedPkgDir;
|
|
112
|
-
}
|
|
113
|
-
return null;
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
104
|
* Create symlink from .skilld dir to package directory
|
|
117
105
|
*
|
|
118
106
|
* Structure:
|
|
@@ -173,19 +161,6 @@ function getPkgKeyFiles(name, cwd, version) {
|
|
|
173
161
|
return [...new Set(files)];
|
|
174
162
|
}
|
|
175
163
|
/**
|
|
176
|
-
* Check if package ships a skills/ directory with SKILL.md or _SKILL.md subdirs
|
|
177
|
-
*/
|
|
178
|
-
function getShippedSkills(name, cwd, version) {
|
|
179
|
-
const pkgPath = resolvePkgDir(name, cwd, version);
|
|
180
|
-
if (!pkgPath) return [];
|
|
181
|
-
const skillsPath = join(pkgPath, "skills");
|
|
182
|
-
if (!existsSync(skillsPath)) return [];
|
|
183
|
-
return readdirSync(skillsPath, { withFileTypes: true }).filter((d) => d.isDirectory() && (existsSync(join(skillsPath, d.name, "SKILL.md")) || existsSync(join(skillsPath, d.name, "_SKILL.md")))).map((d) => ({
|
|
184
|
-
skillName: d.name,
|
|
185
|
-
skillDir: join(skillsPath, d.name)
|
|
186
|
-
}));
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
164
|
* Write LLM-generated section outputs to global cache for cross-project reuse
|
|
190
165
|
*
|
|
191
166
|
* Structure:
|
|
@@ -207,18 +182,6 @@ function readCachedSection(name, version, file) {
|
|
|
207
182
|
if (!existsSync(path)) return null;
|
|
208
183
|
return readFileSync(path, "utf-8");
|
|
209
184
|
}
|
|
210
|
-
/**
|
|
211
|
-
* Create symlink from skills dir to shipped skill dir
|
|
212
|
-
*/
|
|
213
|
-
function linkShippedSkill(baseDir, skillName, targetDir) {
|
|
214
|
-
const linkPath = join(baseDir, skillName);
|
|
215
|
-
if (existsSync(linkPath)) if (lstatSync(linkPath).isSymbolicLink()) unlinkSync(linkPath);
|
|
216
|
-
else rmSync(linkPath, {
|
|
217
|
-
recursive: true,
|
|
218
|
-
force: true
|
|
219
|
-
});
|
|
220
|
-
symlinkSync(targetDir, linkPath);
|
|
221
|
-
}
|
|
222
185
|
function hasShippedDocs(name, cwd, version) {
|
|
223
186
|
const pkgPath = resolvePkgDir(name, cwd, version);
|
|
224
187
|
if (!pkgPath) return false;
|
|
@@ -311,6 +274,6 @@ function listReferenceFiles(skillDir, maxDepth = 3) {
|
|
|
311
274
|
return files;
|
|
312
275
|
}
|
|
313
276
|
//#endregion
|
|
314
|
-
export {
|
|
277
|
+
export { writeToRepoCache as _, hasShippedDocs as a, linkPkg as c, listCached as d, listReferenceFiles as f, writeToCache as g, writeSections as h, getPkgKeyFiles as i, linkPkgNamed as l, readCachedSection as m, clearCache as n, isCached as o, readCachedDocs as p, ensureCacheDir as r, linkCachedDir as s, clearAllCache as t, linkRepoCachedDir as u };
|
|
315
278
|
|
|
316
279
|
//# sourceMappingURL=cache.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.mjs","names":[],"sources":["../../src/cache/storage.ts"],"sourcesContent":["/**\n * Cache storage operations\n */\n\nimport type { CachedDoc, CachedPackage } from './types.ts'\nimport { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { basename, join, resolve } from 'pathe'\nimport { sanitizeMarkdown } from '../core/sanitize.ts'\nimport { getRepoCacheDir, REFERENCES_DIR, REPOS_DIR } from './config.ts'\nimport { getCacheDir } from './version.ts'\n\n/** Safely create a symlink, validating target is under REFERENCES_DIR or REPOS_DIR */\nfunction safeSymlink(target: string, linkPath: string): void {\n const resolved = resolve(target)\n if (!resolved.startsWith(REFERENCES_DIR) && !resolved.startsWith(REPOS_DIR))\n throw new Error(`Symlink target outside allowed dirs: ${resolved}`)\n // Remove pre-existing symlink (check with lstat to detect symlinks)\n try {\n const stat = lstatSync(linkPath)\n if (stat.isSymbolicLink() || stat.isFile())\n unlinkSync(linkPath)\n }\n catch {}\n symlinkSync(target, linkPath, 'junction')\n}\n\n/**\n * Check if package is cached at given version\n */\nexport function isCached(name: string, version: string): boolean {\n return existsSync(getCacheDir(name, version))\n}\n\n/**\n * Ensure cache directories exist\n */\nexport function ensureCacheDir(): void {\n mkdirSync(REFERENCES_DIR, { recursive: true, mode: 0o700 })\n mkdirSync(REPOS_DIR, { recursive: true, mode: 0o700 })\n}\n\n/**\n * Write docs to cache\n */\nexport function writeToCache(\n name: string,\n version: string,\n docs: CachedDoc[],\n): string {\n const cacheDir = getCacheDir(name, version)\n mkdirSync(cacheDir, { recursive: true, mode: 0o700 })\n\n for (const doc of docs) {\n const filePath = join(cacheDir, doc.path)\n mkdirSync(join(filePath, '..'), { recursive: true, mode: 0o700 })\n writeFileSync(filePath, sanitizeMarkdown(doc.content), { mode: 0o600 })\n }\n\n return cacheDir\n}\n\n/**\n * Write docs to repo-level cache (~/.skilld/repos/<owner>/<repo>/)\n */\nexport function writeToRepoCache(\n owner: string,\n repo: string,\n docs: CachedDoc[],\n): string {\n const repoDir = getRepoCacheDir(owner, repo)\n mkdirSync(repoDir, { recursive: true, mode: 0o700 })\n\n for (const doc of docs) {\n const filePath = join(repoDir, doc.path)\n mkdirSync(join(filePath, '..'), { recursive: true, mode: 0o700 })\n writeFileSync(filePath, sanitizeMarkdown(doc.content), { mode: 0o600 })\n }\n\n return repoDir\n}\n\n/**\n * Create symlink from .skilld dir to a repo-level cached subdirectory.\n * .claude/skills/<skill>/.skilld/<subdir> -> ~/.skilld/repos/<owner>/<repo>/<subdir>\n */\nexport function linkRepoCachedDir(skillDir: string, owner: string, repo: string, subdir: string): void {\n const repoDir = getRepoCacheDir(owner, repo)\n const referencesDir = join(skillDir, '.skilld')\n const linkPath = join(referencesDir, subdir)\n const cachedPath = join(repoDir, subdir)\n\n mkdirSync(referencesDir, { recursive: true })\n\n if (existsSync(cachedPath)) {\n safeSymlink(cachedPath, linkPath)\n }\n}\n\n/**\n * Create symlink from .skilld dir to a cached subdirectory.\n * Unified handler for docs, issues, discussions, sections, releases.\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/<subdir> -> ~/.skilld/references/<pkg>@<version>/<subdir>\n *\n * The .skilld/ dirs are gitignored. After clone, `skilld install` recreates from lockfile.\n */\nexport function linkCachedDir(skillDir: string, name: string, version: string, subdir: string): void {\n const cacheDir = getCacheDir(name, version)\n const referencesDir = join(skillDir, '.skilld')\n const linkPath = join(referencesDir, subdir)\n const cachedPath = join(cacheDir, subdir)\n\n mkdirSync(referencesDir, { recursive: true })\n\n if (existsSync(cachedPath)) {\n safeSymlink(cachedPath, linkPath)\n }\n}\n\n/**\n * Resolve the package directory: node_modules first, then cached dist fallback.\n * Returns the path if found, null otherwise.\n */\nexport function resolvePkgDir(name: string, cwd: string, version?: string): string | null {\n const nodeModulesPath = join(cwd, 'node_modules', name)\n if (existsSync(nodeModulesPath))\n return nodeModulesPath\n\n // Fallback: check cached npm dist\n if (version) {\n const cachedPkgDir = join(getCacheDir(name, version), 'pkg')\n if (existsSync(join(cachedPkgDir, 'package.json')))\n return cachedPkgDir\n }\n\n return null\n}\n\n/**\n * Create symlink from .skilld dir to package directory\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/pkg -> node_modules/<pkg> OR ~/.skilld/references/<pkg>@<version>/pkg\n *\n * This gives access to package.json, README.md, dist/, and any shipped docs/\n */\nexport function linkPkg(skillDir: string, name: string, cwd: string, version?: string): void {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return\n\n const referencesDir = join(skillDir, '.skilld')\n mkdirSync(referencesDir, { recursive: true })\n\n const pkgLinkPath = join(referencesDir, 'pkg')\n try {\n lstatSync(pkgLinkPath)\n unlinkSync(pkgLinkPath)\n }\n catch {}\n symlinkSync(pkgPath, pkgLinkPath, 'junction')\n}\n\n/**\n * Create named symlink from .skilld dir to package directory.\n * Short name = last segment of package name (e.g., @vue/reactivity → pkg-reactivity)\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/pkg-<short> -> node_modules/<pkg>\n */\nexport function linkPkgNamed(skillDir: string, name: string, cwd: string, version?: string): void {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return\n\n const shortName = name.split('/').pop()!.toLowerCase()\n const referencesDir = join(skillDir, '.skilld')\n mkdirSync(referencesDir, { recursive: true })\n\n const linkPath = join(referencesDir, `pkg-${shortName}`)\n try {\n lstatSync(linkPath)\n unlinkSync(linkPath)\n }\n catch {}\n symlinkSync(pkgPath, linkPath, 'junction')\n}\n\n/**\n * Get key files from a package directory for display\n * Returns entry points + docs files\n */\nexport function getPkgKeyFiles(name: string, cwd: string, version?: string): string[] {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return []\n\n const files: string[] = []\n const pkgJsonPath = join(pkgPath, 'package.json')\n\n if (existsSync(pkgJsonPath)) {\n const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'))\n\n // Entry points\n if (pkg.main)\n files.push(basename(pkg.main))\n if (pkg.module && pkg.module !== pkg.main)\n files.push(basename(pkg.module))\n\n // Type definitions (relative path preserved for LLM tool hints)\n const typesPath = pkg.types || pkg.typings\n if (typesPath && existsSync(join(pkgPath, typesPath)))\n files.push(typesPath)\n }\n\n // Check for common doc files (case-insensitive readme match)\n const entries = readdirSync(pkgPath).filter(f =>\n /^readme\\.md$/i.test(f) || /^changelog\\.md$/i.test(f),\n )\n files.push(...entries)\n\n return [...new Set(files)]\n}\n\n/**\n * Check if package ships its own docs folder\n */\nexport interface ShippedSkill {\n skillName: string\n skillDir: string\n}\n\n/**\n * Check if package ships a skills/ directory with SKILL.md or _SKILL.md subdirs\n */\nexport function getShippedSkills(name: string, cwd: string, version?: string): ShippedSkill[] {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return []\n\n const skillsPath = join(pkgPath, 'skills')\n if (!existsSync(skillsPath))\n return []\n\n return readdirSync(skillsPath, { withFileTypes: true })\n .filter(d => d.isDirectory() && (existsSync(join(skillsPath, d.name, 'SKILL.md')) || existsSync(join(skillsPath, d.name, '_SKILL.md'))))\n .map(d => ({ skillName: d.name, skillDir: join(skillsPath, d.name) }))\n}\n\n/**\n * Write LLM-generated section outputs to global cache for cross-project reuse\n *\n * Structure:\n * ~/.skilld/references/<pkg>@<version>/sections/_BEST_PRACTICES.md\n */\nexport function writeSections(name: string, version: string, sections: Array<{ file: string, content: string }>): void {\n const cacheDir = getCacheDir(name, version)\n const sectionsDir = join(cacheDir, 'sections')\n mkdirSync(sectionsDir, { recursive: true, mode: 0o700 })\n for (const { file, content } of sections) {\n writeFileSync(join(sectionsDir, file), content, { mode: 0o600 })\n }\n}\n\n/**\n * Read a cached section from the global references dir\n */\nexport function readCachedSection(name: string, version: string, file: string): string | null {\n const path = join(getCacheDir(name, version), 'sections', file)\n if (!existsSync(path))\n return null\n return readFileSync(path, 'utf-8')\n}\n\n/**\n * Create symlink from skills dir to shipped skill dir\n */\nexport function linkShippedSkill(baseDir: string, skillName: string, targetDir: string): void {\n const linkPath = join(baseDir, skillName)\n if (existsSync(linkPath)) {\n const stat = lstatSync(linkPath)\n if (stat.isSymbolicLink())\n unlinkSync(linkPath)\n else rmSync(linkPath, { recursive: true, force: true })\n }\n symlinkSync(targetDir, linkPath)\n}\n\nexport function hasShippedDocs(name: string, cwd: string, version?: string): boolean {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return false\n\n const docsCandidates = ['docs', 'documentation', 'doc']\n for (const candidate of docsCandidates) {\n const docsPath = join(pkgPath, candidate)\n if (existsSync(docsPath))\n return true\n }\n return false\n}\n\n/**\n * List all cached packages\n */\nexport function listCached(): CachedPackage[] {\n if (!existsSync(REFERENCES_DIR))\n return []\n\n return readdirSync(REFERENCES_DIR)\n .filter(name => name.includes('@'))\n .map((dir) => {\n const atIdx = dir.lastIndexOf('@')\n return { name: dir.slice(0, atIdx), version: dir.slice(atIdx + 1), dir: join(REFERENCES_DIR, dir) }\n })\n}\n\n/**\n * Read cached docs for a package\n */\nexport function readCachedDocs(name: string, version: string): CachedDoc[] {\n const cacheDir = getCacheDir(name, version)\n if (!existsSync(cacheDir))\n return []\n\n const docs: CachedDoc[] = []\n\n function walk(dir: string, prefix = '') {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const entryPath = join(dir, entry.name)\n const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name\n\n if (entry.isDirectory()) {\n walk(entryPath, relativePath)\n }\n else if (entry.name.endsWith('.md') || entry.name.endsWith('.mdx')) {\n docs.push({\n path: relativePath,\n content: readFileSync(entryPath, 'utf-8'),\n })\n }\n }\n }\n\n walk(cacheDir)\n return docs\n}\n\n/**\n * Clear cache for a specific package\n */\nexport function clearCache(name: string, version: string): boolean {\n const cacheDir = getCacheDir(name, version)\n if (!existsSync(cacheDir))\n return false\n\n rmSync(cacheDir, { recursive: true })\n return true\n}\n\n/**\n * Clear all cache\n */\nexport function clearAllCache(): number {\n const packages = listCached()\n for (const pkg of packages) {\n clearCache(pkg.name, pkg.version)\n }\n // Also clear repo-level cache\n if (existsSync(REPOS_DIR))\n rmSync(REPOS_DIR, { recursive: true })\n return packages.length\n}\n\n/**\n * List files in .skilld directory (pkg + docs) as relative paths for prompt context\n * Returns paths like ./.skilld/pkg/README.md, ./.skilld/docs/api.md\n */\nexport function listReferenceFiles(skillDir: string, maxDepth = 3): string[] {\n const referencesDir = join(skillDir, '.skilld')\n if (!existsSync(referencesDir))\n return []\n\n const files: string[] = []\n\n function walk(dir: string, depth: number) {\n if (depth > maxDepth)\n return\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name)\n if (entry.isDirectory() || entry.isSymbolicLink()) {\n try {\n const stat = statSync(full)\n if (stat.isDirectory()) {\n walk(full, depth + 1)\n continue\n }\n }\n catch { continue }\n }\n if (entry.name.endsWith('.md')) {\n files.push(full)\n }\n }\n }\n catch {\n // Broken symlink or permission error\n }\n }\n\n walk(referencesDir, 0)\n return files\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cache.mjs","names":[],"sources":["../../src/cache/storage.ts"],"sourcesContent":["/**\n * Cache storage operations\n */\n\nimport type { CachedDoc, CachedPackage } from './types.ts'\nimport { existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { basename, join, resolve } from 'pathe'\nimport { resolvePkgDir } from '../core/prepare.ts'\nimport { sanitizeMarkdown } from '../core/sanitize.ts'\nimport { getRepoCacheDir, REFERENCES_DIR, REPOS_DIR } from './config.ts'\nimport { getCacheDir } from './version.ts'\n\n/** Safely create a symlink, validating target is under REFERENCES_DIR or REPOS_DIR */\nfunction safeSymlink(target: string, linkPath: string): void {\n const resolved = resolve(target)\n if (!resolved.startsWith(REFERENCES_DIR) && !resolved.startsWith(REPOS_DIR))\n throw new Error(`Symlink target outside allowed dirs: ${resolved}`)\n // Remove pre-existing symlink (check with lstat to detect symlinks)\n try {\n const stat = lstatSync(linkPath)\n if (stat.isSymbolicLink() || stat.isFile())\n unlinkSync(linkPath)\n }\n catch {}\n symlinkSync(target, linkPath, 'junction')\n}\n\n/**\n * Check if package is cached at given version\n */\nexport function isCached(name: string, version: string): boolean {\n return existsSync(getCacheDir(name, version))\n}\n\n/**\n * Ensure cache directories exist\n */\nexport function ensureCacheDir(): void {\n mkdirSync(REFERENCES_DIR, { recursive: true, mode: 0o700 })\n mkdirSync(REPOS_DIR, { recursive: true, mode: 0o700 })\n}\n\n/**\n * Write docs to cache\n */\nexport function writeToCache(\n name: string,\n version: string,\n docs: CachedDoc[],\n): string {\n const cacheDir = getCacheDir(name, version)\n mkdirSync(cacheDir, { recursive: true, mode: 0o700 })\n\n for (const doc of docs) {\n const filePath = join(cacheDir, doc.path)\n mkdirSync(join(filePath, '..'), { recursive: true, mode: 0o700 })\n writeFileSync(filePath, sanitizeMarkdown(doc.content), { mode: 0o600 })\n }\n\n return cacheDir\n}\n\n/**\n * Write docs to repo-level cache (~/.skilld/repos/<owner>/<repo>/)\n */\nexport function writeToRepoCache(\n owner: string,\n repo: string,\n docs: CachedDoc[],\n): string {\n const repoDir = getRepoCacheDir(owner, repo)\n mkdirSync(repoDir, { recursive: true, mode: 0o700 })\n\n for (const doc of docs) {\n const filePath = join(repoDir, doc.path)\n mkdirSync(join(filePath, '..'), { recursive: true, mode: 0o700 })\n writeFileSync(filePath, sanitizeMarkdown(doc.content), { mode: 0o600 })\n }\n\n return repoDir\n}\n\n/**\n * Create symlink from .skilld dir to a repo-level cached subdirectory.\n * .claude/skills/<skill>/.skilld/<subdir> -> ~/.skilld/repos/<owner>/<repo>/<subdir>\n */\nexport function linkRepoCachedDir(skillDir: string, owner: string, repo: string, subdir: string): void {\n const repoDir = getRepoCacheDir(owner, repo)\n const referencesDir = join(skillDir, '.skilld')\n const linkPath = join(referencesDir, subdir)\n const cachedPath = join(repoDir, subdir)\n\n mkdirSync(referencesDir, { recursive: true })\n\n if (existsSync(cachedPath)) {\n safeSymlink(cachedPath, linkPath)\n }\n}\n\n/**\n * Create symlink from .skilld dir to a cached subdirectory.\n * Unified handler for docs, issues, discussions, sections, releases.\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/<subdir> -> ~/.skilld/references/<pkg>@<version>/<subdir>\n *\n * The .skilld/ dirs are gitignored. After clone, `skilld install` recreates from lockfile.\n */\nexport function linkCachedDir(skillDir: string, name: string, version: string, subdir: string): void {\n const cacheDir = getCacheDir(name, version)\n const referencesDir = join(skillDir, '.skilld')\n const linkPath = join(referencesDir, subdir)\n const cachedPath = join(cacheDir, subdir)\n\n mkdirSync(referencesDir, { recursive: true })\n\n if (existsSync(cachedPath)) {\n safeSymlink(cachedPath, linkPath)\n }\n}\n\n/**\n * Resolve the package directory: node_modules first, then cached dist fallback.\n * Returns the path if found, null otherwise.\n */\nexport { resolvePkgDir } from '../core/prepare.ts'\nexport { getShippedSkills, linkShippedSkill } from '../core/prepare.ts'\nexport type { ShippedSkill } from '../core/prepare.ts'\n\n/**\n * Create symlink from .skilld dir to package directory\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/pkg -> node_modules/<pkg> OR ~/.skilld/references/<pkg>@<version>/pkg\n *\n * This gives access to package.json, README.md, dist/, and any shipped docs/\n */\nexport function linkPkg(skillDir: string, name: string, cwd: string, version?: string): void {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return\n\n const referencesDir = join(skillDir, '.skilld')\n mkdirSync(referencesDir, { recursive: true })\n\n const pkgLinkPath = join(referencesDir, 'pkg')\n try {\n lstatSync(pkgLinkPath)\n unlinkSync(pkgLinkPath)\n }\n catch {}\n symlinkSync(pkgPath, pkgLinkPath, 'junction')\n}\n\n/**\n * Create named symlink from .skilld dir to package directory.\n * Short name = last segment of package name (e.g., @vue/reactivity → pkg-reactivity)\n *\n * Structure:\n * .claude/skills/<skill>/.skilld/pkg-<short> -> node_modules/<pkg>\n */\nexport function linkPkgNamed(skillDir: string, name: string, cwd: string, version?: string): void {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return\n\n const shortName = name.split('/').pop()!.toLowerCase()\n const referencesDir = join(skillDir, '.skilld')\n mkdirSync(referencesDir, { recursive: true })\n\n const linkPath = join(referencesDir, `pkg-${shortName}`)\n try {\n lstatSync(linkPath)\n unlinkSync(linkPath)\n }\n catch {}\n symlinkSync(pkgPath, linkPath, 'junction')\n}\n\n/**\n * Get key files from a package directory for display\n * Returns entry points + docs files\n */\nexport function getPkgKeyFiles(name: string, cwd: string, version?: string): string[] {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return []\n\n const files: string[] = []\n const pkgJsonPath = join(pkgPath, 'package.json')\n\n if (existsSync(pkgJsonPath)) {\n const pkg = JSON.parse(readFileSync(pkgJsonPath, 'utf-8'))\n\n // Entry points\n if (pkg.main)\n files.push(basename(pkg.main))\n if (pkg.module && pkg.module !== pkg.main)\n files.push(basename(pkg.module))\n\n // Type definitions (relative path preserved for LLM tool hints)\n const typesPath = pkg.types || pkg.typings\n if (typesPath && existsSync(join(pkgPath, typesPath)))\n files.push(typesPath)\n }\n\n // Check for common doc files (case-insensitive readme match)\n const entries = readdirSync(pkgPath).filter(f =>\n /^readme\\.md$/i.test(f) || /^changelog\\.md$/i.test(f),\n )\n files.push(...entries)\n\n return [...new Set(files)]\n}\n\n/**\n * Write LLM-generated section outputs to global cache for cross-project reuse\n *\n * Structure:\n * ~/.skilld/references/<pkg>@<version>/sections/_BEST_PRACTICES.md\n */\nexport function writeSections(name: string, version: string, sections: Array<{ file: string, content: string }>): void {\n const cacheDir = getCacheDir(name, version)\n const sectionsDir = join(cacheDir, 'sections')\n mkdirSync(sectionsDir, { recursive: true, mode: 0o700 })\n for (const { file, content } of sections) {\n writeFileSync(join(sectionsDir, file), content, { mode: 0o600 })\n }\n}\n\n/**\n * Read a cached section from the global references dir\n */\nexport function readCachedSection(name: string, version: string, file: string): string | null {\n const path = join(getCacheDir(name, version), 'sections', file)\n if (!existsSync(path))\n return null\n return readFileSync(path, 'utf-8')\n}\n\nexport function hasShippedDocs(name: string, cwd: string, version?: string): boolean {\n const pkgPath = resolvePkgDir(name, cwd, version)\n if (!pkgPath)\n return false\n\n const docsCandidates = ['docs', 'documentation', 'doc']\n for (const candidate of docsCandidates) {\n const docsPath = join(pkgPath, candidate)\n if (existsSync(docsPath))\n return true\n }\n return false\n}\n\n/**\n * List all cached packages\n */\nexport function listCached(): CachedPackage[] {\n if (!existsSync(REFERENCES_DIR))\n return []\n\n return readdirSync(REFERENCES_DIR)\n .filter(name => name.includes('@'))\n .map((dir) => {\n const atIdx = dir.lastIndexOf('@')\n return { name: dir.slice(0, atIdx), version: dir.slice(atIdx + 1), dir: join(REFERENCES_DIR, dir) }\n })\n}\n\n/**\n * Read cached docs for a package\n */\nexport function readCachedDocs(name: string, version: string): CachedDoc[] {\n const cacheDir = getCacheDir(name, version)\n if (!existsSync(cacheDir))\n return []\n\n const docs: CachedDoc[] = []\n\n function walk(dir: string, prefix = '') {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const entryPath = join(dir, entry.name)\n const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name\n\n if (entry.isDirectory()) {\n walk(entryPath, relativePath)\n }\n else if (entry.name.endsWith('.md') || entry.name.endsWith('.mdx')) {\n docs.push({\n path: relativePath,\n content: readFileSync(entryPath, 'utf-8'),\n })\n }\n }\n }\n\n walk(cacheDir)\n return docs\n}\n\n/**\n * Clear cache for a specific package\n */\nexport function clearCache(name: string, version: string): boolean {\n const cacheDir = getCacheDir(name, version)\n if (!existsSync(cacheDir))\n return false\n\n rmSync(cacheDir, { recursive: true })\n return true\n}\n\n/**\n * Clear all cache\n */\nexport function clearAllCache(): number {\n const packages = listCached()\n for (const pkg of packages) {\n clearCache(pkg.name, pkg.version)\n }\n // Also clear repo-level cache\n if (existsSync(REPOS_DIR))\n rmSync(REPOS_DIR, { recursive: true })\n return packages.length\n}\n\n/**\n * List files in .skilld directory (pkg + docs) as relative paths for prompt context\n * Returns paths like ./.skilld/pkg/README.md, ./.skilld/docs/api.md\n */\nexport function listReferenceFiles(skillDir: string, maxDepth = 3): string[] {\n const referencesDir = join(skillDir, '.skilld')\n if (!existsSync(referencesDir))\n return []\n\n const files: string[] = []\n\n function walk(dir: string, depth: number) {\n if (depth > maxDepth)\n return\n try {\n for (const entry of readdirSync(dir, { withFileTypes: true })) {\n const full = join(dir, entry.name)\n if (entry.isDirectory() || entry.isSymbolicLink()) {\n try {\n const stat = statSync(full)\n if (stat.isDirectory()) {\n walk(full, depth + 1)\n continue\n }\n }\n catch { continue }\n }\n if (entry.name.endsWith('.md')) {\n files.push(full)\n }\n }\n }\n catch {\n // Broken symlink or permission error\n }\n }\n\n walk(referencesDir, 0)\n return files\n}\n"],"mappings":"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"}
|
package/dist/_chunks/cache2.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { t as CACHE_DIR } from "./config.mjs";
|
|
2
|
+
import "./prepare.mjs";
|
|
2
3
|
import "./sanitize.mjs";
|
|
3
4
|
import "./cache.mjs";
|
|
4
|
-
import { clearEmbeddingCache } from "./embedding-
|
|
5
|
+
import { n as clearEmbeddingCache } from "./embedding-cache2.mjs";
|
|
5
6
|
import { join } from "pathe";
|
|
6
7
|
import { existsSync, readFileSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
7
8
|
import * as p from "@clack/prompts";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache2.mjs","names":[],"sources":["../../src/commands/cache.ts"],"sourcesContent":["/**\n * Cache management commands\n */\n\nimport { existsSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join } from 'pathe'\nimport { CACHE_DIR } from '../cache/index.ts'\nimport { clearEmbeddingCache } from '../retriv/embedding-cache.ts'\n\nconst LLM_CACHE_DIR = join(CACHE_DIR, 'llm-cache')\nconst LLM_CACHE_MAX_AGE = 7 * 24 * 60 * 60 * 1000\n\nfunction safeRemove(path: string): number {\n try {\n const size = statSync(path).size\n rmSync(path)\n return size\n }\n catch {\n try {\n rmSync(path)\n }\n catch {}\n return 0\n }\n}\n\nexport async function cacheCleanCommand(): Promise<void> {\n let expiredLlm = 0\n let freedBytes = 0\n\n // Clean expired LLM cache entries\n if (existsSync(LLM_CACHE_DIR)) {\n const now = Date.now()\n for (const entry of readdirSync(LLM_CACHE_DIR)) {\n const path = join(LLM_CACHE_DIR, entry)\n try {\n const { timestamp } = JSON.parse(readFileSync(path, 'utf-8'))\n if (now - timestamp > LLM_CACHE_MAX_AGE) {\n freedBytes += safeRemove(path)\n expiredLlm++\n }\n }\n catch {\n // Corrupt cache entry — remove it\n freedBytes += safeRemove(path)\n expiredLlm++\n }\n }\n }\n\n // Clear embedding cache\n const embeddingDbPath = join(CACHE_DIR, 'embeddings.db')\n let embeddingCleared = false\n if (existsSync(embeddingDbPath)) {\n const size = statSync(embeddingDbPath).size\n clearEmbeddingCache()\n freedBytes += size\n embeddingCleared = true\n }\n\n const freedKB = Math.round(freedBytes / 1024)\n if (expiredLlm > 0 || embeddingCleared) {\n const parts: string[] = []\n if (expiredLlm > 0)\n parts.push(`${expiredLlm} expired enhancement cache entries`)\n if (embeddingCleared)\n parts.push('embedding cache')\n p.log.success(`Removed ${parts.join(' + ')} (${freedKB}KB freed)`)\n }\n else {\n p.log.info('Cache is clean — no expired entries')\n }\n}\n\nexport const cacheCommandDef = defineCommand({\n meta: { name: 'cache', description: 'Cache management', hidden: true },\n args: {\n clean: {\n type: 'boolean',\n description: 'Remove expired enhancement cache entries',\n default: true,\n },\n },\n async run() {\n p.intro(`\\x1B[1m\\x1B[35mskilld\\x1B[0m cache clean`)\n await cacheCleanCommand()\n },\n})\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"cache2.mjs","names":[],"sources":["../../src/commands/cache.ts"],"sourcesContent":["/**\n * Cache management commands\n */\n\nimport { existsSync, readdirSync, readFileSync, rmSync, statSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join } from 'pathe'\nimport { CACHE_DIR } from '../cache/index.ts'\nimport { clearEmbeddingCache } from '../retriv/embedding-cache.ts'\n\nconst LLM_CACHE_DIR = join(CACHE_DIR, 'llm-cache')\nconst LLM_CACHE_MAX_AGE = 7 * 24 * 60 * 60 * 1000\n\nfunction safeRemove(path: string): number {\n try {\n const size = statSync(path).size\n rmSync(path)\n return size\n }\n catch {\n try {\n rmSync(path)\n }\n catch {}\n return 0\n }\n}\n\nexport async function cacheCleanCommand(): Promise<void> {\n let expiredLlm = 0\n let freedBytes = 0\n\n // Clean expired LLM cache entries\n if (existsSync(LLM_CACHE_DIR)) {\n const now = Date.now()\n for (const entry of readdirSync(LLM_CACHE_DIR)) {\n const path = join(LLM_CACHE_DIR, entry)\n try {\n const { timestamp } = JSON.parse(readFileSync(path, 'utf-8'))\n if (now - timestamp > LLM_CACHE_MAX_AGE) {\n freedBytes += safeRemove(path)\n expiredLlm++\n }\n }\n catch {\n // Corrupt cache entry — remove it\n freedBytes += safeRemove(path)\n expiredLlm++\n }\n }\n }\n\n // Clear embedding cache\n const embeddingDbPath = join(CACHE_DIR, 'embeddings.db')\n let embeddingCleared = false\n if (existsSync(embeddingDbPath)) {\n const size = statSync(embeddingDbPath).size\n clearEmbeddingCache()\n freedBytes += size\n embeddingCleared = true\n }\n\n const freedKB = Math.round(freedBytes / 1024)\n if (expiredLlm > 0 || embeddingCleared) {\n const parts: string[] = []\n if (expiredLlm > 0)\n parts.push(`${expiredLlm} expired enhancement cache entries`)\n if (embeddingCleared)\n parts.push('embedding cache')\n p.log.success(`Removed ${parts.join(' + ')} (${freedKB}KB freed)`)\n }\n else {\n p.log.info('Cache is clean — no expired entries')\n }\n}\n\nexport const cacheCommandDef = defineCommand({\n meta: { name: 'cache', description: 'Cache management', hidden: true },\n args: {\n clean: {\n type: 'boolean',\n description: 'Remove expired enhancement cache entries',\n default: true,\n },\n },\n async run() {\n p.intro(`\\x1B[1m\\x1B[35mskilld\\x1B[0m cache clean`)\n await cacheCleanCommand()\n },\n})\n"],"mappings":";;;;;;;;;;;;;AAWA,MAAM,gBAAgB,KAAK,WAAW,YAAY;AAClD,MAAM,oBAAoB,QAAc,KAAK;AAE7C,SAAS,WAAW,MAAsB;AACxC,KAAI;EACF,MAAM,OAAO,SAAS,KAAK,CAAC;AAC5B,SAAO,KAAK;AACZ,SAAO;SAEH;AACJ,MAAI;AACF,UAAO,KAAK;UAER;AACN,SAAO;;;AAIX,eAAsB,oBAAmC;CACvD,IAAI,aAAa;CACjB,IAAI,aAAa;AAGjB,KAAI,WAAW,cAAc,EAAE;EAC7B,MAAM,MAAM,KAAK,KAAK;AACtB,OAAK,MAAM,SAAS,YAAY,cAAc,EAAE;GAC9C,MAAM,OAAO,KAAK,eAAe,MAAM;AACvC,OAAI;IACF,MAAM,EAAE,cAAc,KAAK,MAAM,aAAa,MAAM,QAAQ,CAAC;AAC7D,QAAI,MAAM,YAAY,mBAAmB;AACvC,mBAAc,WAAW,KAAK;AAC9B;;WAGE;AAEJ,kBAAc,WAAW,KAAK;AAC9B;;;;CAMN,MAAM,kBAAkB,KAAK,WAAW,gBAAgB;CACxD,IAAI,mBAAmB;AACvB,KAAI,WAAW,gBAAgB,EAAE;EAC/B,MAAM,OAAO,SAAS,gBAAgB,CAAC;AACvC,uBAAqB;AACrB,gBAAc;AACd,qBAAmB;;CAGrB,MAAM,UAAU,KAAK,MAAM,aAAa,KAAK;AAC7C,KAAI,aAAa,KAAK,kBAAkB;EACtC,MAAM,QAAkB,EAAE;AAC1B,MAAI,aAAa,EACf,OAAM,KAAK,GAAG,WAAW,oCAAoC;AAC/D,MAAI,iBACF,OAAM,KAAK,kBAAkB;AAC/B,IAAE,IAAI,QAAQ,WAAW,MAAM,KAAK,MAAM,CAAC,IAAI,QAAQ,WAAW;OAGlE,GAAE,IAAI,KAAK,sCAAsC;;AAIrD,MAAa,kBAAkB,cAAc;CAC3C,MAAM;EAAE,MAAM;EAAS,aAAa;EAAoB,QAAQ;EAAM;CACtE,MAAM,EACJ,OAAO;EACL,MAAM;EACN,aAAa;EACb,SAAS;EACV,EACF;CACD,MAAM,MAAM;AACV,IAAE,MAAM,2CAA2C;AACnD,QAAM,mBAAmB;;CAE5B,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { o as getModelName } from "./agent.mjs";
|
|
2
2
|
import { n as yamlParseKV, r as yamlUnescape, t as yamlEscape } from "./yaml.mjs";
|
|
3
3
|
import { a as targets, i as getAgentVersion, n as detectProjectAgents, r as detectTargetAgent, t as detectInstalledAgents } from "./detect.mjs";
|
|
4
4
|
import { homedir } from "node:os";
|
|
@@ -202,29 +202,6 @@ function findPackageJson() {
|
|
|
202
202
|
const version = JSON.parse(findPackageJson()).version;
|
|
203
203
|
//#endregion
|
|
204
204
|
//#region src/cli-helpers.ts
|
|
205
|
-
var cli_helpers_exports = /* @__PURE__ */ __exportAll({
|
|
206
|
-
MenuCancel: () => MenuCancel,
|
|
207
|
-
NO_MODELS_MESSAGE: () => NO_MODELS_MESSAGE,
|
|
208
|
-
OAUTH_NOTE: () => OAUTH_NOTE,
|
|
209
|
-
buildPrepareScript: () => buildPrepareScript,
|
|
210
|
-
formatStatus: () => formatStatus,
|
|
211
|
-
getInstalledGenerators: () => getInstalledGenerators,
|
|
212
|
-
getLastSynced: () => getLastSynced,
|
|
213
|
-
getRepoHint: () => getRepoHint,
|
|
214
|
-
groupModelsByProvider: () => groupModelsByProvider,
|
|
215
|
-
guard: () => guard,
|
|
216
|
-
introLine: () => introLine,
|
|
217
|
-
isInteractive: () => isInteractive,
|
|
218
|
-
isRunningInsideAgent: () => isRunningInsideAgent,
|
|
219
|
-
menuLoop: () => menuLoop,
|
|
220
|
-
pickModel: () => pickModel,
|
|
221
|
-
promptForAgent: () => promptForAgent,
|
|
222
|
-
relativeTime: () => relativeTime,
|
|
223
|
-
requireInteractive: () => requireInteractive,
|
|
224
|
-
resolveAgent: () => resolveAgent,
|
|
225
|
-
sharedArgs: () => sharedArgs,
|
|
226
|
-
suggestPrepareHook: () => suggestPrepareHook
|
|
227
|
-
});
|
|
228
205
|
const sharedArgs = {
|
|
229
206
|
global: {
|
|
230
207
|
type: "boolean",
|
|
@@ -533,10 +510,11 @@ async function suggestPrepareHook(cwd = process.cwd()) {
|
|
|
533
510
|
* Build the full prepare script value, safely appending to any existing command.
|
|
534
511
|
*/
|
|
535
512
|
function buildPrepareScript(existing) {
|
|
536
|
-
|
|
513
|
+
const cmd = "skilld prepare || true";
|
|
514
|
+
if (!existing || !existing.trim()) return cmd;
|
|
537
515
|
const cleaned = existing.trim().replace(/[&|;]+\s*$/, "").trim();
|
|
538
|
-
if (!cleaned) return
|
|
539
|
-
return `${cleaned} &&
|
|
516
|
+
if (!cleaned) return cmd;
|
|
517
|
+
return `${cleaned} && (${cmd})`;
|
|
540
518
|
}
|
|
541
519
|
function getRepoHint(name, cwd) {
|
|
542
520
|
const pkgJsonPath = join(cwd, "node_modules", name, "package.json");
|
|
@@ -547,6 +525,6 @@ function getRepoHint(name, cwd) {
|
|
|
547
525
|
return url.replace(/^git\+/, "").replace(/\.git$/, "").replace(/^git:\/\//, "https://").replace(/^ssh:\/\/git@github\.com/, "https://github.com").replace(/^https?:\/\/(www\.)?github\.com\//, "");
|
|
548
526
|
}
|
|
549
527
|
//#endregion
|
|
550
|
-
export {
|
|
528
|
+
export { registerProject as A, appendToJsonArray as C, hasCompletedWizard as D, getRegisteredProjects as E, updateConfig as M, hasConfig as O, version as S, defaultFeatures as T, relativeTime as _, formatStatus as a, sharedArgs as b, getRepoHint as c, introLine as d, isInteractive as f, promptForAgent as g, pickModel as h, buildPrepareScript as i, unregisterProject as j, readConfig as k, groupModelsByProvider as l, menuLoop as m, NO_MODELS_MESSAGE as n, getInstalledGenerators as o, isRunningInsideAgent as p, OAUTH_NOTE as r, getLastSynced as s, MenuCancel as t, guard as u, requireInteractive as v, patchPackageJson as w, suggestPrepareHook as x, resolveAgent as y };
|
|
551
529
|
|
|
552
530
|
//# sourceMappingURL=cli-helpers.mjs.map
|