skilld 1.2.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/agent.mjs +4 -0
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +14 -6
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/index2.d.mts.map +1 -1
- package/dist/_chunks/prompts.mjs +1 -1
- package/dist/_chunks/sanitize.mjs +1 -1
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/shared.mjs +6 -2
- package/dist/_chunks/shared.mjs.map +1 -1
- package/dist/_chunks/skills.mjs +4 -2
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/sources.mjs +59 -41
- package/dist/_chunks/sources.mjs.map +1 -1
- package/dist/_chunks/sync.mjs +1 -1
- package/dist/sources/index.mjs +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.mjs","names":["_semverGt"],"sources":["../../src/sources/package-registry.ts","../../src/core/shared.ts"],"sourcesContent":["/**\n * Unified package registry — single source of truth for package metadata.\n * Consolidates doc overrides, blog presets, and file patterns.\n * Keyed by GitHub 'owner/repo' (source code repo).\n */\n\nexport interface BlogRelease {\n version: string\n url: string\n date: string\n title?: string\n}\n\nexport interface PackageEntry {\n filePatterns?: string[]\n primary?: boolean\n /** Extra rules injected into skill generation prompts */\n rules?: string[]\n}\n\nexport interface RepoEntry {\n owner: string\n repo: string\n /** Separate docs repo name (e.g. 'docs' → owner/docs) */\n docsRepo?: string\n /** Path prefix to filter markdown files */\n docsPath?: string\n /** Branch/ref override */\n docsRef?: string\n /** Homepage URL */\n homepage?: string\n /** URL pattern to crawl for docs (glob, e.g. 'https://example.com/docs/**') */\n crawlUrl?: string\n /** Branch to fetch CHANGELOG.md from when installed version is a prerelease (e.g. 'minor' for Vue) */\n prereleaseChangelogRef?: string\n /** Packages in this repo */\n packages: Record<string, PackageEntry>\n /** Curated blog release posts */\n blogReleases?: BlogRelease[]\n}\n\n// Backwards-compatible types\nexport interface DocOverride {\n owner: string\n repo: string\n path: string\n ref?: string\n homepage?: string\n}\n\nexport interface BlogPreset {\n packageName: string\n releases: BlogRelease[]\n}\n\n// ── Registry ──\n\nconst REPO_REGISTRY: Record<string, RepoEntry> = {\n // ── Frameworks with doc overrides ──\n\n 'vuejs/core': {\n owner: 'vuejs',\n repo: 'core',\n docsRepo: 'docs',\n docsPath: 'src',\n homepage: 'https://vuejs.org',\n prereleaseChangelogRef: 'minor',\n packages: {\n 'vue': { primary: true, filePatterns: ['*.vue'], rules: ['ALWAYS use `<script setup lang=\"ts\">`', 'Use ```vue code fences for SFC examples containing `<script>` or `<template>` tags, ```ts for plain TypeScript'] },\n '@vue/compiler-core': {},\n '@vue/compiler-dom': {},\n '@vue/reactivity': {},\n '@vue/runtime-core': {},\n '@vue/runtime-dom': {},\n '@vue/shared': {},\n },\n blogReleases: [\n { version: '3.5', url: 'https://blog.vuejs.org/posts/vue-3-5', date: '2024-09-01' },\n { version: '3.4', url: 'https://blog.vuejs.org/posts/vue-3-4', date: '2023-12-28' },\n { version: '3.3', url: 'https://blog.vuejs.org/posts/vue-3-3', date: '2023-05-11' },\n { version: '3.2', url: 'https://blog.vuejs.org/posts/vue-3-2', date: '2021-08-05' },\n { version: '3.1', url: 'https://blog.vuejs.org/posts/vue-3-1', date: '2021-06-07' },\n { version: '3.0', url: 'https://blog.vuejs.org/posts/vue-3-0', date: '2020-09-18' },\n ],\n },\n\n 'tailwindlabs/tailwindcss': {\n owner: 'tailwindlabs',\n repo: 'tailwindcss',\n docsRepo: 'tailwindcss.com',\n docsPath: 'src/docs',\n homepage: 'https://tailwindcss.com',\n packages: {\n tailwindcss: { primary: true },\n },\n },\n\n 'withastro/astro': {\n owner: 'withastro',\n repo: 'astro',\n docsRepo: 'docs',\n docsPath: 'src/content/docs/en',\n homepage: 'https://docs.astro.build',\n packages: {\n astro: { primary: true, filePatterns: ['*.astro'] },\n },\n },\n\n 'vueuse/vueuse': {\n owner: 'vueuse',\n repo: 'vueuse',\n docsPath: 'packages',\n packages: {\n '@vueuse/core': { primary: true },\n },\n },\n\n // ── Frameworks (file patterns only) ──\n\n 'sveltejs/svelte': {\n owner: 'sveltejs',\n repo: 'svelte',\n packages: {\n svelte: { primary: true, filePatterns: ['*.svelte'], rules: ['ALWAYS use runes syntax ($state, $derived, $effect, $props)'] },\n },\n },\n\n 'solidjs/solid': {\n owner: 'solidjs',\n repo: 'solid',\n packages: {\n 'solid-js': { primary: true, filePatterns: ['*.jsx', '*.tsx'] },\n },\n },\n\n 'QwikDev/qwik': {\n owner: 'QwikDev',\n repo: 'qwik',\n packages: {\n qwik: { primary: true, filePatterns: ['*.tsx'] },\n },\n },\n\n 'marko-js/marko': {\n owner: 'marko-js',\n repo: 'marko',\n packages: {\n marko: { primary: true, filePatterns: ['*.marko'] },\n },\n },\n\n 'riot/riot': {\n owner: 'riot',\n repo: 'riot',\n packages: {\n riot: { primary: true, filePatterns: ['*.riot'] },\n },\n },\n\n // ── Languages/transpilers ──\n\n 'microsoft/TypeScript': {\n owner: 'microsoft',\n repo: 'TypeScript',\n packages: {\n typescript: { primary: true, filePatterns: ['*.ts', '*.tsx', '*.mts', '*.cts'] },\n },\n blogReleases: [\n { version: '6.0', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-6-0-beta/', date: '2026-02-11', title: 'Announcing TypeScript 6.0 Beta' },\n { version: '5.9', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-5-9/', date: '2025-08-01', title: 'Announcing TypeScript 5.9' },\n { version: '5.8', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-5-8/', date: '2025-02-28', title: 'Announcing TypeScript 5.8' },\n { version: '5.7', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-5-7/', date: '2024-11-22', title: 'Announcing TypeScript 5.7' },\n { version: '5.6', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-5-6/', date: '2024-09-09', title: 'Announcing TypeScript 5.6' },\n { version: '5.5', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/', date: '2024-06-20', title: 'Announcing TypeScript 5.5' },\n ],\n },\n\n 'jashkenas/coffeescript': {\n owner: 'jashkenas',\n repo: 'coffeescript',\n packages: {\n coffeescript: { primary: true, filePatterns: ['*.coffee'] },\n },\n },\n\n 'gkz/LiveScript': {\n owner: 'gkz',\n repo: 'LiveScript',\n packages: {\n livescript: { primary: true, filePatterns: ['*.ls'] },\n },\n },\n\n 'elm/compiler': {\n owner: 'elm',\n repo: 'compiler',\n packages: {\n elm: { primary: true, filePatterns: ['*.elm'] },\n },\n },\n\n // ── CSS preprocessors ──\n\n 'sass/dart-sass': {\n owner: 'sass',\n repo: 'dart-sass',\n packages: {\n sass: { primary: true, filePatterns: ['*.scss', '*.sass'] },\n },\n },\n\n 'less/less.js': {\n owner: 'less',\n repo: 'less.js',\n packages: {\n less: { primary: true, filePatterns: ['*.less'] },\n },\n },\n\n 'stylus/stylus': {\n owner: 'stylus',\n repo: 'stylus',\n packages: {\n stylus: { primary: true, filePatterns: ['*.styl'] },\n },\n },\n\n 'postcss/postcss': {\n owner: 'postcss',\n repo: 'postcss',\n packages: {\n postcss: { primary: true, filePatterns: ['*.css', '*.pcss'] },\n },\n },\n\n // ── Template engines ──\n\n 'pugjs/pug': {\n owner: 'pugjs',\n repo: 'pug',\n packages: {\n pug: { primary: true, filePatterns: ['*.pug'] },\n },\n },\n\n 'mde/ejs': {\n owner: 'mde',\n repo: 'ejs',\n packages: {\n ejs: { primary: true, filePatterns: ['*.ejs'] },\n },\n },\n\n 'handlebars-lang/handlebars.js': {\n owner: 'handlebars-lang',\n repo: 'handlebars.js',\n packages: {\n handlebars: { primary: true, filePatterns: ['*.hbs', '*.handlebars'] },\n },\n },\n\n 'janl/mustache.js': {\n owner: 'janl',\n repo: 'mustache.js',\n packages: {\n mustache: { primary: true, filePatterns: ['*.mustache'] },\n },\n },\n\n 'mozilla/nunjucks': {\n owner: 'mozilla',\n repo: 'nunjucks',\n packages: {\n nunjucks: { primary: true, filePatterns: ['*.njk'] },\n },\n },\n\n 'Shopify/liquid': {\n owner: 'Shopify',\n repo: 'liquid',\n packages: {\n liquid: { primary: true, filePatterns: ['*.liquid'] },\n },\n },\n\n // ── Data formats ──\n\n 'eemeli/yaml': {\n owner: 'eemeli',\n repo: 'yaml',\n packages: {\n yaml: { primary: true, filePatterns: ['*.yaml', '*.yml'] },\n },\n },\n\n 'nodeca/js-yaml': {\n owner: 'nodeca',\n repo: 'js-yaml',\n packages: {\n 'js-yaml': { primary: true, filePatterns: ['*.yaml', '*.yml'] },\n },\n },\n\n 'BinaryMuse/toml-node': {\n owner: 'BinaryMuse',\n repo: 'toml-node',\n packages: {\n 'toml': { primary: true, filePatterns: ['*.toml'] },\n '@iarna/toml': { filePatterns: ['*.toml'] },\n },\n },\n\n 'json5/json5': {\n owner: 'json5',\n repo: 'json5',\n packages: {\n json5: { primary: true, filePatterns: ['*.json5'] },\n },\n },\n\n 'microsoft/node-jsonc-parser': {\n owner: 'microsoft',\n repo: 'node-jsonc-parser',\n packages: {\n 'jsonc-parser': { primary: true, filePatterns: ['*.jsonc'] },\n },\n },\n\n // ── Markdown ──\n\n 'markdown-it/markdown-it': {\n owner: 'markdown-it',\n repo: 'markdown-it',\n packages: {\n 'markdown-it': { primary: true, filePatterns: ['*.md'] },\n },\n },\n\n 'markedjs/marked': {\n owner: 'markedjs',\n repo: 'marked',\n packages: {\n marked: { primary: true, filePatterns: ['*.md'] },\n },\n },\n\n 'remarkjs/remark': {\n owner: 'remarkjs',\n repo: 'remark',\n packages: {\n remark: { primary: true, filePatterns: ['*.md', '*.mdx'] },\n },\n },\n\n 'mdx-js/mdx': {\n owner: 'mdx-js',\n repo: 'mdx',\n packages: {\n '@mdx-js/mdx': { primary: true, filePatterns: ['*.mdx'] },\n },\n },\n\n // ── GraphQL ──\n\n 'graphql/graphql-js': {\n owner: 'graphql',\n repo: 'graphql-js',\n packages: {\n 'graphql': { primary: true, filePatterns: ['*.graphql', '*.gql'] },\n 'graphql-tag': { filePatterns: ['*.graphql', '*.gql'] },\n },\n },\n\n 'dotansimha/graphql-code-generator': {\n owner: 'dotansimha',\n repo: 'graphql-code-generator',\n packages: {\n '@graphql-codegen/cli': { primary: true, filePatterns: ['*.graphql', '*.gql'] },\n },\n },\n\n // ── UI Frameworks ──\n\n 'quasarframework/quasar': {\n owner: 'quasarframework',\n repo: 'quasar',\n docsPath: 'docs/src/pages',\n docsRef: 'dev',\n homepage: 'https://quasar.dev',\n packages: {\n quasar: { primary: true },\n },\n },\n\n // ── Animation ──\n\n 'motiondivision/motion-vue': {\n owner: 'motiondivision',\n repo: 'motion-vue',\n homepage: 'https://motion.dev',\n crawlUrl: 'https://motion.dev/docs/vue**',\n packages: {\n 'motion-v': { primary: true },\n },\n },\n\n // ── Other ──\n\n 'prisma/prisma': {\n owner: 'prisma',\n repo: 'prisma',\n packages: {\n 'prisma': { primary: true, filePatterns: ['*.prisma'] },\n '@prisma/client': { filePatterns: ['*.prisma'] },\n },\n },\n\n 'nicolo-ribaudo/tc39-proposal-wasm-esm-integration': {\n owner: 'nicolo-ribaudo',\n repo: 'tc39-proposal-wasm-esm-integration',\n packages: {\n 'wasm-pack': { primary: true, filePatterns: ['*.wasm'] },\n },\n },\n}\n\n// ── Reverse index (auto-generated) ──\n\nconst PACKAGE_TO_REPO_MAP: Record<string, string> = {}\n\nfor (const [repoKey, entry] of Object.entries(REPO_REGISTRY)) {\n for (const packageName of Object.keys(entry.packages)) {\n PACKAGE_TO_REPO_MAP[packageName] = repoKey\n }\n}\n\n// ── Backwards-compatible helpers ──\n\nexport function getDocOverride(packageName: string): DocOverride | undefined {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return undefined\n const entry = REPO_REGISTRY[repoKey]\n if (!entry?.docsRepo && !entry?.docsPath)\n return undefined\n\n return {\n owner: entry.owner,\n repo: entry.docsRepo || entry.repo,\n path: entry.docsPath || '',\n ref: entry.docsRef,\n homepage: entry.homepage,\n }\n}\n\nexport function getBlogPreset(packageName: string): BlogPreset | undefined {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return undefined\n const entry = REPO_REGISTRY[repoKey]\n if (!entry?.blogReleases)\n return undefined\n\n return {\n packageName,\n releases: entry.blogReleases,\n }\n}\n\nexport function getFilePatterns(packageName: string): string[] | undefined {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return undefined\n return REPO_REGISTRY[repoKey]?.packages[packageName]?.filePatterns\n}\n\n// ── New APIs ──\n\nexport function getRepoEntry(repoKey: string): RepoEntry | undefined {\n return REPO_REGISTRY[repoKey]\n}\n\nexport function getRepoKeyForPackage(packageName: string): string | undefined {\n return PACKAGE_TO_REPO_MAP[packageName]\n}\n\nexport function getPackageRules(packageName: string): string[] {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return []\n return REPO_REGISTRY[repoKey]?.packages[packageName]?.rules ?? []\n}\n\nexport function getPrereleaseChangelogRef(packageName: string): string | undefined {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return undefined\n return REPO_REGISTRY[repoKey]?.prereleaseChangelogRef\n}\n\nexport function getCrawlUrl(packageName: string): string | undefined {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return undefined\n return REPO_REGISTRY[repoKey]?.crawlUrl\n}\n\nexport function getRelatedPackages(packageName: string): string[] {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return []\n const entry = REPO_REGISTRY[repoKey]\n if (!entry)\n return []\n return Object.keys(entry.packages)\n}\n","import { execSync } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { gt as _semverGt } from 'semver'\nimport { isWindows } from 'std-env'\n\n/** Get-or-create for Maps. Polyfill for Map.getOrInsertComputed (not yet in Node.js). */\nexport function mapInsert<K, V>(map: Map<K, V>, key: K, create: () => V): V {\n let val = map.get(key)\n if (val === undefined) {\n val = create()\n map.set(key, val)\n }\n return val\n}\n\n/** Compare two semver strings: returns true if a > b. Handles prereleases. */\nexport function semverGt(a: string, b: string): boolean {\n return _semverGt(a, b, true)\n}\n\nlet _skilldCommand: string | undefined\n\n/** Resolve the skilld CLI command — returns `skilld` if the binary is in PATH, otherwise `npx -y skilld` */\nexport function resolveSkilldCommand(): string {\n if (_skilldCommand !== undefined)\n return _skilldCommand\n try {\n const lookup = isWindows ? 'where' : 'which'\n execSync(`${lookup} skilld`, { stdio: 'ignore' })\n _skilldCommand = 'skilld'\n }\n catch {\n _skilldCommand = 'npx -y skilld'\n }\n return _skilldCommand\n}\n\nexport const SHARED_SKILLS_DIR = '.skills'\n\n/** Returns the shared skills directory path if `.skills/` exists at project root, else null */\nexport function getSharedSkillsDir(cwd: string = process.cwd()): string | null {\n const dir = join(cwd, SHARED_SKILLS_DIR)\n return existsSync(dir) ? dir : null\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"shared.mjs","names":["_semverValid","_semverGt"],"sources":["../../src/sources/package-registry.ts","../../src/core/shared.ts"],"sourcesContent":["/**\n * Unified package registry — single source of truth for package metadata.\n * Consolidates doc overrides, blog presets, and file patterns.\n * Keyed by GitHub 'owner/repo' (source code repo).\n */\n\nexport interface BlogRelease {\n version: string\n url: string\n date: string\n title?: string\n}\n\nexport interface PackageEntry {\n filePatterns?: string[]\n primary?: boolean\n /** Extra rules injected into skill generation prompts */\n rules?: string[]\n}\n\nexport interface RepoEntry {\n owner: string\n repo: string\n /** Separate docs repo name (e.g. 'docs' → owner/docs) */\n docsRepo?: string\n /** Path prefix to filter markdown files */\n docsPath?: string\n /** Branch/ref override */\n docsRef?: string\n /** Homepage URL */\n homepage?: string\n /** URL pattern to crawl for docs (glob, e.g. 'https://example.com/docs/**') */\n crawlUrl?: string\n /** Branch to fetch CHANGELOG.md from when installed version is a prerelease (e.g. 'minor' for Vue) */\n prereleaseChangelogRef?: string\n /** Packages in this repo */\n packages: Record<string, PackageEntry>\n /** Curated blog release posts */\n blogReleases?: BlogRelease[]\n}\n\n// Backwards-compatible types\nexport interface DocOverride {\n owner: string\n repo: string\n path: string\n ref?: string\n homepage?: string\n}\n\nexport interface BlogPreset {\n packageName: string\n releases: BlogRelease[]\n}\n\n// ── Registry ──\n\nconst REPO_REGISTRY: Record<string, RepoEntry> = {\n // ── Frameworks with doc overrides ──\n\n 'vuejs/core': {\n owner: 'vuejs',\n repo: 'core',\n docsRepo: 'docs',\n docsPath: 'src',\n homepage: 'https://vuejs.org',\n prereleaseChangelogRef: 'minor',\n packages: {\n 'vue': { primary: true, filePatterns: ['*.vue'], rules: ['ALWAYS use `<script setup lang=\"ts\">`', 'Use ```vue code fences for SFC examples containing `<script>` or `<template>` tags, ```ts for plain TypeScript'] },\n '@vue/compiler-core': {},\n '@vue/compiler-dom': {},\n '@vue/reactivity': {},\n '@vue/runtime-core': {},\n '@vue/runtime-dom': {},\n '@vue/shared': {},\n },\n blogReleases: [\n { version: '3.5', url: 'https://blog.vuejs.org/posts/vue-3-5', date: '2024-09-01' },\n { version: '3.4', url: 'https://blog.vuejs.org/posts/vue-3-4', date: '2023-12-28' },\n { version: '3.3', url: 'https://blog.vuejs.org/posts/vue-3-3', date: '2023-05-11' },\n { version: '3.2', url: 'https://blog.vuejs.org/posts/vue-3-2', date: '2021-08-05' },\n { version: '3.1', url: 'https://blog.vuejs.org/posts/vue-3-1', date: '2021-06-07' },\n { version: '3.0', url: 'https://blog.vuejs.org/posts/vue-3-0', date: '2020-09-18' },\n ],\n },\n\n 'tailwindlabs/tailwindcss': {\n owner: 'tailwindlabs',\n repo: 'tailwindcss',\n docsRepo: 'tailwindcss.com',\n docsPath: 'src/docs',\n homepage: 'https://tailwindcss.com',\n packages: {\n tailwindcss: { primary: true },\n },\n },\n\n 'withastro/astro': {\n owner: 'withastro',\n repo: 'astro',\n docsRepo: 'docs',\n docsPath: 'src/content/docs/en',\n homepage: 'https://docs.astro.build',\n packages: {\n astro: { primary: true, filePatterns: ['*.astro'] },\n },\n },\n\n 'vueuse/vueuse': {\n owner: 'vueuse',\n repo: 'vueuse',\n docsPath: 'packages',\n packages: {\n '@vueuse/core': { primary: true },\n },\n },\n\n // ── Frameworks (file patterns only) ──\n\n 'sveltejs/svelte': {\n owner: 'sveltejs',\n repo: 'svelte',\n packages: {\n svelte: { primary: true, filePatterns: ['*.svelte'], rules: ['ALWAYS use runes syntax ($state, $derived, $effect, $props)'] },\n },\n },\n\n 'solidjs/solid': {\n owner: 'solidjs',\n repo: 'solid',\n packages: {\n 'solid-js': { primary: true, filePatterns: ['*.jsx', '*.tsx'] },\n },\n },\n\n 'QwikDev/qwik': {\n owner: 'QwikDev',\n repo: 'qwik',\n packages: {\n qwik: { primary: true, filePatterns: ['*.tsx'] },\n },\n },\n\n 'marko-js/marko': {\n owner: 'marko-js',\n repo: 'marko',\n packages: {\n marko: { primary: true, filePatterns: ['*.marko'] },\n },\n },\n\n 'riot/riot': {\n owner: 'riot',\n repo: 'riot',\n packages: {\n riot: { primary: true, filePatterns: ['*.riot'] },\n },\n },\n\n // ── Languages/transpilers ──\n\n 'microsoft/TypeScript': {\n owner: 'microsoft',\n repo: 'TypeScript',\n packages: {\n typescript: { primary: true, filePatterns: ['*.ts', '*.tsx', '*.mts', '*.cts'] },\n },\n blogReleases: [\n { version: '6.0', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-6-0-beta/', date: '2026-02-11', title: 'Announcing TypeScript 6.0 Beta' },\n { version: '5.9', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-5-9/', date: '2025-08-01', title: 'Announcing TypeScript 5.9' },\n { version: '5.8', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-5-8/', date: '2025-02-28', title: 'Announcing TypeScript 5.8' },\n { version: '5.7', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-5-7/', date: '2024-11-22', title: 'Announcing TypeScript 5.7' },\n { version: '5.6', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-5-6/', date: '2024-09-09', title: 'Announcing TypeScript 5.6' },\n { version: '5.5', url: 'https://devblogs.microsoft.com/typescript/announcing-typescript-5-5/', date: '2024-06-20', title: 'Announcing TypeScript 5.5' },\n ],\n },\n\n 'jashkenas/coffeescript': {\n owner: 'jashkenas',\n repo: 'coffeescript',\n packages: {\n coffeescript: { primary: true, filePatterns: ['*.coffee'] },\n },\n },\n\n 'gkz/LiveScript': {\n owner: 'gkz',\n repo: 'LiveScript',\n packages: {\n livescript: { primary: true, filePatterns: ['*.ls'] },\n },\n },\n\n 'elm/compiler': {\n owner: 'elm',\n repo: 'compiler',\n packages: {\n elm: { primary: true, filePatterns: ['*.elm'] },\n },\n },\n\n // ── CSS preprocessors ──\n\n 'sass/dart-sass': {\n owner: 'sass',\n repo: 'dart-sass',\n packages: {\n sass: { primary: true, filePatterns: ['*.scss', '*.sass'] },\n },\n },\n\n 'less/less.js': {\n owner: 'less',\n repo: 'less.js',\n packages: {\n less: { primary: true, filePatterns: ['*.less'] },\n },\n },\n\n 'stylus/stylus': {\n owner: 'stylus',\n repo: 'stylus',\n packages: {\n stylus: { primary: true, filePatterns: ['*.styl'] },\n },\n },\n\n 'postcss/postcss': {\n owner: 'postcss',\n repo: 'postcss',\n packages: {\n postcss: { primary: true, filePatterns: ['*.css', '*.pcss'] },\n },\n },\n\n // ── Template engines ──\n\n 'pugjs/pug': {\n owner: 'pugjs',\n repo: 'pug',\n packages: {\n pug: { primary: true, filePatterns: ['*.pug'] },\n },\n },\n\n 'mde/ejs': {\n owner: 'mde',\n repo: 'ejs',\n packages: {\n ejs: { primary: true, filePatterns: ['*.ejs'] },\n },\n },\n\n 'handlebars-lang/handlebars.js': {\n owner: 'handlebars-lang',\n repo: 'handlebars.js',\n packages: {\n handlebars: { primary: true, filePatterns: ['*.hbs', '*.handlebars'] },\n },\n },\n\n 'janl/mustache.js': {\n owner: 'janl',\n repo: 'mustache.js',\n packages: {\n mustache: { primary: true, filePatterns: ['*.mustache'] },\n },\n },\n\n 'mozilla/nunjucks': {\n owner: 'mozilla',\n repo: 'nunjucks',\n packages: {\n nunjucks: { primary: true, filePatterns: ['*.njk'] },\n },\n },\n\n 'Shopify/liquid': {\n owner: 'Shopify',\n repo: 'liquid',\n packages: {\n liquid: { primary: true, filePatterns: ['*.liquid'] },\n },\n },\n\n // ── Data formats ──\n\n 'eemeli/yaml': {\n owner: 'eemeli',\n repo: 'yaml',\n packages: {\n yaml: { primary: true, filePatterns: ['*.yaml', '*.yml'] },\n },\n },\n\n 'nodeca/js-yaml': {\n owner: 'nodeca',\n repo: 'js-yaml',\n packages: {\n 'js-yaml': { primary: true, filePatterns: ['*.yaml', '*.yml'] },\n },\n },\n\n 'BinaryMuse/toml-node': {\n owner: 'BinaryMuse',\n repo: 'toml-node',\n packages: {\n 'toml': { primary: true, filePatterns: ['*.toml'] },\n '@iarna/toml': { filePatterns: ['*.toml'] },\n },\n },\n\n 'json5/json5': {\n owner: 'json5',\n repo: 'json5',\n packages: {\n json5: { primary: true, filePatterns: ['*.json5'] },\n },\n },\n\n 'microsoft/node-jsonc-parser': {\n owner: 'microsoft',\n repo: 'node-jsonc-parser',\n packages: {\n 'jsonc-parser': { primary: true, filePatterns: ['*.jsonc'] },\n },\n },\n\n // ── Markdown ──\n\n 'markdown-it/markdown-it': {\n owner: 'markdown-it',\n repo: 'markdown-it',\n packages: {\n 'markdown-it': { primary: true, filePatterns: ['*.md'] },\n },\n },\n\n 'markedjs/marked': {\n owner: 'markedjs',\n repo: 'marked',\n packages: {\n marked: { primary: true, filePatterns: ['*.md'] },\n },\n },\n\n 'remarkjs/remark': {\n owner: 'remarkjs',\n repo: 'remark',\n packages: {\n remark: { primary: true, filePatterns: ['*.md', '*.mdx'] },\n },\n },\n\n 'mdx-js/mdx': {\n owner: 'mdx-js',\n repo: 'mdx',\n packages: {\n '@mdx-js/mdx': { primary: true, filePatterns: ['*.mdx'] },\n },\n },\n\n // ── GraphQL ──\n\n 'graphql/graphql-js': {\n owner: 'graphql',\n repo: 'graphql-js',\n packages: {\n 'graphql': { primary: true, filePatterns: ['*.graphql', '*.gql'] },\n 'graphql-tag': { filePatterns: ['*.graphql', '*.gql'] },\n },\n },\n\n 'dotansimha/graphql-code-generator': {\n owner: 'dotansimha',\n repo: 'graphql-code-generator',\n packages: {\n '@graphql-codegen/cli': { primary: true, filePatterns: ['*.graphql', '*.gql'] },\n },\n },\n\n // ── UI Frameworks ──\n\n 'quasarframework/quasar': {\n owner: 'quasarframework',\n repo: 'quasar',\n docsPath: 'docs/src/pages',\n docsRef: 'dev',\n homepage: 'https://quasar.dev',\n packages: {\n quasar: { primary: true },\n },\n },\n\n // ── Animation ──\n\n 'motiondivision/motion-vue': {\n owner: 'motiondivision',\n repo: 'motion-vue',\n homepage: 'https://motion.dev',\n crawlUrl: 'https://motion.dev/docs/vue**',\n packages: {\n 'motion-v': { primary: true },\n },\n },\n\n // ── Other ──\n\n 'prisma/prisma': {\n owner: 'prisma',\n repo: 'prisma',\n packages: {\n 'prisma': { primary: true, filePatterns: ['*.prisma'] },\n '@prisma/client': { filePatterns: ['*.prisma'] },\n },\n },\n\n 'nicolo-ribaudo/tc39-proposal-wasm-esm-integration': {\n owner: 'nicolo-ribaudo',\n repo: 'tc39-proposal-wasm-esm-integration',\n packages: {\n 'wasm-pack': { primary: true, filePatterns: ['*.wasm'] },\n },\n },\n}\n\n// ── Reverse index (auto-generated) ──\n\nconst PACKAGE_TO_REPO_MAP: Record<string, string> = {}\n\nfor (const [repoKey, entry] of Object.entries(REPO_REGISTRY)) {\n for (const packageName of Object.keys(entry.packages)) {\n PACKAGE_TO_REPO_MAP[packageName] = repoKey\n }\n}\n\n// ── Backwards-compatible helpers ──\n\nexport function getDocOverride(packageName: string): DocOverride | undefined {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return undefined\n const entry = REPO_REGISTRY[repoKey]\n if (!entry?.docsRepo && !entry?.docsPath)\n return undefined\n\n return {\n owner: entry.owner,\n repo: entry.docsRepo || entry.repo,\n path: entry.docsPath || '',\n ref: entry.docsRef,\n homepage: entry.homepage,\n }\n}\n\nexport function getBlogPreset(packageName: string): BlogPreset | undefined {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return undefined\n const entry = REPO_REGISTRY[repoKey]\n if (!entry?.blogReleases)\n return undefined\n\n return {\n packageName,\n releases: entry.blogReleases,\n }\n}\n\nexport function getFilePatterns(packageName: string): string[] | undefined {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return undefined\n return REPO_REGISTRY[repoKey]?.packages[packageName]?.filePatterns\n}\n\n// ── New APIs ──\n\nexport function getRepoEntry(repoKey: string): RepoEntry | undefined {\n return REPO_REGISTRY[repoKey]\n}\n\nexport function getRepoKeyForPackage(packageName: string): string | undefined {\n return PACKAGE_TO_REPO_MAP[packageName]\n}\n\nexport function getPackageRules(packageName: string): string[] {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return []\n return REPO_REGISTRY[repoKey]?.packages[packageName]?.rules ?? []\n}\n\nexport function getPrereleaseChangelogRef(packageName: string): string | undefined {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return undefined\n return REPO_REGISTRY[repoKey]?.prereleaseChangelogRef\n}\n\nexport function getCrawlUrl(packageName: string): string | undefined {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return undefined\n return REPO_REGISTRY[repoKey]?.crawlUrl\n}\n\nexport function getRelatedPackages(packageName: string): string[] {\n const repoKey = PACKAGE_TO_REPO_MAP[packageName]\n if (!repoKey)\n return []\n const entry = REPO_REGISTRY[repoKey]\n if (!entry)\n return []\n return Object.keys(entry.packages)\n}\n","import { execSync } from 'node:child_process'\nimport { existsSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { gt as _semverGt, valid as _semverValid } from 'semver'\nimport { isWindows } from 'std-env'\n\n/** Get-or-create for Maps. Polyfill for Map.getOrInsertComputed (not yet in Node.js). */\nexport function mapInsert<K, V>(map: Map<K, V>, key: K, create: () => V): V {\n let val = map.get(key)\n if (val === undefined) {\n val = create()\n map.set(key, val)\n }\n return val\n}\n\n/** Returns the cleaned version if valid semver, null otherwise. */\nexport function semverValid(v: string): string | null {\n return _semverValid(v, true)\n}\n\n/** Compare two semver strings: returns true if a > b. Handles prereleases. */\nexport function semverGt(a: string, b: string): boolean {\n return _semverGt(a, b, true)\n}\n\nlet _skilldCommand: string | undefined\n\n/** Resolve the skilld CLI command — returns `skilld` if the binary is in PATH, otherwise `npx -y skilld` */\nexport function resolveSkilldCommand(): string {\n if (_skilldCommand !== undefined)\n return _skilldCommand\n try {\n const lookup = isWindows ? 'where' : 'which'\n execSync(`${lookup} skilld`, { stdio: 'ignore' })\n _skilldCommand = 'skilld'\n }\n catch {\n _skilldCommand = 'npx -y skilld'\n }\n return _skilldCommand\n}\n\nexport const SHARED_SKILLS_DIR = '.skills'\n\n/** Returns the shared skills directory path if `.skills/` exists at project root, else null */\nexport function getSharedSkillsDir(cwd: string = process.cwd()): string | null {\n const dir = join(cwd, SHARED_SKILLS_DIR)\n return existsSync(dir) ? dir : null\n}\n"],"mappings":";;;;;;AAyDA,MAAM,gBAA2C;CAG/C,cAAc;EACZ,OAAO;EACP,MAAM;EACN,UAAU;EACV,UAAU;EACV,UAAU;EACV,wBAAwB;EACxB,UAAU;GACR,OAAO;IAAE,SAAS;IAAM,cAAc,CAAC,QAAQ;IAAE,OAAO,CAAC,2CAAyC,iHAAA;IAAmH;GACrN,sBAAsB,EAAE;GACxB,qBAAqB,EAAE;GACvB,mBAAmB,EAAE;GACrB,qBAAqB,EAAE;GACvB,oBAAoB,EAAE;GACtB,eAAe,EAAA;GAChB;EACD,cAAc;GACZ;IAAE,SAAS;IAAO,KAAK;IAAwC,MAAM;IAAc;GACnF;IAAE,SAAS;IAAO,KAAK;IAAwC,MAAM;IAAc;GACnF;IAAE,SAAS;IAAO,KAAK;IAAwC,MAAM;IAAc;GACnF;IAAE,SAAS;IAAO,KAAK;IAAwC,MAAM;IAAc;GACnF;IAAE,SAAS;IAAO,KAAK;IAAwC,MAAM;IAAc;GACnF;IAAE,SAAS;IAAO,KAAK;IAAwC,MAAM;;;EAExE;CAED,4BAA4B;EAC1B,OAAO;EACP,MAAM;EACN,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU,EACR,aAAa,EAAE,SAAS,MAAM,EAAA;EAEjC;CAED,mBAAmB;EACjB,OAAO;EACP,MAAM;EACN,UAAU;EACV,UAAU;EACV,UAAU;EACV,UAAU,EACR,OAAO;GAAE,SAAS;GAAM,cAAc,CAAC,UAAA;GAAY,EAAA;EAEtD;CAED,iBAAiB;EACf,OAAO;EACP,MAAM;EACN,UAAU;EACV,UAAU,EACR,gBAAgB,EAAE,SAAS,MAAM,EAAA;EAEpC;CAID,mBAAmB;EACjB,OAAO;EACP,MAAM;EACN,UAAU,EACR,QAAQ;GAAE,SAAS;GAAM,cAAc,CAAC,WAAW;GAAE,OAAO,CAAC,8DAAA;GAAgE,EAAA;EAEhI;CAED,iBAAiB;EACf,OAAO;EACP,MAAM;EACN,UAAU,EACR,YAAY;GAAE,SAAS;GAAM,cAAc,CAAC,SAAS,QAAA;GAAU,EAAA;EAElE;CAED,gBAAgB;EACd,OAAO;EACP,MAAM;EACN,UAAU,EACR,MAAM;GAAE,SAAS;GAAM,cAAc,CAAC,QAAA;GAAU,EAAA;EAEnD;CAED,kBAAkB;EAChB,OAAO;EACP,MAAM;EACN,UAAU,EACR,OAAO;GAAE,SAAS;GAAM,cAAc,CAAC,UAAA;GAAY,EAAA;EAEtD;CAED,aAAa;EACX,OAAO;EACP,MAAM;EACN,UAAU,EACR,MAAM;GAAE,SAAS;GAAM,cAAc,CAAC,SAAA;GAAW,EAAA;EAEpD;CAID,wBAAwB;EACtB,OAAO;EACP,MAAM;EACN,UAAU,EACR,YAAY;GAAE,SAAS;GAAM,cAAc;IAAC;IAAQ;IAAS;IAAS;;GAAU,EACjF;EACD,cAAc;GACZ;IAAE,SAAS;IAAO,KAAK;IAA6E,MAAM;IAAc,OAAO;IAAkC;GACjK;IAAE,SAAS;IAAO,KAAK;IAAwE,MAAM;IAAc,OAAO;IAA6B;GACvJ;IAAE,SAAS;IAAO,KAAK;IAAwE,MAAM;IAAc,OAAO;IAA6B;GACvJ;IAAE,SAAS;IAAO,KAAK;IAAwE,MAAM;IAAc,OAAO;IAA6B;GACvJ;IAAE,SAAS;IAAO,KAAK;IAAwE,MAAM;IAAc,OAAO;IAA6B;GACvJ;IAAE,SAAS;IAAO,KAAK;IAAwE,MAAM;IAAc,OAAO;;;EAE7H;CAED,0BAA0B;EACxB,OAAO;EACP,MAAM;EACN,UAAU,EACR,cAAc;GAAE,SAAS;GAAM,cAAc,CAAC,WAAA;GAAa,EAAA;EAE9D;CAED,kBAAkB;EAChB,OAAO;EACP,MAAM;EACN,UAAU,EACR,YAAY;GAAE,SAAS;GAAM,cAAc,CAAC,OAAA;GAAS,EAAA;EAExD;CAED,gBAAgB;EACd,OAAO;EACP,MAAM;EACN,UAAU,EACR,KAAK;GAAE,SAAS;GAAM,cAAc,CAAC,QAAA;GAAU,EAAA;EAElD;CAID,kBAAkB;EAChB,OAAO;EACP,MAAM;EACN,UAAU,EACR,MAAM;GAAE,SAAS;GAAM,cAAc,CAAC,UAAU,SAAA;GAAW,EAAA;EAE9D;CAED,gBAAgB;EACd,OAAO;EACP,MAAM;EACN,UAAU,EACR,MAAM;GAAE,SAAS;GAAM,cAAc,CAAC,SAAA;GAAW,EAAA;EAEpD;CAED,iBAAiB;EACf,OAAO;EACP,MAAM;EACN,UAAU,EACR,QAAQ;GAAE,SAAS;GAAM,cAAc,CAAC,SAAA;GAAW,EAAA;EAEtD;CAED,mBAAmB;EACjB,OAAO;EACP,MAAM;EACN,UAAU,EACR,SAAS;GAAE,SAAS;GAAM,cAAc,CAAC,SAAS,SAAA;GAAW,EAAA;EAEhE;CAID,aAAa;EACX,OAAO;EACP,MAAM;EACN,UAAU,EACR,KAAK;GAAE,SAAS;GAAM,cAAc,CAAC,QAAA;GAAU,EAAA;EAElD;CAED,WAAW;EACT,OAAO;EACP,MAAM;EACN,UAAU,EACR,KAAK;GAAE,SAAS;GAAM,cAAc,CAAC,QAAA;GAAU,EAAA;EAElD;CAED,iCAAiC;EAC/B,OAAO;EACP,MAAM;EACN,UAAU,EACR,YAAY;GAAE,SAAS;GAAM,cAAc,CAAC,SAAS,eAAA;GAAiB,EAAA;EAEzE;CAED,oBAAoB;EAClB,OAAO;EACP,MAAM;EACN,UAAU,EACR,UAAU;GAAE,SAAS;GAAM,cAAc,CAAC,aAAA;GAAe,EAAA;EAE5D;CAED,oBAAoB;EAClB,OAAO;EACP,MAAM;EACN,UAAU,EACR,UAAU;GAAE,SAAS;GAAM,cAAc,CAAC,QAAA;GAAU,EAAA;EAEvD;CAED,kBAAkB;EAChB,OAAO;EACP,MAAM;EACN,UAAU,EACR,QAAQ;GAAE,SAAS;GAAM,cAAc,CAAC,WAAA;GAAa,EAAA;EAExD;CAID,eAAe;EACb,OAAO;EACP,MAAM;EACN,UAAU,EACR,MAAM;GAAE,SAAS;GAAM,cAAc,CAAC,UAAU,QAAA;GAAU,EAAA;EAE7D;CAED,kBAAkB;EAChB,OAAO;EACP,MAAM;EACN,UAAU,EACR,WAAW;GAAE,SAAS;GAAM,cAAc,CAAC,UAAU,QAAA;GAAU,EAAA;EAElE;CAED,wBAAwB;EACtB,OAAO;EACP,MAAM;EACN,UAAU;GACR,QAAQ;IAAE,SAAS;IAAM,cAAc,CAAC,SAAA;IAAW;GACnD,eAAe,EAAE,cAAc,CAAC,SAAS,EAAA;;EAE5C;CAED,eAAe;EACb,OAAO;EACP,MAAM;EACN,UAAU,EACR,OAAO;GAAE,SAAS;GAAM,cAAc,CAAC,UAAA;GAAY,EAAA;EAEtD;CAED,+BAA+B;EAC7B,OAAO;EACP,MAAM;EACN,UAAU,EACR,gBAAgB;GAAE,SAAS;GAAM,cAAc,CAAC,UAAA;GAAY,EAAA;EAE/D;CAID,2BAA2B;EACzB,OAAO;EACP,MAAM;EACN,UAAU,EACR,eAAe;GAAE,SAAS;GAAM,cAAc,CAAC,OAAA;GAAS,EAAA;EAE3D;CAED,mBAAmB;EACjB,OAAO;EACP,MAAM;EACN,UAAU,EACR,QAAQ;GAAE,SAAS;GAAM,cAAc,CAAC,OAAA;GAAS,EAAA;EAEpD;CAED,mBAAmB;EACjB,OAAO;EACP,MAAM;EACN,UAAU,EACR,QAAQ;GAAE,SAAS;GAAM,cAAc,CAAC,QAAQ,QAAA;GAAU,EAAA;EAE7D;CAED,cAAc;EACZ,OAAO;EACP,MAAM;EACN,UAAU,EACR,eAAe;GAAE,SAAS;GAAM,cAAc,CAAC,QAAA;GAAU,EAAA;EAE5D;CAID,sBAAsB;EACpB,OAAO;EACP,MAAM;EACN,UAAU;GACR,WAAW;IAAE,SAAS;IAAM,cAAc,CAAC,aAAa,QAAA;IAAU;GAClE,eAAe,EAAE,cAAc,CAAC,aAAa,QAAQ,EAAA;;EAExD;CAED,qCAAqC;EACnC,OAAO;EACP,MAAM;EACN,UAAU,EACR,wBAAwB;GAAE,SAAS;GAAM,cAAc,CAAC,aAAa,QAAA;GAAU,EAAA;EAElF;CAID,0BAA0B;EACxB,OAAO;EACP,MAAM;EACN,UAAU;EACV,SAAS;EACT,UAAU;EACV,UAAU,EACR,QAAQ,EAAE,SAAS,MAAM,EAAA;EAE5B;CAID,6BAA6B;EAC3B,OAAO;EACP,MAAM;EACN,UAAU;EACV,UAAU;EACV,UAAU,EACR,YAAY,EAAE,SAAS,MAAM,EAAA;EAEhC;CAID,iBAAiB;EACf,OAAO;EACP,MAAM;EACN,UAAU;GACR,UAAU;IAAE,SAAS;IAAM,cAAc,CAAC,WAAA;IAAa;GACvD,kBAAkB,EAAE,cAAc,CAAC,WAAW,EAAA;;EAEjD;CAED,qDAAqD;EACnD,OAAO;EACP,MAAM;EACN,UAAU,EACR,aAAa;GAAE,SAAS;GAAM,cAAc,CAAC,SAAA;GAAW,EAAA;;CAG7D;AAID,MAAM,sBAA8C,EAAE;AAEtD,KAAK,MAAM,CAAC,SAAS,UAAU,OAAO,QAAQ,cAAc,CAC1D,MAAK,MAAM,eAAe,OAAO,KAAK,MAAM,SAAS,CACnD,qBAAoB,eAAe;AAMvC,SAAgB,eAAe,aAA8C;CAC3E,MAAM,UAAU,oBAAoB;AACpC,KAAI,CAAC,QACH,QAAO,KAAA;CACT,MAAM,QAAQ,cAAc;AAC5B,KAAI,CAAC,OAAO,YAAY,CAAC,OAAO,SAC9B,QAAO,KAAA;AAET,QAAO;EACL,OAAO,MAAM;EACb,MAAM,MAAM,YAAY,MAAM;EAC9B,MAAM,MAAM,YAAY;EACxB,KAAK,MAAM;EACX,UAAU,MAAM;EACjB;;AAGH,SAAgB,cAAc,aAA6C;CACzE,MAAM,UAAU,oBAAoB;AACpC,KAAI,CAAC,QACH,QAAO,KAAA;CACT,MAAM,QAAQ,cAAc;AAC5B,KAAI,CAAC,OAAO,aACV,QAAO,KAAA;AAET,QAAO;EACL;EACA,UAAU,MAAM;EACjB;;AAGH,SAAgB,gBAAgB,aAA2C;CACzE,MAAM,UAAU,oBAAoB;AACpC,KAAI,CAAC,QACH,QAAO,KAAA;AACT,QAAO,cAAc,UAAU,SAAS,cAAc;;AAKxD,SAAgB,aAAa,SAAwC;AACnE,QAAO,cAAc;;AAGvB,SAAgB,qBAAqB,aAAyC;AAC5E,QAAO,oBAAoB;;AAG7B,SAAgB,gBAAgB,aAA+B;CAC7D,MAAM,UAAU,oBAAoB;AACpC,KAAI,CAAC,QACH,QAAO,EAAE;AACX,QAAO,cAAc,UAAU,SAAS,cAAc,SAAS,EAAE;;AAGnE,SAAgB,0BAA0B,aAAyC;CACjF,MAAM,UAAU,oBAAoB;AACpC,KAAI,CAAC,QACH,QAAO,KAAA;AACT,QAAO,cAAc,UAAU;;AAGjC,SAAgB,YAAY,aAAyC;CACnE,MAAM,UAAU,oBAAoB;AACpC,KAAI,CAAC,QACH,QAAO,KAAA;AACT,QAAO,cAAc,UAAU;;AAGjC,SAAgB,mBAAmB,aAA+B;CAChE,MAAM,UAAU,oBAAoB;AACpC,KAAI,CAAC,QACH,QAAO,EAAE;CACX,MAAM,QAAQ,cAAc;AAC5B,KAAI,CAAC,MACH,QAAO,EAAE;AACX,QAAO,OAAO,KAAK,MAAM,SAAS;;;;;AC3fpC,SAAgB,UAAgB,KAAgB,KAAQ,QAAoB;CAC1E,IAAI,MAAM,IAAI,IAAI,IAAI;AACtB,KAAI,QAAQ,KAAA,GAAW;AACrB,QAAM,QAAQ;AACd,MAAI,IAAI,KAAK,IAAI;;AAEnB,QAAO;;;AAIT,SAAgB,YAAY,GAA0B;AACpD,QAAOA,MAAa,GAAG,KAAK;;;AAI9B,SAAgB,SAAS,GAAW,GAAoB;AACtD,QAAOC,GAAU,GAAG,GAAG,KAAK;;AAG9B,IAAI;;AAGJ,SAAgB,uBAA+B;AAC7C,KAAI,mBAAmB,KAAA,EACrB,QAAO;AACT,KAAI;AAEF,WAAS,GADM,YAAY,UAAU,QAClB,UAAU,EAAE,OAAO,UAAU,CAAC;AACjD,mBAAiB;SAEb;AACJ,mBAAiB;;AAEnB,QAAO;;AAGT,MAAa,oBAAoB;;AAGjC,SAAgB,mBAAmB,MAAc,QAAQ,KAAK,EAAiB;CAC7E,MAAM,MAAM,KAAK,KAAK,kBAAkB;AACxC,QAAO,WAAW,IAAI,GAAG,MAAM"}
|
package/dist/_chunks/skills.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as yamlParseKV, t as yamlEscape } from "./yaml.mjs";
|
|
2
2
|
import { i as parseFrontmatter } from "./markdown.mjs";
|
|
3
|
-
import { a as semverGt, n as getSharedSkillsDir } from "./shared.mjs";
|
|
3
|
+
import { a as semverGt, n as getSharedSkillsDir, o as semverValid } from "./shared.mjs";
|
|
4
4
|
import { s as readLocalDependencies } from "./sources.mjs";
|
|
5
5
|
import { a as targets } from "./detect.mjs";
|
|
6
6
|
import { join } from "pathe";
|
|
@@ -230,7 +230,9 @@ function* iterateSkills(opts = {}) {
|
|
|
230
230
|
}
|
|
231
231
|
function isOutdated(skill, depVersion) {
|
|
232
232
|
if (!skill.info?.version) return true;
|
|
233
|
-
|
|
233
|
+
const depClean = depVersion.replace(/^[\^~>=<]+/, "");
|
|
234
|
+
if (!semverValid(depClean)) return false;
|
|
235
|
+
return semverGt(depClean, skill.info.version);
|
|
234
236
|
}
|
|
235
237
|
async function getProjectState(cwd = process.cwd()) {
|
|
236
238
|
const skills = [...iterateSkills({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills.mjs","names":["agents"],"sources":["../../src/core/lockfile.ts","../../src/core/skills.ts"],"sourcesContent":["import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { parseFrontmatter } from './markdown.ts'\nimport { yamlEscape, yamlParseKV } from './yaml.ts'\n\nexport interface SkillInfo {\n packageName?: string\n version?: string\n /** All tracked packages as comma-separated \"name@version\" pairs (multi-package skills) */\n packages?: string\n repo?: string\n source?: string\n syncedAt?: string\n generator?: string\n /** Skill path within repo (git-sourced skills) */\n path?: string\n /** Git ref tracked for updates */\n ref?: string\n /** Git commit SHA at install time */\n commit?: string\n}\n\nexport function parsePackages(packages?: string): Array<{ name: string, version: string }> {\n if (!packages)\n return []\n return packages.split(',').map((s) => {\n const trimmed = s.trim()\n const atIdx = trimmed.lastIndexOf('@')\n if (atIdx <= 0)\n return { name: trimmed, version: '' }\n return { name: trimmed.slice(0, atIdx), version: trimmed.slice(atIdx + 1) }\n }).filter(p => p.name)\n}\n\nexport function serializePackages(pkgs: Array<{ name: string, version: string }>): string {\n return pkgs.map(p => `${p.name}@${p.version}`).join(', ')\n}\n\nexport interface SkilldLock {\n skills: Record<string, SkillInfo>\n}\n\nconst SKILL_FM_KEYS: (keyof SkillInfo)[] = ['packageName', 'version', 'packages', 'repo', 'source', 'syncedAt', 'generator', 'path', 'ref', 'commit']\n\nfunction isSkillInfoKey(key: string): key is keyof SkillInfo {\n return (SKILL_FM_KEYS as readonly string[]).includes(key)\n}\n\nexport function parseSkillFrontmatter(skillPath: string): SkillInfo | null {\n if (!existsSync(skillPath))\n return null\n const content = readFileSync(skillPath, 'utf-8')\n const fm = parseFrontmatter(content)\n if (Object.keys(fm).length === 0)\n return null\n\n const info: SkillInfo = {}\n for (const key of SKILL_FM_KEYS) {\n if (fm[key])\n info[key] = fm[key]\n }\n return info\n}\n\nexport function readLock(skillsDir: string): SkilldLock | null {\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n if (!existsSync(lockPath))\n return null\n const content = readFileSync(lockPath, 'utf-8')\n\n const skills: Record<string, SkillInfo> = {}\n let currentSkill: string | null = null\n\n for (const line of content.split('\\n')) {\n const skillMatch = line.match(/^ {2}(\\S+):$/)\n if (skillMatch) {\n currentSkill = skillMatch[1]\n skills[currentSkill] = {}\n continue\n }\n if (currentSkill && line.startsWith(' ')) {\n const kv = yamlParseKV(line)\n if (kv && isSkillInfoKey(kv[0]))\n skills[currentSkill]![kv[0]] = kv[1]\n }\n }\n return { skills }\n}\n\nfunction serializeLock(lock: SkilldLock): string {\n let yaml = 'skills:\\n'\n for (const [name, skill] of Object.entries(lock.skills)) {\n yaml += ` ${name}:\\n`\n for (const key of SKILL_FM_KEYS) {\n if (skill[key])\n yaml += ` ${key}: ${yamlEscape(skill[key])}\\n`\n }\n }\n return yaml\n}\n\nexport function writeLock(skillsDir: string, skillName: string, info: SkillInfo): void {\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n let lock: SkilldLock = { skills: {} }\n if (existsSync(lockPath)) {\n lock = readLock(skillsDir) || { skills: {} }\n }\n\n const existing = lock.skills[skillName]\n if (existing && info.packageName) {\n // Merge packages list\n const existingPkgs = parsePackages(existing.packages)\n // Also include existing primary if not yet in packages list\n if (existing.packageName && !existingPkgs.some(p => p.name === existing.packageName)) {\n existingPkgs.unshift({ name: existing.packageName, version: existing.version || '' })\n }\n // Add/update new package\n const idx = existingPkgs.findIndex(p => p.name === info.packageName)\n if (idx >= 0) {\n existingPkgs[idx]!.version = info.version || ''\n }\n else {\n existingPkgs.push({ name: info.packageName, version: info.version || '' })\n }\n info.packages = serializePackages(existingPkgs)\n // Keep primary as first package\n info.packageName = existingPkgs[0]!.name\n info.version = existingPkgs[0]!.version\n // Preserve fields from existing entry that aren't in new info\n if (!info.repo && existing.repo)\n info.repo = existing.repo\n if (!info.source && existing.source)\n info.source = existing.source\n if (!info.generator && existing.generator)\n info.generator = existing.generator\n }\n\n lock.skills[skillName] = info\n writeFileSync(lockPath, serializeLock(lock))\n}\n\n/**\n * Merge multiple lockfiles, preferring the most recently synced entry per skill.\n */\nexport function mergeLocks(locks: SkilldLock[]): SkilldLock {\n const merged: Record<string, SkillInfo> = {}\n for (const lock of locks) {\n for (const [name, info] of Object.entries(lock.skills)) {\n const existing = merged[name]\n if (!existing || (info.syncedAt && (!existing.syncedAt || info.syncedAt > existing.syncedAt)))\n merged[name] = info\n }\n }\n return { skills: merged }\n}\n\n/**\n * Sync a lockfile to all other dirs that already have a skilld-lock.yaml.\n * Only updates existing lockfiles — does not create new ones.\n */\nexport function syncLockfilesToDirs(sourceLock: SkilldLock, dirs: string[]): void {\n for (const dir of dirs) {\n const lockPath = join(dir, 'skilld-lock.yaml')\n if (!existsSync(lockPath))\n continue\n const existing = readLock(dir)\n if (!existing)\n continue\n // Merge source into existing\n const merged = mergeLocks([existing, sourceLock])\n writeFileSync(lockPath, serializeLock(merged))\n }\n}\n\nexport function removeLockEntry(skillsDir: string, skillName: string): void {\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n const lock = readLock(skillsDir)\n if (!lock)\n return\n\n delete lock.skills[skillName]\n\n if (Object.keys(lock.skills).length === 0) {\n unlinkSync(lockPath)\n return\n }\n\n writeFileSync(lockPath, serializeLock(lock))\n}\n","import type { AgentType } from '../agent/index.ts'\nimport type { SkillInfo } from './lockfile.ts'\nimport { existsSync, readdirSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { agents } from '../agent/index.ts'\nimport { readLocalDependencies } from '../sources/index.ts'\nimport { parsePackages, parseSkillFrontmatter, readLock } from './lockfile.ts'\nimport { getSharedSkillsDir, semverGt } from './shared.ts'\n\nexport interface SkillEntry {\n name: string\n dir: string\n agent: AgentType\n info: SkillInfo | null\n scope: 'local' | 'global'\n /** Original package name from package.json (e.g., @scope/pkg) */\n packageName?: string\n /** Latest version from package.json deps */\n latestVersion?: string\n}\n\nexport interface ProjectState {\n skills: SkillEntry[]\n deps: Map<string, string>\n missing: string[]\n outdated: SkillEntry[]\n synced: SkillEntry[]\n /** Skills in lockfile but not matched to any local dep */\n unmatched: SkillEntry[]\n}\n\nexport interface IterateSkillsOptions {\n scope?: 'local' | 'global' | 'all'\n agents?: AgentType[]\n cwd?: string\n}\n\nexport function* iterateSkills(opts: IterateSkillsOptions = {}): Generator<SkillEntry> {\n const { scope = 'all', cwd = process.cwd() } = opts\n const agentTypes = opts.agents ?? (Object.keys(agents) as AgentType[])\n\n // When shared dir exists, read local skills from there (avoid duplicates from agent symlinks)\n const sharedDir = getSharedSkillsDir(cwd)\n let yieldedLocal = false\n\n if (sharedDir && (scope === 'local' || scope === 'all')) {\n yieldedLocal = true\n const lock = readLock(sharedDir)\n const entries = readdirSync(sharedDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n // Use first detected agent as the representative\n const firstAgent = agentTypes[0] ?? (Object.keys(agents) as AgentType[])[0]!\n for (const name of entries) {\n const dir = join(sharedDir, name)\n if (lock?.skills[name]) {\n yield { name, dir, agent: firstAgent, info: lock.skills[name], scope: 'local' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: firstAgent, info, scope: 'local' }\n }\n }\n }\n }\n\n for (const agentType of agentTypes) {\n const agent = agents[agentType]\n\n // Local skills (skip if already yielded from shared dir)\n if (!yieldedLocal && (scope === 'local' || scope === 'all')) {\n const localDir = join(cwd, agent.skillsDir)\n if (existsSync(localDir)) {\n const lock = readLock(localDir)\n const entries = readdirSync(localDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n for (const name of entries) {\n const dir = join(localDir, name)\n // Only track skills in lockfile OR with generator: \"skilld\"\n if (lock?.skills[name]) {\n yield { name, dir, agent: agentType, info: lock.skills[name], scope: 'local' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: agentType, info, scope: 'local' }\n }\n }\n }\n }\n }\n\n // Global skills\n if ((scope === 'global' || scope === 'all') && agent.globalSkillsDir) {\n const globalDir = agent.globalSkillsDir\n if (existsSync(globalDir)) {\n const lock = readLock(globalDir)\n const entries = readdirSync(globalDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n for (const name of entries) {\n const dir = join(globalDir, name)\n // Only track skills in lockfile OR with generator: \"skilld\"\n if (lock?.skills[name]) {\n yield { name, dir, agent: agentType, info: lock.skills[name], scope: 'global' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: agentType, info, scope: 'global' }\n }\n }\n }\n }\n }\n }\n}\n\nexport function isOutdated(skill: SkillEntry, depVersion: string): boolean {\n if (!skill.info?.version)\n return true\n\n const depClean = depVersion.replace(/^[\\^~]/, '')\n\n return semverGt(depClean, skill.info.version)\n}\n\nexport async function getProjectState(cwd: string = process.cwd()): Promise<ProjectState> {\n const skills = [...iterateSkills({ scope: 'local', cwd })]\n\n // Get package.json deps\n const localDeps = await readLocalDependencies(cwd).catch(() => [])\n const deps = new Map(localDeps.map(d => [d.name, d.version]))\n\n // Build skill name -> entry map (for lookup by package name)\n const skillByName = new Map(skills.map(s => [s.name, s]))\n\n // Secondary lookup: packageName from lockfile (shipped skills have different names)\n // Also includes all packages from multi-package skills\n const skillByPkgName = new Map<string, SkillEntry>()\n for (const s of skills) {\n if (s.info?.packageName)\n skillByPkgName.set(s.info.packageName, s)\n for (const pkg of parsePackages(s.info?.packages))\n skillByPkgName.set(pkg.name, s)\n }\n\n const missing: string[] = []\n const outdated: SkillEntry[] = []\n const synced: SkillEntry[] = []\n const matchedSkillNames = new Set<string>()\n\n for (const [pkgName, version] of deps) {\n // Normalize package name (e.g., @scope/pkg -> scope-pkg)\n const normalizedName = pkgName.replace(/^@/, '').replace(/\\//g, '-')\n const skill = skillByName.get(`${normalizedName}-skilld`) || skillByName.get(normalizedName) || skillByName.get(pkgName) || skillByPkgName.get(pkgName)\n\n if (!skill) {\n missing.push(pkgName)\n }\n else {\n matchedSkillNames.add(skill.name)\n if (isOutdated(skill, version)) {\n outdated.push({ ...skill, packageName: pkgName, latestVersion: version })\n }\n else {\n synced.push({ ...skill, packageName: pkgName, latestVersion: version })\n }\n }\n }\n\n // Skills in lockfile but not matched to any local dep\n const unmatched = skills.filter(s => !matchedSkillNames.has(s.name))\n\n return { skills, deps, missing, outdated, synced, unmatched }\n}\n\nexport function getSkillsDir(agent: AgentType, scope: 'local' | 'global', cwd: string = process.cwd()): string {\n const agentConfig = agents[agent]\n if (scope === 'global') {\n if (!agentConfig.globalSkillsDir) {\n throw new Error(`Agent ${agent} does not support global skills`)\n }\n return agentConfig.globalSkillsDir\n }\n return getSharedSkillsDir(cwd) || join(cwd, agentConfig.skillsDir)\n}\n"],"mappings":";;;;;;;;AAsBA,SAAgB,cAAc,UAA6D;AACzF,KAAI,CAAC,SACH,QAAO,EAAE;AACX,QAAO,SAAS,MAAM,IAAI,CAAC,KAAK,MAAM;EACpC,MAAM,UAAU,EAAE,MAAM;EACxB,MAAM,QAAQ,QAAQ,YAAY,IAAI;AACtC,MAAI,SAAS,EACX,QAAO;GAAE,MAAM;GAAS,SAAS;GAAI;AACvC,SAAO;GAAE,MAAM,QAAQ,MAAM,GAAG,MAAM;GAAE,SAAS,QAAQ,MAAM,QAAQ,EAAA;GAAI;GAC3E,CAAC,QAAO,MAAK,EAAE,KAAK;;AAGxB,SAAgB,kBAAkB,MAAwD;AACxF,QAAO,KAAK,KAAI,MAAK,GAAG,EAAE,KAAK,GAAG,EAAE,UAAU,CAAC,KAAK,KAAK;;AAO3D,MAAM,gBAAqC;CAAC;CAAe;CAAW;CAAY;CAAQ;CAAU;CAAY;CAAa;CAAQ;CAAO;CAAS;AAErJ,SAAS,eAAe,KAAqC;AAC3D,QAAQ,cAAoC,SAAS,IAAI;;AAG3D,SAAgB,sBAAsB,WAAqC;AACzE,KAAI,CAAC,WAAW,UAAU,CACxB,QAAO;CAET,MAAM,KAAK,iBADK,aAAa,WAAW,QAAQ,CACZ;AACpC,KAAI,OAAO,KAAK,GAAG,CAAC,WAAW,EAC7B,QAAO;CAET,MAAM,OAAkB,EAAE;AAC1B,MAAK,MAAM,OAAO,cAChB,KAAI,GAAG,KACL,MAAK,OAAO,GAAG;AAEnB,QAAO;;AAGT,SAAgB,SAAS,WAAsC;CAC7D,MAAM,WAAW,KAAK,WAAW,mBAAmB;AACpD,KAAI,CAAC,WAAW,SAAS,CACvB,QAAO;CACT,MAAM,UAAU,aAAa,UAAU,QAAQ;CAE/C,MAAM,SAAoC,EAAE;CAC5C,IAAI,eAA8B;AAElC,MAAK,MAAM,QAAQ,QAAQ,MAAM,KAAK,EAAE;EACtC,MAAM,aAAa,KAAK,MAAM,eAAe;AAC7C,MAAI,YAAY;AACd,kBAAe,WAAW;AAC1B,UAAO,gBAAgB,EAAE;AACzB;;AAEF,MAAI,gBAAgB,KAAK,WAAW,OAAO,EAAE;GAC3C,MAAM,KAAK,YAAY,KAAK;AAC5B,OAAI,MAAM,eAAe,GAAG,GAAG,CAC7B,QAAO,cAAe,GAAG,MAAM,GAAG;;;AAGxC,QAAO,EAAE,QAAQ;;AAGnB,SAAS,cAAc,MAA0B;CAC/C,IAAI,OAAO;AACX,MAAK,MAAM,CAAC,MAAM,UAAU,OAAO,QAAQ,KAAK,OAAO,EAAE;AACvD,UAAQ,KAAK,KAAK;AAClB,OAAK,MAAM,OAAO,cAChB,KAAI,MAAM,KACR,SAAQ,OAAO,IAAI,IAAI,WAAW,MAAM,KAAK,CAAC;;AAGpD,QAAO;;AAGT,SAAgB,UAAU,WAAmB,WAAmB,MAAuB;CACrF,MAAM,WAAW,KAAK,WAAW,mBAAmB;CACpD,IAAI,OAAmB,EAAE,QAAQ,EAAE,EAAE;AACrC,KAAI,WAAW,SAAS,CACtB,QAAO,SAAS,UAAU,IAAI,EAAE,QAAQ,EAAE,EAAE;CAG9C,MAAM,WAAW,KAAK,OAAO;AAC7B,KAAI,YAAY,KAAK,aAAa;EAEhC,MAAM,eAAe,cAAc,SAAS,SAAS;AAErD,MAAI,SAAS,eAAe,CAAC,aAAa,MAAK,MAAK,EAAE,SAAS,SAAS,YAAY,CAClF,cAAa,QAAQ;GAAE,MAAM,SAAS;GAAa,SAAS,SAAS,WAAW;GAAI,CAAC;EAGvF,MAAM,MAAM,aAAa,WAAU,MAAK,EAAE,SAAS,KAAK,YAAY;AACpE,MAAI,OAAO,EACT,cAAa,KAAM,UAAU,KAAK,WAAW;MAG7C,cAAa,KAAK;GAAE,MAAM,KAAK;GAAa,SAAS,KAAK,WAAW;GAAI,CAAC;AAE5E,OAAK,WAAW,kBAAkB,aAAa;AAE/C,OAAK,cAAc,aAAa,GAAI;AACpC,OAAK,UAAU,aAAa,GAAI;AAEhC,MAAI,CAAC,KAAK,QAAQ,SAAS,KACzB,MAAK,OAAO,SAAS;AACvB,MAAI,CAAC,KAAK,UAAU,SAAS,OAC3B,MAAK,SAAS,SAAS;AACzB,MAAI,CAAC,KAAK,aAAa,SAAS,UAC9B,MAAK,YAAY,SAAS;;AAG9B,MAAK,OAAO,aAAa;AACzB,eAAc,UAAU,cAAc,KAAK,CAAC;;;;;AAM9C,SAAgB,WAAW,OAAiC;CAC1D,MAAM,SAAoC,EAAE;AAC5C,MAAK,MAAM,QAAQ,MACjB,MAAK,MAAM,CAAC,MAAM,SAAS,OAAO,QAAQ,KAAK,OAAO,EAAE;EACtD,MAAM,WAAW,OAAO;AACxB,MAAI,CAAC,YAAa,KAAK,aAAa,CAAC,SAAS,YAAY,KAAK,WAAW,SAAS,UACjF,QAAO,QAAQ;;AAGrB,QAAO,EAAE,QAAQ,QAAQ;;;;;;AAO3B,SAAgB,oBAAoB,YAAwB,MAAsB;AAChF,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,WAAW,KAAK,KAAK,mBAAmB;AAC9C,MAAI,CAAC,WAAW,SAAS,CACvB;EACF,MAAM,WAAW,SAAS,IAAI;AAC9B,MAAI,CAAC,SACH;AAGF,gBAAc,UAAU,cADT,WAAW,CAAC,UAAU,WAAW,CAAC,CACJ,CAAC;;;AAIlD,SAAgB,gBAAgB,WAAmB,WAAyB;CAC1E,MAAM,WAAW,KAAK,WAAW,mBAAmB;CACpD,MAAM,OAAO,SAAS,UAAU;AAChC,KAAI,CAAC,KACH;AAEF,QAAO,KAAK,OAAO;AAEnB,KAAI,OAAO,KAAK,KAAK,OAAO,CAAC,WAAW,GAAG;AACzC,aAAW,SAAS;AACpB;;AAGF,eAAc,UAAU,cAAc,KAAK,CAAC;;;;ACtJ9C,UAAiB,cAAc,OAA6B,EAAE,EAAyB;CACrF,MAAM,EAAE,QAAQ,OAAO,MAAM,QAAQ,KAAK,KAAK;CAC/C,MAAM,aAAa,KAAK,UAAW,OAAO,KAAKA,QAAO;CAGtD,MAAM,YAAY,mBAAmB,IAAI;CACzC,IAAI,eAAe;AAEnB,KAAI,cAAc,UAAU,WAAW,UAAU,QAAQ;AACvD,iBAAe;EACf,MAAM,OAAO,SAAS,UAAU;EAChC,MAAM,UAAU,YAAY,UAAU,CAAC,QAAO,MAAK,CAAC,EAAE,WAAW,IAAI,IAAI,MAAM,mBAAmB;EAElG,MAAM,aAAa,WAAW,MAAO,OAAO,KAAKA,QAAO,CAAiB;AACzE,OAAK,MAAM,QAAQ,SAAS;GAC1B,MAAM,MAAM,KAAK,WAAW,KAAK;AACjC,OAAI,MAAM,OAAO,MACf,OAAM;IAAE;IAAM;IAAK,OAAO;IAAY,MAAM,KAAK,OAAO;IAAO,OAAO;IAAS;QAE5E;IACH,MAAM,OAAO,sBAAsB,KAAK,KAAK,WAAW,YAAY,CAAC;AACrE,QAAI,MAAM,cAAc,SACtB,OAAM;KAAE;KAAM;KAAK,OAAO;KAAY;KAAM,OAAO;KAAS;;;;AAMpE,MAAK,MAAM,aAAa,YAAY;EAClC,MAAM,QAAQA,QAAO;AAGrB,MAAI,CAAC,iBAAiB,UAAU,WAAW,UAAU,QAAQ;GAC3D,MAAM,WAAW,KAAK,KAAK,MAAM,UAAU;AAC3C,OAAI,WAAW,SAAS,EAAE;IACxB,MAAM,OAAO,SAAS,SAAS;IAC/B,MAAM,UAAU,YAAY,SAAS,CAAC,QAAO,MAAK,CAAC,EAAE,WAAW,IAAI,IAAI,MAAM,mBAAmB;AACjG,SAAK,MAAM,QAAQ,SAAS;KAC1B,MAAM,MAAM,KAAK,UAAU,KAAK;AAEhC,SAAI,MAAM,OAAO,MACf,OAAM;MAAE;MAAM;MAAK,OAAO;MAAW,MAAM,KAAK,OAAO;MAAO,OAAO;MAAS;UAE3E;MACH,MAAM,OAAO,sBAAsB,KAAK,KAAK,WAAW,YAAY,CAAC;AACrE,UAAI,MAAM,cAAc,SACtB,OAAM;OAAE;OAAM;OAAK,OAAO;OAAW;OAAM,OAAO;OAAS;;;;;AAQrE,OAAK,UAAU,YAAY,UAAU,UAAU,MAAM,iBAAiB;GACpE,MAAM,YAAY,MAAM;AACxB,OAAI,WAAW,UAAU,EAAE;IACzB,MAAM,OAAO,SAAS,UAAU;IAChC,MAAM,UAAU,YAAY,UAAU,CAAC,QAAO,MAAK,CAAC,EAAE,WAAW,IAAI,IAAI,MAAM,mBAAmB;AAClG,SAAK,MAAM,QAAQ,SAAS;KAC1B,MAAM,MAAM,KAAK,WAAW,KAAK;AAEjC,SAAI,MAAM,OAAO,MACf,OAAM;MAAE;MAAM;MAAK,OAAO;MAAW,MAAM,KAAK,OAAO;MAAO,OAAO;MAAU;UAE5E;MACH,MAAM,OAAO,sBAAsB,KAAK,KAAK,WAAW,YAAY,CAAC;AACrE,UAAI,MAAM,cAAc,SACtB,OAAM;OAAE;OAAM;OAAK,OAAO;OAAW;OAAM,OAAO;OAAU;;;;;;;AAS1E,SAAgB,WAAW,OAAmB,YAA6B;AACzE,KAAI,CAAC,MAAM,MAAM,QACf,QAAO;AAIT,QAAO,SAFU,WAAW,QAAQ,UAAU,GAAG,EAEvB,MAAM,KAAK,QAAQ;;AAG/C,eAAsB,gBAAgB,MAAc,QAAQ,KAAK,EAAyB;CACxF,MAAM,SAAS,CAAC,GAAG,cAAc;EAAE,OAAO;EAAS;EAAK,CAAC,CAAC;CAG1D,MAAM,YAAY,MAAM,sBAAsB,IAAI,CAAC,YAAY,EAAE,CAAC;CAClE,MAAM,OAAO,IAAI,IAAI,UAAU,KAAI,MAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;CAG7D,MAAM,cAAc,IAAI,IAAI,OAAO,KAAI,MAAK,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;CAIzD,MAAM,iCAAiB,IAAI,KAAyB;AACpD,MAAK,MAAM,KAAK,QAAQ;AACtB,MAAI,EAAE,MAAM,YACV,gBAAe,IAAI,EAAE,KAAK,aAAa,EAAE;AAC3C,OAAK,MAAM,OAAO,cAAc,EAAE,MAAM,SAAS,CAC/C,gBAAe,IAAI,IAAI,MAAM,EAAE;;CAGnC,MAAM,UAAoB,EAAE;CAC5B,MAAM,WAAyB,EAAE;CACjC,MAAM,SAAuB,EAAE;CAC/B,MAAM,oCAAoB,IAAI,KAAa;AAE3C,MAAK,MAAM,CAAC,SAAS,YAAY,MAAM;EAErC,MAAM,iBAAiB,QAAQ,QAAQ,MAAM,GAAG,CAAC,QAAQ,OAAO,IAAI;EACpE,MAAM,QAAQ,YAAY,IAAI,GAAG,eAAe,SAAS,IAAI,YAAY,IAAI,eAAe,IAAI,YAAY,IAAI,QAAQ,IAAI,eAAe,IAAI,QAAQ;AAEvJ,MAAI,CAAC,MACH,SAAQ,KAAK,QAAQ;OAElB;AACH,qBAAkB,IAAI,MAAM,KAAK;AACjC,OAAI,WAAW,OAAO,QAAQ,CAC5B,UAAS,KAAK;IAAE,GAAG;IAAO,aAAa;IAAS,eAAe;IAAS,CAAC;OAGzE,QAAO,KAAK;IAAE,GAAG;IAAO,aAAa;IAAS,eAAe;IAAS,CAAC;;;AAQ7E,QAAO;EAAE;EAAQ;EAAM;EAAS;EAAU;EAAQ,WAFhC,OAAO,QAAO,MAAK,CAAC,kBAAkB,IAAI,EAAE,KAAK,CAAA;EAEN;;AAG/D,SAAgB,aAAa,OAAkB,OAA2B,MAAc,QAAQ,KAAK,EAAU;CAC7G,MAAM,cAAcA,QAAO;AAC3B,KAAI,UAAU,UAAU;AACtB,MAAI,CAAC,YAAY,gBACf,OAAM,IAAI,MAAM,SAAS,MAAM,iCAAiC;AAElE,SAAO,YAAY;;AAErB,QAAO,mBAAmB,IAAI,IAAI,KAAK,KAAK,YAAY,UAAU"}
|
|
1
|
+
{"version":3,"file":"skills.mjs","names":["agents"],"sources":["../../src/core/lockfile.ts","../../src/core/skills.ts"],"sourcesContent":["import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { parseFrontmatter } from './markdown.ts'\nimport { yamlEscape, yamlParseKV } from './yaml.ts'\n\nexport interface SkillInfo {\n packageName?: string\n version?: string\n /** All tracked packages as comma-separated \"name@version\" pairs (multi-package skills) */\n packages?: string\n repo?: string\n source?: string\n syncedAt?: string\n generator?: string\n /** Skill path within repo (git-sourced skills) */\n path?: string\n /** Git ref tracked for updates */\n ref?: string\n /** Git commit SHA at install time */\n commit?: string\n}\n\nexport function parsePackages(packages?: string): Array<{ name: string, version: string }> {\n if (!packages)\n return []\n return packages.split(',').map((s) => {\n const trimmed = s.trim()\n const atIdx = trimmed.lastIndexOf('@')\n if (atIdx <= 0)\n return { name: trimmed, version: '' }\n return { name: trimmed.slice(0, atIdx), version: trimmed.slice(atIdx + 1) }\n }).filter(p => p.name)\n}\n\nexport function serializePackages(pkgs: Array<{ name: string, version: string }>): string {\n return pkgs.map(p => `${p.name}@${p.version}`).join(', ')\n}\n\nexport interface SkilldLock {\n skills: Record<string, SkillInfo>\n}\n\nconst SKILL_FM_KEYS: (keyof SkillInfo)[] = ['packageName', 'version', 'packages', 'repo', 'source', 'syncedAt', 'generator', 'path', 'ref', 'commit']\n\nfunction isSkillInfoKey(key: string): key is keyof SkillInfo {\n return (SKILL_FM_KEYS as readonly string[]).includes(key)\n}\n\nexport function parseSkillFrontmatter(skillPath: string): SkillInfo | null {\n if (!existsSync(skillPath))\n return null\n const content = readFileSync(skillPath, 'utf-8')\n const fm = parseFrontmatter(content)\n if (Object.keys(fm).length === 0)\n return null\n\n const info: SkillInfo = {}\n for (const key of SKILL_FM_KEYS) {\n if (fm[key])\n info[key] = fm[key]\n }\n return info\n}\n\nexport function readLock(skillsDir: string): SkilldLock | null {\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n if (!existsSync(lockPath))\n return null\n const content = readFileSync(lockPath, 'utf-8')\n\n const skills: Record<string, SkillInfo> = {}\n let currentSkill: string | null = null\n\n for (const line of content.split('\\n')) {\n const skillMatch = line.match(/^ {2}(\\S+):$/)\n if (skillMatch) {\n currentSkill = skillMatch[1]\n skills[currentSkill] = {}\n continue\n }\n if (currentSkill && line.startsWith(' ')) {\n const kv = yamlParseKV(line)\n if (kv && isSkillInfoKey(kv[0]))\n skills[currentSkill]![kv[0]] = kv[1]\n }\n }\n return { skills }\n}\n\nfunction serializeLock(lock: SkilldLock): string {\n let yaml = 'skills:\\n'\n for (const [name, skill] of Object.entries(lock.skills)) {\n yaml += ` ${name}:\\n`\n for (const key of SKILL_FM_KEYS) {\n if (skill[key])\n yaml += ` ${key}: ${yamlEscape(skill[key])}\\n`\n }\n }\n return yaml\n}\n\nexport function writeLock(skillsDir: string, skillName: string, info: SkillInfo): void {\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n let lock: SkilldLock = { skills: {} }\n if (existsSync(lockPath)) {\n lock = readLock(skillsDir) || { skills: {} }\n }\n\n const existing = lock.skills[skillName]\n if (existing && info.packageName) {\n // Merge packages list\n const existingPkgs = parsePackages(existing.packages)\n // Also include existing primary if not yet in packages list\n if (existing.packageName && !existingPkgs.some(p => p.name === existing.packageName)) {\n existingPkgs.unshift({ name: existing.packageName, version: existing.version || '' })\n }\n // Add/update new package\n const idx = existingPkgs.findIndex(p => p.name === info.packageName)\n if (idx >= 0) {\n existingPkgs[idx]!.version = info.version || ''\n }\n else {\n existingPkgs.push({ name: info.packageName, version: info.version || '' })\n }\n info.packages = serializePackages(existingPkgs)\n // Keep primary as first package\n info.packageName = existingPkgs[0]!.name\n info.version = existingPkgs[0]!.version\n // Preserve fields from existing entry that aren't in new info\n if (!info.repo && existing.repo)\n info.repo = existing.repo\n if (!info.source && existing.source)\n info.source = existing.source\n if (!info.generator && existing.generator)\n info.generator = existing.generator\n }\n\n lock.skills[skillName] = info\n writeFileSync(lockPath, serializeLock(lock))\n}\n\n/**\n * Merge multiple lockfiles, preferring the most recently synced entry per skill.\n */\nexport function mergeLocks(locks: SkilldLock[]): SkilldLock {\n const merged: Record<string, SkillInfo> = {}\n for (const lock of locks) {\n for (const [name, info] of Object.entries(lock.skills)) {\n const existing = merged[name]\n if (!existing || (info.syncedAt && (!existing.syncedAt || info.syncedAt > existing.syncedAt)))\n merged[name] = info\n }\n }\n return { skills: merged }\n}\n\n/**\n * Sync a lockfile to all other dirs that already have a skilld-lock.yaml.\n * Only updates existing lockfiles — does not create new ones.\n */\nexport function syncLockfilesToDirs(sourceLock: SkilldLock, dirs: string[]): void {\n for (const dir of dirs) {\n const lockPath = join(dir, 'skilld-lock.yaml')\n if (!existsSync(lockPath))\n continue\n const existing = readLock(dir)\n if (!existing)\n continue\n // Merge source into existing\n const merged = mergeLocks([existing, sourceLock])\n writeFileSync(lockPath, serializeLock(merged))\n }\n}\n\nexport function removeLockEntry(skillsDir: string, skillName: string): void {\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n const lock = readLock(skillsDir)\n if (!lock)\n return\n\n delete lock.skills[skillName]\n\n if (Object.keys(lock.skills).length === 0) {\n unlinkSync(lockPath)\n return\n }\n\n writeFileSync(lockPath, serializeLock(lock))\n}\n","import type { AgentType } from '../agent/index.ts'\nimport type { SkillInfo } from './lockfile.ts'\nimport { existsSync, readdirSync } from 'node:fs'\nimport { join } from 'pathe'\nimport { agents } from '../agent/index.ts'\nimport { readLocalDependencies } from '../sources/index.ts'\nimport { parsePackages, parseSkillFrontmatter, readLock } from './lockfile.ts'\nimport { getSharedSkillsDir, semverGt, semverValid } from './shared.ts'\n\nexport interface SkillEntry {\n name: string\n dir: string\n agent: AgentType\n info: SkillInfo | null\n scope: 'local' | 'global'\n /** Original package name from package.json (e.g., @scope/pkg) */\n packageName?: string\n /** Latest version from package.json deps */\n latestVersion?: string\n}\n\nexport interface ProjectState {\n skills: SkillEntry[]\n deps: Map<string, string>\n missing: string[]\n outdated: SkillEntry[]\n synced: SkillEntry[]\n /** Skills in lockfile but not matched to any local dep */\n unmatched: SkillEntry[]\n}\n\nexport interface IterateSkillsOptions {\n scope?: 'local' | 'global' | 'all'\n agents?: AgentType[]\n cwd?: string\n}\n\nexport function* iterateSkills(opts: IterateSkillsOptions = {}): Generator<SkillEntry> {\n const { scope = 'all', cwd = process.cwd() } = opts\n const agentTypes = opts.agents ?? (Object.keys(agents) as AgentType[])\n\n // When shared dir exists, read local skills from there (avoid duplicates from agent symlinks)\n const sharedDir = getSharedSkillsDir(cwd)\n let yieldedLocal = false\n\n if (sharedDir && (scope === 'local' || scope === 'all')) {\n yieldedLocal = true\n const lock = readLock(sharedDir)\n const entries = readdirSync(sharedDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n // Use first detected agent as the representative\n const firstAgent = agentTypes[0] ?? (Object.keys(agents) as AgentType[])[0]!\n for (const name of entries) {\n const dir = join(sharedDir, name)\n if (lock?.skills[name]) {\n yield { name, dir, agent: firstAgent, info: lock.skills[name], scope: 'local' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: firstAgent, info, scope: 'local' }\n }\n }\n }\n }\n\n for (const agentType of agentTypes) {\n const agent = agents[agentType]\n\n // Local skills (skip if already yielded from shared dir)\n if (!yieldedLocal && (scope === 'local' || scope === 'all')) {\n const localDir = join(cwd, agent.skillsDir)\n if (existsSync(localDir)) {\n const lock = readLock(localDir)\n const entries = readdirSync(localDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n for (const name of entries) {\n const dir = join(localDir, name)\n // Only track skills in lockfile OR with generator: \"skilld\"\n if (lock?.skills[name]) {\n yield { name, dir, agent: agentType, info: lock.skills[name], scope: 'local' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: agentType, info, scope: 'local' }\n }\n }\n }\n }\n }\n\n // Global skills\n if ((scope === 'global' || scope === 'all') && agent.globalSkillsDir) {\n const globalDir = agent.globalSkillsDir\n if (existsSync(globalDir)) {\n const lock = readLock(globalDir)\n const entries = readdirSync(globalDir).filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml')\n for (const name of entries) {\n const dir = join(globalDir, name)\n // Only track skills in lockfile OR with generator: \"skilld\"\n if (lock?.skills[name]) {\n yield { name, dir, agent: agentType, info: lock.skills[name], scope: 'global' }\n }\n else {\n const info = parseSkillFrontmatter(join(dir, '.skilld', '_SKILL.md'))\n if (info?.generator === 'skilld') {\n yield { name, dir, agent: agentType, info, scope: 'global' }\n }\n }\n }\n }\n }\n }\n}\n\nexport function isOutdated(skill: SkillEntry, depVersion: string): boolean {\n if (!skill.info?.version)\n return true\n\n const depClean = depVersion.replace(/^[\\^~>=<]+/, '')\n\n // Non-semver versions (e.g. '*' from catalog:/workspace: specifiers) can't be compared\n if (!semverValid(depClean))\n return false\n\n return semverGt(depClean, skill.info.version)\n}\n\nexport async function getProjectState(cwd: string = process.cwd()): Promise<ProjectState> {\n const skills = [...iterateSkills({ scope: 'local', cwd })]\n\n // Get package.json deps\n const localDeps = await readLocalDependencies(cwd).catch(() => [])\n const deps = new Map(localDeps.map(d => [d.name, d.version]))\n\n // Build skill name -> entry map (for lookup by package name)\n const skillByName = new Map(skills.map(s => [s.name, s]))\n\n // Secondary lookup: packageName from lockfile (shipped skills have different names)\n // Also includes all packages from multi-package skills\n const skillByPkgName = new Map<string, SkillEntry>()\n for (const s of skills) {\n if (s.info?.packageName)\n skillByPkgName.set(s.info.packageName, s)\n for (const pkg of parsePackages(s.info?.packages))\n skillByPkgName.set(pkg.name, s)\n }\n\n const missing: string[] = []\n const outdated: SkillEntry[] = []\n const synced: SkillEntry[] = []\n const matchedSkillNames = new Set<string>()\n\n for (const [pkgName, version] of deps) {\n // Normalize package name (e.g., @scope/pkg -> scope-pkg)\n const normalizedName = pkgName.replace(/^@/, '').replace(/\\//g, '-')\n const skill = skillByName.get(`${normalizedName}-skilld`) || skillByName.get(normalizedName) || skillByName.get(pkgName) || skillByPkgName.get(pkgName)\n\n if (!skill) {\n missing.push(pkgName)\n }\n else {\n matchedSkillNames.add(skill.name)\n if (isOutdated(skill, version)) {\n outdated.push({ ...skill, packageName: pkgName, latestVersion: version })\n }\n else {\n synced.push({ ...skill, packageName: pkgName, latestVersion: version })\n }\n }\n }\n\n // Skills in lockfile but not matched to any local dep\n const unmatched = skills.filter(s => !matchedSkillNames.has(s.name))\n\n return { skills, deps, missing, outdated, synced, unmatched }\n}\n\nexport function getSkillsDir(agent: AgentType, scope: 'local' | 'global', cwd: string = process.cwd()): string {\n const agentConfig = agents[agent]\n if (scope === 'global') {\n if (!agentConfig.globalSkillsDir) {\n throw new Error(`Agent ${agent} does not support global skills`)\n }\n return agentConfig.globalSkillsDir\n }\n return getSharedSkillsDir(cwd) || join(cwd, agentConfig.skillsDir)\n}\n"],"mappings":"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"}
|
package/dist/_chunks/sources.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { o as getCacheDir } from "./config.mjs";
|
|
2
|
+
import { t as yamlEscape } from "./yaml.mjs";
|
|
2
3
|
import { i as parseFrontmatter, n as extractLinks, r as extractTitle, t as extractDescription } from "./markdown.mjs";
|
|
3
|
-
import { c as
|
|
4
|
+
import { c as getCrawlUrl, l as getDocOverride, r as mapInsert, s as getBlogPreset } from "./shared.mjs";
|
|
4
5
|
import { tmpdir } from "node:os";
|
|
5
6
|
import { basename, dirname, join, resolve } from "pathe";
|
|
6
|
-
import { createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, rmSync
|
|
7
|
+
import { createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, rmSync } from "node:fs";
|
|
7
8
|
import { htmlToMarkdown } from "mdream";
|
|
8
9
|
import { spawnSync } from "node:child_process";
|
|
9
10
|
import { ofetch } from "ofetch";
|
|
@@ -30,7 +31,7 @@ const isoDate = (iso) => iso.split("T")[0];
|
|
|
30
31
|
/** Build YAML frontmatter from a key-value object, auto-quoting strings with special chars */
|
|
31
32
|
function buildFrontmatter(fields) {
|
|
32
33
|
const lines = ["---"];
|
|
33
|
-
for (const [k, v] of Object.entries(fields)) if (v !== void 0) lines.push(`${k}: ${typeof v === "string"
|
|
34
|
+
for (const [k, v] of Object.entries(fields)) if (v !== void 0) lines.push(`${k}: ${typeof v === "string" ? yamlEscape(v) : v}`);
|
|
34
35
|
lines.push("---");
|
|
35
36
|
return lines.join("\n");
|
|
36
37
|
}
|
|
@@ -1687,10 +1688,9 @@ function isSafeUrl(url) {
|
|
|
1687
1688
|
const parsed = new URL(url);
|
|
1688
1689
|
if (parsed.protocol !== "https:") return false;
|
|
1689
1690
|
const host = parsed.hostname;
|
|
1690
|
-
if (host === "localhost" || host === "
|
|
1691
|
-
if (
|
|
1692
|
-
if (
|
|
1693
|
-
if (host.startsWith("[")) return false;
|
|
1691
|
+
if (host === "localhost" || host === "0.0.0.0" || host === "[::1]") return false;
|
|
1692
|
+
if (/^(?:127\.|10\.|172\.(?:1[6-9]|2\d|3[01])\.|192\.168\.|169\.254\.)/.test(host)) return false;
|
|
1693
|
+
if (/^\[(?:f[cd]|fe[89ab]|::ffff:)/i.test(host)) return false;
|
|
1694
1694
|
return true;
|
|
1695
1695
|
} catch {
|
|
1696
1696
|
return false;
|
|
@@ -1702,8 +1702,8 @@ async function downloadLlmsDocs(llmsContent, baseUrl, onProgress) {
|
|
|
1702
1702
|
return (await Promise.all(llmsContent.links.map((link) => limit(async () => {
|
|
1703
1703
|
const url = link.url.startsWith("http") ? link.url : `${baseUrl.replace(/\/$/, "")}${link.url.startsWith("/") ? "" : "/"}${link.url}`;
|
|
1704
1704
|
if (!isSafeUrl(url)) return null;
|
|
1705
|
-
onProgress?.(link.url, completed++, llmsContent.links.length);
|
|
1706
1705
|
const content = await fetchText(url);
|
|
1706
|
+
onProgress?.(link.url, ++completed, llmsContent.links.length);
|
|
1707
1707
|
if (content && content.length > 100) return {
|
|
1708
1708
|
url: link.url.startsWith("http") ? new URL(link.url).pathname : link.url,
|
|
1709
1709
|
title: link.title,
|
|
@@ -2269,7 +2269,7 @@ async function fetchNpmPackage(packageName) {
|
|
|
2269
2269
|
*/
|
|
2270
2270
|
async function fetchNpmRegistryMeta(packageName, version) {
|
|
2271
2271
|
const { name: barePackageName } = parsePackageSpec(packageName);
|
|
2272
|
-
const data = await $fetch(`https://registry.npmjs.org/${barePackageName}
|
|
2272
|
+
const data = await $fetch(`https://registry.npmjs.org/${barePackageName}`, { headers: { Accept: "application/vnd.npm.install-v1+json" } }).catch(() => null);
|
|
2273
2273
|
if (!data) return {};
|
|
2274
2274
|
const distTags = data["dist-tags"] ? Object.fromEntries(Object.entries(data["dist-tags"]).map(([tag, ver]) => [tag, {
|
|
2275
2275
|
version: ver,
|
|
@@ -2538,7 +2538,9 @@ function resolveInstalledVersion(name, cwd) {
|
|
|
2538
2538
|
while (dir && basename(dir) !== "node_modules") {
|
|
2539
2539
|
const pkgPath = join(dir, "package.json");
|
|
2540
2540
|
if (existsSync(pkgPath)) return JSON.parse(readFileSync(pkgPath, "utf-8")).version || null;
|
|
2541
|
-
|
|
2541
|
+
const parent = dirname(dir);
|
|
2542
|
+
if (parent === dir) break;
|
|
2543
|
+
dir = parent;
|
|
2542
2544
|
}
|
|
2543
2545
|
} catch {}
|
|
2544
2546
|
return null;
|
|
@@ -2632,51 +2634,67 @@ async function fetchPkgDist(name, version) {
|
|
|
2632
2634
|
mkdirSync(pkgDir, { recursive: true });
|
|
2633
2635
|
const tmpTarball = join(cacheDir, "_pkg.tgz");
|
|
2634
2636
|
const fileStream = createWriteStream(tmpTarball);
|
|
2637
|
+
const fileClosed = new Promise((resolve) => fileStream.once("close", resolve));
|
|
2635
2638
|
const reader = tarballRes.body.getReader();
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2639
|
+
try {
|
|
2640
|
+
await new Promise((res, reject) => {
|
|
2641
|
+
const writable = new Writable({ write(chunk, _encoding, callback) {
|
|
2642
|
+
fileStream.write(chunk, callback);
|
|
2643
|
+
} });
|
|
2644
|
+
writable.on("finish", () => {
|
|
2645
|
+
fileStream.end();
|
|
2646
|
+
});
|
|
2647
|
+
fileStream.on("close", () => res());
|
|
2648
|
+
writable.on("error", reject);
|
|
2649
|
+
fileStream.on("error", reject);
|
|
2650
|
+
function pump() {
|
|
2651
|
+
reader.read().then(({ done, value }) => {
|
|
2652
|
+
if (done) {
|
|
2653
|
+
writable.end();
|
|
2654
|
+
return;
|
|
2655
|
+
}
|
|
2656
|
+
writable.write(value, () => pump());
|
|
2657
|
+
}).catch(reject);
|
|
2658
|
+
}
|
|
2659
|
+
pump();
|
|
2642
2660
|
});
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2661
|
+
const { status } = spawnSync("tar", [
|
|
2662
|
+
"xzf",
|
|
2663
|
+
tmpTarball,
|
|
2664
|
+
"--strip-components=1",
|
|
2665
|
+
"-C",
|
|
2666
|
+
pkgDir
|
|
2667
|
+
], { stdio: "ignore" });
|
|
2668
|
+
if (status !== 0) {
|
|
2669
|
+
rmSync(pkgDir, {
|
|
2670
|
+
recursive: true,
|
|
2671
|
+
force: true
|
|
2672
|
+
});
|
|
2673
|
+
return null;
|
|
2654
2674
|
}
|
|
2655
|
-
|
|
2656
|
-
}
|
|
2657
|
-
const { status } = spawnSync("tar", [
|
|
2658
|
-
"xzf",
|
|
2659
|
-
tmpTarball,
|
|
2660
|
-
"--strip-components=1",
|
|
2661
|
-
"-C",
|
|
2662
|
-
pkgDir
|
|
2663
|
-
], { stdio: "ignore" });
|
|
2664
|
-
if (status !== 0) {
|
|
2675
|
+
return pkgDir;
|
|
2676
|
+
} catch {
|
|
2665
2677
|
rmSync(pkgDir, {
|
|
2666
2678
|
recursive: true,
|
|
2667
2679
|
force: true
|
|
2668
2680
|
});
|
|
2669
|
-
rmSync(tmpTarball, { force: true });
|
|
2670
2681
|
return null;
|
|
2682
|
+
} finally {
|
|
2683
|
+
reader.cancel().catch(() => {});
|
|
2684
|
+
fileStream.destroy();
|
|
2685
|
+
await fileClosed;
|
|
2686
|
+
try {
|
|
2687
|
+
rmSync(tmpTarball, { force: true });
|
|
2688
|
+
} catch {}
|
|
2671
2689
|
}
|
|
2672
|
-
unlinkSync(tmpTarball);
|
|
2673
|
-
return pkgDir;
|
|
2674
2690
|
}
|
|
2675
2691
|
/**
|
|
2676
2692
|
* Fetch just the latest version string from npm (lightweight)
|
|
2677
2693
|
*/
|
|
2678
2694
|
async function fetchLatestVersion(packageName) {
|
|
2679
|
-
|
|
2695
|
+
const data = await $fetch(`https://unpkg.com/${packageName}/package.json`).catch(() => null);
|
|
2696
|
+
if (data?.version) return data.version;
|
|
2697
|
+
return (await $fetch(`https://registry.npmjs.org/${packageName}`, { headers: { Accept: "application/vnd.npm.install-v1+json" } }).catch(() => null))?.["dist-tags"]?.latest || null;
|
|
2680
2698
|
}
|
|
2681
2699
|
/**
|
|
2682
2700
|
* Get installed skill version from SKILL.md
|