skilld 1.5.5 → 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -23
- package/dist/_chunks/agent.mjs +2 -78
- package/dist/_chunks/agent.mjs.map +1 -1
- package/dist/_chunks/assemble.mjs +1 -18
- package/dist/_chunks/assemble.mjs.map +1 -1
- package/dist/_chunks/author-group.mjs +17 -0
- package/dist/_chunks/author-group.mjs.map +1 -0
- package/dist/_chunks/author.mjs +8 -24
- package/dist/_chunks/author.mjs.map +1 -1
- package/dist/_chunks/cache.mjs +1 -73
- package/dist/_chunks/cache.mjs.map +1 -1
- package/dist/_chunks/cache2.mjs +84 -17
- package/dist/_chunks/cache2.mjs.map +1 -1
- package/dist/_chunks/cli-helpers.mjs +3 -166
- package/dist/_chunks/cli-helpers.mjs.map +1 -1
- package/dist/_chunks/cli-helpers2.mjs +0 -11
- package/dist/_chunks/config.mjs +119 -54
- package/dist/_chunks/config.mjs.map +1 -1
- package/dist/_chunks/core.mjs +9 -0
- package/dist/_chunks/detect.mjs +29 -226
- package/dist/_chunks/detect.mjs.map +1 -1
- package/dist/_chunks/embedding-cache.mjs +0 -5
- package/dist/_chunks/embedding-cache2.mjs +2 -3
- package/dist/_chunks/formatting.mjs +0 -6
- package/dist/_chunks/formatting.mjs.map +1 -1
- package/dist/_chunks/index.d.mts +0 -10
- package/dist/_chunks/index.d.mts.map +1 -1
- package/dist/_chunks/index2.d.mts +3 -6
- package/dist/_chunks/index2.d.mts.map +1 -1
- package/dist/_chunks/index3.d.mts +81 -109
- package/dist/_chunks/index3.d.mts.map +1 -1
- package/dist/_chunks/install.mjs +85 -550
- package/dist/_chunks/install.mjs.map +1 -1
- package/dist/_chunks/install2.mjs +554 -0
- package/dist/_chunks/install2.mjs.map +1 -0
- package/dist/_chunks/libs/@sinclair/typebox.mjs +0 -444
- package/dist/_chunks/libs/@sinclair/typebox.mjs.map +1 -1
- package/dist/_chunks/list.mjs +0 -16
- package/dist/_chunks/list.mjs.map +1 -1
- package/dist/_chunks/lockfile.mjs +2 -10
- package/dist/_chunks/lockfile.mjs.map +1 -1
- package/dist/_chunks/markdown.mjs +0 -9
- package/dist/_chunks/markdown.mjs.map +1 -1
- package/dist/_chunks/package-json.mjs +0 -25
- package/dist/_chunks/package-json.mjs.map +1 -1
- package/dist/_chunks/package-registry.mjs +465 -0
- package/dist/_chunks/package-registry.mjs.map +1 -0
- package/dist/_chunks/pool2.mjs +0 -2
- package/dist/_chunks/pool2.mjs.map +1 -1
- package/dist/_chunks/prefix.mjs +108 -0
- package/dist/_chunks/prefix.mjs.map +1 -0
- package/dist/_chunks/prepare.mjs +14 -9
- package/dist/_chunks/prepare.mjs.map +1 -1
- package/dist/_chunks/prepare2.mjs +1 -19
- package/dist/_chunks/prepare2.mjs.map +1 -1
- package/dist/_chunks/prompts.mjs +6 -201
- package/dist/_chunks/prompts.mjs.map +1 -1
- package/dist/_chunks/retriv.mjs +23 -24
- package/dist/_chunks/retriv.mjs.map +1 -1
- package/dist/_chunks/rolldown-runtime.mjs +0 -2
- package/dist/_chunks/sanitize.mjs +0 -78
- package/dist/_chunks/sanitize.mjs.map +1 -1
- package/dist/_chunks/search-helpers.mjs +99 -0
- package/dist/_chunks/search-helpers.mjs.map +1 -0
- package/dist/_chunks/search-interactive.mjs +1 -18
- package/dist/_chunks/search-interactive.mjs.map +1 -1
- package/dist/_chunks/search.mjs +218 -19
- package/dist/_chunks/search.mjs.map +1 -0
- package/dist/_chunks/setup.mjs +0 -13
- package/dist/_chunks/setup.mjs.map +1 -1
- package/dist/_chunks/shared.mjs +1 -473
- package/dist/_chunks/shared.mjs.map +1 -1
- package/dist/_chunks/skills.mjs +3 -3
- package/dist/_chunks/skills.mjs.map +1 -1
- package/dist/_chunks/sources.mjs +1179 -1440
- package/dist/_chunks/sources.mjs.map +1 -1
- package/dist/_chunks/sync-registry.mjs +59 -0
- package/dist/_chunks/sync-registry.mjs.map +1 -0
- package/dist/_chunks/sync-shared.mjs +0 -16
- package/dist/_chunks/sync-shared2.mjs +10 -49
- package/dist/_chunks/sync-shared2.mjs.map +1 -1
- package/dist/_chunks/sync.mjs +209 -120
- package/dist/_chunks/sync.mjs.map +1 -1
- package/dist/_chunks/sync2.mjs +1 -21
- package/dist/_chunks/types.d.mts +0 -2
- package/dist/_chunks/types.d.mts.map +1 -1
- package/dist/_chunks/uninstall.mjs +3 -27
- package/dist/_chunks/uninstall.mjs.map +1 -1
- package/dist/_chunks/upload.mjs +152 -0
- package/dist/_chunks/upload.mjs.map +1 -0
- package/dist/_chunks/validate.mjs +1 -8
- package/dist/_chunks/validate.mjs.map +1 -1
- package/dist/_chunks/version.mjs +30 -0
- package/dist/_chunks/version.mjs.map +1 -0
- package/dist/_chunks/wizard.mjs +2 -3
- package/dist/_chunks/yaml.mjs +0 -21
- package/dist/_chunks/yaml.mjs.map +1 -1
- package/dist/agent/index.d.mts +0 -24
- package/dist/agent/index.d.mts.map +1 -1
- package/dist/agent/index.mjs +2 -9
- package/dist/cache/index.mjs +1 -3
- package/dist/cli-entry.mjs +0 -6
- package/dist/cli-entry.mjs.map +1 -1
- package/dist/cli.mjs +48 -33
- package/dist/cli.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -8
- package/dist/prepare.mjs +0 -12
- package/dist/prepare.mjs.map +1 -1
- package/dist/retriv/index.mjs +0 -2
- package/dist/retriv/worker.d.mts +0 -3
- package/dist/retriv/worker.d.mts.map +1 -1
- package/dist/retriv/worker.mjs +0 -2
- package/dist/retriv/worker.mjs.map +1 -1
- package/dist/sources/index.d.mts +2 -2
- package/dist/sources/index.mjs +3 -7
- package/dist/types.d.mts +1 -1
- package/package.json +20 -21
- package/dist/_chunks/search2.mjs +0 -319
- package/dist/_chunks/search2.mjs.map +0 -1
package/dist/_chunks/types.d.mts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
//#region src/retriv/types.d.ts
|
|
2
1
|
interface ChunkEntity {
|
|
3
2
|
name: string;
|
|
4
3
|
type: string;
|
|
@@ -85,6 +84,5 @@ interface SearchSnippet {
|
|
|
85
84
|
/** Containing scope chain */
|
|
86
85
|
scope?: ChunkEntity[];
|
|
87
86
|
}
|
|
88
|
-
//#endregion
|
|
89
87
|
export { IndexProgress as a, SearchResult as c, IndexPhase as i, SearchSnippet as l, Document as n, SearchFilter as o, IndexConfig as r, SearchOptions as s, ChunkEntity as t };
|
|
90
88
|
//# sourceMappingURL=types.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.mts","names":[],"sources":["../../src/retriv/types.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../src/retriv/types.ts"],"mappings":"UAAiB,WAAA;EACf,IAAA;EACA,IAAA;EACA,SAAA;EACA,SAAA;AAAA;AAAA,UAGe,QAAA;EACf,EAAA;EACA,OAAA;EACA,QAAA,GAAW,MAAA;AAAA;AAAA,UAGI,eAAA;EACf,SAAA;EACA,YAAA;AAAA;AAAA,KAGU,UAAA;AAAA,UAEK,aAAA;EACf,KAAA,EAAO,UAAA;EACP,OAAA;EACA,KAAA;AAAA;AAAA,UAGe,WAAA;EACf,MAAA;EACA,KAAA;EACA,QAAA,GAAW,eAAA;EAXD;EAaV,UAAA,IAAc,QAAA,EAAU,aAAA;AAAA;AAAA,UAGT,YAAA;EACf,EAAA;EACA,OAAA;EACA,KAAA;EACA,QAAA,EAAU,MAAA;EACV,UAAA;EAlBA;EAoBA,SAAA;EACA,QAAA,GAAW,WAAA;EACX,KAAA,GAAQ,WAAA;AAAA;AAAA,KAGE,cAAA;EACJ,GAAA;AAAA;EACA,GAAA;AAAA;EACA,GAAA;AAAA;EACA,IAAA;AAAA;EACA,GAAA;AAAA;EACA,IAAA;AAAA;EACA,GAAA;AAAA;EACA,OAAA;AAAA;EACA,OAAA;AAAA;AAAA,KAEI,WAAA,+BAA0C,cAAA;AAAA,KAC1C,YAAA,GAAe,MAAA,SAAe,WAAA;AAAA,UAEzB,aAAA;EAzBf;EA2BA,KAAA;EAzBA;EA2BA,MAAA,GAAS,YAAA;AAAA;AAAA,UAGM,aAAA;EA1Bf;EA4BA,OAAA;EA3BW;EA6BX,MAAA;EA5BQ;EA8BR,SAAA;EA9BmB;EAgCnB,OAAA;EA7BwB;EA+BxB,OAAA;EA/BwB;EAiCxB,KAAA;EA/BM;EAiCN,UAAA;EA/BM;EAiCN,QAAA,GAAW,WAAA;EA/BL;EAiCN,KAAA,GAAQ,WAAA;AAAA"}
|
|
@@ -1,35 +1,17 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import "./package-json.mjs";
|
|
3
|
-
import "./prepare.mjs";
|
|
4
|
-
import "./sanitize.mjs";
|
|
1
|
+
import { i as CACHE_DIR } from "./version.mjs";
|
|
5
2
|
import "./cache.mjs";
|
|
6
|
-
import "./yaml.mjs";
|
|
7
|
-
import "./markdown.mjs";
|
|
8
|
-
import "./retriv.mjs";
|
|
9
3
|
import { r as mapInsert, t as SHARED_SKILLS_DIR } from "./shared.mjs";
|
|
10
|
-
import "./sources.mjs";
|
|
11
4
|
import { a as targets } from "./detect.mjs";
|
|
12
|
-
import "./prompts.mjs";
|
|
13
5
|
import "./agent.mjs";
|
|
14
|
-
import "./
|
|
15
|
-
import {
|
|
6
|
+
import { n as getRegisteredProjects, s as unregisterProject } from "./config.mjs";
|
|
7
|
+
import { p as isInteractive, x as sharedArgs } from "./cli-helpers.mjs";
|
|
16
8
|
import { i as readLock } from "./lockfile.mjs";
|
|
17
|
-
import "./skills.mjs";
|
|
18
|
-
import "./formatting.mjs";
|
|
19
|
-
import "./wizard.mjs";
|
|
20
9
|
import { i as SKILLD_MARKER_START, r as SKILLD_MARKER_END } from "./sync-shared2.mjs";
|
|
21
|
-
import "./pool2.mjs";
|
|
22
10
|
import "./sync.mjs";
|
|
23
11
|
import { join } from "pathe";
|
|
24
12
|
import { existsSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
25
13
|
import * as p from "@clack/prompts";
|
|
26
14
|
import { defineCommand } from "citty";
|
|
27
|
-
//#region src/commands/uninstall.ts
|
|
28
|
-
/**
|
|
29
|
-
* Remove the skilld marker block from an agent's instruction file.
|
|
30
|
-
* For .mdc files (dedicated skilld files), delete the entire file.
|
|
31
|
-
* Also cleans up legacy .cursorrules markers for backwards compat.
|
|
32
|
-
*/
|
|
33
15
|
function removeAgentInstructions(agent, projectPath) {
|
|
34
16
|
const agentConfig = targets[agent];
|
|
35
17
|
if (!agentConfig.instructionFile) return false;
|
|
@@ -58,11 +40,6 @@ function removeMarkerBlock(filePath) {
|
|
|
58
40
|
else writeFileSync(filePath, updated.endsWith("\n") ? updated : `${updated}\n`);
|
|
59
41
|
return true;
|
|
60
42
|
}
|
|
61
|
-
/**
|
|
62
|
-
* Uninstall skilld skills by scope:
|
|
63
|
-
* - project: Remove project skills (cwd)
|
|
64
|
-
* - all: All registered projects + global skills + cache
|
|
65
|
-
*/
|
|
66
43
|
async function uninstallCommand(opts) {
|
|
67
44
|
let scope = opts.scope;
|
|
68
45
|
const registeredProjects = getRegisteredProjects();
|
|
@@ -226,7 +203,6 @@ const uninstallCommandDef = defineCommand({
|
|
|
226
203
|
});
|
|
227
204
|
}
|
|
228
205
|
});
|
|
229
|
-
//#endregion
|
|
230
206
|
export { uninstallCommandDef };
|
|
231
207
|
|
|
232
208
|
//# sourceMappingURL=uninstall.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uninstall.mjs","names":["agents"],"sources":["../../src/commands/uninstall.ts"],"sourcesContent":["import type { AgentType } from '../agent/index.ts'\nimport { existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join } from 'pathe'\nimport { agents } from '../agent/index.ts'\nimport { CACHE_DIR } from '../cache/index.ts'\nimport { isInteractive, sharedArgs } from '../cli-helpers.ts'\nimport { getRegisteredProjects, unregisterProject } from '../core/config.ts'\nimport { readLock } from '../core/lockfile.ts'\nimport { mapInsert, SHARED_SKILLS_DIR } from '../core/shared.ts'\nimport { SKILLD_MARKER_END, SKILLD_MARKER_START } from './sync.ts'\n\n/**\n * Remove the skilld marker block from an agent's instruction file.\n * For .mdc files (dedicated skilld files), delete the entire file.\n * Also cleans up legacy .cursorrules markers for backwards compat.\n */\nfunction removeAgentInstructions(agent: AgentType, projectPath: string): boolean {\n const agentConfig = agents[agent]\n if (!agentConfig.instructionFile)\n return false\n\n let removed = false\n\n // Handle current instruction file\n const filePath = join(projectPath, agentConfig.instructionFile)\n if (agentConfig.instructionFile.endsWith('.mdc')) {\n // MDC files are dedicated skilld files - just delete\n if (existsSync(filePath)) {\n rmSync(filePath)\n removed = true\n }\n // Also clean up legacy .cursorrules markers (cursor-specific)\n if (agent === 'cursor')\n removed = removeMarkerBlock(join(projectPath, '.cursorrules')) || removed\n }\n else if (existsSync(filePath)) {\n removed = removeMarkerBlock(filePath)\n }\n\n return removed\n}\n\nfunction removeMarkerBlock(filePath: string): boolean {\n if (!existsSync(filePath))\n return false\n\n const content = readFileSync(filePath, 'utf-8')\n const startIdx = content.indexOf(SKILLD_MARKER_START)\n if (startIdx === -1)\n return false\n\n const endIdx = content.indexOf(SKILLD_MARKER_END, startIdx)\n if (endIdx === -1)\n return false\n\n // Remove marker block plus surrounding blank lines\n const before = content.slice(0, startIdx).replace(/\\n+$/, '')\n const after = content.slice(endIdx + SKILLD_MARKER_END.length).replace(/^\\n+/, '')\n const updated = before + (before && after ? '\\n' : '') + after\n\n if (updated.trim() === '') {\n rmSync(filePath)\n }\n else {\n writeFileSync(filePath, updated.endsWith('\\n') ? updated : `${updated}\\n`)\n }\n return true\n}\n\nexport interface UninstallOptions {\n scope?: 'project' | 'all'\n agent?: AgentType\n yes: boolean\n}\n\n/**\n * Uninstall skilld skills by scope:\n * - project: Remove project skills (cwd)\n * - all: All registered projects + global skills + cache\n */\nexport async function uninstallCommand(opts: UninstallOptions): Promise<void> {\n let scope = opts.scope\n const registeredProjects = getRegisteredProjects()\n\n // Prompt for scope if not provided\n if (!scope) {\n if (!isInteractive()) {\n scope = 'project'\n }\n else {\n const allHint = registeredProjects.length > 0\n ? `${registeredProjects.length} projects + global + cache`\n : 'global skills + cache'\n\n const selected = await p.select({\n message: 'What do you want to uninstall?',\n options: [\n { label: 'This project', value: 'project', hint: 'current project only' },\n { label: 'Everything', value: 'all', hint: allHint },\n ],\n })\n\n if (p.isCancel(selected)) {\n p.cancel('Cancelled')\n return\n }\n scope = selected as 'project' | 'all'\n }\n }\n\n interface RemoveItem { label: string, path: string, version?: string }\n const toRemove: RemoveItem[] = []\n const seenPaths = new Set<string>()\n const projectsToUnregister: string[] = []\n const agentFilter = opts.agent ? [opts.agent] : undefined\n\n const addToRemove = (label: string, path: string, version?: string) => {\n if (seenPaths.has(path))\n return\n seenPaths.add(path)\n toRemove.push({ label, path, version })\n }\n\n // Helper to add skills from a lockfile\n const addSkillsFromLock = (skillsDir: string, label: string): string[] => {\n const trackedNames: string[] = []\n const lock = readLock(skillsDir)\n\n if (lock?.skills) {\n for (const [skillName, info] of Object.entries(lock.skills)) {\n trackedNames.push(skillName)\n const skillDir = join(skillsDir, skillName)\n if (existsSync(skillDir)) {\n const version = info.version ? `${info.version.split('.').slice(0, 2).join('.')}.x` : undefined\n addToRemove(`${label}: ${skillName}`, skillDir, version)\n }\n }\n\n // Also add the lockfile itself\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n if (existsSync(lockPath)) {\n addToRemove(`${label}: skilld-lock.yaml`, lockPath)\n }\n }\n\n return trackedNames\n }\n\n // Helper to find untracked skills in a directory\n const findUntrackedSkills = (skillsDir: string, trackedNames: string[]): string[] => {\n if (!existsSync(skillsDir))\n return []\n const tracked = new Set(trackedNames)\n return readdirSync(skillsDir)\n .filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml' && !tracked.has(f))\n }\n\n // Track untracked skills per directory (dedupe by path)\n const untrackedByDir = new Map<string, { label: string, skills: string[] }>()\n const processedDirs = new Set<string>()\n\n // Helper to process a skills directory (with deduping)\n const processSkillsDir = (skillsDir: string, label: string) => {\n if (processedDirs.has(skillsDir))\n return\n processedDirs.add(skillsDir)\n\n const tracked = addSkillsFromLock(skillsDir, label)\n const untracked = findUntrackedSkills(skillsDir, tracked)\n if (untracked.length > 0) {\n untrackedByDir.set(skillsDir, { label, skills: untracked })\n }\n }\n\n // Project skills\n if (scope === 'project') {\n // Shared dir\n const sharedDir = join(process.cwd(), SHARED_SKILLS_DIR)\n if (existsSync(sharedDir))\n processSkillsDir(sharedDir, 'project (.skills)')\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n processSkillsDir(join(process.cwd(), agent.skillsDir), 'project')\n }\n projectsToUnregister.push(process.cwd())\n }\n\n // All registered projects + global\n if (scope === 'all') {\n const projectPaths = registeredProjects.length > 0 ? registeredProjects : [process.cwd()]\n\n // Show which projects will be affected\n if (registeredProjects.length > 0) {\n p.log.info('Projects to uninstall from:')\n for (const proj of projectPaths) {\n p.log.message(` ${proj}`)\n }\n }\n\n // Project skills from lockfiles\n for (const projectPath of projectPaths) {\n if (!existsSync(projectPath))\n continue\n\n const shortPath = projectPath.replace(process.env.HOME || '', '~')\n\n // Shared dir\n const sharedDir = join(projectPath, SHARED_SKILLS_DIR)\n if (existsSync(sharedDir))\n processSkillsDir(sharedDir, `${shortPath} (.skills)`)\n\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n processSkillsDir(join(projectPath, agent.skillsDir), shortPath)\n }\n\n projectsToUnregister.push(projectPath)\n }\n\n // Global skills from lockfiles\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n if (!agent.globalSkillsDir)\n continue\n processSkillsDir(agent.globalSkillsDir, 'user')\n }\n\n // Cache directory\n if (existsSync(CACHE_DIR)) {\n addToRemove('~/.skilld cache', CACHE_DIR)\n }\n }\n\n // Warn about untracked skills that will remain (grouped by label, deduped)\n if (untrackedByDir.size > 0) {\n const groupedUntracked = new Map<string, Set<string>>()\n for (const [_dir, { label, skills }] of untrackedByDir) {\n const set = mapInsert(groupedUntracked, label, () => new Set())\n for (const s of skills) set.add(s)\n }\n\n const totalUntracked = [...groupedUntracked.values()].reduce((sum, s) => sum + s.size, 0)\n p.log.warn(`${totalUntracked} untracked skill(s) will remain (not managed by skilld):`)\n for (const [label, skills] of groupedUntracked) {\n p.log.message(` ${label}: ${[...skills].join(', ')}`)\n }\n }\n\n if (toRemove.length === 0) {\n p.log.info('Nothing to uninstall')\n return\n }\n\n // Group by prefix for display\n const groups = new Map<string, Array<{ name: string, version?: string }>>()\n for (const item of toRemove) {\n const [prefix, name] = item.label.includes(': ')\n ? item.label.split(': ', 2)\n : ['other', item.label]\n mapInsert(groups, prefix!, () => []).push({ name: name!, version: item.version })\n }\n\n const formatGroup = (items: Array<{ name: string, version?: string }>) =>\n items.map(i => i.version ? `${i.name}@${i.version}` : i.name).join(', ')\n\n p.log.info(`Will remove ${toRemove.length} items:`)\n for (const [prefix, items] of groups) {\n p.log.message(` ${prefix}: ${formatGroup(items)}`)\n }\n\n if (!opts.yes && isInteractive()) {\n const confirmed = await p.confirm({\n message: 'Proceed with uninstall?',\n })\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Cancelled')\n return\n }\n }\n\n // Remove all items\n for (const item of toRemove) {\n rmSync(item.path, { recursive: true, force: true })\n }\n\n // Show grouped removal summary\n for (const [prefix, items] of groups) {\n p.log.success(`Removed ${prefix}: ${formatGroup(items)}`)\n }\n\n // Remove skilld instructions from agent instruction files\n const agentTypes = agentFilter || (Object.keys(agents) as AgentType[])\n for (const proj of projectsToUnregister) {\n for (const agent of agentTypes) {\n if (removeAgentInstructions(agent, proj)) {\n const file = agents[agent].instructionFile!\n p.log.success(`Cleaned ${file}`)\n }\n }\n }\n\n // Unregister projects from config (skip if cache dir was removed — config is gone)\n if (scope !== 'all') {\n for (const proj of projectsToUnregister) {\n unregisterProject(proj)\n }\n }\n\n p.outro('skilld uninstalled')\n}\n\nexport const uninstallCommandDef = defineCommand({\n meta: { name: 'uninstall', description: 'Remove skilld data' },\n args: {\n ...sharedArgs,\n },\n async run({ args }) {\n p.intro(`\\x1B[1m\\x1B[35mskilld\\x1B[0m uninstall`)\n return uninstallCommand({\n scope: args.global ? 'all' : undefined,\n agent: args.agent as AgentType | undefined,\n yes: args.yes,\n })\n },\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"uninstall.mjs","names":["agents"],"sources":["../../src/commands/uninstall.ts"],"sourcesContent":["import type { AgentType } from '../agent/index.ts'\nimport { existsSync, readdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { join } from 'pathe'\nimport { agents } from '../agent/index.ts'\nimport { CACHE_DIR } from '../cache/index.ts'\nimport { isInteractive, sharedArgs } from '../cli-helpers.ts'\nimport { getRegisteredProjects, unregisterProject } from '../core/config.ts'\nimport { readLock } from '../core/lockfile.ts'\nimport { mapInsert, SHARED_SKILLS_DIR } from '../core/shared.ts'\nimport { SKILLD_MARKER_END, SKILLD_MARKER_START } from './sync.ts'\n\n/**\n * Remove the skilld marker block from an agent's instruction file.\n * For .mdc files (dedicated skilld files), delete the entire file.\n * Also cleans up legacy .cursorrules markers for backwards compat.\n */\nfunction removeAgentInstructions(agent: AgentType, projectPath: string): boolean {\n const agentConfig = agents[agent]\n if (!agentConfig.instructionFile)\n return false\n\n let removed = false\n\n // Handle current instruction file\n const filePath = join(projectPath, agentConfig.instructionFile)\n if (agentConfig.instructionFile.endsWith('.mdc')) {\n // MDC files are dedicated skilld files - just delete\n if (existsSync(filePath)) {\n rmSync(filePath)\n removed = true\n }\n // Also clean up legacy .cursorrules markers (cursor-specific)\n if (agent === 'cursor')\n removed = removeMarkerBlock(join(projectPath, '.cursorrules')) || removed\n }\n else if (existsSync(filePath)) {\n removed = removeMarkerBlock(filePath)\n }\n\n return removed\n}\n\nfunction removeMarkerBlock(filePath: string): boolean {\n if (!existsSync(filePath))\n return false\n\n const content = readFileSync(filePath, 'utf-8')\n const startIdx = content.indexOf(SKILLD_MARKER_START)\n if (startIdx === -1)\n return false\n\n const endIdx = content.indexOf(SKILLD_MARKER_END, startIdx)\n if (endIdx === -1)\n return false\n\n // Remove marker block plus surrounding blank lines\n const before = content.slice(0, startIdx).replace(/\\n+$/, '')\n const after = content.slice(endIdx + SKILLD_MARKER_END.length).replace(/^\\n+/, '')\n const updated = before + (before && after ? '\\n' : '') + after\n\n if (updated.trim() === '') {\n rmSync(filePath)\n }\n else {\n writeFileSync(filePath, updated.endsWith('\\n') ? updated : `${updated}\\n`)\n }\n return true\n}\n\nexport interface UninstallOptions {\n scope?: 'project' | 'all'\n agent?: AgentType\n yes: boolean\n}\n\n/**\n * Uninstall skilld skills by scope:\n * - project: Remove project skills (cwd)\n * - all: All registered projects + global skills + cache\n */\nexport async function uninstallCommand(opts: UninstallOptions): Promise<void> {\n let scope = opts.scope\n const registeredProjects = getRegisteredProjects()\n\n // Prompt for scope if not provided\n if (!scope) {\n if (!isInteractive()) {\n scope = 'project'\n }\n else {\n const allHint = registeredProjects.length > 0\n ? `${registeredProjects.length} projects + global + cache`\n : 'global skills + cache'\n\n const selected = await p.select({\n message: 'What do you want to uninstall?',\n options: [\n { label: 'This project', value: 'project', hint: 'current project only' },\n { label: 'Everything', value: 'all', hint: allHint },\n ],\n })\n\n if (p.isCancel(selected)) {\n p.cancel('Cancelled')\n return\n }\n scope = selected as 'project' | 'all'\n }\n }\n\n interface RemoveItem { label: string, path: string, version?: string }\n const toRemove: RemoveItem[] = []\n const seenPaths = new Set<string>()\n const projectsToUnregister: string[] = []\n const agentFilter = opts.agent ? [opts.agent] : undefined\n\n const addToRemove = (label: string, path: string, version?: string) => {\n if (seenPaths.has(path))\n return\n seenPaths.add(path)\n toRemove.push({ label, path, version })\n }\n\n // Helper to add skills from a lockfile\n const addSkillsFromLock = (skillsDir: string, label: string): string[] => {\n const trackedNames: string[] = []\n const lock = readLock(skillsDir)\n\n if (lock?.skills) {\n for (const [skillName, info] of Object.entries(lock.skills)) {\n trackedNames.push(skillName)\n const skillDir = join(skillsDir, skillName)\n if (existsSync(skillDir)) {\n const version = info.version ? `${info.version.split('.').slice(0, 2).join('.')}.x` : undefined\n addToRemove(`${label}: ${skillName}`, skillDir, version)\n }\n }\n\n // Also add the lockfile itself\n const lockPath = join(skillsDir, 'skilld-lock.yaml')\n if (existsSync(lockPath)) {\n addToRemove(`${label}: skilld-lock.yaml`, lockPath)\n }\n }\n\n return trackedNames\n }\n\n // Helper to find untracked skills in a directory\n const findUntrackedSkills = (skillsDir: string, trackedNames: string[]): string[] => {\n if (!existsSync(skillsDir))\n return []\n const tracked = new Set(trackedNames)\n return readdirSync(skillsDir)\n .filter(f => !f.startsWith('.') && f !== 'skilld-lock.yaml' && !tracked.has(f))\n }\n\n // Track untracked skills per directory (dedupe by path)\n const untrackedByDir = new Map<string, { label: string, skills: string[] }>()\n const processedDirs = new Set<string>()\n\n // Helper to process a skills directory (with deduping)\n const processSkillsDir = (skillsDir: string, label: string) => {\n if (processedDirs.has(skillsDir))\n return\n processedDirs.add(skillsDir)\n\n const tracked = addSkillsFromLock(skillsDir, label)\n const untracked = findUntrackedSkills(skillsDir, tracked)\n if (untracked.length > 0) {\n untrackedByDir.set(skillsDir, { label, skills: untracked })\n }\n }\n\n // Project skills\n if (scope === 'project') {\n // Shared dir\n const sharedDir = join(process.cwd(), SHARED_SKILLS_DIR)\n if (existsSync(sharedDir))\n processSkillsDir(sharedDir, 'project (.skills)')\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n processSkillsDir(join(process.cwd(), agent.skillsDir), 'project')\n }\n projectsToUnregister.push(process.cwd())\n }\n\n // All registered projects + global\n if (scope === 'all') {\n const projectPaths = registeredProjects.length > 0 ? registeredProjects : [process.cwd()]\n\n // Show which projects will be affected\n if (registeredProjects.length > 0) {\n p.log.info('Projects to uninstall from:')\n for (const proj of projectPaths) {\n p.log.message(` ${proj}`)\n }\n }\n\n // Project skills from lockfiles\n for (const projectPath of projectPaths) {\n if (!existsSync(projectPath))\n continue\n\n const shortPath = projectPath.replace(process.env.HOME || '', '~')\n\n // Shared dir\n const sharedDir = join(projectPath, SHARED_SKILLS_DIR)\n if (existsSync(sharedDir))\n processSkillsDir(sharedDir, `${shortPath} (.skills)`)\n\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n processSkillsDir(join(projectPath, agent.skillsDir), shortPath)\n }\n\n projectsToUnregister.push(projectPath)\n }\n\n // Global skills from lockfiles\n for (const [name, agent] of Object.entries(agents)) {\n if (agentFilter && !agentFilter.includes(name as AgentType))\n continue\n if (!agent.globalSkillsDir)\n continue\n processSkillsDir(agent.globalSkillsDir, 'user')\n }\n\n // Cache directory\n if (existsSync(CACHE_DIR)) {\n addToRemove('~/.skilld cache', CACHE_DIR)\n }\n }\n\n // Warn about untracked skills that will remain (grouped by label, deduped)\n if (untrackedByDir.size > 0) {\n const groupedUntracked = new Map<string, Set<string>>()\n for (const [_dir, { label, skills }] of untrackedByDir) {\n const set = mapInsert(groupedUntracked, label, () => new Set())\n for (const s of skills) set.add(s)\n }\n\n const totalUntracked = [...groupedUntracked.values()].reduce((sum, s) => sum + s.size, 0)\n p.log.warn(`${totalUntracked} untracked skill(s) will remain (not managed by skilld):`)\n for (const [label, skills] of groupedUntracked) {\n p.log.message(` ${label}: ${[...skills].join(', ')}`)\n }\n }\n\n if (toRemove.length === 0) {\n p.log.info('Nothing to uninstall')\n return\n }\n\n // Group by prefix for display\n const groups = new Map<string, Array<{ name: string, version?: string }>>()\n for (const item of toRemove) {\n const [prefix, name] = item.label.includes(': ')\n ? item.label.split(': ', 2)\n : ['other', item.label]\n mapInsert(groups, prefix!, () => []).push({ name: name!, version: item.version })\n }\n\n const formatGroup = (items: Array<{ name: string, version?: string }>) =>\n items.map(i => i.version ? `${i.name}@${i.version}` : i.name).join(', ')\n\n p.log.info(`Will remove ${toRemove.length} items:`)\n for (const [prefix, items] of groups) {\n p.log.message(` ${prefix}: ${formatGroup(items)}`)\n }\n\n if (!opts.yes && isInteractive()) {\n const confirmed = await p.confirm({\n message: 'Proceed with uninstall?',\n })\n\n if (p.isCancel(confirmed) || !confirmed) {\n p.cancel('Cancelled')\n return\n }\n }\n\n // Remove all items\n for (const item of toRemove) {\n rmSync(item.path, { recursive: true, force: true })\n }\n\n // Show grouped removal summary\n for (const [prefix, items] of groups) {\n p.log.success(`Removed ${prefix}: ${formatGroup(items)}`)\n }\n\n // Remove skilld instructions from agent instruction files\n const agentTypes = agentFilter || (Object.keys(agents) as AgentType[])\n for (const proj of projectsToUnregister) {\n for (const agent of agentTypes) {\n if (removeAgentInstructions(agent, proj)) {\n const file = agents[agent].instructionFile!\n p.log.success(`Cleaned ${file}`)\n }\n }\n }\n\n // Unregister projects from config (skip if cache dir was removed — config is gone)\n if (scope !== 'all') {\n for (const proj of projectsToUnregister) {\n unregisterProject(proj)\n }\n }\n\n p.outro('skilld uninstalled')\n}\n\nexport const uninstallCommandDef = defineCommand({\n meta: { name: 'uninstall', description: 'Remove skilld data' },\n args: {\n ...sharedArgs,\n },\n async run({ args }) {\n p.intro(`\\x1B[1m\\x1B[35mskilld\\x1B[0m uninstall`)\n return uninstallCommand({\n scope: args.global ? 'all' : undefined,\n agent: args.agent as AgentType | undefined,\n yes: args.yes,\n })\n },\n})\n"],"mappings":"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"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { i as parseFrontmatter } from "./markdown.mjs";
|
|
2
|
+
import { i as readLock } from "./lockfile.mjs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "pathe";
|
|
5
|
+
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
6
|
+
import { ofetch } from "ofetch";
|
|
7
|
+
import { multiselect } from "@clack/prompts";
|
|
8
|
+
import { defineCommand } from "citty";
|
|
9
|
+
import { colorize } from "consola/utils";
|
|
10
|
+
const UPLOAD_URL = "https://skilld.dev/api/collections/import";
|
|
11
|
+
function readSkillsFromDir(dir, source, extraLockDirs) {
|
|
12
|
+
if (!existsSync(dir)) return [];
|
|
13
|
+
let lock = readLock(dir);
|
|
14
|
+
if (!lock && extraLockDirs) for (const d of extraLockDirs) {
|
|
15
|
+
lock = readLock(d);
|
|
16
|
+
if (lock) break;
|
|
17
|
+
}
|
|
18
|
+
const entries = readdirSync(dir).filter((f) => {
|
|
19
|
+
if (f.startsWith(".") || f.endsWith(".yaml") || f.endsWith(".yml")) return false;
|
|
20
|
+
return statSync(join(dir, f)).isDirectory();
|
|
21
|
+
});
|
|
22
|
+
const skills = [];
|
|
23
|
+
for (const dirName of entries) {
|
|
24
|
+
const skillMd = join(dir, dirName, "SKILL.md");
|
|
25
|
+
if (!existsSync(skillMd)) continue;
|
|
26
|
+
const fm = parseFrontmatter(readFileSync(skillMd, "utf-8"));
|
|
27
|
+
const lockInfo = lock?.skills[dirName];
|
|
28
|
+
skills.push({
|
|
29
|
+
name: fm.name || dirName,
|
|
30
|
+
description: fm.description,
|
|
31
|
+
version: fm.version || lockInfo?.version,
|
|
32
|
+
repo: lockInfo?.repo,
|
|
33
|
+
generator: lockInfo?.generator,
|
|
34
|
+
source
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
return skills;
|
|
38
|
+
}
|
|
39
|
+
function readPlugins(configDir) {
|
|
40
|
+
const settingsPath = join(configDir, "settings.json");
|
|
41
|
+
if (!existsSync(settingsPath)) return [];
|
|
42
|
+
const enabledPlugins = JSON.parse(readFileSync(settingsPath, "utf-8")).enabledPlugins;
|
|
43
|
+
if (!enabledPlugins) return [];
|
|
44
|
+
const marketplacesPath = join(configDir, "plugins", "known_marketplaces.json");
|
|
45
|
+
const marketplaces = existsSync(marketplacesPath) ? JSON.parse(readFileSync(marketplacesPath, "utf-8")) : {};
|
|
46
|
+
const installedPath = join(configDir, "plugins", "installed_plugins.json");
|
|
47
|
+
const installed = existsSync(installedPath) ? JSON.parse(readFileSync(installedPath, "utf-8")) : { plugins: {} };
|
|
48
|
+
return Object.entries(enabledPlugins).filter(([, enabled]) => enabled).map(([id]) => {
|
|
49
|
+
const marketplace = id.split("@")[1];
|
|
50
|
+
const pluginName = id.split("@")[0];
|
|
51
|
+
const repo = (marketplace ? marketplaces[marketplace] : void 0)?.source?.repo;
|
|
52
|
+
const versions = installed.plugins[id];
|
|
53
|
+
return {
|
|
54
|
+
name: pluginName,
|
|
55
|
+
version: versions?.[0]?.version !== "unknown" ? versions?.[0]?.version : void 0,
|
|
56
|
+
repo: repo ? `${repo}` : void 0,
|
|
57
|
+
source: "plugin"
|
|
58
|
+
};
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function discoverAllSkills(cwd) {
|
|
62
|
+
const claudeHome = process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude");
|
|
63
|
+
const localDir = join(cwd, ".claude", "skills");
|
|
64
|
+
const globalDir = join(claudeHome, "skills");
|
|
65
|
+
const skilldGlobalDir = join(homedir(), ".skilld", "skills");
|
|
66
|
+
const local = readSkillsFromDir(localDir, "local");
|
|
67
|
+
const global = readSkillsFromDir(globalDir, "global", [skilldGlobalDir]);
|
|
68
|
+
const plugins = readPlugins(claudeHome);
|
|
69
|
+
const seenRepos = /* @__PURE__ */ new Set();
|
|
70
|
+
const all = [];
|
|
71
|
+
for (const skill of [
|
|
72
|
+
...local,
|
|
73
|
+
...global,
|
|
74
|
+
...plugins
|
|
75
|
+
]) {
|
|
76
|
+
if (!skill.repo || seenRepos.has(skill.repo)) continue;
|
|
77
|
+
if (skill.generator === "skilld") continue;
|
|
78
|
+
seenRepos.add(skill.repo);
|
|
79
|
+
all.push(skill);
|
|
80
|
+
}
|
|
81
|
+
return all;
|
|
82
|
+
}
|
|
83
|
+
const SOURCE_COLORS = {
|
|
84
|
+
local: "green",
|
|
85
|
+
global: "blue",
|
|
86
|
+
plugin: "magenta"
|
|
87
|
+
};
|
|
88
|
+
async function uploadCommand(options) {
|
|
89
|
+
const skills = discoverAllSkills(process.cwd());
|
|
90
|
+
if (skills.length === 0) {
|
|
91
|
+
process.stdout.write("No skills found.\n");
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (options?.dryRun) {
|
|
95
|
+
process.stdout.write(`Found ${colorize("bold", String(skills.length))} skill${skills.length === 1 ? "" : "s"}:\n\n`);
|
|
96
|
+
for (const skill of skills) {
|
|
97
|
+
const version = skill.version ? colorize("dim", ` v${skill.version}`) : "";
|
|
98
|
+
const tag = colorize(SOURCE_COLORS[skill.source] || "dim", skill.source);
|
|
99
|
+
const repo = skill.repo ? colorize("dim", ` github.com/${skill.repo}`) : "";
|
|
100
|
+
process.stdout.write(` ${colorize("cyan", skill.name)}${version} ${tag}${repo}\n`);
|
|
101
|
+
}
|
|
102
|
+
process.stdout.write(`\n${colorize("dim", "Dry run complete. No requests were made.")}\n`);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
const selected = await multiselect({
|
|
106
|
+
message: `Select skills to upload (${skills.length} found)`,
|
|
107
|
+
options: skills.map((s) => {
|
|
108
|
+
const version = s.version ? ` v${s.version}` : "";
|
|
109
|
+
const repo = s.repo ? ` github.com/${s.repo}` : "";
|
|
110
|
+
return {
|
|
111
|
+
value: s.name,
|
|
112
|
+
label: `${s.name}${version}`,
|
|
113
|
+
hint: `${s.source}${repo}`
|
|
114
|
+
};
|
|
115
|
+
}),
|
|
116
|
+
initialValues: []
|
|
117
|
+
});
|
|
118
|
+
if (typeof selected === "symbol" || selected.length === 0) return;
|
|
119
|
+
const selectedSet = new Set(selected);
|
|
120
|
+
const { token, expires } = await ofetch(UPLOAD_URL, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
body: { skills: skills.filter((s) => selectedSet.has(s.name)).map((s) => ({
|
|
123
|
+
name: s.name,
|
|
124
|
+
version: s.version,
|
|
125
|
+
repo: s.repo,
|
|
126
|
+
source: s.source
|
|
127
|
+
})) }
|
|
128
|
+
});
|
|
129
|
+
const expiresDate = new Date(expires);
|
|
130
|
+
const minutesLeft = Math.round((expiresDate.getTime() - Date.now()) / 6e4);
|
|
131
|
+
process.stdout.write(`\nToken: ${colorize("green", token)}\n\n`);
|
|
132
|
+
process.stdout.write(`Paste this token at: ${colorize("cyan", "https://skilld.dev/people/YOUR_HANDLE/edit-skills")}\n`);
|
|
133
|
+
process.stdout.write(colorize("dim", `Token expires in ${minutesLeft} minutes.\n`));
|
|
134
|
+
}
|
|
135
|
+
const uploadCommandDef = defineCommand({
|
|
136
|
+
meta: {
|
|
137
|
+
name: "publish",
|
|
138
|
+
description: "Publish your skill list to skilld.dev"
|
|
139
|
+
},
|
|
140
|
+
args: { dryRun: {
|
|
141
|
+
type: "boolean",
|
|
142
|
+
alias: "d",
|
|
143
|
+
description: "Show what would be uploaded without making any requests",
|
|
144
|
+
default: false
|
|
145
|
+
} },
|
|
146
|
+
run({ args }) {
|
|
147
|
+
return uploadCommand({ dryRun: args.dryRun });
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
export { uploadCommandDef };
|
|
151
|
+
|
|
152
|
+
//# sourceMappingURL=upload.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upload.mjs","names":[],"sources":["../../src/commands/upload.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'\nimport { homedir } from 'node:os'\nimport { multiselect } from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { colorize } from 'consola/utils'\nimport { ofetch } from 'ofetch'\nimport { join } from 'pathe'\nimport { readLock } from '../core/lockfile.ts'\nimport { parseFrontmatter } from '../core/markdown.ts'\n\nconst UPLOAD_URL = 'https://skilld.dev/api/collections/import'\n\ninterface DiscoveredSkill {\n name: string\n description?: string\n version?: string\n repo?: string\n generator?: string\n source: 'local' | 'global' | 'plugin'\n}\n\nfunction readSkillsFromDir(dir: string, source: 'local' | 'global', extraLockDirs?: string[]): DiscoveredSkill[] {\n if (!existsSync(dir))\n return []\n\n // Merge lockfiles: primary dir + any extra dirs (e.g. ~/.skilld/skills/ for global)\n let lock = readLock(dir)\n if (!lock && extraLockDirs) {\n for (const d of extraLockDirs) {\n lock = readLock(d)\n if (lock)\n break\n }\n }\n const entries = readdirSync(dir).filter((f) => {\n if (f.startsWith('.') || f.endsWith('.yaml') || f.endsWith('.yml'))\n return false\n const full = join(dir, f)\n return statSync(full).isDirectory()\n })\n\n const skills: DiscoveredSkill[] = []\n for (const dirName of entries) {\n const skillMd = join(dir, dirName, 'SKILL.md')\n if (!existsSync(skillMd))\n continue\n const content = readFileSync(skillMd, 'utf-8')\n const fm = parseFrontmatter(content)\n const lockInfo = lock?.skills[dirName]\n skills.push({\n name: fm.name || dirName,\n description: fm.description,\n version: fm.version || lockInfo?.version,\n repo: lockInfo?.repo,\n generator: lockInfo?.generator,\n source,\n })\n }\n\n return skills\n}\n\ninterface MarketplaceInfo {\n source: { source: string, repo: string }\n}\n\nfunction readPlugins(configDir: string): DiscoveredSkill[] {\n const settingsPath = join(configDir, 'settings.json')\n if (!existsSync(settingsPath))\n return []\n\n const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'))\n const enabledPlugins = settings.enabledPlugins as Record<string, boolean> | undefined\n if (!enabledPlugins)\n return []\n\n // Load marketplace repos for GitHub links\n const marketplacesPath = join(configDir, 'plugins', 'known_marketplaces.json')\n const marketplaces: Record<string, MarketplaceInfo> = existsSync(marketplacesPath)\n ? JSON.parse(readFileSync(marketplacesPath, 'utf-8'))\n : {}\n\n // Load installed plugins for version info\n const installedPath = join(configDir, 'plugins', 'installed_plugins.json')\n const installed: { plugins: Record<string, Array<{ version?: string }>> } = existsSync(installedPath)\n ? JSON.parse(readFileSync(installedPath, 'utf-8'))\n : { plugins: {} }\n\n return Object.entries(enabledPlugins)\n .filter(([, enabled]) => enabled)\n .map(([id]) => {\n const marketplace = id.split('@')[1]\n const pluginName = id.split('@')[0]\n const marketplaceInfo = marketplace ? marketplaces[marketplace] : undefined\n const repo = marketplaceInfo?.source?.repo\n const versions = installed.plugins[id]\n const version = versions?.[0]?.version !== 'unknown' ? versions?.[0]?.version : undefined\n\n return {\n name: pluginName!,\n version,\n repo: repo ? `${repo}` : undefined,\n source: 'plugin' as const,\n }\n })\n}\n\nfunction discoverAllSkills(cwd: string): DiscoveredSkill[] {\n const claudeHome = process.env.CLAUDE_CONFIG_DIR || join(homedir(), '.claude')\n const localDir = join(cwd, '.claude', 'skills')\n const globalDir = join(claudeHome, 'skills')\n\n const skilldGlobalDir = join(homedir(), '.skilld', 'skills')\n const local = readSkillsFromDir(localDir, 'local')\n const global = readSkillsFromDir(globalDir, 'global', [skilldGlobalDir])\n const plugins = readPlugins(claudeHome)\n\n // Filter out skilld-generated skills, deduplicate by repo\n const seenRepos = new Set<string>()\n const all: DiscoveredSkill[] = []\n for (const skill of [...local, ...global, ...plugins]) {\n if (!skill.repo || seenRepos.has(skill.repo))\n continue\n if (skill.generator === 'skilld')\n continue\n seenRepos.add(skill.repo)\n all.push(skill)\n }\n return all\n}\n\nconst SOURCE_COLORS: Record<string, string> = {\n local: 'green',\n global: 'blue',\n plugin: 'magenta',\n}\n\nexport async function uploadCommand(options?: { dryRun?: boolean }): Promise<void> {\n const skills = discoverAllSkills(process.cwd())\n\n if (skills.length === 0) {\n process.stdout.write('No skills found.\\n')\n return\n }\n\n if (options?.dryRun) {\n process.stdout.write(`Found ${colorize('bold', String(skills.length))} skill${skills.length === 1 ? '' : 's'}:\\n\\n`)\n for (const skill of skills) {\n const version = skill.version ? colorize('dim', ` v${skill.version}`) : ''\n const tag = colorize((SOURCE_COLORS[skill.source] || 'dim') as 'dim', skill.source)\n const repo = skill.repo ? colorize('dim', ` github.com/${skill.repo}`) : ''\n process.stdout.write(` ${colorize('cyan', skill.name)}${version} ${tag}${repo}\\n`)\n }\n process.stdout.write(`\\n${colorize('dim', 'Dry run complete. No requests were made.')}\\n`)\n return\n }\n\n const selected = await multiselect({\n message: `Select skills to upload (${skills.length} found)`,\n options: skills.map((s) => {\n const version = s.version ? ` v${s.version}` : ''\n const repo = s.repo ? ` github.com/${s.repo}` : ''\n return {\n value: s.name,\n label: `${s.name}${version}`,\n hint: `${s.source}${repo}`,\n }\n }),\n initialValues: [],\n })\n\n if (typeof selected === 'symbol' || selected.length === 0)\n return\n\n const selectedSet = new Set(selected)\n const payload = skills\n .filter(s => selectedSet.has(s.name))\n .map(s => ({\n name: s.name,\n version: s.version,\n repo: s.repo,\n source: s.source,\n }))\n\n const { token, expires } = await ofetch<{ token: string, expires: string }>(UPLOAD_URL, {\n method: 'POST',\n body: { skills: payload },\n })\n\n const expiresDate = new Date(expires)\n const minutesLeft = Math.round((expiresDate.getTime() - Date.now()) / 60000)\n\n process.stdout.write(`\\nToken: ${colorize('green', token)}\\n\\n`)\n process.stdout.write(`Paste this token at: ${colorize('cyan', 'https://skilld.dev/people/YOUR_HANDLE/edit-skills')}\\n`)\n process.stdout.write(colorize('dim', `Token expires in ${minutesLeft} minutes.\\n`))\n}\n\nexport const uploadCommandDef = defineCommand({\n meta: { name: 'publish', description: 'Publish your skill list to skilld.dev' },\n args: {\n dryRun: {\n type: 'boolean',\n alias: 'd',\n description: 'Show what would be uploaded without making any requests',\n default: false,\n },\n },\n run({ args }) {\n return uploadCommand({ dryRun: args.dryRun })\n },\n})\n"],"mappings":"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"}
|
|
@@ -1,16 +1,10 @@
|
|
|
1
|
-
import "./
|
|
2
|
-
import "./yaml.mjs";
|
|
3
|
-
import "./shared.mjs";
|
|
4
|
-
import "./detect.mjs";
|
|
5
|
-
import { f as getSectionValidator } from "./prompts.mjs";
|
|
1
|
+
import { s as getSectionValidator } from "./prompts.mjs";
|
|
6
2
|
import { existsSync, readFileSync } from "node:fs";
|
|
7
3
|
import { defineCommand } from "citty";
|
|
8
|
-
//#region src/commands/validate.ts
|
|
9
4
|
const SECTION_HEADINGS = {
|
|
10
5
|
"## API Changes": "api-changes",
|
|
11
6
|
"## Best Practices": "best-practices"
|
|
12
7
|
};
|
|
13
|
-
/** Infer section type from content headings */
|
|
14
8
|
function inferSection(content) {
|
|
15
9
|
for (const [heading, section] of Object.entries(SECTION_HEADINGS)) if (content.includes(heading)) return section;
|
|
16
10
|
return "custom";
|
|
@@ -61,7 +55,6 @@ const validateCommandDef = defineCommand({
|
|
|
61
55
|
process.exit(1);
|
|
62
56
|
}
|
|
63
57
|
});
|
|
64
|
-
//#endregion
|
|
65
58
|
export { validateCommandDef };
|
|
66
59
|
|
|
67
60
|
//# sourceMappingURL=validate.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.mjs","names":[],"sources":["../../src/commands/validate.ts"],"sourcesContent":["/**\n * skilld validate <file> [--section <type>]\n *\n * Validates a generated skill section file against quality heuristics.\n * Exits non-zero on warnings so the LLM agent detects issues via exit code.\n */\n\nimport type { SkillSection } from '../agent/prompts/index.ts'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { defineCommand } from 'citty'\nimport { getSectionValidator } from '../agent/prompts/index.ts'\n\nconst SECTION_HEADINGS: Record<string, SkillSection> = {\n '## API Changes': 'api-changes',\n '## Best Practices': 'best-practices',\n}\n\n/** Infer section type from content headings */\nfunction inferSection(content: string): SkillSection | null {\n for (const [heading, section] of Object.entries(SECTION_HEADINGS)) {\n if (content.includes(heading))\n return section\n }\n // Custom sections don't have a fixed heading — fall back\n return 'custom'\n}\n\nexport const validateCommandDef = defineCommand({\n meta: { name: 'validate', description: 'Validate a generated skill section' },\n args: {\n file: {\n type: 'positional',\n description: 'Path to the section file to validate',\n required: true,\n },\n section: {\n type: 'string',\n description: 'Section type (api-changes, best-practices, custom). Auto-detected from heading if omitted.',\n },\n },\n\n /* eslint-disable no-console */\n async run({ args }) {\n const filePath = args.file as string\n if (!existsSync(filePath)) {\n console.error(`File not found: ${filePath}`)\n process.exit(1)\n }\n\n const content = readFileSync(filePath, 'utf-8').trim()\n if (!content) {\n console.error('File is empty')\n process.exit(1)\n }\n\n const section = (args.section as SkillSection) || inferSection(content)\n if (!section) {\n console.error('Could not infer section type — use --section flag')\n process.exit(1)\n }\n\n const validator = getSectionValidator(section)\n if (!validator) {\n console.log('OK: No validator for section type:', section)\n process.exit(0)\n }\n\n const warnings = validator(content)\n\n if (warnings.length === 0) {\n console.log('OK: No validation warnings')\n process.exit(0)\n }\n\n for (const w of warnings)\n console.log(`WARNING: ${w.warning}`)\n\n process.exit(1)\n },\n})\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"validate.mjs","names":[],"sources":["../../src/commands/validate.ts"],"sourcesContent":["/**\n * skilld validate <file> [--section <type>]\n *\n * Validates a generated skill section file against quality heuristics.\n * Exits non-zero on warnings so the LLM agent detects issues via exit code.\n */\n\nimport type { SkillSection } from '../agent/prompts/index.ts'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { defineCommand } from 'citty'\nimport { getSectionValidator } from '../agent/prompts/index.ts'\n\nconst SECTION_HEADINGS: Record<string, SkillSection> = {\n '## API Changes': 'api-changes',\n '## Best Practices': 'best-practices',\n}\n\n/** Infer section type from content headings */\nfunction inferSection(content: string): SkillSection | null {\n for (const [heading, section] of Object.entries(SECTION_HEADINGS)) {\n if (content.includes(heading))\n return section\n }\n // Custom sections don't have a fixed heading — fall back\n return 'custom'\n}\n\nexport const validateCommandDef = defineCommand({\n meta: { name: 'validate', description: 'Validate a generated skill section' },\n args: {\n file: {\n type: 'positional',\n description: 'Path to the section file to validate',\n required: true,\n },\n section: {\n type: 'string',\n description: 'Section type (api-changes, best-practices, custom). Auto-detected from heading if omitted.',\n },\n },\n\n /* eslint-disable no-console */\n async run({ args }) {\n const filePath = args.file as string\n if (!existsSync(filePath)) {\n console.error(`File not found: ${filePath}`)\n process.exit(1)\n }\n\n const content = readFileSync(filePath, 'utf-8').trim()\n if (!content) {\n console.error('File is empty')\n process.exit(1)\n }\n\n const section = (args.section as SkillSection) || inferSection(content)\n if (!section) {\n console.error('Could not infer section type — use --section flag')\n process.exit(1)\n }\n\n const validator = getSectionValidator(section)\n if (!validator) {\n console.log('OK: No validator for section type:', section)\n process.exit(0)\n }\n\n const warnings = validator(content)\n\n if (warnings.length === 0) {\n console.log('OK: No validation warnings')\n process.exit(0)\n }\n\n for (const w of warnings)\n console.log(`WARNING: ${w.warning}`)\n\n process.exit(1)\n },\n})\n"],"mappings":";;;AAYA,MAAM,mBAAiD;CACrD,kBAAkB;CAClB,qBAAqB;CACtB;AAGD,SAAS,aAAa,SAAsC;AAC1D,MAAK,MAAM,CAAC,SAAS,YAAY,OAAO,QAAQ,iBAAiB,CAC/D,KAAI,QAAQ,SAAS,QAAQ,CAC3B,QAAO;AAGX,QAAO;;AAGT,MAAa,qBAAqB,cAAc;CAC9C,MAAM;EAAE,MAAM;EAAY,aAAa;EAAsC;CAC7E,MAAM;EACJ,MAAM;GACJ,MAAM;GACN,aAAa;GACb,UAAU;GACX;EACD,SAAS;GACP,MAAM;GACN,aAAa;;EAEhB;CAGD,MAAM,IAAI,EAAE,QAAQ;EAClB,MAAM,WAAW,KAAK;AACtB,MAAI,CAAC,WAAW,SAAS,EAAE;AACzB,WAAQ,MAAM,mBAAmB,WAAW;AAC5C,WAAQ,KAAK,EAAE;;EAGjB,MAAM,UAAU,aAAa,UAAU,QAAQ,CAAC,MAAM;AACtD,MAAI,CAAC,SAAS;AACZ,WAAQ,MAAM,gBAAgB;AAC9B,WAAQ,KAAK,EAAE;;EAGjB,MAAM,UAAW,KAAK,WAA4B,aAAa,QAAQ;AACvE,MAAI,CAAC,SAAS;AACZ,WAAQ,MAAM,oDAAoD;AAClE,WAAQ,KAAK,EAAE;;EAGjB,MAAM,YAAY,oBAAoB,QAAQ;AAC9C,MAAI,CAAC,WAAW;AACd,WAAQ,IAAI,sCAAsC,QAAQ;AAC1D,WAAQ,KAAK,EAAE;;EAGjB,MAAM,WAAW,UAAU,QAAQ;AAEnC,MAAI,SAAS,WAAW,GAAG;AACzB,WAAQ,IAAI,6BAA6B;AACzC,WAAQ,KAAK,EAAE;;AAGjB,OAAK,MAAM,KAAK,SACd,SAAQ,IAAI,YAAY,EAAE,UAAU;AAEtC,UAAQ,KAAK,EAAE;;CAElB,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { join, resolve } from "pathe";
|
|
3
|
+
const CACHE_DIR = join(homedir(), ".skilld");
|
|
4
|
+
const REFERENCES_DIR = join(CACHE_DIR, "references");
|
|
5
|
+
const REPOS_DIR = join(CACHE_DIR, "repos");
|
|
6
|
+
function getRepoCacheDir(owner, repo) {
|
|
7
|
+
if (owner.includes("..") || repo.includes("..") || owner.includes("/") || repo.includes("/")) throw new Error(`Invalid repo path: ${owner}/${repo}`);
|
|
8
|
+
return join(REPOS_DIR, owner, repo);
|
|
9
|
+
}
|
|
10
|
+
function getPackageDbPath(name, version) {
|
|
11
|
+
return join(REFERENCES_DIR, `${name}@${version}`, "search.db");
|
|
12
|
+
}
|
|
13
|
+
const VALID_PKG_NAME = /^(?:@[a-z0-9][-a-z0-9._]*\/)?[a-z0-9][-a-z0-9._]*$/;
|
|
14
|
+
const VALID_VERSION = /^[a-z0-9][-\w.+]*$/i;
|
|
15
|
+
function getVersionKey(version) {
|
|
16
|
+
return version;
|
|
17
|
+
}
|
|
18
|
+
function getCacheKey(name, version) {
|
|
19
|
+
return `${name}@${getVersionKey(version)}`;
|
|
20
|
+
}
|
|
21
|
+
function getCacheDir(name, version) {
|
|
22
|
+
if (!VALID_PKG_NAME.test(name)) throw new Error(`Invalid package name: ${name}`);
|
|
23
|
+
if (!VALID_VERSION.test(version)) throw new Error(`Invalid version: ${version}`);
|
|
24
|
+
const dir = resolve(REFERENCES_DIR, getCacheKey(name, version));
|
|
25
|
+
if (!dir.startsWith(REFERENCES_DIR)) throw new Error(`Path traversal detected: ${dir}`);
|
|
26
|
+
return dir;
|
|
27
|
+
}
|
|
28
|
+
export { REFERENCES_DIR as a, getRepoCacheDir as c, CACHE_DIR as i, getCacheKey as n, REPOS_DIR as o, getVersionKey as r, getPackageDbPath as s, getCacheDir as t };
|
|
29
|
+
|
|
30
|
+
//# sourceMappingURL=version.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.mjs","names":[],"sources":["../../src/cache/config.ts","../../src/cache/version.ts"],"sourcesContent":["/**\n * Cache configuration\n */\n\nimport { homedir } from 'node:os'\nimport { join } from 'pathe'\n\n/** Global cache directory */\nexport const CACHE_DIR = join(homedir(), '.skilld')\n\n/** References subdirectory */\nexport const REFERENCES_DIR = join(CACHE_DIR, 'references')\n\n/** Repo-level cache (issues, discussions, releases shared across monorepo packages) */\nexport const REPOS_DIR = join(CACHE_DIR, 'repos')\n\n/** Get repo cache dir for owner/repo with path traversal validation */\nexport function getRepoCacheDir(owner: string, repo: string): string {\n if (owner.includes('..') || repo.includes('..') || owner.includes('/') || repo.includes('/'))\n throw new Error(`Invalid repo path: ${owner}/${repo}`)\n return join(REPOS_DIR, owner, repo)\n}\n\n/** Get search DB path for a specific package@version */\nexport function getPackageDbPath(name: string, version: string): string {\n return join(REFERENCES_DIR, `${name}@${version}`, 'search.db')\n}\n","/**\n * Version utilities\n */\n\nimport { resolve } from 'pathe'\nimport { REFERENCES_DIR } from './config.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"],"mappings":";;;AAQA,MAAa,iBAAiB,KAAA,WAAW,aAAU;AAGnD,MAAa,YAAA,KAAiB,WAAK,QAAW;AAG9C,SAAa,gBAAiB,OAAA,MAAW;;AAGzC,QAAA,KAAgB,WAAA,OAAgB,KAAe;;;;;;;ACT/C,SAAM,cAAiB,SAAA;;;;;;;;;;AAevB,KAAA,CAAA,IAAgB,WAAY,eAAuC,CAAA,OAAA,IAAA,MAAA,4BAAA,MAAA;AACjE,QAAO"}
|
package/dist/_chunks/wizard.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { a as targets } from "./detect.mjs";
|
|
2
2
|
import { c as getOAuthProviderList, i as getAvailableModels, l as loginOAuthProvider, o as getModelName } from "./agent.mjs";
|
|
3
|
-
import {
|
|
3
|
+
import { c as updateConfig, t as defaultFeatures } from "./config.mjs";
|
|
4
|
+
import { g as pickModel, n as NO_MODELS_MESSAGE, p as isInteractive, r as OAUTH_NOTE } from "./cli-helpers.mjs";
|
|
4
5
|
import { execSync } from "node:child_process";
|
|
5
6
|
import * as p from "@clack/prompts";
|
|
6
|
-
//#region src/commands/wizard.ts
|
|
7
7
|
function hasGhCli() {
|
|
8
8
|
if (process.env.SKILLD_NO_GH) return false;
|
|
9
9
|
try {
|
|
@@ -185,7 +185,6 @@ async function wizardConnectProvider() {
|
|
|
185
185
|
p.log.success(`Connected to ${name}`);
|
|
186
186
|
}
|
|
187
187
|
}
|
|
188
|
-
//#endregion
|
|
189
188
|
export { runWizard as t };
|
|
190
189
|
|
|
191
190
|
//# sourceMappingURL=wizard.mjs.map
|
package/dist/_chunks/yaml.mjs
CHANGED
|
@@ -1,24 +1,8 @@
|
|
|
1
|
-
//#region src/core/yaml.ts
|
|
2
|
-
/**
|
|
3
|
-
* Minimal YAML value escaping/unescaping for our hand-rolled parsers.
|
|
4
|
-
*
|
|
5
|
-
* Handles the characters that break naive `:` splitting and quote stripping:
|
|
6
|
-
* colons, quotes, newlines, backslashes.
|
|
7
|
-
*/
|
|
8
|
-
/** Characters that require double-quoting in YAML values */
|
|
9
1
|
const NEEDS_QUOTING = /[:"'\\\n\r\t#{}[\],&*!|>%@`]/;
|
|
10
|
-
/**
|
|
11
|
-
* Escape a value for safe YAML emission. Always double-quotes if the value
|
|
12
|
-
* contains any special characters; returns unquoted for simple values.
|
|
13
|
-
*/
|
|
14
2
|
function yamlEscape(value) {
|
|
15
3
|
if (!NEEDS_QUOTING.test(value)) return value;
|
|
16
4
|
return `"${value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t")}"`;
|
|
17
5
|
}
|
|
18
|
-
/**
|
|
19
|
-
* Parse a raw YAML value string back to its actual value.
|
|
20
|
-
* Handles double-quoted (with escapes), single-quoted, and unquoted values.
|
|
21
|
-
*/
|
|
22
6
|
function yamlUnescape(raw) {
|
|
23
7
|
const trimmed = raw.trim();
|
|
24
8
|
if (!trimmed) return "";
|
|
@@ -35,10 +19,6 @@ function yamlUnescape(raw) {
|
|
|
35
19
|
if (trimmed.startsWith("'") && trimmed.endsWith("'")) return trimmed.slice(1, -1);
|
|
36
20
|
return trimmed;
|
|
37
21
|
}
|
|
38
|
-
/**
|
|
39
|
-
* Parse a YAML `key: value` line, correctly handling colons inside quoted values.
|
|
40
|
-
* Returns [key, value] or null if not a valid KV line.
|
|
41
|
-
*/
|
|
42
22
|
function yamlParseKV(line) {
|
|
43
23
|
const trimmed = line.trim();
|
|
44
24
|
const colonIdx = trimmed.indexOf(":");
|
|
@@ -48,7 +28,6 @@ function yamlParseKV(line) {
|
|
|
48
28
|
if (!key) return null;
|
|
49
29
|
return [key, yamlUnescape(rawValue)];
|
|
50
30
|
}
|
|
51
|
-
//#endregion
|
|
52
31
|
export { yamlParseKV as n, yamlUnescape as r, yamlEscape as t };
|
|
53
32
|
|
|
54
33
|
//# sourceMappingURL=yaml.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yaml.mjs","names":[],"sources":["../../src/core/yaml.ts"],"sourcesContent":["/**\n * Minimal YAML value escaping/unescaping for our hand-rolled parsers.\n *\n * Handles the characters that break naive `:` splitting and quote stripping:\n * colons, quotes, newlines, backslashes.\n */\n\n/** Characters that require double-quoting in YAML values */\nconst NEEDS_QUOTING = /[:\"'\\\\\\n\\r\\t#{}[\\],&*!|>%@`]/\n\n/**\n * Escape a value for safe YAML emission. Always double-quotes if the value\n * contains any special characters; returns unquoted for simple values.\n */\nexport function yamlEscape(value: string): string {\n if (!NEEDS_QUOTING.test(value))\n return value\n // Escape backslashes first, then double quotes, then control chars\n const escaped = value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\t/g, '\\\\t')\n return `\"${escaped}\"`\n}\n\n/**\n * Parse a raw YAML value string back to its actual value.\n * Handles double-quoted (with escapes), single-quoted, and unquoted values.\n */\nexport function yamlUnescape(raw: string): string {\n const trimmed = raw.trim()\n if (!trimmed)\n return ''\n\n // Double-quoted: single-pass escape processing to handle backslashes correctly\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n return trimmed.slice(1, -1)\n .replace(/\\\\([\\\\nrt\"])/g, (_, c) => {\n switch (c) {\n case '\\\\': return '\\\\'\n case 'n': return '\\n'\n case 'r': return '\\r'\n case 't': return '\\t'\n case '\"': return '\"'\n default: return c\n }\n })\n }\n\n // Single-quoted: no escape processing, just strip quotes\n if (trimmed.startsWith('\\'') && trimmed.endsWith('\\''))\n return trimmed.slice(1, -1)\n\n return trimmed\n}\n\n/**\n * Parse a YAML `key: value` line, correctly handling colons inside quoted values.\n * Returns [key, value] or null if not a valid KV line.\n */\nexport function yamlParseKV(line: string): [string, string] | null {\n const trimmed = line.trim()\n // Find the first `: ` or `:\\n` or `:$` — the YAML key-value separator\n const colonIdx = trimmed.indexOf(':')\n if (colonIdx === -1)\n return null\n const key = trimmed.slice(0, colonIdx).trim()\n const rawValue = trimmed.slice(colonIdx + 1)\n if (!key)\n return null\n return [key, yamlUnescape(rawValue)]\n}\n"],"mappings":";;;;;;;;
|
|
1
|
+
{"version":3,"file":"yaml.mjs","names":[],"sources":["../../src/core/yaml.ts"],"sourcesContent":["/**\n * Minimal YAML value escaping/unescaping for our hand-rolled parsers.\n *\n * Handles the characters that break naive `:` splitting and quote stripping:\n * colons, quotes, newlines, backslashes.\n */\n\n/** Characters that require double-quoting in YAML values */\nconst NEEDS_QUOTING = /[:\"'\\\\\\n\\r\\t#{}[\\],&*!|>%@`]/\n\n/**\n * Escape a value for safe YAML emission. Always double-quotes if the value\n * contains any special characters; returns unquoted for simple values.\n */\nexport function yamlEscape(value: string): string {\n if (!NEEDS_QUOTING.test(value))\n return value\n // Escape backslashes first, then double quotes, then control chars\n const escaped = value\n .replace(/\\\\/g, '\\\\\\\\')\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, '\\\\n')\n .replace(/\\r/g, '\\\\r')\n .replace(/\\t/g, '\\\\t')\n return `\"${escaped}\"`\n}\n\n/**\n * Parse a raw YAML value string back to its actual value.\n * Handles double-quoted (with escapes), single-quoted, and unquoted values.\n */\nexport function yamlUnescape(raw: string): string {\n const trimmed = raw.trim()\n if (!trimmed)\n return ''\n\n // Double-quoted: single-pass escape processing to handle backslashes correctly\n if (trimmed.startsWith('\"') && trimmed.endsWith('\"')) {\n return trimmed.slice(1, -1)\n .replace(/\\\\([\\\\nrt\"])/g, (_, c) => {\n switch (c) {\n case '\\\\': return '\\\\'\n case 'n': return '\\n'\n case 'r': return '\\r'\n case 't': return '\\t'\n case '\"': return '\"'\n default: return c\n }\n })\n }\n\n // Single-quoted: no escape processing, just strip quotes\n if (trimmed.startsWith('\\'') && trimmed.endsWith('\\''))\n return trimmed.slice(1, -1)\n\n return trimmed\n}\n\n/**\n * Parse a YAML `key: value` line, correctly handling colons inside quoted values.\n * Returns [key, value] or null if not a valid KV line.\n */\nexport function yamlParseKV(line: string): [string, string] | null {\n const trimmed = line.trim()\n // Find the first `: ` or `:\\n` or `:$` — the YAML key-value separator\n const colonIdx = trimmed.indexOf(':')\n if (colonIdx === -1)\n return null\n const key = trimmed.slice(0, colonIdx).trim()\n const rawValue = trimmed.slice(colonIdx + 1)\n if (!key)\n return null\n return [key, yamlUnescape(rawValue)]\n}\n"],"mappings":";;;;;;;;AAcA,KAAA,QAAgB,WAAW,KAAuB,IAAA,QAAA,SAAA,KAAA,CAAA,QAAA,QAAA,MAAA,GAAA,GAAA,CAAA,QAAA,kBAAA,GAAA,MAAA;AAChD,UAAK,GAAL;GASA,KAAO,KANS,QACb;;;;;;;GAaH;AACA,KAAI,QAAC,WACI,IAAA,IAAA,QAAA,SAAA,IAAA,CAAA,QAAA,QAAA,MAAA,GAAA,GAAA;AAGT,QAAI;;SAKS,YAAY,MAAA;OACjB,UAAU,KAAO,MAAA;OACjB,WAAU,QAAO,QAAA,IAAA;KACjB,aAAU,GAAO,QAAA;OACjB,MAAS,QAAO,MAAA,GAAA,SAAA,CAAA,MAAA;;KAElB,CAAA,IAAA,QAAA;AAIN,QAAI,CAAA,KAAQ,aAAW,SAAS,CAAA"}
|
package/dist/agent/index.d.mts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
|
-
//#region src/core/config.d.ts
|
|
2
1
|
interface FeaturesConfig {
|
|
3
2
|
search: boolean;
|
|
4
3
|
issues: boolean;
|
|
5
4
|
discussions: boolean;
|
|
6
5
|
releases: boolean;
|
|
7
6
|
}
|
|
8
|
-
//#endregion
|
|
9
|
-
//#region src/agent/prompts/optional/types.d.ts
|
|
10
7
|
interface SectionValidationWarning {
|
|
11
8
|
warning: string;
|
|
12
9
|
}
|
|
@@ -14,8 +11,6 @@ interface CustomPrompt {
|
|
|
14
11
|
heading: string;
|
|
15
12
|
body: string;
|
|
16
13
|
}
|
|
17
|
-
//#endregion
|
|
18
|
-
//#region src/agent/prompts/prompt.d.ts
|
|
19
14
|
type SkillSection = 'api-changes' | 'best-practices' | 'custom';
|
|
20
15
|
/** Output file per section (inside .skilld/) */
|
|
21
16
|
declare const SECTION_OUTPUT_FILES: Record<SkillSection, string>;
|
|
@@ -85,8 +80,6 @@ declare function buildAllSectionPrompts(opts: BuildSkillPromptOptions & {
|
|
|
85
80
|
* - Strips agent-specific rules
|
|
86
81
|
*/
|
|
87
82
|
declare function portabilizePrompt(prompt: string, section?: SkillSection): string;
|
|
88
|
-
//#endregion
|
|
89
|
-
//#region src/agent/prompts/skill.d.ts
|
|
90
83
|
interface SkillOptions {
|
|
91
84
|
name: string;
|
|
92
85
|
version?: string;
|
|
@@ -125,8 +118,6 @@ interface SkillOptions {
|
|
|
125
118
|
eject?: boolean;
|
|
126
119
|
}
|
|
127
120
|
declare function generateSkillMd(opts: SkillOptions): string;
|
|
128
|
-
//#endregion
|
|
129
|
-
//#region src/agent/types.d.ts
|
|
130
121
|
/**
|
|
131
122
|
* Agent types and interfaces
|
|
132
123
|
*/
|
|
@@ -138,8 +129,6 @@ interface SkillMetadata {
|
|
|
138
129
|
releasedAt?: string;
|
|
139
130
|
description?: string;
|
|
140
131
|
}
|
|
141
|
-
//#endregion
|
|
142
|
-
//#region src/agent/clis/types.d.ts
|
|
143
132
|
type OptimizeModel = 'opus' | 'sonnet' | 'haiku' | 'gemini-3.1-pro' | 'gemini-3-flash' | 'gpt-5.3-codex' | 'gpt-5.3-codex-spark' | 'gpt-5.2-codex' | `pi:${string}`;
|
|
144
133
|
interface ModelInfo {
|
|
145
134
|
id: OptimizeModel;
|
|
@@ -204,8 +193,6 @@ interface OptimizeResult {
|
|
|
204
193
|
cost?: number;
|
|
205
194
|
debugLogsDir?: string;
|
|
206
195
|
}
|
|
207
|
-
//#endregion
|
|
208
|
-
//#region src/agent/clis/index.d.ts
|
|
209
196
|
interface ToolProgressLog {
|
|
210
197
|
message: (msg: string) => void;
|
|
211
198
|
}
|
|
@@ -215,8 +202,6 @@ declare function getModelName(id: OptimizeModel): string;
|
|
|
215
202
|
declare function getModelLabel(id: OptimizeModel): string;
|
|
216
203
|
declare function getAvailableModels(): Promise<ModelInfo[]>;
|
|
217
204
|
declare function optimizeDocs(opts: OptimizeDocsOptions): Promise<OptimizeResult>;
|
|
218
|
-
//#endregion
|
|
219
|
-
//#region src/agent/detect-imports.d.ts
|
|
220
205
|
/**
|
|
221
206
|
* Detect directly-used npm packages by scanning source files
|
|
222
207
|
* Uses mlly for proper ES module parsing + tinyglobby for file discovery
|
|
@@ -235,8 +220,6 @@ interface DetectResult {
|
|
|
235
220
|
* Async with gitignore support for proper spinner animation
|
|
236
221
|
*/
|
|
237
222
|
declare function detectImportedPackages(cwd?: string): Promise<DetectResult>;
|
|
238
|
-
//#endregion
|
|
239
|
-
//#region src/agent/detect.d.ts
|
|
240
223
|
/**
|
|
241
224
|
* Detect which agents are installed on the system
|
|
242
225
|
*/
|
|
@@ -259,8 +242,6 @@ declare function detectProjectAgents(): AgentType[];
|
|
|
259
242
|
* Get the version of an agent's CLI (if available)
|
|
260
243
|
*/
|
|
261
244
|
declare function getAgentVersion(agentType: AgentType): string | null;
|
|
262
|
-
//#endregion
|
|
263
|
-
//#region src/agent/install.d.ts
|
|
264
245
|
/**
|
|
265
246
|
* Sanitize skill name for filesystem
|
|
266
247
|
*/
|
|
@@ -304,8 +285,6 @@ declare function linkSkillToAgents(skillName: string, sharedDir: string, cwd: st
|
|
|
304
285
|
* Remove per-agent symlinks for a skill when removing from shared dir.
|
|
305
286
|
*/
|
|
306
287
|
declare function unlinkSkillFromAgents(skillName: string, cwd: string, agentType?: AgentType): void;
|
|
307
|
-
//#endregion
|
|
308
|
-
//#region src/agent/targets/types.d.ts
|
|
309
288
|
interface FrontmatterField {
|
|
310
289
|
/** Field name in YAML frontmatter */
|
|
311
290
|
name: string;
|
|
@@ -360,9 +339,6 @@ interface AgentTarget {
|
|
|
360
339
|
/** Agent-specific instruction text for skill activation (written to instructionFile) */
|
|
361
340
|
skillActivationHint?: string;
|
|
362
341
|
}
|
|
363
|
-
//#endregion
|
|
364
|
-
//#region src/agent/targets/registry.d.ts
|
|
365
342
|
declare const targets: Record<AgentType, AgentTarget>;
|
|
366
|
-
//#endregion
|
|
367
343
|
export { type AgentTarget, type AgentType, type CustomPrompt, type FrontmatterField, type ModelInfo, type OptimizeDocsOptions, type OptimizeModel, type OptimizeResult, SECTION_MERGE_ORDER, SECTION_OUTPUT_FILES, type SkillMetadata, type SkillOptions, type SkillSection, type StreamProgress, targets as agents, buildAllSectionPrompts, buildSectionPrompt, computeSkillDirName, createToolProgress, detectImportedPackages, detectInstalledAgents, detectProjectAgents, detectTargetAgent, extractMarkedSections, generateSkillMd, getAgentVersion, getAvailableModels, getModelLabel, getModelName, getSectionValidator, installSkillForAgents, linkSkillToAgents, optimizeDocs, portabilizePrompt, sanitizeName, unlinkSkillFromAgents, wrapSection };
|
|
368
344
|
//# sourceMappingURL=index.d.mts.map
|