skiller 0.9.5 → 0.9.6
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/cli/handlers.js
CHANGED
|
@@ -71,6 +71,15 @@ async function executeSkillsWrapper(projectRoot, args) {
|
|
|
71
71
|
function buildClaudePluginMigrationArgs(source) {
|
|
72
72
|
return ['add', source, '--agent', 'universal', '--skill', '*', '-y'];
|
|
73
73
|
}
|
|
74
|
+
function resolveRegistryMatchSource(match) {
|
|
75
|
+
if (match.source)
|
|
76
|
+
return match.source;
|
|
77
|
+
const parts = match.slug.split('/').filter(Boolean);
|
|
78
|
+
if (parts.length >= 2) {
|
|
79
|
+
return `${parts[0]}/${parts[1]}`;
|
|
80
|
+
}
|
|
81
|
+
return match.slug;
|
|
82
|
+
}
|
|
74
83
|
function formatInstalls(count) {
|
|
75
84
|
if (!count || count <= 0)
|
|
76
85
|
return '0 installs';
|
|
@@ -168,6 +177,34 @@ async function cleanupLegacyClaudePluginState(projectRoot, pluginIds) {
|
|
|
168
177
|
await fs.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + '\n');
|
|
169
178
|
}
|
|
170
179
|
}
|
|
180
|
+
async function cleanupMigratedPluginAuxiliaryRules(projectRoot, sources) {
|
|
181
|
+
const candidateRuleNames = await (0, ClaudePluginMigration_1.listClaudePluginAuxiliaryRuleNames)(sources);
|
|
182
|
+
if (candidateRuleNames.length === 0)
|
|
183
|
+
return [];
|
|
184
|
+
const sourceSet = new Set(sources);
|
|
185
|
+
const plan = await (0, RulesToSkillsMigration_1.planRulesToSkillsMigration)(projectRoot, candidateRuleNames);
|
|
186
|
+
const removable = new Set(plan.unmatched);
|
|
187
|
+
for (const candidate of plan.candidates) {
|
|
188
|
+
const exactMatchSources = candidate.matches.map(resolveRegistryMatchSource);
|
|
189
|
+
if (exactMatchSources.length === 0 ||
|
|
190
|
+
exactMatchSources.every((source) => sourceSet.has(source))) {
|
|
191
|
+
removable.add(candidate.ruleName);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
const removed = [...removable].sort((a, b) => a.localeCompare(b));
|
|
195
|
+
for (const ruleName of removed) {
|
|
196
|
+
await (0, RulesToSkillsMigration_1.removeLocalRuleReplacementState)(projectRoot, ruleName, false);
|
|
197
|
+
await fs.rm(path.join(projectRoot, '.agents', 'skills', ruleName), {
|
|
198
|
+
force: true,
|
|
199
|
+
recursive: true,
|
|
200
|
+
});
|
|
201
|
+
await fs.rm(path.join(projectRoot, '.claude', 'skills', ruleName), {
|
|
202
|
+
force: true,
|
|
203
|
+
recursive: true,
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
return removed;
|
|
207
|
+
}
|
|
171
208
|
async function promptLine(message) {
|
|
172
209
|
const rl = readline.createInterface({
|
|
173
210
|
input: process.stdin,
|
|
@@ -415,6 +452,10 @@ async function migrateClaudePluginsHandler(argv) {
|
|
|
415
452
|
...plan.installs.flatMap((install) => install.pluginIds),
|
|
416
453
|
...plan.unresolved.map((entry) => entry.pluginId),
|
|
417
454
|
]);
|
|
455
|
+
const removedAuxiliaryRules = await cleanupMigratedPluginAuxiliaryRules(projectRoot, plan.installs.map((install) => install.source));
|
|
456
|
+
if (removedAuxiliaryRules.length > 0) {
|
|
457
|
+
console.log(`[skiller] Removed stale plugin-derived local rules:\n${removedAuxiliaryRules.map((name) => `- ${name}`).join('\n')}`);
|
|
458
|
+
}
|
|
418
459
|
if (plan.unresolved.length > 0) {
|
|
419
460
|
console.log(`[skiller] Skipped unresolved plugins:\n${plan.unresolved.map((entry) => `- ${entry.pluginId}: ${entry.reason}`).join('\n')}`);
|
|
420
461
|
}
|
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.listClaudePluginAuxiliaryRuleNames = listClaudePluginAuxiliaryRuleNames;
|
|
36
37
|
exports.planClaudePluginSkillsMigration = planClaudePluginSkillsMigration;
|
|
37
38
|
const fs = __importStar(require("fs/promises"));
|
|
38
39
|
const os = __importStar(require("os"));
|
|
@@ -86,6 +87,20 @@ function normalizeCloneSource(source) {
|
|
|
86
87
|
}
|
|
87
88
|
return source;
|
|
88
89
|
}
|
|
90
|
+
function normalizeSkillNameForDir(value) {
|
|
91
|
+
return value.replace(/:/g, '-').trim();
|
|
92
|
+
}
|
|
93
|
+
function extractAuxiliarySkillNames(skillMd) {
|
|
94
|
+
const names = new Set();
|
|
95
|
+
const pattern = /\b[a-z0-9-]+:[a-z0-9-]+:([a-z0-9-]+)\b/g;
|
|
96
|
+
for (const match of skillMd.toLowerCase().matchAll(pattern)) {
|
|
97
|
+
const candidate = match[1]?.trim();
|
|
98
|
+
if (!candidate || !/[a-z]/.test(candidate))
|
|
99
|
+
continue;
|
|
100
|
+
names.add(candidate);
|
|
101
|
+
}
|
|
102
|
+
return [...names];
|
|
103
|
+
}
|
|
89
104
|
function formatInspectionError(source, err) {
|
|
90
105
|
if (typeof err === 'object' && err !== null) {
|
|
91
106
|
const stderr = 'stderr' in err ? err.stderr : '';
|
|
@@ -112,18 +127,30 @@ async function inspectSkillsInstallSource(source) {
|
|
|
112
127
|
repoDir,
|
|
113
128
|
]);
|
|
114
129
|
const { skills } = await (0, SkillsUtils_1.walkSkillsTree)(repoDir);
|
|
130
|
+
const publishedSkillNames = new Set();
|
|
131
|
+
const auxiliarySkillNames = new Set();
|
|
115
132
|
for (const skill of skills) {
|
|
116
133
|
try {
|
|
117
134
|
const skillMd = await fs.readFile(path.join(skill.path, 'SKILL.md'), 'utf8');
|
|
118
135
|
const { frontmatter } = (0, FrontmatterParser_1.parseFrontmatter)(skillMd);
|
|
119
136
|
if (frontmatter?.name && frontmatter.description) {
|
|
120
|
-
|
|
137
|
+
publishedSkillNames.add(normalizeSkillNameForDir(String(frontmatter.name)));
|
|
138
|
+
for (const auxiliaryName of extractAuxiliarySkillNames(skillMd)) {
|
|
139
|
+
auxiliarySkillNames.add(auxiliaryName);
|
|
140
|
+
}
|
|
121
141
|
}
|
|
122
142
|
}
|
|
123
143
|
catch {
|
|
124
144
|
// Keep scanning. One malformed skill should not hide valid siblings.
|
|
125
145
|
}
|
|
126
146
|
}
|
|
147
|
+
if (publishedSkillNames.size > 0) {
|
|
148
|
+
return {
|
|
149
|
+
installable: true,
|
|
150
|
+
auxiliarySkillNames: [...auxiliarySkillNames].sort((a, b) => a.localeCompare(b)),
|
|
151
|
+
publishedSkillNames: [...publishedSkillNames].sort((a, b) => a.localeCompare(b)),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
127
154
|
return {
|
|
128
155
|
installable: false,
|
|
129
156
|
reason: `Resolved source ${source} has no valid SKILL.md files with name and description`,
|
|
@@ -139,6 +166,23 @@ async function inspectSkillsInstallSource(source) {
|
|
|
139
166
|
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
140
167
|
}
|
|
141
168
|
}
|
|
169
|
+
async function listClaudePluginAuxiliaryRuleNames(sources, options = {}) {
|
|
170
|
+
const inspectSource = options.inspectSource ?? inspectSkillsInstallSource;
|
|
171
|
+
const auxiliarySkillNames = new Set();
|
|
172
|
+
for (const source of [...new Set(sources)].sort((a, b) => a.localeCompare(b))) {
|
|
173
|
+
const inspection = await inspectSource(source);
|
|
174
|
+
if (!inspection.installable)
|
|
175
|
+
continue;
|
|
176
|
+
const published = new Set((inspection.publishedSkillNames ?? []).map(normalizeSkillNameForDir));
|
|
177
|
+
for (const auxiliaryName of inspection.auxiliarySkillNames ?? []) {
|
|
178
|
+
const normalized = normalizeSkillNameForDir(auxiliaryName);
|
|
179
|
+
if (!normalized || published.has(normalized))
|
|
180
|
+
continue;
|
|
181
|
+
auxiliarySkillNames.add(normalized);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return [...auxiliarySkillNames].sort((a, b) => a.localeCompare(b));
|
|
185
|
+
}
|
|
142
186
|
async function readEnabledPluginIds(projectRoot) {
|
|
143
187
|
const settingsPath = path.join(projectRoot, project_paths_1.LEGACY_SKILLER_DIR, 'settings.json');
|
|
144
188
|
const raw = await readJsonFile(settingsPath);
|