skillvault 0.8.0 → 0.8.1

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.
Files changed (2) hide show
  1. package/dist/cli.js +86 -13
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -20,12 +20,31 @@
20
20
  import { existsSync, readFileSync, writeFileSync, mkdirSync, readdirSync, rmSync } from 'node:fs';
21
21
  import { join } from 'node:path';
22
22
  import { createDecipheriv, createHmac, createPublicKey, diffieHellman, hkdfSync, generateKeyPairSync, } from 'node:crypto';
23
- const VERSION = '0.8.0';
23
+ const VERSION = '0.8.1';
24
24
  const HOME = process.env.HOME || process.env.USERPROFILE || '~';
25
25
  const API_URL = process.env.SKILLVAULT_API_URL || 'https://api.getskillvault.com';
26
26
  const CONFIG_DIR = join(HOME, '.skillvault');
27
27
  const CONFIG_PATH = join(CONFIG_DIR, 'agent-config.json');
28
28
  const VAULT_DIR = join(CONFIG_DIR, 'vaults');
29
+ const AGENTS_SKILLS_DIR = join(HOME, '.agents', 'skills'); // agent-agnostic source of truth
30
+ const AGENTS_LOCK_PATH = join(HOME, '.agents', '.skill-lock.json');
31
+ /** Detect which AI agent platforms are installed and return their skill directories */
32
+ function detectAgentPlatforms() {
33
+ const platforms = [];
34
+ const checks = [
35
+ { name: 'Claude Code', dir: join(HOME, '.claude', 'skills'), marker: join(HOME, '.claude') },
36
+ { name: 'Cursor', dir: join(HOME, '.cursor', 'skills'), marker: join(HOME, '.cursor') },
37
+ { name: 'Windsurf', dir: join(HOME, '.windsurf', 'skills'), marker: join(HOME, '.windsurf') },
38
+ { name: 'Codex', dir: join(HOME, '.codex', 'skills'), marker: join(HOME, '.codex') },
39
+ ];
40
+ for (const check of checks) {
41
+ if (existsSync(check.marker)) {
42
+ platforms.push({ name: check.name, dir: check.dir });
43
+ }
44
+ }
45
+ return platforms;
46
+ }
47
+ // Legacy: SKILLS_DIR points to Claude for backward compat in other functions
29
48
  const SKILLS_DIR = join(HOME, '.claude', 'skills');
30
49
  // ── CLI Argument Parsing ──
31
50
  const args = process.argv.slice(2);
@@ -395,14 +414,23 @@ async function syncSkills() {
395
414
  const localSkillName = vaultFile.replace(/\.vault$/, '');
396
415
  if (!remoteSkillNames.has(localSkillName)) {
397
416
  console.error(`[sync] Grant revoked: "${localSkillName}" from ${pub.name}`);
398
- const skillDir = join(SKILLS_DIR, localSkillName);
417
+ // Remove from agent-agnostic dir
418
+ const agentDir = join(AGENTS_SKILLS_DIR, localSkillName);
399
419
  try {
400
- if (existsSync(skillDir) && existsSync(join(skillDir, 'manifest.json'))) {
401
- rmSync(skillDir, { recursive: true, force: true });
402
- console.error(`[sync] Removed: ~/.claude/skills/${localSkillName}/`);
403
- }
420
+ if (existsSync(agentDir))
421
+ rmSync(agentDir, { recursive: true, force: true });
404
422
  }
405
423
  catch { }
424
+ // Remove from all detected agent platforms
425
+ for (const platform of detectAgentPlatforms()) {
426
+ const platformDir = join(platform.dir, localSkillName);
427
+ try {
428
+ if (existsSync(platformDir))
429
+ rmSync(platformDir, { recursive: true, force: true });
430
+ }
431
+ catch { }
432
+ }
433
+ console.error(`[sync] Removed "${localSkillName}" from all agent platforms`);
406
434
  }
407
435
  }
408
436
  }
