skiller 0.8.2 → 0.9.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.
@@ -37,10 +37,13 @@ exports.SKILLS_MANIFEST_VERSION = exports.LEGACY_CLAUDE_MANIFEST_FILENAME = expo
37
37
  exports.isPluginManifestEntry = isPluginManifestEntry;
38
38
  exports.isClaudeManifestEntry = isClaudeManifestEntry;
39
39
  exports.loadSkillsManifestEntries = loadSkillsManifestEntries;
40
+ exports.loadLocalSkillNames = loadLocalSkillNames;
41
+ exports.writeLocalSkillNames = writeLocalSkillNames;
40
42
  exports.writeSkillsManifestEntries = writeSkillsManifestEntries;
41
43
  exports.listSkillDirectories = listSkillDirectories;
42
44
  const fs = __importStar(require("fs/promises"));
43
45
  const path = __importStar(require("path"));
46
+ const project_paths_1 = require("./project-paths");
44
47
  // Project-level manifest (stored in `.claude/.skiller.json`) that tracks what
45
48
  // Skiller installed into each target agent skills directory for this project.
46
49
  exports.SKILLS_MANIFEST_FILENAME = '.skiller.json';
@@ -154,6 +157,24 @@ function computeTargetKey(projectRoot, targetSkillsDir) {
154
157
  }
155
158
  return normalizePathForKey(resolvedTarget);
156
159
  }
160
+ function computeCompatibleTargetKeys(projectRoot, targetSkillsDir) {
161
+ const keys = new Set([
162
+ computeTargetKey(projectRoot, targetSkillsDir),
163
+ normalizePathForKey(targetSkillsDir),
164
+ ]);
165
+ const resolvedTarget = path.resolve(targetSkillsDir);
166
+ const canonicalSkillsDir = path.resolve(projectRoot, project_paths_1.CANONICAL_SKILLER_DIR, 'skills');
167
+ const legacySkillsDir = path.resolve(projectRoot, project_paths_1.LEGACY_SKILLER_DIR, 'skills');
168
+ if (resolvedTarget === canonicalSkillsDir ||
169
+ resolvedTarget === legacySkillsDir) {
170
+ const aliasTarget = resolvedTarget === canonicalSkillsDir
171
+ ? legacySkillsDir
172
+ : canonicalSkillsDir;
173
+ keys.add(computeTargetKey(projectRoot, aliasTarget));
174
+ keys.add(normalizePathForKey(aliasTarget));
175
+ }
176
+ return [...keys];
177
+ }
157
178
  function parseProjectTargets(raw) {
158
179
  if (!raw || typeof raw !== 'object')
159
180
  return {};
@@ -170,6 +191,31 @@ function parseProjectTargets(raw) {
170
191
  }
171
192
  return out;
172
193
  }
194
+ function parseLocalSkills(raw) {
195
+ if (!raw || typeof raw !== 'object')
196
+ return [];
197
+ const obj = raw;
198
+ if (!Array.isArray(obj.localSkills))
199
+ return [];
200
+ return [
201
+ ...new Set(obj.localSkills.filter((v) => typeof v === 'string')),
202
+ ].sort((a, b) => a.localeCompare(b));
203
+ }
204
+ async function readProjectManifestRaw(projectRoot) {
205
+ const canonicalManifestPath = path.join(projectRoot, project_paths_1.CANONICAL_SKILLER_DIR, exports.SKILLS_MANIFEST_FILENAME);
206
+ const legacyManifestPath = path.join(projectRoot, project_paths_1.LEGACY_SKILLER_DIR, exports.SKILLS_MANIFEST_FILENAME);
207
+ for (const manifestPath of [canonicalManifestPath, legacyManifestPath]) {
208
+ if (!(await fileExists(manifestPath)))
209
+ continue;
210
+ try {
211
+ return JSON.parse(await fs.readFile(manifestPath, 'utf8'));
212
+ }
213
+ catch {
214
+ return null;
215
+ }
216
+ }
217
+ return null;
218
+ }
173
219
  function parseLegacyPluginEntries(raw) {
174
220
  if (!raw || typeof raw !== 'object')
175
221
  return [];
@@ -277,40 +323,49 @@ async function loadLegacyTargetSkillsManifestEntries(targetSkillsDir) {
277
323
  return normalizeEntries(merged);
278
324
  }
279
325
  async function loadSkillsManifestEntries(projectRoot, targetSkillsDir) {
280
- const projectClaudeDir = path.join(projectRoot, '.claude');
281
- const projectManifestPath = path.join(projectClaudeDir, exports.SKILLS_MANIFEST_FILENAME);
282
- const preferredTargetKey = computeTargetKey(projectRoot, targetSkillsDir);
283
- const absoluteTargetKey = normalizePathForKey(targetSkillsDir);
284
- if (await fileExists(projectManifestPath)) {
285
- try {
286
- const raw = JSON.parse(await fs.readFile(projectManifestPath, 'utf8'));
287
- const targets = parseProjectTargets(raw);
288
- const entries = targets[preferredTargetKey] ?? targets[absoluteTargetKey] ?? [];
289
- return normalizeEntries(entries);
290
- }
291
- catch {
292
- return [];
326
+ const raw = await readProjectManifestRaw(projectRoot);
327
+ if (raw) {
328
+ const targets = parseProjectTargets(raw);
329
+ for (const key of computeCompatibleTargetKeys(projectRoot, targetSkillsDir)) {
330
+ const entries = targets[key];
331
+ if (entries)
332
+ return normalizeEntries(entries);
293
333
  }
334
+ return [];
294
335
  }
295
336
  // Legacy migration: prior versions stored manifests in the target skills dir.
296
337
  return await loadLegacyTargetSkillsManifestEntries(targetSkillsDir);
297
338
  }
339
+ async function loadLocalSkillNames(projectRoot) {
340
+ const raw = await readProjectManifestRaw(projectRoot);
341
+ return parseLocalSkills(raw);
342
+ }
343
+ async function writeLocalSkillNames(projectRoot, localSkillNames, dryRun) {
344
+ const projectSkillerDir = path.join(projectRoot, project_paths_1.CANONICAL_SKILLER_DIR);
345
+ const projectManifestPath = path.join(projectSkillerDir, exports.SKILLS_MANIFEST_FILENAME);
346
+ const raw = await readProjectManifestRaw(projectRoot);
347
+ const existingTargets = parseProjectTargets(raw);
348
+ const nextLocalSkills = [...new Set(localSkillNames)].sort((a, b) => a.localeCompare(b));
349
+ if (dryRun)
350
+ return;
351
+ await fs.mkdir(projectSkillerDir, { recursive: true });
352
+ const manifest = {
353
+ version: exports.SKILLS_MANIFEST_VERSION,
354
+ targets: existingTargets,
355
+ localSkills: nextLocalSkills,
356
+ };
357
+ await fs.writeFile(projectManifestPath, JSON.stringify(manifest, null, 2) + '\n');
358
+ }
298
359
  async function writeSkillsManifestEntries(projectRoot, targetSkillsDir, entries, dryRun) {
299
360
  const normalized = normalizeEntries(entries);
300
- const projectClaudeDir = path.join(projectRoot, '.claude');
361
+ const projectClaudeDir = path.join(projectRoot, project_paths_1.CANONICAL_SKILLER_DIR);
301
362
  const projectManifestPath = path.join(projectClaudeDir, exports.SKILLS_MANIFEST_FILENAME);
302
363
  const preferredTargetKey = computeTargetKey(projectRoot, targetSkillsDir);
303
364
  const absoluteTargetKey = normalizePathForKey(targetSkillsDir);
304
365
  let existingTargets = {};
305
- if (await fileExists(projectManifestPath)) {
306
- try {
307
- const raw = JSON.parse(await fs.readFile(projectManifestPath, 'utf8'));
308
- existingTargets = parseProjectTargets(raw);
309
- }
310
- catch {
311
- existingTargets = {};
312
- }
313
- }
366
+ const raw = await readProjectManifestRaw(projectRoot);
367
+ existingTargets = parseProjectTargets(raw);
368
+ const existingLocalSkills = parseLocalSkills(raw);
314
369
  if (normalized.length === 0) {
315
370
  delete existingTargets[preferredTargetKey];
316
371
  if (preferredTargetKey !== absoluteTargetKey) {
@@ -338,6 +393,7 @@ async function writeSkillsManifestEntries(projectRoot, targetSkillsDir, entries,
338
393
  const manifest = {
339
394
  version: exports.SKILLS_MANIFEST_VERSION,
340
395
  targets: nextTargets,
396
+ localSkills: existingLocalSkills,
341
397
  };
342
398
  await fs.writeFile(projectManifestPath, JSON.stringify(manifest, null, 2) + '\n');
343
399
  }