skilld 1.7.4 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/add.mjs +66 -0
- package/dist/_chunks/add.mjs.map +1 -0
- package/dist/_chunks/agent-prompt.mjs +88 -0
- package/dist/_chunks/agent-prompt.mjs.map +1 -0
- package/dist/_chunks/agent.mjs +81 -57
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/args.mjs +42 -0
- package/dist/_chunks/args.mjs.map +1 -0
- package/dist/_chunks/assemble.mjs +10 -7
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author.mjs +33 -17
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +143 -183
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +7 -6
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/client.mjs +117 -0
- package/dist/_chunks/client.mjs.map +1 -0
- package/dist/_chunks/core.mjs +5 -5
- package/dist/_chunks/detect.mjs +53 -43
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/eject.mjs +69 -0
- package/dist/_chunks/eject.mjs.map +1 -0
- package/dist/_chunks/embedding-cache2.mjs +1 -1
- package/dist/_chunks/env.mjs +19 -0
- package/dist/_chunks/env.mjs.map +1 -0
- package/dist/_chunks/install-many.mjs +376 -0
- package/dist/_chunks/install-many.mjs.map +1 -0
- package/dist/_chunks/install.mjs +81 -326
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/intro.mjs +63 -0
- package/dist/_chunks/intro.mjs.map +1 -0
- package/dist/_chunks/list.mjs +2 -2
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/lockfile.mjs +3 -2
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/login.mjs +233 -0
- package/dist/_chunks/login.mjs.map +1 -0
- package/dist/_chunks/logout.mjs +27 -0
- package/dist/_chunks/logout.mjs.map +1 -0
- package/dist/_chunks/map.mjs +11 -0
- package/dist/_chunks/map.mjs.map +1 -0
- package/dist/_chunks/markdown.mjs +79 -54
- package/dist/_chunks/markdown.mjs.map +1 -1
- package/dist/_chunks/menu.mjs +33 -0
- package/dist/_chunks/menu.mjs.map +1 -0
- package/dist/_chunks/model-picker.mjs +61 -0
- package/dist/_chunks/model-picker.mjs.map +1 -0
- package/dist/_chunks/monorepo.mjs +4 -2
- package/dist/_chunks/monorepo.mjs.map +1 -1
- package/dist/_chunks/package-json.mjs.map +1 -1
- package/dist/_chunks/paths.mjs +3 -5
- package/dist/_chunks/paths.mjs.map +1 -1
- package/dist/_chunks/{sync-pipeline.mjs → pipeline.mjs} +346 -313
- package/dist/_chunks/pipeline.mjs.map +1 -0
- package/dist/_chunks/pool2.mjs +1 -1
- package/dist/_chunks/portable.mjs +151 -0
- package/dist/_chunks/portable.mjs.map +1 -0
- package/dist/_chunks/prepare-hook.mjs +2 -0
- package/dist/_chunks/prepare-hook2.mjs +61 -0
- package/dist/_chunks/prepare-hook2.mjs.map +1 -0
- package/dist/_chunks/prepare.mjs +47 -3
- package/dist/_chunks/prepare.mjs.map +1 -1
- package/dist/_chunks/prepare2.mjs +7 -6
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +484 -74
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/pull.mjs +219 -0
- package/dist/_chunks/pull.mjs.map +1 -0
- package/dist/_chunks/regex.mjs +19 -0
- package/dist/_chunks/regex.mjs.map +1 -0
- package/dist/_chunks/retriv.mjs +2 -171
- package/dist/_chunks/retriv2.mjs +159 -0
- package/dist/_chunks/retriv2.mjs.map +1 -0
- package/dist/_chunks/sanitize.mjs +12 -9
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-helpers.mjs +8 -6
- package/dist/_chunks/search-helpers.mjs.map +1 -1
- package/dist/_chunks/search-interactive.mjs +23 -20
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +3 -3
- package/dist/_chunks/search.mjs.map +1 -1
- package/dist/_chunks/semver.mjs +2755 -1
- package/dist/_chunks/semver.mjs.map +1 -1
- package/dist/_chunks/skill-installer2.mjs +10 -11
- package/dist/_chunks/skill-installer2.mjs.map +1 -1
- package/dist/_chunks/skills.mjs +6 -7
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/store.mjs +107 -0
- package/dist/_chunks/store.mjs.map +1 -0
- package/dist/_chunks/sync.mjs +411 -910
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +2 -5
- package/dist/_chunks/telemetry.mjs +26 -0
- package/dist/_chunks/telemetry.mjs.map +1 -0
- package/dist/_chunks/uninstall.mjs +12 -9
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/update.mjs +171 -0
- package/dist/_chunks/update.mjs.map +1 -0
- package/dist/_chunks/upload.mjs +3 -3
- package/dist/_chunks/validate.mjs +1 -1
- package/dist/_chunks/version.mjs +16 -17
- package/dist/_chunks/version.mjs.map +1 -1
- package/dist/_chunks/whoami.mjs +21 -0
- package/dist/_chunks/whoami.mjs.map +1 -0
- package/dist/_chunks/wizard.mjs +2 -190
- package/dist/_chunks/wizard2.mjs +200 -0
- package/dist/_chunks/wizard2.mjs.map +1 -0
- package/dist/cli.mjs +72 -53
- package/dist/cli.mjs.map +1 -1
- package/dist/prepare.mjs +4 -3
- package/dist/prepare.mjs.map +1 -1
- package/dist/retriv/worker.d.mts +5 -1
- package/dist/retriv/worker.d.mts.map +1 -1
- package/dist/retriv/worker.mjs +1 -1
- package/package.json +19 -28
- package/dist/_chunks/author-group.mjs +0 -17
- package/dist/_chunks/author-group.mjs.map +0 -1
- package/dist/_chunks/cli-helpers.mjs +0 -335
- package/dist/_chunks/cli-helpers.mjs.map +0 -1
- package/dist/_chunks/cli-helpers2.mjs +0 -2
- package/dist/_chunks/index.d.mts +0 -344
- package/dist/_chunks/index.d.mts.map +0 -1
- package/dist/_chunks/index2.d.mts +0 -279
- package/dist/_chunks/index2.d.mts.map +0 -1
- package/dist/_chunks/index3.d.mts +0 -44
- package/dist/_chunks/index3.d.mts.map +0 -1
- package/dist/_chunks/index4.d.mts +0 -553
- package/dist/_chunks/index4.d.mts.map +0 -1
- package/dist/_chunks/package-registry.mjs +0 -465
- package/dist/_chunks/package-registry.mjs.map +0 -1
- package/dist/_chunks/retriv.mjs.map +0 -1
- package/dist/_chunks/setup.mjs +0 -17
- package/dist/_chunks/setup.mjs.map +0 -1
- package/dist/_chunks/sources.mjs +0 -2654
- package/dist/_chunks/sources.mjs.map +0 -1
- package/dist/_chunks/sync-pipeline.mjs.map +0 -1
- package/dist/_chunks/sync-registry.mjs +0 -65
- package/dist/_chunks/sync-registry.mjs.map +0 -1
- package/dist/_chunks/types.d.mts +0 -76
- package/dist/_chunks/types.d.mts.map +0 -1
- package/dist/_chunks/types2.d.mts +0 -88
- package/dist/_chunks/types2.d.mts.map +0 -1
- package/dist/_chunks/wizard.mjs.map +0 -1
- package/dist/agent/index.d.mts +0 -2
- package/dist/agent/index.mjs +0 -4
- package/dist/cache/index.d.mts +0 -2
- package/dist/cache/index.mjs +0 -5
- package/dist/index.d.mts +0 -6
- package/dist/index.mjs +0 -6
- package/dist/retriv/index.d.mts +0 -3
- package/dist/retriv/index.mjs +0 -2
- package/dist/sources/index.d.mts +0 -3
- package/dist/sources/index.mjs +0 -3
- package/dist/types.d.mts +0 -4
- package/dist/types.mjs +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.mjs","names":[],"sources":["../../src/agent/skill-builder.ts","../../src/commands/llm-prompts.ts","../../src/retriv/index-pipeline.ts","../../src/sources/resolvers/cascade.ts","../../src/sources/resolvers/content/crawl-url.ts","../../src/sources/resolvers/content/docs-crawl.ts","../../src/sources/resolvers/content/git-docs.ts","../../src/sources/resolvers/content/llms-txt.ts","../../src/sources/resolvers/content/readme.ts","../../src/sources/resolvers/content/index.ts","../../src/sources/content-resolver.ts","../../src/sources/resolvers/timeline/discussions.ts","../../src/sources/resolvers/timeline/issues.ts","../../src/sources/resolvers/timeline/releases.ts","../../src/sources/resolvers/timeline/index.ts","../../src/sources/timeline-resolver.ts","../../src/commands/sync/pipeline.ts"],"sourcesContent":["/**\n * SkillBuilder: turns cached references into a generated SKILL.md.\n *\n * Two entry points, both consume a `SkillContext` (skill-state) plus a\n * per-call `RunOptions` (invocation intent):\n * - `enhanceSkillWithLLM` — runs the LLM optimization pipeline and writes\n * the final SKILL.md (with cost/warning surfacing).\n * - `writePromptFiles` — emits PROMPT_*.md per section into `.skilld/`\n * for manual LLM usage (no LLM call).\n *\n * Both share the same per-section prompt assembly via `buildAllSectionPrompts`.\n */\n\nimport type { FeaturesConfig } from '../core/config.ts'\nimport type { CustomPrompt, OptimizeModel, OptimizeResult, SkillSection, StreamProgress } from './index.ts'\nimport { mkdirSync, writeFileSync } from 'node:fs'\nimport { styleText } from 'node:util'\nimport * as p from '@clack/prompts'\nimport { join, relative } from 'pathe'\nimport { createReferenceCache, listReferenceFiles } from '../cache/index.ts'\nimport { skillInternalDir } from '../core/paths.ts'\nimport {\n buildAllSectionPrompts,\n createToolProgress,\n getModelLabel,\n optimizeDocs,\n SECTION_MERGE_ORDER,\n SECTION_OUTPUT_FILES,\n wrapSection,\n writeGeneratedSkillMd,\n} from './index.ts'\n\nconst RATE_LIMIT_RE = /\\b429\\b|rate.?limit|exhausted.*capacity|quota.*reset/i\n\n/** Upstream metadata gathered during URL/content resolution. */\nexport interface ResolvedSkillMeta {\n repoUrl?: string\n llmsUrl?: string\n releasedAt?: string\n description?: string\n docsUrl?: string\n gitRef?: string\n dependencies?: Record<string, string>\n distTags?: Record<string, { version: string, releasedAt?: string }>\n}\n\n/** Reference-cache state for a skill: what's been linked under `.skilld/`. */\nexport interface SkillReferences {\n docsType: 'llms.txt' | 'readme' | 'docs'\n hasShippedDocs: boolean\n pkgFiles: string[]\n hasIssues: boolean\n hasDiscussions: boolean\n hasReleases: boolean\n hasChangelog: string | false\n}\n\n/**\n * Everything a SkillBuilder needs to know about a skill *before* deciding how\n * to invoke the LLM. Constructed by the orchestrator after fetch+link finish.\n */\nexport interface SkillContext {\n /** Identity for display/frontmatter; storage key defaults to name. */\n packageName: string\n cachePackageName?: string\n version: string\n skillDir: string\n dirName?: string\n references: SkillReferences\n resolved: ResolvedSkillMeta\n relatedSkills: string[]\n packages?: Array<{ name: string }>\n features?: FeaturesConfig\n /** Lines consumed by SKILL.md overhead (frontmatter, etc.) */\n overheadLines?: number\n}\n\n/** Per-call flags for `enhanceSkillWithLLM`. */\nexport interface EnhanceRunOptions {\n model: OptimizeModel\n force?: boolean\n debug?: boolean\n eject?: boolean\n sections?: SkillSection[]\n customPrompt?: CustomPrompt\n}\n\n/** Per-call flags for `writePromptFiles`. */\nexport interface PromptRunOptions {\n sections: SkillSection[]\n customPrompt?: CustomPrompt\n}\n\n/**\n * Pure entry: invoke the LLM, write SKILL.md on success, return the result.\n * No clack UI, no error handling — caller decides how to surface progress and\n * what to do on failure (warn vs throw).\n */\nexport async function runSkillEnhancement(\n ctx: SkillContext,\n run: EnhanceRunOptions,\n onProgress: (progress: StreamProgress) => void,\n): Promise<OptimizeResult> {\n const { packageName, cachePackageName, version, skillDir, dirName, resolved, relatedSkills, references, packages, features, overheadLines } = ctx\n const { docsType, hasShippedDocs: shippedDocs, pkgFiles, hasIssues, hasDiscussions, hasReleases, hasChangelog } = references\n const { model, force, debug, sections, customPrompt, eject } = run\n const cacheKey = cachePackageName || packageName\n\n const docFiles = listReferenceFiles(skillDir)\n const hasGithub = hasIssues || hasDiscussions\n const result = await optimizeDocs({\n packageName: cacheKey,\n skillDir,\n model,\n version,\n hasGithub,\n hasReleases,\n hasChangelog,\n docFiles,\n docsType,\n hasShippedDocs: shippedDocs,\n noCache: force,\n debug,\n sections,\n customPrompt,\n features,\n pkgFiles,\n overheadLines,\n onProgress,\n })\n\n if (result.wasOptimized) {\n writeGeneratedSkillMd(skillDir, {\n name: packageName,\n version,\n releasedAt: resolved.releasedAt,\n distTags: resolved.distTags,\n body: result.optimized,\n relatedSkills,\n hasIssues,\n hasDiscussions,\n hasReleases,\n hasChangelog,\n docsType,\n hasShippedDocs: shippedDocs,\n pkgFiles,\n generatedBy: getModelLabel(model),\n dirName,\n packages,\n repoUrl: resolved.repoUrl,\n features,\n eject,\n })\n }\n\n return result\n}\n\n/**\n * Interactive entry: wraps `runSkillEnhancement` with a clack `taskLog` and\n * surfaces cost/warnings/errors. Use this from interactive sync flows.\n */\nexport async function enhanceSkillWithLLM(ctx: SkillContext, run: EnhanceRunOptions): Promise<void> {\n const llmLog = p.taskLog({ title: `Agent exploring ${ctx.packageName}`, limit: 3 })\n const { wasOptimized, usage, cost, warnings, error, debugLogsDir } = await runSkillEnhancement(ctx, run, createToolProgress(llmLog))\n\n if (wasOptimized) {\n const costParts: string[] = []\n if (usage) {\n const totalK = Math.round(usage.totalTokens / 1000)\n costParts.push(`${totalK}k tokens`)\n }\n if (cost)\n costParts.push(`$${cost.toFixed(2)}`)\n const costSuffix = costParts.length > 0 ? ` (${costParts.join(', ')})` : ''\n llmLog.success(`Generated best practices${costSuffix}`)\n if (debugLogsDir)\n p.log.info(`Debug logs: ${relative(process.cwd(), debugLogsDir)}`)\n if (error)\n p.log.warn(styleText('yellow', `Partial failure: ${error}`))\n if (warnings?.length) {\n for (const w of warnings)\n p.log.warn(styleText('yellow', w))\n }\n }\n else {\n if (error && RATE_LIMIT_RE.test(error))\n llmLog.error(`Rate limited by LLM provider. Try again shortly or use a different model via \\`skilld config\\``)\n else\n llmLog.error(`Enhancement failed${error ? `: ${error}` : ''}`)\n }\n}\n\n/** Per-call options for `writeBaseSkill`. */\nexport interface BaseSkillOptions {\n /** LLM-generated body inserted between header and footer. */\n body?: string\n /** Label written into frontmatter (`generated_by`); use 'cached' for replays. */\n generatedBy?: string\n /** Eject mode: portable layout with `./references/` paths. */\n eject?: boolean\n}\n\n/**\n * Write the SKILL.md for `ctx`. Single seam for the writeGeneratedSkillMd\n * field-bag every sync command was assembling inline.\n *\n * Returns the written content (callers use it for line-count diagnostics).\n */\nexport function writeBaseSkill(ctx: SkillContext, opts: BaseSkillOptions = {}): string {\n const { packageName, version, skillDir, dirName, references, resolved, relatedSkills, packages, features } = ctx\n return writeGeneratedSkillMd(skillDir, {\n name: packageName,\n version,\n releasedAt: resolved.releasedAt,\n description: resolved.description,\n distTags: resolved.distTags,\n body: opts.body,\n relatedSkills,\n hasIssues: references.hasIssues,\n hasDiscussions: references.hasDiscussions,\n hasReleases: references.hasReleases,\n hasChangelog: references.hasChangelog,\n docsType: references.docsType,\n hasShippedDocs: references.hasShippedDocs,\n pkgFiles: references.pkgFiles,\n generatedBy: opts.generatedBy,\n dirName,\n packages,\n repoUrl: resolved.repoUrl,\n features,\n eject: opts.eject,\n })\n}\n\n/**\n * If every section in `sections` has cached LLM output for this package,\n * assemble the body and write SKILL.md with `generated_by: cached`.\n *\n * Returns true when applied. Caller passes `DEFAULT_SECTIONS` (or an override)\n * so the agent layer doesn't need to know about command-layer defaults.\n */\nexport function applyCachedSections(ctx: SkillContext, sections: SkillSection[], opts: { eject?: boolean } = {}): boolean {\n const cache = createReferenceCache(ctx.cachePackageName || ctx.packageName, ctx.version)\n const allCached = sections.every(s => cache.readSection(SECTION_OUTPUT_FILES[s]) !== null)\n if (!allCached)\n return false\n\n const parts: string[] = []\n for (const s of SECTION_MERGE_ORDER) {\n if (!sections.includes(s))\n continue\n const content = cache.readSection(SECTION_OUTPUT_FILES[s])\n if (content)\n parts.push(wrapSection(s, content))\n }\n writeBaseSkill(ctx, { body: parts.join('\\n\\n'), generatedBy: 'cached', eject: opts.eject })\n return true\n}\n\n/**\n * Build and write PROMPT_*.md files for manual LLM use.\n * Returns the list of sections that had prompts written.\n */\nexport function writePromptFiles(ctx: SkillContext, run: PromptRunOptions): SkillSection[] {\n const { packageName, version, skillDir, references, features, overheadLines } = ctx\n const { sections, customPrompt } = run\n const docFiles = listReferenceFiles(skillDir)\n const prompts = buildAllSectionPrompts({\n packageName,\n skillDir,\n version,\n hasIssues: references.hasIssues,\n hasDiscussions: references.hasDiscussions,\n hasReleases: references.hasReleases,\n hasChangelog: references.hasChangelog,\n docFiles,\n docsType: references.docsType,\n hasShippedDocs: references.hasShippedDocs,\n pkgFiles: references.pkgFiles,\n customPrompt,\n features,\n overheadLines,\n sections,\n })\n\n const skilldDir = skillInternalDir(skillDir)\n mkdirSync(skilldDir, { recursive: true })\n\n for (const [section, prompt] of prompts)\n writeFileSync(join(skilldDir, `PROMPT_${section}.md`), prompt)\n\n const written = [...prompts.keys()]\n if (written.length > 0) {\n const relDir = relative(process.cwd(), skillDir)\n const promptFiles = written.map(s => `PROMPT_${s}.md`).join(', ')\n const outputFileList = written.map(s => SECTION_OUTPUT_FILES[s]).join(', ')\n p.log.info(`Prompt files written to ${relDir}/.skilld/\\n${styleText(['dim', 'italic'], ` Read each prompt file (${promptFiles}) in ${relDir}/.skilld/, read the\\n referenced files, then write your output to the matching file (${outputFileList}).\\n When done, run: skilld assemble`)}`)\n }\n\n return written\n}\n","/**\n * Interactive @clack/prompts UI for LLM model + section selection.\n *\n * Three entry points:\n * - `selectModel` — pick a model (or use configured) for one-off use\n * - `selectSkillSections` — pick which SKILL.md sections to enhance\n * - `selectLlmConfig` — combined flow: model + sections + prompt-only\n * option, with update-context hints\n *\n * All return `null` on cancel/no-models/no-tty. Updates `config.model` when\n * the user picks a non-default model.\n */\n\nimport type { CustomPrompt, OptimizeModel, SkillSection } from '../agent/index.ts'\nimport { styleText } from 'node:util'\nimport * as p from '@clack/prompts'\nimport { getAvailableModels, getModelName } from '../agent/index.ts'\nimport { maxItems, maxLines } from '../agent/prompts/optional/budget.ts'\nimport { isInteractive } from '../cli/env.ts'\nimport { NO_MODELS_MESSAGE, pickModel } from '../cli/model-picker.ts'\nimport { readConfig, updateConfig } from '../core/config.ts'\nimport { semverDiff } from '../core/semver.ts'\n\n/** Default sections when model is pre-set (non-interactive) */\nexport const DEFAULT_SECTIONS: SkillSection[] = ['best-practices', 'api-changes']\n\n/**\n * Resolve the model to use when `-y` is passed without `-m`. Returns the\n * caller-supplied override, then the configured model, then the recommended\n * available model. Returns `undefined` when no model can be auto-picked\n * (skipLlm set, no `-y`, or no models installed).\n */\nexport async function resolveAutoModel(\n override: OptimizeModel | undefined,\n yes: boolean | undefined,\n): Promise<OptimizeModel | undefined> {\n if (override)\n return override\n const config = readConfig()\n if (!yes || config.skipLlm)\n return undefined\n if (config.model)\n return config.model\n const available = await getAvailableModels()\n const auto = available.find(m => m.recommended)?.id ?? available[0]?.id\n return auto as OptimizeModel | undefined\n}\n\n/** Select LLM model for SKILL.md generation (independent of target agent) */\nexport async function selectModel(skipPrompt: boolean): Promise<OptimizeModel | null> {\n const config = readConfig()\n const available = await getAvailableModels()\n\n if (available.length === 0) {\n p.log.warn(NO_MODELS_MESSAGE)\n return null\n }\n\n if (skipPrompt) {\n if (config.model && available.some(m => m.id === config.model))\n return config.model\n if (config.model)\n p.log.warn(`Configured model ${styleText('cyan', config.model)} is unavailable — using auto-selected fallback`)\n return available.find(m => m.recommended)?.id ?? available[0]!.id\n }\n\n const choice = await pickModel(available)\n if (!choice)\n return null\n\n updateConfig({ model: choice as OptimizeModel })\n return choice as OptimizeModel\n}\n\nexport async function selectSkillSections(message = 'Enhance SKILL.md'): Promise<{ sections: SkillSection[], customPrompt?: CustomPrompt, cancelled: boolean }> {\n p.log.info('Budgets adapt to package release density.')\n const selected = await p.multiselect({\n message,\n options: [\n { label: 'API changes', value: 'api-changes' as SkillSection, hint: 'new/deprecated APIs from version history' },\n { label: 'Best practices', value: 'best-practices' as SkillSection, hint: 'gotchas, pitfalls, patterns' },\n { label: 'Custom section', value: 'custom' as SkillSection, hint: 'add your own section' },\n ],\n initialValues: DEFAULT_SECTIONS,\n required: false,\n })\n\n if (p.isCancel(selected))\n return { sections: [], cancelled: true }\n\n const sections = selected as SkillSection[]\n if (sections.length === 0)\n return { sections: [], cancelled: false }\n\n if (sections.length > 1) {\n const n = sections.length\n const budgetLines: string[] = []\n for (const s of sections) {\n switch (s) {\n case 'api-changes':\n budgetLines.push(` API changes ${maxItems(6, 12, n)}–${maxItems(6, Math.round(12 * 1.6), n)} items (adapts to release churn)`)\n break\n case 'best-practices':\n budgetLines.push(` Best practices ${maxItems(4, 10, n)}–${maxItems(4, Math.round(10 * 1.3), n)} items`)\n break\n case 'custom':\n budgetLines.push(` Custom ≤${maxLines(50, 80, n)} lines`)\n break\n }\n }\n p.log.info(`Budget (${n} sections):\\n${budgetLines.join('\\n')}`)\n }\n\n let customPrompt: CustomPrompt | undefined\n if (sections.includes('custom')) {\n const heading = await p.text({\n message: 'Section heading',\n placeholder: 'e.g. \"Migration from v2\" or \"SSR Patterns\"',\n })\n if (p.isCancel(heading))\n return { sections: [], cancelled: true }\n\n const body = await p.text({\n message: 'Instructions for this section',\n placeholder: 'e.g. \"Document breaking changes and migration steps from v2 to v3\"',\n })\n if (p.isCancel(body))\n return { sections: [], cancelled: true }\n\n customPrompt = { heading: heading as string, body: body as string }\n }\n\n return { sections, customPrompt, cancelled: false }\n}\n\nexport interface LlmConfig {\n model: OptimizeModel\n sections: SkillSection[]\n customPrompt?: CustomPrompt\n promptOnly?: boolean\n}\n\n/** Context about the existing skill when running an update (not a fresh add). */\nexport interface UpdateContext {\n oldVersion?: string\n newVersion?: string\n syncedAt?: string\n /** Whether the existing SKILL.md was LLM-enhanced (has generated_by in frontmatter). */\n wasEnhanced: boolean\n /** Pre-computed bump type (used by parallel sync to pass the max across packages). */\n bumpType?: string\n}\n\n/**\n * Resolve sections + model for LLM enhancement.\n * If presetModel is provided, uses DEFAULT_SECTIONS without prompting.\n * Returns null if cancelled or no sections/model selected.\n */\nexport async function selectLlmConfig(presetModel?: OptimizeModel, message?: string, updateCtx?: UpdateContext): Promise<LlmConfig | null> {\n if (presetModel) {\n const available = await getAvailableModels()\n if (available.some(m => m.id === presetModel))\n return { model: presetModel, sections: DEFAULT_SECTIONS }\n if (!isInteractive())\n return null\n }\n\n if (!isInteractive())\n return null\n\n const config = readConfig()\n const available = await getAvailableModels()\n\n if (available.length === 0) {\n p.log.warn(NO_MODELS_MESSAGE)\n return null\n }\n\n let defaultModel: OptimizeModel\n if (config.model && available.some(m => m.id === config.model)) {\n defaultModel = config.model\n }\n else {\n if (config.model)\n p.log.warn(`Configured model ${styleText('cyan', config.model)} is unavailable — using auto-selected fallback`)\n defaultModel = (available.find(m => m.recommended)?.id ?? available[0]!.id) as OptimizeModel\n }\n\n const defaultModelName = getModelName(defaultModel)\n const defaultModelInfo = available.find(m => m.id === defaultModel)\n const providerHint = defaultModelInfo?.providerName ?? ''\n const sourceHint = config.model === defaultModel ? 'configured' : 'recommended'\n const defaultHint = providerHint ? `${providerHint} · ${sourceHint}` : sourceHint\n\n let enhanceMessage = message ? `${message}?` : 'Enhance SKILL.md?'\n let defaultToSkip = false\n if (updateCtx) {\n const diff = updateCtx.bumpType\n ?? (updateCtx.oldVersion && updateCtx.newVersion ? semverDiff(updateCtx.oldVersion, updateCtx.newVersion) : null)\n const isSmallBump = diff === 'patch' || diff === 'prerelease' || diff === 'prepatch' || diff === 'preminor' || diff === 'premajor'\n\n const ageParts: string[] = []\n if (diff)\n ageParts.push(diff)\n if (updateCtx.syncedAt) {\n const syncedAtMs = new Date(updateCtx.syncedAt).getTime()\n if (Number.isFinite(syncedAtMs)) {\n const days = Math.floor((Date.now() - syncedAtMs) / 86_400_000)\n ageParts.push(days === 0 ? 'today' : days === 1 ? '1d ago' : `${days}d ago`)\n }\n }\n if (updateCtx.wasEnhanced)\n ageParts.push('LLM-enhanced')\n\n const versionHint = updateCtx.oldVersion && updateCtx.newVersion\n ? `${updateCtx.oldVersion} → ${updateCtx.newVersion}`\n : null\n const hint = [versionHint, ...ageParts].filter(Boolean).join(' · ')\n if (hint)\n enhanceMessage = `Enhance SKILL.md? ${styleText('gray', `(${hint})`)}`\n\n if (updateCtx.wasEnhanced && isSmallBump)\n defaultToSkip = true\n }\n\n const choice = await p.select({\n message: enhanceMessage,\n options: [\n { label: defaultModelName, value: 'default' as const, hint: defaultHint },\n { label: 'Different model', value: 'pick' as const, hint: 'choose another enhancement model' },\n { label: 'Prompt only', value: 'prompt' as const, hint: 'write prompts for manual use' },\n { label: 'Skip', value: 'skip' as const, hint: 'base skill with docs, issues, and types' },\n ],\n ...(defaultToSkip ? { initialValue: 'skip' as const } : {}),\n })\n\n if (p.isCancel(choice))\n return null\n\n if (choice === 'skip')\n return null\n\n if (choice === 'prompt') {\n const { sections, customPrompt, cancelled } = await selectSkillSections(\n message ? `${message} (prompt only)` : 'Select sections for prompt generation',\n )\n if (cancelled || sections.length === 0)\n return null\n return { model: defaultModel, sections, customPrompt, promptOnly: true }\n }\n\n let model: OptimizeModel\n if (choice === 'pick') {\n const picked = await pickModel(available)\n if (!picked)\n return null\n updateConfig({ model: picked as OptimizeModel })\n model = picked as OptimizeModel\n }\n else {\n model = defaultModel\n }\n if (!model)\n return null\n\n const modelName = getModelName(model)\n const { sections, customPrompt, cancelled } = await selectSkillSections(\n message ? `${message} (${modelName})` : `Enhance SKILL.md with ${modelName}`,\n )\n\n if (cancelled || sections.length === 0)\n return null\n\n return { model, sections, customPrompt }\n}\n","/**\n * Search-index pipeline: builds and incrementally updates the per-package\n * sqlite-vec database.\n *\n * Wraps `createIndex` / `listIndexIds` with the higher-level concerns of\n * adding `pkg/` entry files, capping doc count, computing diffs against the\n * existing index, and gracefully degrading when native deps are unavailable.\n */\n\nimport type { FeaturesConfig } from '../core/config.ts'\nimport type { IndexDoc } from '../sources/content-resolver.ts'\nimport { existsSync } from 'node:fs'\nimport { getPackageDbPath } from '../cache/index.ts'\nimport { defaultFeatures, readConfig } from '../core/config.ts'\nimport { resolvePkgDir } from '../core/prepare.ts'\nimport { resolveEntryFiles } from '../sources/index.ts'\nimport { createIndex, listIndexIds, SearchDepsUnavailableError } from './index.ts'\n\n/** Max docs sent to the embedding pipeline to prevent oversized indexes */\nexport const MAX_INDEX_DOCS = 250\n\n/**\n * Extract the parent document ID from a chunk ID.\n * Chunk IDs have the form \"docId#chunk-N\"; non-chunk IDs return as-is.\n */\nfunction parentDocId(id: string): string {\n const idx = id.indexOf('#chunk-')\n return idx === -1 ? id : id.slice(0, idx)\n}\n\n/** Cap and sort docs by type priority, mutates and truncates allDocs in place */\nfunction capDocs(allDocs: IndexDoc[], max: number, onProgress: (msg: string) => void): void {\n if (allDocs.length <= max)\n return\n const TYPE_PRIORITY: Record<string, number> = { doc: 0, issue: 1, discussion: 2, release: 3, source: 4, types: 5 }\n allDocs.sort((a, b) => {\n const ta = TYPE_PRIORITY[a.metadata?.type || 'doc'] ?? 3\n const tb = TYPE_PRIORITY[b.metadata?.type || 'doc'] ?? 3\n if (ta !== tb)\n return ta - tb\n return a.id.localeCompare(b.id)\n })\n onProgress(`Indexing capped at ${max}/${allDocs.length} docs (prioritized by type)`)\n allDocs.length = max\n}\n\nexport interface IndexResourcesOptions {\n packageName: string\n version: string\n cwd: string\n docsToIndex: IndexDoc[]\n features?: FeaturesConfig\n onProgress: (message: string) => void\n}\n\n/** Index all resources into the search database, with incremental support */\nexport async function indexResources(opts: IndexResourcesOptions): Promise<void> {\n const { packageName, version, cwd, onProgress } = opts\n const features = opts.features ?? readConfig().features ?? defaultFeatures\n\n if (!features.search)\n return\n\n const dbPath = getPackageDbPath(packageName, version)\n const dbExists = existsSync(dbPath)\n\n const allDocs = [...opts.docsToIndex]\n\n // Add entry files\n const pkgDir = resolvePkgDir(packageName, cwd, version)\n if (features.search && pkgDir) {\n onProgress('Scanning exports')\n const entryFiles = await resolveEntryFiles(pkgDir)\n for (const e of entryFiles) {\n allDocs.push({\n id: e.path,\n content: e.content,\n metadata: { package: packageName, source: `pkg/${e.path}`, type: e.type },\n })\n }\n }\n\n if (allDocs.length === 0)\n return\n\n capDocs(allDocs, MAX_INDEX_DOCS, onProgress)\n\n // Full build when no existing DB\n if (!dbExists) {\n onProgress(`Building search index (${allDocs.length} docs)`)\n try {\n await createIndex(allDocs, {\n dbPath,\n onProgress: ({ phase, current, total }) => {\n if (phase === 'storing') {\n const d = allDocs[current - 1]\n const type = d?.metadata?.type === 'source' || d?.metadata?.type === 'types' ? 'code' : (d?.metadata?.type || 'doc')\n onProgress(`Storing ${type} (${current}/${total})`)\n }\n else if (phase === 'embedding') {\n onProgress(`Creating embeddings (${current}/${total})`)\n }\n },\n })\n }\n catch (err) {\n if (err instanceof SearchDepsUnavailableError)\n onProgress('Search indexing skipped (native deps unavailable)')\n else\n throw err\n }\n return\n }\n\n // Incremental update: diff incoming docs against existing index\n let existingIds: string[]\n try {\n existingIds = await listIndexIds({ dbPath })\n }\n catch (err) {\n if (err instanceof SearchDepsUnavailableError) {\n onProgress('Search indexing skipped (native deps unavailable)')\n return\n }\n throw err\n }\n\n const existingParentIds = new Set(existingIds.map(parentDocId))\n const incomingIds = new Set(allDocs.map(d => d.id))\n\n const newDocs = allDocs.filter(d => !existingParentIds.has(d.id))\n const removeIds = existingIds.filter(id => !incomingIds.has(parentDocId(id)))\n\n if (newDocs.length === 0 && removeIds.length === 0) {\n onProgress('Search index up to date')\n return\n }\n\n const parts: string[] = []\n if (newDocs.length > 0)\n parts.push(`+${newDocs.length} new`)\n if (removeIds.length > 0)\n parts.push(`-${removeIds.length} stale`)\n onProgress(`Updating search index (${parts.join(', ')})`)\n\n try {\n await createIndex(newDocs, {\n dbPath,\n removeIds,\n onProgress: ({ phase, current, total }) => {\n if (phase === 'storing') {\n const d = newDocs[current - 1]\n const type = d?.metadata?.type === 'source' || d?.metadata?.type === 'types' ? 'code' : (d?.metadata?.type || 'doc')\n onProgress(`Storing ${type} (${current}/${total})`)\n }\n else if (phase === 'embedding') {\n onProgress(`Creating embeddings (${current}/${total})`)\n }\n },\n })\n }\n catch (err) {\n if (err instanceof SearchDepsUnavailableError)\n onProgress('Search indexing skipped (native deps unavailable)')\n else\n throw err\n }\n}\n","/**\n * Tiny cascade walker for content + timeline resolvers.\n *\n * Each step is `{ id, canResolve?, run }`. Steps mutate a shared `ctx`\n * accumulator in order. Unlike URL resolution there is no fatal/skip outcome —\n * steps return void; `canResolve` short-circuits cheap pre-checks.\n */\n\nexport interface StepResolver<TCtx> {\n id: string\n canResolve?: (ctx: TCtx) => boolean\n run: (ctx: TCtx) => Promise<void>\n}\n\nexport function defineStep<TCtx>(step: StepResolver<TCtx>): StepResolver<TCtx> {\n return step\n}\n\nexport async function walkSteps<TCtx>(steps: ReadonlyArray<StepResolver<TCtx>>, ctx: TCtx): Promise<void> {\n for (const step of steps) {\n if (step.canResolve && !step.canResolve(ctx))\n continue\n await step.run(ctx)\n }\n}\n","/**\n * Registry-configured crawl-URL step: fetch docs from a curated crawl pattern\n * (e.g. motion-v's website). Runs only when no primary docs are committed yet.\n */\n\nimport type { StepResolver } from '../cascade.ts'\nimport type { ContentCtx } from './types.ts'\nimport { fetchCrawledDocs } from '../../crawl.ts'\nimport { defineStep } from '../cascade.ts'\n\nexport const crawlUrlStep: StepResolver<ContentCtx> = defineStep<ContentCtx>({\n id: 'crawl-url',\n canResolve: ctx => !!ctx.resolved.crawlUrl && ctx.docs.length === 0,\n async run(ctx) {\n const crawlUrl = ctx.resolved.crawlUrl!\n ctx.onProgress('Crawling website')\n const crawled = await fetchCrawledDocs(crawlUrl, ctx.onProgress).catch((err) => {\n ctx.warnings.push(`Crawl failed for ${crawlUrl}: ${err?.message || err}`)\n return []\n })\n if (crawled.length === 0)\n ctx.warnings.push(`Crawl returned 0 docs from ${crawlUrl}`)\n\n let added = 0\n for (const doc of crawled) {\n if (!ctx.isFrameworkDoc(doc.path))\n continue\n ctx.docs.push(doc)\n ctx.docsToIndex.push({\n id: doc.path,\n content: doc.content,\n metadata: { package: ctx.packageName, source: doc.path, type: 'doc' },\n })\n added++\n }\n if (added > 0) {\n ctx.docSource = crawlUrl\n ctx.docsType = 'docs'\n }\n },\n})\n","/**\n * docsUrl fallback crawl: when no actual doc files have been committed yet,\n * crawl the package's documentation site via its sitemap / docsUrl pattern.\n */\n\nimport type { StepResolver } from '../cascade.ts'\nimport type { ContentCtx } from './types.ts'\nimport { fetchCrawledDocs, toCrawlPattern } from '../../crawl.ts'\nimport { defineStep } from '../cascade.ts'\n\nexport const docsCrawlStep: StepResolver<ContentCtx> = defineStep<ContentCtx>({\n id: 'docs-crawl',\n canResolve: ctx => !!ctx.resolved.docsUrl && !ctx.docs.some(d => d.path.startsWith('docs/')),\n async run(ctx) {\n const crawlPattern = ctx.resolved.crawlUrl || toCrawlPattern(ctx.resolved.docsUrl!)\n ctx.onProgress('Crawling docs site')\n const maxPages = ctx.resolved.crawlUrl ? 200 : 400\n const crawled = await fetchCrawledDocs(crawlPattern, ctx.onProgress, maxPages).catch((err) => {\n ctx.warnings.push(`Crawl failed for ${crawlPattern}: ${err?.message || err}`)\n return []\n })\n let added = 0\n for (const doc of crawled) {\n if (!ctx.isFrameworkDoc(doc.path))\n continue\n ctx.docs.push(doc)\n ctx.docsToIndex.push({\n id: doc.path,\n content: doc.content,\n metadata: { package: ctx.packageName, source: doc.path, type: 'doc' },\n })\n added++\n }\n if (added > 0) {\n ctx.docSource = crawlPattern\n ctx.docsType = 'docs'\n }\n },\n})\n","/**\n * Versioned git-docs step: fetch `docs/**` at the package's git tag.\n *\n * Two outcomes:\n * - Enough docs found → commit as primary (ctx.docsType='docs'), and also\n * cache the package's `llms.txt` + linked supplementary docs.\n * - \"Shallow\" result with an `llms.txt` available → write nothing and let\n * the llms.txt step take over. A warning records the fallback ref.\n */\n\nimport type { CachedDoc, IndexDoc } from '../../content-resolver.ts'\nimport type { StepResolver } from '../cascade.ts'\nimport type { ContentCtx } from './types.ts'\nimport { join } from 'pathe'\nimport { parseGitHubUrl } from '../../../core/url.ts'\nimport { fetchGitDocs, isShallowGitDocs } from '../../github.ts'\nimport { downloadLlmsDocs, fetchLlmsTxt, normalizeLlmsLinks } from '../../llms.ts'\nimport { fetchGitHubRaw } from '../../utils.ts'\nimport { defineStep } from '../cascade.ts'\n\nconst BATCH_SIZE = 20\n\nexport const gitDocsStep: StepResolver<ContentCtx> = defineStep<ContentCtx>({\n id: 'git-docs',\n canResolve: ctx => !!ctx.resolved.gitDocsUrl && !!ctx.resolved.repoUrl,\n async run(ctx) {\n const gh = parseGitHubUrl(ctx.resolved.repoUrl!)\n if (!gh)\n return\n\n ctx.onProgress('Fetching git docs')\n const gitDocs = await fetchGitDocs(gh.owner, gh.repo, ctx.version, ctx.packageName)\n if (!gitDocs || gitDocs.files.length === 0)\n return\n\n if (gitDocs.fallback)\n ctx.warnings.push(`Docs fetched from ${gitDocs.ref} branch (no tag found for v${ctx.version})`)\n\n const results: Array<{ file: string, content: string } | null> = []\n for (let i = 0; i < gitDocs.files.length; i += BATCH_SIZE) {\n const batch = gitDocs.files.slice(i, i + BATCH_SIZE)\n ctx.onProgress(`Downloading docs ${Math.min(i + BATCH_SIZE, gitDocs.files.length)}/${gitDocs.files.length} from ${gitDocs.ref}`)\n const batchResults = await Promise.all(\n batch.map(async (file) => {\n const url = `${gitDocs.baseUrl}/${file}`\n const content = await fetchGitHubRaw(url)\n return content ? { file, content } : null\n }),\n )\n results.push(...batchResults)\n }\n\n const docs: CachedDoc[] = []\n const docsToIndex: IndexDoc[] = []\n for (const r of results) {\n if (!r)\n continue\n const stripped = gitDocs.docsPrefix ? r.file.replace(gitDocs.docsPrefix, '') : r.file\n const cachePath = stripped.startsWith('docs/') ? stripped : `docs/${stripped}`\n docs.push({ path: cachePath, content: r.content })\n docsToIndex.push({\n id: cachePath,\n content: r.content,\n metadata: { package: ctx.packageName, source: cachePath, type: 'doc' },\n })\n }\n\n // Shallow git-docs: defer to llms.txt step (don't commit anything yet).\n if (isShallowGitDocs(docs.length) && ctx.resolved.llmsUrl) {\n ctx.onProgress(`Shallow git-docs (${docs.length} files), trying llms.txt`)\n return\n }\n\n ctx.docs.push(...docs)\n ctx.docsToIndex.push(...docsToIndex)\n ctx.docSource = `${ctx.resolved.repoUrl}/tree/${gitDocs.ref}/docs`\n ctx.docsType = 'docs'\n\n // Always cache llms.txt alongside good git-docs as supplementary reference.\n if (ctx.resolved.llmsUrl) {\n ctx.onProgress('Caching supplementary llms.txt')\n const llmsContent = await fetchLlmsTxt(ctx.resolved.llmsUrl)\n if (llmsContent) {\n const baseUrl = ctx.resolved.docsUrl || new URL(ctx.resolved.llmsUrl).origin\n ctx.docs.push({ path: 'llms.txt', content: normalizeLlmsLinks(llmsContent.raw, baseUrl) })\n if (llmsContent.links.length > 0) {\n ctx.onProgress(`Downloading ${llmsContent.links.length} supplementary docs`)\n const supplementary = await downloadLlmsDocs(llmsContent, baseUrl, (_url, done, total) => {\n ctx.onProgress(`Downloading supplementary doc ${done + 1}/${total}`)\n })\n for (const doc of supplementary) {\n if (!ctx.isFrameworkDoc(doc.url))\n continue\n const localPath = doc.url.startsWith('/') ? doc.url.slice(1) : doc.url\n ctx.docs.push({ path: join('llms-docs', ...localPath.split('/')), content: doc.content })\n }\n }\n }\n }\n },\n})\n","/**\n * llms.txt step: fetch the package's `llms.txt`, download linked docs.\n * Runs only when no primary docs are committed yet.\n */\n\nimport type { StepResolver } from '../cascade.ts'\nimport type { ContentCtx } from './types.ts'\nimport { join } from 'pathe'\nimport { downloadLlmsDocs, fetchLlmsTxt, normalizeLlmsLinks } from '../../llms.ts'\nimport { defineStep } from '../cascade.ts'\n\nexport const llmsTxtStep: StepResolver<ContentCtx> = defineStep<ContentCtx>({\n id: 'llms.txt',\n canResolve: ctx => !!ctx.resolved.llmsUrl && ctx.docs.length === 0,\n async run(ctx) {\n const llmsUrl = ctx.resolved.llmsUrl!\n ctx.onProgress('Fetching llms.txt')\n const llmsContent = await fetchLlmsTxt(llmsUrl)\n if (!llmsContent)\n return\n\n ctx.docSource = llmsUrl\n ctx.docsType = 'llms.txt'\n const baseUrl = ctx.resolved.docsUrl || new URL(llmsUrl).origin\n ctx.docs.push({ path: 'llms.txt', content: normalizeLlmsLinks(llmsContent.raw, baseUrl) })\n\n if (llmsContent.links.length > 0) {\n ctx.onProgress(`Downloading ${llmsContent.links.length} linked docs`)\n const linked = await downloadLlmsDocs(llmsContent, baseUrl, (_url, done, total) => {\n ctx.onProgress(`Downloading linked doc ${done + 1}/${total}`)\n })\n for (const doc of linked) {\n if (!ctx.isFrameworkDoc(doc.url))\n continue\n const localPath = doc.url.startsWith('/') ? doc.url.slice(1) : doc.url\n const cachePath = join('docs', ...localPath.split('/'))\n ctx.docs.push({ path: cachePath, content: doc.content })\n ctx.docsToIndex.push({\n id: doc.url,\n content: doc.content,\n metadata: { package: ctx.packageName, source: cachePath, type: 'doc' },\n })\n }\n if (linked.length > 0)\n ctx.docsType = 'docs'\n }\n },\n})\n","/**\n * README fallback: last-resort primary doc when nothing else committed.\n */\n\nimport type { StepResolver } from '../cascade.ts'\nimport type { ContentCtx } from './types.ts'\nimport { fetchReadmeContent } from '../../github.ts'\nimport { defineStep } from '../cascade.ts'\n\nexport const readmeStep: StepResolver<ContentCtx> = defineStep<ContentCtx>({\n id: 'readme',\n canResolve: ctx => !!ctx.resolved.readmeUrl && ctx.docs.length === 0,\n async run(ctx) {\n ctx.onProgress('Fetching README')\n const content = await fetchReadmeContent(ctx.resolved.readmeUrl!)\n if (!content)\n return\n ctx.docs.push({ path: 'docs/README.md', content })\n ctx.docsToIndex.push({\n id: 'README.md',\n content,\n metadata: { package: ctx.packageName, source: 'docs/README.md', type: 'doc' },\n })\n },\n})\n","/**\n * Default content cascade order. Order is load-bearing.\n *\n * 1. git-docs — versioned docs/** at the package's git tag\n * 2. crawl-url — registry-configured crawl pattern (e.g. motion-v)\n * 3. llms-txt — package's llms.txt + linked docs\n * 4. docs-crawl — sitemap-driven crawl of docsUrl\n * 5. readme — README fallback\n */\n\nimport type { StepResolver } from '../cascade.ts'\nimport type { ContentCtx } from './types.ts'\nimport { crawlUrlStep } from './crawl-url.ts'\nimport { docsCrawlStep } from './docs-crawl.ts'\nimport { gitDocsStep } from './git-docs.ts'\nimport { llmsTxtStep } from './llms-txt.ts'\nimport { readmeStep } from './readme.ts'\n\nexport type { ContentCtx } from './types.ts'\n\nexport const defaultContentSteps: ReadonlyArray<StepResolver<ContentCtx>> = [\n gitDocsStep,\n crawlUrlStep,\n llmsTxtStep,\n docsCrawlStep,\n readmeStep,\n]\n","/**\n * Content cascade: resolve in-memory docs for a package given its already-resolved URLs.\n *\n * Pure: no fs writes. The caller owns persistence; a single cache-write seam.\n *\n * Cascade order is defined by `defaultContentSteps` in\n * `./resolvers/content/index.ts`. Each step is a `StepResolver<ContentCtx>`\n * with its own `canResolve` predicate; see step files for the full ladder.\n */\n\nimport type { ContentCtx } from './resolvers/content/index.ts'\nimport type { ResolvedPackage } from './types.ts'\nimport { filterFrameworkDocs } from './github.ts'\nimport { walkSteps } from './resolvers/cascade.ts'\nimport { defaultContentSteps } from './resolvers/content/index.ts'\n\nexport interface CachedDoc {\n path: string\n content: string\n}\n\nexport interface IndexDoc {\n id: string\n content: string\n metadata: Record<string, any>\n}\n\nexport interface ResolvedContent {\n /** Docs to persist to the package cache (path is cache-relative) */\n docs: CachedDoc[]\n /** Docs to feed the embedding index (id may differ from cache path) */\n docsToIndex: IndexDoc[]\n /** Human-readable origin (URL or label) of the chosen primary source */\n docSource: string\n /** Which kind of source won */\n docsType: 'docs' | 'llms.txt' | 'readme'\n /** Non-fatal issues to surface to the user */\n warnings: string[]\n}\n\nexport interface ResolveContentOptions {\n packageName: string\n resolved: ResolvedPackage\n version: string\n onProgress: (message: string) => void\n}\n\nexport async function resolveContentDocs(opts: ResolveContentOptions): Promise<ResolvedContent> {\n const { packageName, resolved, version, onProgress } = opts\n\n const ctx: ContentCtx = {\n packageName,\n resolved,\n version,\n onProgress,\n isFrameworkDoc: path => filterFrameworkDocs([path], packageName).length > 0,\n docs: [],\n docsToIndex: [],\n warnings: [],\n docSource: resolved.readmeUrl || 'readme',\n docsType: 'readme',\n }\n\n await walkSteps(defaultContentSteps, ctx)\n\n return {\n docs: ctx.docs,\n docsToIndex: ctx.docsToIndex,\n docSource: ctx.docSource,\n docsType: ctx.docsType,\n warnings: ctx.warnings,\n }\n}\n","/**\n * Discussions step: fetch GitHub discussions, write to repo cache,\n * queue for the search index.\n */\n\nimport type { StepResolver } from '../cascade.ts'\nimport type { TimelineCtx } from './types.ts'\nimport { existsSync } from 'node:fs'\nimport { writeToRepoCache } from '../../../cache/internal/storage.ts'\nimport { sanitizeMarkdown } from '../../../core/sanitize.ts'\nimport { fetchGitHubDiscussions, formatDiscussionAsMarkdown, generateDiscussionIndex } from '../../discussions.ts'\nimport { isGhAvailable } from '../../issues.ts'\nimport { defineStep } from '../cascade.ts'\n\nexport const discussionsStep: StepResolver<TimelineCtx> = defineStep<TimelineCtx>({\n id: 'discussions',\n canResolve: ctx => ctx.features.discussions && !!ctx.repoInfo && isGhAvailable() && !existsSync(ctx.discussionsDir),\n async run(ctx) {\n const { owner, repo } = ctx.repoInfo!\n ctx.onProgress('Fetching discussions via GitHub API')\n const discussions = await fetchGitHubDiscussions(owner, repo, 20, ctx.resolved.releasedAt, ctx.from).catch(() => [])\n if (discussions.length === 0)\n return\n\n ctx.onProgress(`Caching ${discussions.length} discussions`)\n const docs = [\n ...discussions.map(d => ({\n path: `discussions/discussion-${d.number}.md`,\n content: formatDiscussionAsMarkdown(d),\n })),\n { path: 'discussions/_INDEX.md', content: generateDiscussionIndex(discussions) },\n ]\n writeToRepoCache(owner, repo, docs)\n\n for (const d of discussions) {\n ctx.docsToIndex.push({\n id: `discussion-${d.number}`,\n content: sanitizeMarkdown(`#${d.number}: ${d.title}\\n\\n${d.body || ''}`),\n metadata: { package: ctx.packageName, source: `discussions/discussion-${d.number}.md`, type: 'discussion', number: d.number },\n })\n }\n },\n})\n","/**\n * Issues step: fetch GitHub issues, write them to the repo-cache (or per-package\n * cache when the repo is unknown), and queue them for the search index.\n *\n * Skipped when cache already populated (existsSync guard).\n */\n\nimport type { StepResolver } from '../cascade.ts'\nimport type { TimelineCtx } from './types.ts'\nimport { existsSync } from 'node:fs'\nimport { writeToRepoCache } from '../../../cache/internal/storage.ts'\nimport { sanitizeMarkdown } from '../../../core/sanitize.ts'\nimport { fetchGitHubIssues, formatIssueAsMarkdown, generateIssueIndex, isGhAvailable } from '../../issues.ts'\nimport { defineStep } from '../cascade.ts'\n\nexport const issuesStep: StepResolver<TimelineCtx> = defineStep<TimelineCtx>({\n id: 'issues',\n canResolve: ctx => ctx.features.issues && !!ctx.repoInfo && isGhAvailable() && !existsSync(ctx.issuesDir),\n async run(ctx) {\n const { owner, repo } = ctx.repoInfo!\n ctx.onProgress('Fetching issues via GitHub API')\n const issues = await fetchGitHubIssues(owner, repo, 30, ctx.resolved.releasedAt, ctx.from).catch(() => [])\n if (issues.length === 0)\n return\n\n ctx.onProgress(`Caching ${issues.length} issues`)\n const docs = [\n ...issues.map(issue => ({\n path: `issues/issue-${issue.number}.md`,\n content: formatIssueAsMarkdown(issue),\n })),\n { path: 'issues/_INDEX.md', content: generateIssueIndex(issues) },\n ]\n writeToRepoCache(owner, repo, docs)\n\n for (const issue of issues) {\n ctx.docsToIndex.push({\n id: `issue-${issue.number}`,\n content: sanitizeMarkdown(`#${issue.number}: ${issue.title}\\n\\n${issue.body || ''}`),\n metadata: { package: ctx.packageName, source: `issues/issue-${issue.number}.md`, type: 'issue', number: issue.number },\n })\n }\n },\n})\n","/**\n * Releases step: GitHub releases + curated blog releases + CHANGELOG, unified\n * into a single `releases/` cache dir.\n */\n\nimport type { StepResolver } from '../cascade.ts'\nimport type { TimelineCtx } from './types.ts'\nimport { existsSync } from 'node:fs'\nimport { writeToRepoCache } from '../../../cache/internal/storage.ts'\nimport { parseFrontmatter } from '../../../core/markdown.ts'\nimport { fetchBlogReleases } from '../../blog-releases.ts'\nimport { isGhAvailable } from '../../issues.ts'\nimport { getBlogPreset, getPrereleaseChangelogRef } from '../../package-registry.ts'\nimport { fetchReleaseNotes, generateReleaseIndex, isPrerelease } from '../../releases.ts'\nimport { defineStep } from '../cascade.ts'\n\nconst BLOG_VERSION_RE = /blog-(.+)\\.md$/\n\nexport const releasesStep: StepResolver<TimelineCtx> = defineStep<TimelineCtx>({\n id: 'releases',\n canResolve: ctx => ctx.features.releases && !!ctx.repoInfo && isGhAvailable() && !existsSync(ctx.releasesPath),\n async run(ctx) {\n const { owner, repo } = ctx.repoInfo!\n const { packageName, version, resolved, from } = ctx\n\n ctx.onProgress('Fetching releases via GitHub API')\n const changelogRef = isPrerelease(version) ? getPrereleaseChangelogRef(packageName) : undefined\n const releaseDocs = await fetchReleaseNotes(owner, repo, version, resolved.gitRef, packageName, from, changelogRef).catch(() => [])\n\n let blogDocs: Array<{ path: string, content: string }> = []\n if (getBlogPreset(packageName)) {\n ctx.onProgress('Fetching blog release notes')\n blogDocs = await fetchBlogReleases(packageName, version).catch(() => [])\n }\n\n const allDocs = [...releaseDocs, ...blogDocs]\n\n const blogEntries = blogDocs\n .filter(d => !d.path.endsWith('_INDEX.md'))\n .map((d) => {\n const versionMatch = d.path.match(BLOG_VERSION_RE)\n const fm = parseFrontmatter(d.content)\n return {\n version: versionMatch?.[1] ?? '',\n title: fm.title ?? `Release ${versionMatch?.[1]}`,\n date: fm.date ?? '',\n }\n })\n .filter(b => b.version)\n\n const ghReleases = releaseDocs\n .filter(d => d.path.startsWith('releases/') && !d.path.endsWith('CHANGELOG.md'))\n .map((d) => {\n const fm = parseFrontmatter(d.content)\n const tag = fm.tag ?? ''\n const name = fm.name ?? tag\n const published = fm.published ?? ''\n return { id: 0, tag, name, prerelease: false, createdAt: published, publishedAt: published, markdown: '' }\n })\n .filter(r => r.tag)\n\n const hasChangelog = allDocs.some(d => d.path === 'releases/CHANGELOG.md')\n\n if (ghReleases.length > 0 || blogEntries.length > 0) {\n allDocs.push({\n path: 'releases/_INDEX.md',\n content: generateReleaseIndex({ releases: ghReleases, packageName, blogReleases: blogEntries, hasChangelog }),\n })\n }\n\n if (allDocs.length === 0)\n return\n\n ctx.onProgress(`Caching ${allDocs.length} releases`)\n writeToRepoCache(owner, repo, allDocs)\n for (const doc of allDocs) {\n ctx.docsToIndex.push({\n id: doc.path,\n content: doc.content,\n metadata: { package: packageName, source: doc.path, type: 'release' },\n })\n }\n },\n})\n","/**\n * Default timeline cascade. Order is independent (each step has its own\n * existsSync guard) but kept stable for telemetry consistency:\n * 1. issues 2. discussions 3. releases\n */\n\nimport type { StepResolver } from '../cascade.ts'\nimport type { TimelineCtx } from './types.ts'\nimport { discussionsStep } from './discussions.ts'\nimport { issuesStep } from './issues.ts'\nimport { releasesStep } from './releases.ts'\n\nexport type { TimelineCtx } from './types.ts'\n\nexport const defaultTimelineSteps: ReadonlyArray<StepResolver<TimelineCtx>> = [\n issuesStep,\n discussionsStep,\n releasesStep,\n]\n","/**\n * Timeline-references cascade: GitHub issues, discussions, and releases.\n *\n * Each step is a `StepResolver<TimelineCtx>` in `./resolvers/timeline/`,\n * with its own `existsSync` cache guard and feature-flag gate. Repo-level\n * data lives at `~/.skilld/references/<owner>/<repo>/{issues,discussions,releases}/`\n * when a GitHub repo is known; otherwise the cascade skips (no per-package\n * fallback — that path was unreachable since each step needs owner/repo to\n * call the GitHub API).\n */\n\nimport type { FeaturesConfig } from '../core/config.ts'\nimport type { IndexDoc } from './content-resolver.ts'\nimport type { TimelineCtx } from './resolvers/timeline/index.ts'\nimport type { ResolvedPackage } from './types.ts'\nimport { existsSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { getCacheDir, getRepoCacheDir } from '../cache/index.ts'\nimport { parseGitHubUrl } from '../core/url.ts'\nimport { walkSteps } from './resolvers/cascade.ts'\nimport { defaultTimelineSteps } from './resolvers/timeline/index.ts'\n\nexport interface TimelineReferences {\n docsToIndex: IndexDoc[]\n hasIssues: boolean\n hasDiscussions: boolean\n hasReleases: boolean\n repoInfo?: { owner: string, repo: string }\n}\n\nexport interface ResolveTimelineOptions {\n packageName: string\n resolved: ResolvedPackage\n version: string\n features: FeaturesConfig\n /** Lower-bound date for release/issue/discussion collection (ISO date) */\n from?: string\n onProgress: (message: string) => void\n}\n\nexport async function resolveTimelineReferences(opts: ResolveTimelineOptions): Promise<TimelineReferences> {\n const { packageName, resolved, version, features, from, onProgress } = opts\n\n const gh = resolved.repoUrl ? parseGitHubUrl(resolved.repoUrl) : null\n const repoInfo = gh ? { owner: gh.owner, repo: gh.repo } : undefined\n const repoCacheDir = repoInfo ? getRepoCacheDir(repoInfo.owner, repoInfo.repo) : null\n const cacheDir = getCacheDir(packageName, version)\n\n const ctx: TimelineCtx = {\n packageName,\n version,\n resolved,\n features,\n from,\n onProgress,\n repoInfo,\n issuesDir: repoCacheDir ? join(repoCacheDir, 'issues') : join(cacheDir, 'issues'),\n discussionsDir: repoCacheDir ? join(repoCacheDir, 'discussions') : join(cacheDir, 'discussions'),\n releasesPath: repoCacheDir ? join(repoCacheDir, 'releases') : join(cacheDir, 'releases'),\n docsToIndex: [],\n }\n\n await walkSteps(defaultTimelineSteps, ctx)\n\n return {\n docsToIndex: ctx.docsToIndex,\n hasIssues: features.issues && existsSync(ctx.issuesDir),\n hasDiscussions: features.discussions && existsSync(ctx.discussionsDir),\n hasReleases: features.releases && existsSync(ctx.releasesPath),\n repoInfo,\n }\n}\n","import type { SkillContext } from '../../agent/skill-builder.ts'\nimport type { FeaturesConfig } from '../../core/config.ts'\nimport type { IndexDoc } from '../../sources/content-resolver.ts'\nimport type { ResolvedPackage } from '../../sources/index.ts'\nimport { existsSync, readdirSync, readFileSync } from 'node:fs'\nimport { join, resolve } from 'pathe'\nimport { createReferenceCache } from '../../cache/index.ts'\nimport { defaultFeatures, readConfig } from '../../core/config.ts'\nimport { buildPackageDirMap, readLock } from '../../core/lockfile.ts'\nimport { indexResources } from '../../retriv/index-pipeline.ts'\nimport { resolveContentDocs } from '../../sources/content-resolver.ts'\nimport {\n fetchNpmPackage,\n generateDocsIndex,\n resolveLocalPackageDocs,\n} from '../../sources/index.ts'\nimport { resolveTimelineReferences } from '../../sources/timeline-resolver.ts'\n\nexport type { IndexDoc } from '../../sources/content-resolver.ts'\n\n/** Compatibility helper for tests and older internal callers. */\nexport async function resolveLocalDep(packageName: string, cwd: string): Promise<ResolvedPackage | 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')) as {\n dependencies?: Record<string, string>\n devDependencies?: Record<string, string>\n }\n const depVersion = {\n ...pkg.dependencies,\n ...pkg.devDependencies,\n }[packageName]\n\n if (!depVersion?.startsWith('link:'))\n return null\n\n return resolveLocalPackageDocs(resolve(cwd, depVersion.slice(5)))\n}\n\nexport async function findRelatedSkills(packageName: string, skillsDir: string): Promise<string[]> {\n const related: string[] = []\n\n const npmInfo = await fetchNpmPackage(packageName)\n if (!npmInfo?.dependencies)\n return related\n\n const deps = new Set(Object.keys(npmInfo.dependencies))\n\n if (!existsSync(skillsDir))\n return related\n\n const lock = readLock(skillsDir)\n const pkgToDirName = lock ? buildPackageDirMap(lock) : new Map<string, string>()\n const installedSet = new Set(readdirSync(skillsDir))\n\n for (const dep of deps) {\n const dirName = pkgToDirName.get(dep)\n if (dirName && installedSet.has(dirName))\n related.push(dirName)\n }\n\n return related.slice(0, 5)\n}\n\n/** Detect CHANGELOG.md in a package directory or cached releases */\nexport function detectChangelog(pkgDir: string | null, cacheDir?: string): string | false {\n if (pkgDir) {\n const found = ['CHANGELOG.md', 'changelog.md'].find(f => existsSync(join(pkgDir, f)))\n if (found)\n return `pkg/${found}`\n }\n if (cacheDir && existsSync(join(cacheDir, 'releases', 'CHANGELOG.md')))\n return 'releases/CHANGELOG.md'\n return false\n}\n\nexport interface FetchResult {\n docSource: string\n docsType: 'llms.txt' | 'readme' | 'docs'\n docsToIndex: IndexDoc[]\n hasIssues: boolean\n hasDiscussions: boolean\n hasReleases: boolean\n warnings: string[]\n repoInfo?: { owner: string, repo: string }\n usedCache: boolean\n}\n\n/** Fetch and cache all resources for a package */\nexport async function fetchAndCacheResources(opts: {\n packageName: string\n resolved: ResolvedPackage\n version: string\n useCache: boolean\n features?: FeaturesConfig\n from?: string\n onProgress: (message: string) => void\n}): Promise<FetchResult> {\n const { packageName, resolved, version, onProgress } = opts\n const features = opts.features ?? readConfig().features ?? defaultFeatures\n const cache = createReferenceCache(packageName, version)\n\n const cacheInvalidated = opts.useCache\n && resolved.crawlUrl\n && cache.detectDocs(resolved.repoUrl, resolved.llmsUrl).docsType === 'readme'\n const useCache = opts.useCache && !cacheInvalidated\n let docSource: string = resolved.readmeUrl || 'readme'\n let docsType: 'llms.txt' | 'readme' | 'docs' = 'readme'\n const docsToIndex: IndexDoc[] = []\n const warnings: string[] = []\n if (cacheInvalidated)\n warnings.push(`Retrying crawl for ${resolved.crawlUrl} (previous attempt only cached README)`)\n\n if (!useCache) {\n const content = await resolveContentDocs({ packageName, resolved, version, onProgress })\n docSource = content.docSource\n docsType = content.docsType\n docsToIndex.push(...content.docsToIndex)\n warnings.push(...content.warnings)\n if (content.docs.length > 0) {\n cache.write(content.docs)\n if (docsType !== 'readme' && content.docs.filter(d => d.path.startsWith('docs/') && d.path.endsWith('.md')).length > 1) {\n const docsIndex = generateDocsIndex(content.docs)\n if (docsIndex)\n cache.write([{ path: 'docs/_INDEX.md', content: docsIndex }])\n }\n }\n }\n else {\n const cached = cache.load({\n repoUrl: resolved.repoUrl,\n llmsUrl: resolved.llmsUrl,\n readmeUrl: resolved.readmeUrl,\n onProgress,\n generateDocsIndex,\n })\n docsType = cached.docsType\n docSource = cached.docSource\n docsToIndex.push(...cached.docsToIndex)\n if (cached.backfillIndex)\n cache.write([cached.backfillIndex])\n }\n\n const timeline = await resolveTimelineReferences({\n packageName,\n resolved,\n version,\n features,\n from: opts.from,\n onProgress,\n })\n docsToIndex.push(...timeline.docsToIndex)\n\n return {\n docSource,\n docsType,\n docsToIndex,\n hasIssues: timeline.hasIssues,\n hasDiscussions: timeline.hasDiscussions,\n hasReleases: timeline.hasReleases,\n warnings,\n repoInfo: timeline.repoInfo,\n usedCache: useCache,\n }\n}\n\nexport interface PreparedSkill {\n hasChangelog: string | false\n shippedDocs: boolean\n pkgFiles: string[]\n relatedSkills: string[]\n}\n\nexport async function prepareSkillReferences(opts: {\n packageName: string\n version: string\n cwd: string\n skillDir: string\n resources: FetchResult\n features: FeaturesConfig\n baseDir?: string\n extraPackages?: Array<{ name: string, version?: string }>\n onIndexProgress?: (msg: string) => void\n}): Promise<PreparedSkill> {\n const { packageName, version, cwd, skillDir, resources, features, baseDir, extraPackages, onIndexProgress } = opts\n const cache = createReferenceCache(packageName, version)\n\n cache.linkInto(skillDir, cwd, resources.docsType, { features, repoInfo: resources.repoInfo, extraPackages })\n\n if (features.search) {\n await indexResources({\n packageName,\n version,\n cwd,\n docsToIndex: resources.docsToIndex,\n features,\n onProgress: onIndexProgress ?? (() => {}),\n })\n }\n\n const pkgDir = cache.pkgDir(cwd)\n const hasChangelog = detectChangelog(pkgDir, cache.dir)\n const shippedDocs = cache.hasShipped(cwd)\n const pkgFiles = cache.keyFiles(cwd)\n const relatedSkills = baseDir ? await findRelatedSkills(packageName, baseDir) : []\n\n return { hasChangelog, shippedDocs, pkgFiles, relatedSkills }\n}\n\nexport interface BuildSkillContextOpts {\n packageName: string\n cachePackageName?: string\n version: string\n skillDir: string\n skillDirName: string\n resources: FetchResult\n prepared: PreparedSkill\n resolved: ResolvedPackage\n packages?: Array<{ name: string }>\n features: FeaturesConfig\n overheadLines?: number\n}\n\nexport function buildSkillContext(opts: BuildSkillContextOpts): SkillContext {\n const { packages, cachePackageName, packageName } = opts\n return {\n packageName,\n ...(cachePackageName && cachePackageName !== packageName ? { cachePackageName } : {}),\n version: opts.version,\n skillDir: opts.skillDir,\n dirName: opts.skillDirName,\n references: {\n docsType: opts.resources.docsType,\n hasShippedDocs: opts.prepared.shippedDocs,\n pkgFiles: opts.prepared.pkgFiles,\n hasIssues: opts.resources.hasIssues,\n hasDiscussions: opts.resources.hasDiscussions,\n hasReleases: opts.resources.hasReleases,\n hasChangelog: opts.prepared.hasChangelog,\n },\n resolved: opts.resolved,\n relatedSkills: opts.prepared.relatedSkills,\n packages: packages && packages.length > 1 ? packages : undefined,\n features: opts.features,\n overheadLines: opts.overheadLines,\n }\n}\n"],"mappings":"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"}
|
package/dist/_chunks/pool2.mjs
CHANGED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import "./agent.mjs";
|
|
2
|
+
import { C as SECTION_OUTPUT_FILES, _ as buildAllSectionPrompts, b as portabilizePrompt, g as todayIsoDate, h as timedSpinner, r as computeSkillDirName, t as writeGeneratedSkillMd } from "./prompts.mjs";
|
|
3
|
+
import { i as listReferenceFiles, s as getActiveFeatures, t as createReferenceCache } from "./cache.mjs";
|
|
4
|
+
import { L as parseGitHubRepoSlug, i as resolvePackageOrCrate, p as fetchPkgDist } from "./semver.mjs";
|
|
5
|
+
import { d as writeLock } from "./lockfile.mjs";
|
|
6
|
+
import { a as ensureProjectFiles, i as ensureGitignore, l as resolveBaseDir, s as installSkill } from "./skill-installer2.mjs";
|
|
7
|
+
import { a as prepareSkillReferences, o as DEFAULT_SECTIONS, r as fetchAndCacheResources } from "./pipeline.mjs";
|
|
8
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
9
|
+
import { styleText } from "node:util";
|
|
10
|
+
import * as p from "@clack/prompts";
|
|
11
|
+
import { join, relative, resolve } from "pathe";
|
|
12
|
+
async function exportPortablePrompts(packageSpec, opts) {
|
|
13
|
+
const sections = opts.sections ?? DEFAULT_SECTIONS;
|
|
14
|
+
const spin = timedSpinner();
|
|
15
|
+
spin.start(`Resolving ${packageSpec}`);
|
|
16
|
+
const cwd = process.cwd();
|
|
17
|
+
const { packageName, localVersion, resolved } = await resolvePackageOrCrate(packageSpec, {
|
|
18
|
+
cwd,
|
|
19
|
+
onProgress: (label) => spin.message(`${packageSpec}: ${label}`)
|
|
20
|
+
});
|
|
21
|
+
if (!resolved) {
|
|
22
|
+
spin.stop(`Could not find docs for: ${packageSpec}`);
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const version = localVersion || resolved.version || "latest";
|
|
26
|
+
const cache = createReferenceCache(packageName, version);
|
|
27
|
+
const useCache = !opts.force && cache.has();
|
|
28
|
+
if (!existsSync(join(cwd, "node_modules", packageName))) {
|
|
29
|
+
spin.message(`Downloading ${packageName}@${version} dist`);
|
|
30
|
+
await fetchPkgDist(packageName, version);
|
|
31
|
+
}
|
|
32
|
+
spin.stop(`Resolved ${packageName}@${useCache ? cache.versionKey : version}`);
|
|
33
|
+
cache.ensure();
|
|
34
|
+
const skillDirName = computeSkillDirName(packageName);
|
|
35
|
+
const features = getActiveFeatures();
|
|
36
|
+
const agent = opts.agent === "none" ? null : opts.agent ?? await import("./detect2.mjs").then((m) => m.detectTargetAgent());
|
|
37
|
+
const baseDir = agent ? resolveBaseDir(cwd, agent, false) : join(cwd, ".claude", "skills");
|
|
38
|
+
const skillDir = opts.out ? resolve(cwd, opts.out) : join(baseDir, skillDirName);
|
|
39
|
+
if (existsSync(skillDir) && !opts.force) {
|
|
40
|
+
const existing = Object.values(SECTION_OUTPUT_FILES).filter((f) => existsSync(join(skillDir, f)));
|
|
41
|
+
if (existing.length > 0) p.log.warn(`Overwriting existing output files in ${relative(cwd, skillDir)}: ${existing.join(", ")}`);
|
|
42
|
+
}
|
|
43
|
+
mkdirSync(skillDir, { recursive: true });
|
|
44
|
+
const resSpin = timedSpinner();
|
|
45
|
+
resSpin.start("Fetching resources");
|
|
46
|
+
const resources = await fetchAndCacheResources({
|
|
47
|
+
packageName,
|
|
48
|
+
resolved,
|
|
49
|
+
version,
|
|
50
|
+
useCache,
|
|
51
|
+
features,
|
|
52
|
+
onProgress: (msg) => resSpin.message(msg)
|
|
53
|
+
});
|
|
54
|
+
resSpin.stop("Resources ready");
|
|
55
|
+
for (const w of resources.warnings) p.log.warn(styleText("yellow", w));
|
|
56
|
+
const { hasChangelog, shippedDocs, pkgFiles, relatedSkills } = await prepareSkillReferences({
|
|
57
|
+
packageName,
|
|
58
|
+
version,
|
|
59
|
+
cwd,
|
|
60
|
+
skillDir,
|
|
61
|
+
resources,
|
|
62
|
+
features,
|
|
63
|
+
baseDir: join(skillDir, "..")
|
|
64
|
+
});
|
|
65
|
+
const docFiles = listReferenceFiles(skillDir);
|
|
66
|
+
const prompts = buildAllSectionPrompts({
|
|
67
|
+
packageName,
|
|
68
|
+
skillDir,
|
|
69
|
+
version,
|
|
70
|
+
hasIssues: resources.hasIssues,
|
|
71
|
+
hasDiscussions: resources.hasDiscussions,
|
|
72
|
+
hasReleases: resources.hasReleases,
|
|
73
|
+
hasChangelog,
|
|
74
|
+
docFiles,
|
|
75
|
+
docsType: resources.docsType,
|
|
76
|
+
hasShippedDocs: shippedDocs,
|
|
77
|
+
pkgFiles,
|
|
78
|
+
features,
|
|
79
|
+
sections
|
|
80
|
+
});
|
|
81
|
+
cache.eject(skillDir, cwd, resources.docsType, {
|
|
82
|
+
features,
|
|
83
|
+
repoInfo: resources.repoInfo
|
|
84
|
+
});
|
|
85
|
+
cache.clearSkillInternal(skillDir);
|
|
86
|
+
for (const [section, prompt] of prompts) {
|
|
87
|
+
const portable = portabilizePrompt(prompt, section);
|
|
88
|
+
writeFileSync(join(skillDir, `PROMPT_${section}.md`), portable);
|
|
89
|
+
}
|
|
90
|
+
writeGeneratedSkillMd(skillDir, {
|
|
91
|
+
name: packageName,
|
|
92
|
+
version,
|
|
93
|
+
releasedAt: resolved.releasedAt,
|
|
94
|
+
description: resolved.description,
|
|
95
|
+
distTags: resolved.distTags,
|
|
96
|
+
relatedSkills,
|
|
97
|
+
hasIssues: resources.hasIssues,
|
|
98
|
+
hasDiscussions: resources.hasDiscussions,
|
|
99
|
+
hasReleases: resources.hasReleases,
|
|
100
|
+
hasChangelog,
|
|
101
|
+
docsType: resources.docsType,
|
|
102
|
+
hasShippedDocs: shippedDocs,
|
|
103
|
+
pkgFiles,
|
|
104
|
+
repoUrl: resolved.repoUrl,
|
|
105
|
+
features,
|
|
106
|
+
eject: true
|
|
107
|
+
});
|
|
108
|
+
const repoSlug = parseGitHubRepoSlug(resolved.repoUrl);
|
|
109
|
+
if (agent) {
|
|
110
|
+
const { shared } = installSkill({
|
|
111
|
+
cwd,
|
|
112
|
+
agent,
|
|
113
|
+
global: false,
|
|
114
|
+
baseDir,
|
|
115
|
+
skillDirName,
|
|
116
|
+
lock: {
|
|
117
|
+
packageName,
|
|
118
|
+
version,
|
|
119
|
+
repo: repoSlug,
|
|
120
|
+
source: resources.docSource,
|
|
121
|
+
syncedAt: todayIsoDate(),
|
|
122
|
+
generator: "skilld"
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
await ensureProjectFiles({
|
|
126
|
+
cwd,
|
|
127
|
+
agent,
|
|
128
|
+
global: false,
|
|
129
|
+
shared
|
|
130
|
+
});
|
|
131
|
+
} else {
|
|
132
|
+
writeLock(baseDir, skillDirName, {
|
|
133
|
+
packageName,
|
|
134
|
+
version,
|
|
135
|
+
repo: repoSlug,
|
|
136
|
+
source: resources.docSource,
|
|
137
|
+
syncedAt: todayIsoDate(),
|
|
138
|
+
generator: "skilld"
|
|
139
|
+
});
|
|
140
|
+
await ensureGitignore(".claude/skills", cwd, false);
|
|
141
|
+
}
|
|
142
|
+
const relDir = relative(cwd, skillDir);
|
|
143
|
+
const sectionList = [...prompts.keys()];
|
|
144
|
+
p.log.success(`Skill installed to ${relDir}`);
|
|
145
|
+
const promptFiles = sectionList.map((s) => `PROMPT_${s}.md`).join(", ");
|
|
146
|
+
const outputFileList = sectionList.map((s) => SECTION_OUTPUT_FILES[s]).join(", ");
|
|
147
|
+
p.log.info(`Have your agent enhance the skill. Give it this prompt:\n${styleText(["dim", "italic"], ` Read each prompt file (${promptFiles}) in ${relDir}/, read the\n referenced files, then write your output to the matching file (${outputFileList}).\n When done, run: skilld assemble`)}`);
|
|
148
|
+
}
|
|
149
|
+
export { exportPortablePrompts as t };
|
|
150
|
+
|
|
151
|
+
//# sourceMappingURL=portable.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"portable.mjs","names":[],"sources":["../../src/commands/sync/portable.ts"],"sourcesContent":["import type { AgentType, SkillSection } from '../../agent/index.ts'\nimport { existsSync, mkdirSync, writeFileSync } from 'node:fs'\nimport { styleText } from 'node:util'\nimport * as p from '@clack/prompts'\nimport { join, relative, resolve } from 'pathe'\nimport {\n buildAllSectionPrompts,\n computeSkillDirName,\n portabilizePrompt,\n SECTION_OUTPUT_FILES,\n writeGeneratedSkillMd,\n} from '../../agent/index.ts'\nimport { ensureGitignore, ensureProjectFiles, installSkill, resolveBaseDir } from '../../agent/skill-installer.ts'\nimport { createReferenceCache, listReferenceFiles } from '../../cache/index.ts'\nimport { getActiveFeatures } from '../../core/config.ts'\nimport { timedSpinner, todayIsoDate } from '../../core/formatting.ts'\nimport { writeLock } from '../../core/lockfile.ts'\nimport { parseGitHubRepoSlug } from '../../core/url.ts'\nimport {\n fetchPkgDist,\n resolvePackageOrCrate,\n} from '../../sources/index.ts'\nimport { DEFAULT_SECTIONS } from '../llm-prompts.ts'\nimport {\n fetchAndCacheResources,\n prepareSkillReferences,\n} from './pipeline.ts'\n\nexport async function exportPortablePrompts(packageSpec: string, opts: {\n out?: string\n sections?: SkillSection[]\n force?: boolean\n agent?: AgentType | 'none'\n}): Promise<void> {\n const sections = opts.sections ?? DEFAULT_SECTIONS\n\n const spin = timedSpinner()\n spin.start(`Resolving ${packageSpec}`)\n const cwd = process.cwd()\n\n const { packageName, localVersion, resolved } = await resolvePackageOrCrate(packageSpec, {\n cwd,\n onProgress: label => spin.message(`${packageSpec}: ${label}`),\n })\n\n if (!resolved) {\n spin.stop(`Could not find docs for: ${packageSpec}`)\n return\n }\n\n const version = localVersion || resolved.version || 'latest'\n const cache = createReferenceCache(packageName, version)\n const useCache = !opts.force && cache.has()\n\n if (!existsSync(join(cwd, 'node_modules', packageName))) {\n spin.message(`Downloading ${packageName}@${version} dist`)\n await fetchPkgDist(packageName, version)\n }\n\n spin.stop(`Resolved ${packageName}@${useCache ? cache.versionKey : version}`)\n cache.ensure()\n\n const skillDirName = computeSkillDirName(packageName)\n const features = getActiveFeatures()\n\n const agent: AgentType | null = opts.agent === 'none'\n ? null\n : opts.agent ?? (await import('../../agent/detect.ts').then(m => m.detectTargetAgent()))\n const baseDir = agent\n ? resolveBaseDir(cwd, agent, false)\n : join(cwd, '.claude', 'skills')\n const skillDir = opts.out ? resolve(cwd, opts.out) : join(baseDir, skillDirName)\n\n if (existsSync(skillDir) && !opts.force) {\n const existing = Object.values(SECTION_OUTPUT_FILES).filter(f => existsSync(join(skillDir, f)))\n if (existing.length > 0)\n p.log.warn(`Overwriting existing output files in ${relative(cwd, skillDir)}: ${existing.join(', ')}`)\n }\n mkdirSync(skillDir, { recursive: true })\n\n const resSpin = timedSpinner()\n resSpin.start('Fetching resources')\n const resources = await fetchAndCacheResources({\n packageName,\n resolved,\n version,\n useCache,\n features,\n onProgress: msg => resSpin.message(msg),\n })\n resSpin.stop('Resources ready')\n for (const w of resources.warnings)\n p.log.warn(styleText('yellow', w))\n\n const prepared = await prepareSkillReferences({\n packageName,\n version,\n cwd,\n skillDir,\n resources,\n features,\n baseDir: join(skillDir, '..'),\n })\n const { hasChangelog, shippedDocs, pkgFiles, relatedSkills } = prepared\n const docFiles = listReferenceFiles(skillDir)\n\n const prompts = buildAllSectionPrompts({\n packageName,\n skillDir,\n version,\n hasIssues: resources.hasIssues,\n hasDiscussions: resources.hasDiscussions,\n hasReleases: resources.hasReleases,\n hasChangelog,\n docFiles,\n docsType: resources.docsType,\n hasShippedDocs: shippedDocs,\n pkgFiles,\n features,\n sections,\n })\n\n cache.eject(skillDir, cwd, resources.docsType, { features, repoInfo: resources.repoInfo })\n cache.clearSkillInternal(skillDir)\n\n for (const [section, prompt] of prompts) {\n const portable = portabilizePrompt(prompt, section)\n writeFileSync(join(skillDir, `PROMPT_${section}.md`), portable)\n }\n\n writeGeneratedSkillMd(skillDir, {\n name: packageName,\n version,\n releasedAt: resolved.releasedAt,\n description: resolved.description,\n distTags: resolved.distTags,\n relatedSkills,\n hasIssues: resources.hasIssues,\n hasDiscussions: resources.hasDiscussions,\n hasReleases: resources.hasReleases,\n hasChangelog,\n docsType: resources.docsType,\n hasShippedDocs: shippedDocs,\n pkgFiles,\n repoUrl: resolved.repoUrl,\n features,\n eject: true,\n })\n\n const repoSlug = parseGitHubRepoSlug(resolved.repoUrl)\n if (agent) {\n const { shared } = installSkill({\n cwd,\n agent,\n global: false,\n baseDir,\n skillDirName,\n lock: {\n packageName,\n version,\n repo: repoSlug,\n source: resources.docSource,\n syncedAt: todayIsoDate(),\n generator: 'skilld',\n },\n })\n await ensureProjectFiles({ cwd, agent, global: false, shared })\n }\n else {\n writeLock(baseDir, skillDirName, {\n packageName,\n version,\n repo: repoSlug,\n source: resources.docSource,\n syncedAt: todayIsoDate(),\n generator: 'skilld',\n })\n await ensureGitignore('.claude/skills', cwd, false)\n }\n\n const relDir = relative(cwd, skillDir)\n const sectionList = [...prompts.keys()]\n p.log.success(`Skill installed to ${relDir}`)\n\n const promptFiles = sectionList.map(s => `PROMPT_${s}.md`).join(', ')\n const outputFileList = sectionList.map(s => SECTION_OUTPUT_FILES[s]).join(', ')\n p.log.info(`Have your agent enhance the skill. Give it this prompt:\\n${styleText(['dim', 'italic'], ` Read each prompt file (${promptFiles}) in ${relDir}/, read the\\n referenced files, then write your output to the matching file (${outputFileList}).\\n When done, run: skilld assemble`)}`)\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { i as readPackageJsonSafe, n as editJsonProperty, r as patchPackageJson } from "./package-json.mjs";
|
|
2
|
+
import { t as isInteractive } from "./env.mjs";
|
|
3
|
+
import { styleText } from "node:util";
|
|
4
|
+
import * as p from "@clack/prompts";
|
|
5
|
+
import { join } from "pathe";
|
|
6
|
+
import { parseTree } from "jsonc-parser";
|
|
7
|
+
const STATIC_REGEX_1 = /[&|;]+\s*$/;
|
|
8
|
+
const STATIC_REGEX_2 = /npx|\.store|dlx/;
|
|
9
|
+
function hasPrepareHook(cwd = process.cwd()) {
|
|
10
|
+
const pkg = readPackageJsonSafe(join(cwd, "package.json"));
|
|
11
|
+
if (!pkg) return true;
|
|
12
|
+
const existing = pkg.parsed.scripts?.prepare;
|
|
13
|
+
return typeof existing === "string" && existing.includes("skilld");
|
|
14
|
+
}
|
|
15
|
+
async function suggestPrepareHook(cwd = process.cwd()) {
|
|
16
|
+
const pkgJsonPath = join(cwd, "package.json");
|
|
17
|
+
const pkg = readPackageJsonSafe(pkgJsonPath);
|
|
18
|
+
if (!pkg) return false;
|
|
19
|
+
const rawExisting = pkg.parsed.scripts?.prepare;
|
|
20
|
+
const existing = typeof rawExisting === "string" ? rawExisting : void 0;
|
|
21
|
+
if (existing?.includes("skilld")) return true;
|
|
22
|
+
const prepareCmd = buildPrepareScript(existing, cwd);
|
|
23
|
+
if (!isInteractive()) {
|
|
24
|
+
p.log.info(`${styleText("gray", "Add to package.json scripts:")}\n ${styleText("cyan", `"prepare": "${prepareCmd}"`)}\n ${styleText("gray", "Restores references and shipped skills on install.")}`);
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
const confirmed = await p.confirm({
|
|
28
|
+
message: `Add ${styleText("cyan", `"prepare": "${prepareCmd}"`)} to package.json?`,
|
|
29
|
+
initialValue: true
|
|
30
|
+
});
|
|
31
|
+
if (p.isCancel(confirmed) || !confirmed) return false;
|
|
32
|
+
patchPackageJson(pkgJsonPath, (content) => {
|
|
33
|
+
const hasScripts = parseTree(content)?.children?.some((c) => c.type === "property" && c.children?.[0]?.value === "scripts");
|
|
34
|
+
let patched = content;
|
|
35
|
+
if (!hasScripts) patched = editJsonProperty(patched, ["scripts"], {});
|
|
36
|
+
return editJsonProperty(patched, ["scripts", "prepare"], prepareCmd);
|
|
37
|
+
});
|
|
38
|
+
p.log.success(`Added ${styleText("cyan", "skilld prepare")} to package.json`);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
function buildPrepareScript(existing, cwd = process.cwd()) {
|
|
42
|
+
const cmd = `${isNpxExecution() && !isSkilldDep(cwd) ? "npx skilld" : "skilld"} prepare || true`;
|
|
43
|
+
if (!existing || !existing.trim()) return cmd;
|
|
44
|
+
const cleaned = existing.trim().replace(STATIC_REGEX_1, "").trim();
|
|
45
|
+
if (!cleaned) return cmd;
|
|
46
|
+
return `${cleaned} && (${cmd})`;
|
|
47
|
+
}
|
|
48
|
+
function isNpxExecution() {
|
|
49
|
+
if (process.env.npm_command === "exec") return true;
|
|
50
|
+
const execPath = process.env._ || "";
|
|
51
|
+
return STATIC_REGEX_2.test(execPath);
|
|
52
|
+
}
|
|
53
|
+
function isSkilldDep(cwd) {
|
|
54
|
+
const pkg = readPackageJsonSafe(join(cwd, "package.json"));
|
|
55
|
+
if (!pkg) return false;
|
|
56
|
+
const deps = pkg.parsed;
|
|
57
|
+
return !!(deps.dependencies?.skilld || deps.devDependencies?.skilld);
|
|
58
|
+
}
|
|
59
|
+
export { hasPrepareHook as n, suggestPrepareHook as r, buildPrepareScript as t };
|
|
60
|
+
|
|
61
|
+
//# sourceMappingURL=prepare-hook2.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prepare-hook2.mjs","names":[],"sources":["../../src/cli/prepare-hook.ts"],"sourcesContent":["import { styleText } from 'node:util'\nimport * as p from '@clack/prompts'\nimport { parseTree } from 'jsonc-parser'\nimport { join } from 'pathe'\nimport { editJsonProperty, patchPackageJson, readPackageJsonSafe } from '../core/package-json.ts'\nimport { isInteractive } from './env.ts'\n\nconst STATIC_REGEX_1 = /[&|;]+\\s*$/\nconst STATIC_REGEX_2 = /npx|\\.store|dlx/\n\nexport function hasPrepareHook(cwd: string = process.cwd()): boolean {\n const pkg = readPackageJsonSafe(join(cwd, 'package.json'))\n if (!pkg)\n return true\n const existing = (pkg.parsed.scripts as Record<string, unknown> | undefined)?.prepare\n return typeof existing === 'string' && existing.includes('skilld')\n}\n\nexport async function suggestPrepareHook(cwd: string = process.cwd()): Promise<boolean> {\n const pkgJsonPath = join(cwd, 'package.json')\n const pkg = readPackageJsonSafe(pkgJsonPath)\n if (!pkg)\n return false\n\n const rawExisting = (pkg.parsed.scripts as Record<string, unknown> | undefined)?.prepare\n const existing: string | undefined = typeof rawExisting === 'string' ? rawExisting : undefined\n\n if (existing?.includes('skilld'))\n return true\n\n const prepareCmd = buildPrepareScript(existing, cwd)\n\n if (!isInteractive()) {\n p.log.info(\n `${styleText('gray', 'Add to package.json scripts:')}\\n`\n + ` ${styleText('cyan', `\"prepare\": \"${prepareCmd}\"`)}\\n`\n + ` ${styleText('gray', 'Restores references and shipped skills on install.')}`,\n )\n return false\n }\n\n const confirmed = await p.confirm({\n message: `Add ${styleText('cyan', `\"prepare\": \"${prepareCmd}\"`)} to package.json?`,\n initialValue: true,\n })\n if (p.isCancel(confirmed) || !confirmed)\n return false\n\n patchPackageJson(pkgJsonPath, (content) => {\n const tree = parseTree(content)\n const hasScripts = tree?.children?.some(c =>\n c.type === 'property' && c.children?.[0]?.value === 'scripts',\n )\n\n let patched = content\n if (!hasScripts)\n patched = editJsonProperty(patched, ['scripts'], {})\n\n return editJsonProperty(patched, ['scripts', 'prepare'], prepareCmd)\n })\n p.log.success(`Added ${styleText('cyan', 'skilld prepare')} to package.json`)\n return true\n}\n\nexport function buildPrepareScript(existing: string | undefined, cwd: string = process.cwd()): string {\n const bin = isNpxExecution() && !isSkilldDep(cwd) ? 'npx skilld' : 'skilld'\n const cmd = `${bin} prepare || true`\n if (!existing || !existing.trim())\n return cmd\n\n const trimmed = existing.trim()\n const cleaned = trimmed.replace(STATIC_REGEX_1, '').trim()\n if (!cleaned)\n return cmd\n\n return `${cleaned} && (${cmd})`\n}\n\nfunction isNpxExecution(): boolean {\n if (process.env.npm_command === 'exec')\n return true\n const execPath = process.env._ || ''\n return STATIC_REGEX_2.test(execPath)\n}\n\nfunction isSkilldDep(cwd: string): boolean {\n const pkg = readPackageJsonSafe(join(cwd, 'package.json'))\n if (!pkg)\n return false\n const deps = pkg.parsed as Record<string, any>\n return !!(deps.dependencies?.skilld || deps.devDependencies?.skilld)\n}\n"],"mappings":";;;;;;AAOA,MAAM,iBAAiB;AACvB,MAAM,iBAAiB;AAEvB,SAAgB,eAAe,MAAc,QAAQ,KAAK,EAAW;CACnE,MAAM,MAAM,oBAAoB,KAAK,KAAK,eAAe,CAAC;CAC1D,IAAI,CAAC,KACH,OAAO;CACT,MAAM,WAAY,IAAI,OAAO,SAAiD;CAC9E,OAAO,OAAO,aAAa,YAAY,SAAS,SAAS,SAAS;;AAGpE,eAAsB,mBAAmB,MAAc,QAAQ,KAAK,EAAoB;CACtF,MAAM,cAAc,KAAK,KAAK,eAAe;CAC7C,MAAM,MAAM,oBAAoB,YAAY;CAC5C,IAAI,CAAC,KACH,OAAO;CAET,MAAM,cAAe,IAAI,OAAO,SAAiD;CACjF,MAAM,WAA+B,OAAO,gBAAgB,WAAW,cAAc,KAAA;CAErF,IAAI,UAAU,SAAS,SAAS,EAC9B,OAAO;CAET,MAAM,aAAa,mBAAmB,UAAU,IAAI;CAEpD,IAAI,CAAC,eAAe,EAAE;EACpB,EAAE,IAAI,KACJ,GAAG,UAAU,QAAQ,+BAA+B,CAAC,MAC9C,UAAU,QAAQ,eAAe,WAAW,GAAG,CAAC,MAChD,UAAU,QAAQ,qDAAqD,GAC/E;EACD,OAAO;;CAGT,MAAM,YAAY,MAAM,EAAE,QAAQ;EAChC,SAAS,OAAO,UAAU,QAAQ,eAAe,WAAW,GAAG,CAAC;EAChE,cAAc;EACf,CAAC;CACF,IAAI,EAAE,SAAS,UAAU,IAAI,CAAC,WAC5B,OAAO;CAET,iBAAiB,cAAc,YAAY;EAEzC,MAAM,aADO,UAAU,QACA,EAAE,UAAU,MAAK,MACtC,EAAE,SAAS,cAAc,EAAE,WAAW,IAAI,UAAU,UACrD;EAED,IAAI,UAAU;EACd,IAAI,CAAC,YACH,UAAU,iBAAiB,SAAS,CAAC,UAAU,EAAE,EAAE,CAAC;EAEtD,OAAO,iBAAiB,SAAS,CAAC,WAAW,UAAU,EAAE,WAAW;GACpE;CACF,EAAE,IAAI,QAAQ,SAAS,UAAU,QAAQ,iBAAiB,CAAC,kBAAkB;CAC7E,OAAO;;AAGT,SAAgB,mBAAmB,UAA8B,MAAc,QAAQ,KAAK,EAAU;CAEpG,MAAM,MAAM,GADA,gBAAgB,IAAI,CAAC,YAAY,IAAI,GAAG,eAAe,SAChD;CACnB,IAAI,CAAC,YAAY,CAAC,SAAS,MAAM,EAC/B,OAAO;CAGT,MAAM,UADU,SAAS,MACF,CAAC,QAAQ,gBAAgB,GAAG,CAAC,MAAM;CAC1D,IAAI,CAAC,SACH,OAAO;CAET,OAAO,GAAG,QAAQ,OAAO,IAAI;;AAG/B,SAAS,iBAA0B;CACjC,IAAI,QAAQ,IAAI,gBAAgB,QAC9B,OAAO;CACT,MAAM,WAAW,QAAQ,IAAI,KAAK;CAClC,OAAO,eAAe,KAAK,SAAS;;AAGtC,SAAS,YAAY,KAAsB;CACzC,MAAM,MAAM,oBAAoB,KAAK,KAAK,eAAe,CAAC;CAC1D,IAAI,CAAC,KACH,OAAO;CACT,MAAM,OAAO,IAAI;CACjB,OAAO,CAAC,EAAE,KAAK,cAAc,UAAU,KAAK,iBAAiB"}
|
package/dist/_chunks/prepare.mjs
CHANGED
|
@@ -1,6 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { s as REFERENCES_DIR } from "./paths.mjs";
|
|
2
|
+
import { u as README_FILENAME_RE } from "./regex.mjs";
|
|
3
|
+
import { i as readPackageJsonSafe } from "./package-json.mjs";
|
|
2
4
|
import { existsSync, lstatSync, mkdirSync, readdirSync, rmSync, symlinkSync, unlinkSync } from "node:fs";
|
|
3
|
-
import { join } from "pathe";
|
|
5
|
+
import { basename, join, resolve } from "pathe";
|
|
6
|
+
const VALID_PKG_NAME = /^(?:@[a-z0-9][-a-z0-9._]*\/)?[a-z0-9][-a-z0-9._]*$/;
|
|
7
|
+
const VALID_VERSION = /^[a-z0-9][-\w.+]*$/i;
|
|
8
|
+
function getVersionKey(version) {
|
|
9
|
+
return version;
|
|
10
|
+
}
|
|
11
|
+
function getCacheKey(name, version) {
|
|
12
|
+
return `${name}@${getVersionKey(version)}`;
|
|
13
|
+
}
|
|
14
|
+
function getCacheDir(name, version) {
|
|
15
|
+
if (!VALID_PKG_NAME.test(name)) throw new Error(`Invalid package name: ${name}`);
|
|
16
|
+
if (!VALID_VERSION.test(version)) throw new Error(`Invalid version: ${version}`);
|
|
17
|
+
const dir = resolve(REFERENCES_DIR, getCacheKey(name, version));
|
|
18
|
+
if (!dir.startsWith(REFERENCES_DIR)) throw new Error(`Path traversal detected: ${dir}`);
|
|
19
|
+
return dir;
|
|
20
|
+
}
|
|
21
|
+
const STATIC_REGEX_2 = /^changelog\.md$/i;
|
|
4
22
|
function toStorageName(name) {
|
|
5
23
|
if (name.startsWith("crate:")) return `@skilld-crate/${name.slice(6)}`;
|
|
6
24
|
return name;
|
|
@@ -50,6 +68,32 @@ function linkShippedSkill(baseDir, skillName, targetDir) {
|
|
|
50
68
|
});
|
|
51
69
|
symlinkSync(targetDir, linkPath);
|
|
52
70
|
}
|
|
53
|
-
|
|
71
|
+
function hasShippedDocs(name, cwd, version) {
|
|
72
|
+
const pkgPath = resolvePkgDir(name, cwd, version);
|
|
73
|
+
if (!pkgPath) return false;
|
|
74
|
+
for (const candidate of [
|
|
75
|
+
"docs",
|
|
76
|
+
"documentation",
|
|
77
|
+
"doc"
|
|
78
|
+
]) if (existsSync(join(pkgPath, candidate))) return true;
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
function getPkgKeyFiles(name, cwd, version) {
|
|
82
|
+
const pkgPath = resolvePkgDir(name, cwd, version);
|
|
83
|
+
if (!pkgPath) return [];
|
|
84
|
+
const files = [];
|
|
85
|
+
const pkgJsonResult = readPackageJsonSafe(join(pkgPath, "package.json"));
|
|
86
|
+
if (pkgJsonResult) {
|
|
87
|
+
const pkg = pkgJsonResult.parsed;
|
|
88
|
+
if (pkg.main) files.push(basename(pkg.main));
|
|
89
|
+
if (pkg.module && pkg.module !== pkg.main) files.push(basename(pkg.module));
|
|
90
|
+
const typesPath = pkg.types || pkg.typings;
|
|
91
|
+
if (typesPath && existsSync(join(pkgPath, typesPath))) files.push(typesPath);
|
|
92
|
+
}
|
|
93
|
+
const entries = readdirSync(pkgPath).filter((f) => README_FILENAME_RE.test(f) || STATIC_REGEX_2.test(f));
|
|
94
|
+
files.push(...entries);
|
|
95
|
+
return [...new Set(files)];
|
|
96
|
+
}
|
|
97
|
+
export { resolvePkgDir as a, getVersionKey as c, linkShippedSkill as i, getShippedSkills as n, restorePkgSymlink as o, hasShippedDocs as r, getCacheDir as s, getPkgKeyFiles as t };
|
|
54
98
|
|
|
55
99
|
//# sourceMappingURL=prepare.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepare.mjs","names":[],"sources":["../../src/core/prepare.ts"],"sourcesContent":["/**\n * Shared prepare utilities used by both the fast entry (src/prepare.ts)\n * and the full CLI command (src/commands/prepare.ts).\n *\n * Keep this module lightweight: no imports from agent/, cache/storage.ts,\n * or any module that pulls in sanitize/clack/citty.\n */\n\nimport type { SkillInfo } from './lockfile.ts'\nimport { existsSync, lstatSync, mkdirSync, readdirSync, rmSync, symlinkSync, unlinkSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { getCacheDir } from '../cache/version.ts'\n\n/** Map lockfile identity name to storage-safe cache key (crate:X → @skilld-crate/X) */\nfunction toStorageName(name: string): string {\n if (name.startsWith('crate:'))\n return `@skilld-crate/${name.slice('crate:'.length)}`\n return name\n}\n\n/** Resolve package directory: node_modules first, then global cache */\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 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/** Restore .skilld/pkg symlink to node_modules if broken */\nexport function restorePkgSymlink(skillsDir: string, name: string, info: SkillInfo, cwd: string): void {\n const refsDir = join(skillsDir, name, '.skilld')\n const pkgLink = join(refsDir, 'pkg')\n\n if (!existsSync(join(skillsDir, name)))\n return\n\n // Use lstatSync to detect dangling symlinks — existsSync follows symlinks\n // and returns false for dangling ones, causing symlinkSync to throw EEXIST\n try {\n const stat = lstatSync(pkgLink)\n if (stat.isSymbolicLink()) {\n if (existsSync(pkgLink))\n return // symlink exists and target is valid\n unlinkSync(pkgLink) // dangling symlink — remove before re-creating\n }\n else {\n return // real file/dir exists at this path\n }\n }\n catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT')\n return // permission/IO error — bail instead of masking\n }\n\n const pkgName = toStorageName(info.packageName || name)\n const pkgDir = resolvePkgDir(pkgName, cwd, info.version)\n if (!pkgDir)\n return\n\n mkdirSync(refsDir, { recursive: true })\n symlinkSync(pkgDir, pkgLink)\n}\n\nexport interface ShippedSkill {\n skillName: string\n skillDir: string\n}\n\n/** Check if package ships a skills/ directory with SKILL.md or _SKILL.md subdirs */\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/** Create symlink from skills dir to shipped skill dir */\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"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"prepare.mjs","names":[],"sources":["../../src/cache/internal/version.ts","../../src/core/prepare.ts"],"sourcesContent":["/**\n * Version utilities\n */\n\nimport { resolve } from 'pathe'\nimport { REFERENCES_DIR } from '../../core/paths.ts'\n\n/** Validate npm package name (scoped or unscoped) */\nconst VALID_PKG_NAME = /^(?:@[a-z0-9][-a-z0-9._]*\\/)?[a-z0-9][-a-z0-9._]*$/\n\n/** Validate version string (semver-ish, no path separators) */\nconst VALID_VERSION = /^[a-z0-9][-\\w.+]*$/i\n\n/**\n * Get exact version key for cache keying\n */\nexport function getVersionKey(version: string): string {\n return version\n}\n\n/**\n * Get cache key for a package: name@version\n */\nexport function getCacheKey(name: string, version: string): string {\n return `${name}@${getVersionKey(version)}`\n}\n\n/**\n * Get path to cached package references.\n * Validates name/version to prevent path traversal.\n */\nexport function getCacheDir(name: string, version: string): string {\n if (!VALID_PKG_NAME.test(name))\n throw new Error(`Invalid package name: ${name}`)\n if (!VALID_VERSION.test(version))\n throw new Error(`Invalid version: ${version}`)\n\n const dir = resolve(REFERENCES_DIR, getCacheKey(name, version))\n if (!dir.startsWith(REFERENCES_DIR))\n throw new Error(`Path traversal detected: ${dir}`)\n return dir\n}\n","/**\n * Shared prepare utilities used by both the fast entry (src/prepare.ts)\n * and the full CLI command (src/commands/prepare.ts).\n *\n * Keep this module lightweight: no imports from agent/, cache/storage.ts,\n * or any module that pulls in sanitize/clack/citty.\n */\n\nimport type { SkillInfo } from './lockfile.ts'\nimport { existsSync, lstatSync, mkdirSync, readdirSync, rmSync, symlinkSync, unlinkSync } from 'node:fs'\nimport { basename, join } from 'pathe'\nimport { getCacheDir } from '../cache/internal/version.ts'\nimport { readPackageJsonSafe } from './package-json.ts'\nimport { README_FILENAME_RE } from './regex.ts'\n\nconst STATIC_REGEX_2 = /^changelog\\.md$/i\n\n/** Map lockfile identity name to storage-safe cache key (crate:X → @skilld-crate/X) */\nfunction toStorageName(name: string): string {\n if (name.startsWith('crate:'))\n return `@skilld-crate/${name.slice('crate:'.length)}`\n return name\n}\n\n/** Resolve package directory: node_modules first, then global cache */\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 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/** Restore .skilld/pkg symlink to node_modules if broken */\nexport function restorePkgSymlink(skillsDir: string, name: string, info: SkillInfo, cwd: string): void {\n const refsDir = join(skillsDir, name, '.skilld')\n const pkgLink = join(refsDir, 'pkg')\n\n if (!existsSync(join(skillsDir, name)))\n return\n\n // Use lstatSync to detect dangling symlinks — existsSync follows symlinks\n // and returns false for dangling ones, causing symlinkSync to throw EEXIST\n try {\n const stat = lstatSync(pkgLink)\n if (stat.isSymbolicLink()) {\n if (existsSync(pkgLink))\n return // symlink exists and target is valid\n unlinkSync(pkgLink) // dangling symlink — remove before re-creating\n }\n else {\n return // real file/dir exists at this path\n }\n }\n catch (err) {\n if ((err as NodeJS.ErrnoException).code !== 'ENOENT')\n return // permission/IO error — bail instead of masking\n }\n\n const pkgName = toStorageName(info.packageName || name)\n const pkgDir = resolvePkgDir(pkgName, cwd, info.version)\n if (!pkgDir)\n return\n\n mkdirSync(refsDir, { recursive: true })\n symlinkSync(pkgDir, pkgLink)\n}\n\nexport interface ShippedSkill {\n skillName: string\n skillDir: string\n}\n\n/** Check if package ships a skills/ directory with SKILL.md or _SKILL.md subdirs */\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/** Create symlink from skills dir to shipped skill dir */\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\n/** Check if a package ships a docs/, documentation/, or doc/ directory */\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 * 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 const pkgJsonResult = readPackageJsonSafe(pkgJsonPath)\n if (pkgJsonResult) {\n const pkg = pkgJsonResult.parsed as Record<string, any>\n\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 const typesPath = pkg.types || pkg.typings\n if (typesPath && existsSync(join(pkgPath, typesPath)))\n files.push(typesPath)\n }\n\n const entries = readdirSync(pkgPath).filter(f =>\n README_FILENAME_RE.test(f) || STATIC_REGEX_2.test(f),\n )\n files.push(...entries)\n\n return [...new Set(files)]\n}\n"],"mappings":";;;;;;AAQA,MAAM,gBAAA;AAGN,SAAM,cAAgB,SAAA;;;AAKtB,SAAgB,YAAA,MAAc,SAAyB;CACrD,OAAO,GAAA,KAAA,GAAA,cAAA,QAAA;;;;CAMT,IAAA,CAAA,cAAgB,KAAY,QAAc,EAAA,MAAyB,IAAA,MAAA,oBAAA,UAAA;CACjE,MAAA,MAAU,QAAQ,gBAAc,YAAQ,MAAA,QAAA,CAAA;;;;;SAQnC,cAAe,MAAK;CAEzB,IAAI,KAAC,WAAc,SAAK,EAAA,OACtB,iBAAgB,KAAA,MAAA,EAAA;CAElB,OAAM;;;;CCtBR,IAAA,WAAM,gBAAiB,EAAA,OAAA;;EAGvB,MAAA,eAAuB,KAAA,YAAsB,MAAA,QAAA,EAAA,MAAA;EAC3C,IAAI,WAAK,KAAW,cAClB,eAAO,CAAA,EAAA,OAAsB;;;;SAMzB,kBAAkB,WAAU,MAAA,MAAA,KAAgB;CAClD,MAAI,UAAW,KAAA,WAAgB,MAC7B,UAAO;CAET,MAAI,UAAS,KAAA,SAAA,MAAA;KACX,CAAA,WAAM,KAAA,WAAoB,KAAA,CAAA,EAAY;KACtC;;GAIF,IAAA,WAAO,QAAA,EAAA;;;UAIO,KAAA;EACd,IAAA,IAAM,SAAU,UAAK;;CAGrB,MAAK,SAAA,cAAgB,cACnB,KAAA,eAAA,KAAA,EAAA,KAAA,KAAA,QAAA;CAIF,IAAI,CAAA,QAAA;WACW,SAAU,EAAA,WACd,MAAA,CAAA;aACH,QAAW,QACb;;0BAOM,MAAA,KAAA,SAAA;OACL,UAA8B,cACjC,MAAA,KAAA,QAAA;;CAIJ,MAAM,aAAS,KAAA,SADC,SAAA;CAEhB,IAAI,CAAC,WACH,WAAA,EAAA,OAAA,EAAA;CAEF,OAAA,YAAmB,YAAE,EAAW,eAAO,MAAA,CAAA,CAAA,QAAA,MAAA,EAAA,aAAA,KAAA,WAAA,KAAA,YAAA,EAAA,MAAA,WAAA,CAAA,IAAA,WAAA,KAAA,YAAA,EAAA,MAAA,YAAA,CAAA,EAAA,CAAA,KAAA,OAAA;EACvC,WAAY,EAAA;;;;SAWP,iBACM,SAAA,WAAA,WAAA;CAEX,MAAM,WAAA,KAAa,SAAK,UAAS;CACjC,IAAI,WAAC,SAAW,EAAA,IACd,UAAS,SAAA,CAAA,gBAAA,EAAA,WAAA,SAAA;MAEX,OAAO,UAAY;EAEJ,WAAW;EAAQ,OAAA;EAAoC,CAAA;;;SAKhE,eAAgB,MAAA,KAAS,SAAU;CACzC,MAAI,UAAW,cACA,MAAA,KAAU,QACf;MAEH,SAAO,OAAA;MAAY,MAAA,aAAW;EAAM;EAAa;EAExD;;;;SAMK,eACI,MAAA,KAAA,SAAA;CAGT,MAAK,UAAM,cAAa,MAAA,KAAA,QAAA;KADA,CAAA,SAAA,OAAA,EAAA;OAAQ,QAAA,EAAA;OAAiB,gBAAA,oBAAA,KAAA,SAAA,eAAA,CAAA;KAG/C,eADiB;EAInB,MAAO,MAAA,cAAA;;;;;;CAOT,MAAA,UAAgB,YAAe,QAA2B,CAAA,QAA4B,MAAA,mBAAA,KAAA,EAAA,IAAA,eAAA,KAAA,EAAA,CAAA;CACpF,MAAM,KAAA,GAAA,QAAU;CAChB,OAAK,CAAA,GAAA,IACH,IAAA,MAAS,CAAA;;SAMP,iBAAe,GAAA,iBAAA,GAAA,oBAAA,GAAA,oBAAA,GAAA,qBAAA,GAAA,kBAAA,GAAA,eAAA,GAAA,kBAAA"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { d as getSharedSkillsDir } from "./paths.mjs";
|
|
2
|
-
import { i as restorePkgSymlink, n as linkShippedSkill, t as getShippedSkills } from "./prepare.mjs";
|
|
3
1
|
import { a as targets } from "./detect.mjs";
|
|
4
2
|
import "./agent.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
3
|
+
import { g as todayIsoDate, i as linkSkillToAgents } from "./prompts.mjs";
|
|
4
|
+
import { f as getSharedSkillsDir } from "./paths.mjs";
|
|
5
|
+
import { h as VERSION_RANGE_PREFIX_RE } from "./regex.mjs";
|
|
6
|
+
import { i as linkShippedSkill, n as getShippedSkills, o as restorePkgSymlink } from "./prepare.mjs";
|
|
7
|
+
import { r as resolveAgent } from "./agent-prompt.mjs";
|
|
7
8
|
import { c as readLock, d as writeLock } from "./lockfile.mjs";
|
|
8
9
|
import { t as getProjectState } from "./skills.mjs";
|
|
9
10
|
import { existsSync, mkdirSync } from "node:fs";
|
|
10
|
-
import { join } from "pathe";
|
|
11
11
|
import * as p from "@clack/prompts";
|
|
12
12
|
import { defineCommand } from "citty";
|
|
13
|
+
import { join } from "pathe";
|
|
13
14
|
const prepareCommandDef = defineCommand({
|
|
14
15
|
meta: {
|
|
15
16
|
name: "prepare",
|
|
@@ -50,7 +51,7 @@ const prepareCommandDef = defineCommand({
|
|
|
50
51
|
if (state.shipped.length > 0) {
|
|
51
52
|
mkdirSync(skillsDir, { recursive: true });
|
|
52
53
|
for (const entry of state.shipped) {
|
|
53
|
-
const version = state.deps.get(entry.packageName)?.replace(
|
|
54
|
+
const version = state.deps.get(entry.packageName)?.replace(VERSION_RANGE_PREFIX_RE, "") || "0.0.0";
|
|
54
55
|
for (const skill of entry.skills) {
|
|
55
56
|
linkShippedSkill(skillsDir, skill.skillName, skill.skillDir);
|
|
56
57
|
writeLock(skillsDir, skill.skillName, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prepare2.mjs","names":["agents"],"sources":["../../src/commands/prepare.ts"],"sourcesContent":["/**\n * Prepare command — lightweight hook for package.json \"prepare\" script.\n *\n * Designed to run on every `pnpm install` / `npm install`. Blocking, fast, no LLM calls.\n * 1. Restore broken symlinks from lockfile (like `install` but skips doc fetching)\n * 2. Auto-install shipped skills from deps (just symlinks + lockfile writes)\n * 3. Report outdated skills count and suggest `skilld update`\n */\n\nimport { existsSync, mkdirSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join } from 'pathe'\nimport { agents, linkSkillToAgents } from '../agent/index.ts'\nimport { resolveAgent } from '../cli-
|
|
1
|
+
{"version":3,"file":"prepare2.mjs","names":["agents"],"sources":["../../src/commands/prepare.ts"],"sourcesContent":["/**\n * Prepare command — lightweight hook for package.json \"prepare\" script.\n *\n * Designed to run on every `pnpm install` / `npm install`. Blocking, fast, no LLM calls.\n * 1. Restore broken symlinks from lockfile (like `install` but skips doc fetching)\n * 2. Auto-install shipped skills from deps (just symlinks + lockfile writes)\n * 3. Report outdated skills count and suggest `skilld update`\n */\n\nimport { existsSync, mkdirSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join } from 'pathe'\nimport { agents, linkSkillToAgents } from '../agent/index.ts'\nimport { resolveAgent } from '../cli/agent-prompt.ts'\nimport { todayIsoDate } from '../core/formatting.ts'\nimport { readLock, writeLock } from '../core/lockfile.ts'\nimport { getSharedSkillsDir } from '../core/paths.ts'\nimport { getShippedSkills, linkShippedSkill, restorePkgSymlink } from '../core/prepare.ts'\nimport { VERSION_RANGE_PREFIX_RE } from '../core/regex.ts'\nimport { getProjectState } from '../core/skills.ts'\n\nexport const prepareCommandDef = defineCommand({\n meta: { name: 'prepare', description: 'Restore references and sync shipped skills (for package.json hooks)' },\n args: {\n agent: {\n type: 'enum' as const,\n options: Object.keys(agents),\n alias: 'a',\n description: 'Target agent',\n },\n },\n async run({ args }) {\n const cwd = process.cwd()\n\n const agent = resolveAgent(args.agent)\n if (!agent || agent === 'none')\n return\n\n const agentConfig = agents[agent]\n const shared = getSharedSkillsDir(cwd)\n const skillsDir = shared || join(cwd, agentConfig.skillsDir)\n\n // ── Fast path: read primary lockfile, check all skills intact ──\n\n const lock = readLock(skillsDir)\n if (lock && Object.keys(lock.skills).length > 0) {\n let allIntact = true\n\n for (const [name, info] of Object.entries(lock.skills)) {\n if (!info.version)\n continue\n\n const skillDir = join(skillsDir, name)\n if (existsSync(skillDir)) {\n // Skill dir exists; for non-shipped, also check .skilld/pkg symlink\n if (info.source !== 'shipped')\n restorePkgSymlink(skillsDir, name, info, cwd)\n continue\n }\n\n // Skill dir missing, needs restore\n allIntact = false\n\n if (info.source === 'shipped') {\n const pkgName = info.packageName || name\n const shipped = getShippedSkills(pkgName, cwd, info.version)\n const match = shipped.find(s => s.skillName === name)\n if (match)\n linkShippedSkill(skillsDir, name, match.skillDir)\n }\n }\n\n // If all skills intact, skip expensive getProjectState entirely\n if (allIntact)\n return\n }\n\n // ── Slow path: discover new shipped skills + report outdated ──\n\n const state = await getProjectState(cwd)\n let shippedCount = 0\n\n if (state.shipped.length > 0) {\n mkdirSync(skillsDir, { recursive: true })\n\n for (const entry of state.shipped) {\n const version = state.deps.get(entry.packageName)?.replace(VERSION_RANGE_PREFIX_RE, '') || '0.0.0'\n\n for (const skill of entry.skills) {\n linkShippedSkill(skillsDir, skill.skillName, skill.skillDir)\n writeLock(skillsDir, skill.skillName, {\n packageName: entry.packageName,\n version,\n source: 'shipped',\n syncedAt: todayIsoDate(),\n generator: 'skilld',\n })\n\n if (shared)\n linkSkillToAgents(skill.skillName, shared, cwd, agent)\n\n shippedCount++\n }\n }\n\n if (shippedCount > 0)\n p.log.success(`Installed ${shippedCount} shipped skill${shippedCount > 1 ? 's' : ''}`)\n }\n\n if (state.outdated.length > 0) {\n const n = state.outdated.length\n p.log.info(`${n} package${n > 1 ? 's' : ''} ha${n > 1 ? 've' : 's'} new features and/or breaking changes. Run \\`skilld update\\` to sync.`)\n }\n },\n})\n"],"mappings":";;;;;;;;;;;;;;;;;;;;EAsBA,SAAa,OAAA,KAAA,QAAoB;EAC/B,OAAM;EAAE,aAAM;EAAW,EAAA;OAAoF,IAAA,EAAA,QAAA;EAC7G,MAAM,MACJ,QAAO,KAAA;EACL,MAAM,QAAA,aAAA,KAAA,MAAA;EACN,IAAA,CAAA,SAAS,UAAYA,QAAO;EAC5B,MAAA,cAAO,QAAA;EACP,MAAA,SAAa,mBAAA,IAAA;EACd,MACF,YAAA,UAAA,KAAA,KAAA,YAAA,UAAA;EACD,MAAM,OAAM,SAAQ,UAAA;EAClB,IAAA,QAAY,OAAA,KAAQ,KAAK,OAAA,CAAA,SAAA,GAAA;GAEzB,IAAA,YAAc;GACd,KAAK,MAAA,CAAA,MAAS,SAAU,OACtB,QAAA,KAAA,OAAA,EAAA;IAEF,IAAM,CAAA,KAAA,SAAcA;IACpB,IAAM,WAAS,KAAA,WAAA,KAAuB,CAAA,EAAA;KACtC,IAAM,KAAA,WAAY,WAAe,kBAAiB,WAAU,MAAA,MAAA,IAAA;KAI5D;;IAEE,YAAI;IAEJ,IAAK,KAAA,WAAa,WAAS;KACzB,MAAK,QAAK,iBACR,KAAA,eAAA,MAAA,KAAA,KAAA,QAAA,CAAA,MAAA,MAAA,EAAA,cAAA,KAAA;KAGF,IAAI,OAAA,iBADkB,WACI,MAAA,MAAA,SAAA;;;;;QAUtB,QAAK,MAAA,gBAAsB,IAAA;MAG7B,eADgB;MAEhB,MAAI,QACF,SAAA,GAAA;;;IAKN,MAAI,UACF,MAAA,KAAA,IAAA,MAAA,YAAA,EAAA,QAAA,yBAAA,GAAA,IAAA;;KAKJ,iBAAoB,WAAA,MAAgB,WAAI,MAAA,SAAA;KACxC,UAAI,WAAe,MAAA,WAAA;MAEf,aAAM,MAAQ;MAChB;MAEA,QAAW;MACT,UAAM,cAAgB;MAEtB,WAAW;MACT,CAAA;KACA,IAAA,QAAU,kBAAiB,MAAA,WAAW,QAAA,KAAA,MAAA;;;;OAIpC,eAAU,GAAA,EAAA,IAAc,QAAA,aAAA,aAAA,gBAAA,eAAA,IAAA,MAAA,KAAA;;MAEzB,MAAC,SAAA,SAAA,GAAA;SAEE,IAAA,MACF,SAAA;KAEF,IAAA,KAAA,GAAA,EAAA,UAAA,IAAA,IAAA,MAAA,GAAA,KAAA,IAAA,IAAA,OAAA,IAAA,uEAAA;;;;SAQF"}
|