@@ -472,7 +500,19 @@ async function installSkillStubs() {
472
500
  let installed = 0;
473
501
  let skipped = 0;
474
502
  const errors = [];
475
- mkdirSync(SKILLS_DIR, { recursive: true });
503
+ mkdirSync(AGENTS_SKILLS_DIR, { recursive: true });
504
+ const detectedPlatforms = detectAgentPlatforms();
505
+ for (const platform of detectedPlatforms) {
506
+ mkdirSync(platform.dir, { recursive: true });
507
+ }
508
+ // Load existing lock file
509
+ let lockData = { version: 3, skills: {} };
510
+ try {
511
+ if (existsSync(AGENTS_LOCK_PATH)) {
512
+ lockData = JSON.parse(readFileSync(AGENTS_LOCK_PATH, 'utf8'));
513
+ }
514
+ }
515
+ catch { }
476
516
  for (const pub of config.publishers) {
477
517
  const pubVaultDir = join(VAULT_DIR, pub.id);
478
518
  if (!existsSync(pubVaultDir))
@@ -481,7 +521,8 @@ async function installSkillStubs() {
481
521
  for (const vaultFile of vaultFiles) {
482
522
  const skillName = vaultFile.replace(/\.vault$/, '');
483
523
  const vaultPath = join(pubVaultDir, vaultFile);
484
- const skillDir = join(SKILLS_DIR, skillName);
524
+ const agentSkillDir = join(AGENTS_SKILLS_DIR, skillName);
525
+ const skillDir = agentSkillDir;
485
526
  const manifestPath = join(skillDir, 'manifest.json');
486
527
  const hashPath = vaultPath + '.hash';
487
528
  if (existsSync(manifestPath) && existsSync(hashPath)) {
@@ -542,7 +583,6 @@ async function installSkillStubs() {
542
583
  stubFrontmatter += `${key}: ${value}\n`;
543
584
  }
544
585
  }
545
- mkdirSync(skillDir, { recursive: true });
546
586
  const stub = `---
547
587
  ${stubFrontmatter.trimEnd()}
548
588
  ---
@@ -561,9 +601,8 @@ The command decrypts the skill on demand (license is validated each time) and ou
561
601
 
562
602
  If the command fails with a license error, tell the user their SkillVault license may have expired and to contact their skill provider.
563
603
  `;
564
- writeFileSync(join(skillDir, 'SKILL.md'), stub, { mode: 0o600 });
565
604
  const vaultHash = existsSync(hashPath) ? readFileSync(hashPath, 'utf8').trim() : '';
566
- writeFileSync(manifestPath, JSON.stringify({
605
+ const manifestData = JSON.stringify({
567
606
  publisher: meta.publisher_name || pub.name,
568
607
  publisher_id: pub.id,
569
608
  skill_name: skillName,
@@ -572,11 +611,45 @@ If the command fails with a license error, tell the user their SkillVault licens
572
611
  vault_hash: vaultHash,
573
612
  installed_at: new Date().toISOString(),
574
613
  encrypted: true,
575
- }, null, 2), { mode: 0o600 });
614
+ }, null, 2);
615
+ // Write to ~/.agents/skills/ (agent-agnostic source of truth)
616
+ mkdirSync(agentSkillDir, { recursive: true });
617
+ writeFileSync(join(agentSkillDir, 'SKILL.md'), stub, { mode: 0o600 });
618
+ writeFileSync(join(agentSkillDir, 'manifest.json'), manifestData, { mode: 0o600 });
619
+ // Copy to each detected agent platform's skill directory
620
+ for (const platform of detectedPlatforms) {
621
+ const platformSkillDir = join(platform.dir, skillName);
622
+ try {
623
+ mkdirSync(platformSkillDir, { recursive: true });
624
+ writeFileSync(join(platformSkillDir, 'SKILL.md'), stub, { mode: 0o600 });
625
+ writeFileSync(join(platformSkillDir, 'manifest.json'), manifestData, { mode: 0o600 });
626
+ }
627
+ catch { }
628
+ }
629
+ // Update lock file
630
+ lockData.skills[skillName] = {
631
+ source: `skillvault/${pub.id}`,
632
+ sourceType: 'skillvault',
633
+ publisher: meta.publisher_name || pub.name,
634
+ publisherId: pub.id,
635
+ capabilityName: meta.capability_name || `skill/${skillName}`,
636
+ skillPath: `skills/${skillName}/SKILL.md`,
637
+ skillFolderHash: vaultHash,
638
+ installedAt: new Date().toISOString(),
639
+ updatedAt: new Date().toISOString(),
640
+ encrypted: true,
641
+ };
576
642
  installed++;
577
- console.error(`[install] "${skillName}" ~/.claude/skills/${skillName}/`);
643
+ const platformNames = detectedPlatforms.map(p => p.name).join(', ') || 'none detected';
644
+ console.error(`[install] "${skillName}" → ~/.agents/skills/ + ${platformNames}`);
578
645
  }
579
646
  }
647
+ // Persist lock file
648
+ try {
649
+ mkdirSync(join(HOME, '.agents'), { recursive: true });
650
+ writeFileSync(AGENTS_LOCK_PATH, JSON.stringify(lockData, null, 2), { mode: 0o600 });
651
+ }
652
+ catch { }
580
653
  return { installed, skipped, errors };
581
654
  }
582
655
  // ── Vault Decryption (in-memory only, output to stdout) ──
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillvault",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "SkillVault — secure skill distribution for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {