skillvault 0.7.3 → 0.7.5

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 +23 -24
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -20,7 +20,7 @@
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.7.3';
23
+ const VERSION = '0.7.5';
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');
@@ -108,16 +108,17 @@ async function setup(code) {
108
108
  const err = await response.json().catch(() => ({ message: response.statusText }));
109
109
  console.error(` ❌ Failed: ${err.message}`);
110
110
  console.error('');
111
- if (err.message.includes('404') || err.message.includes('not found')) {
111
+ if (response.status === 404 || err.message.toLowerCase().includes('not found') || err.message.toLowerCase().includes('invalid')) {
112
112
  console.error(' The invite code was not found. Check that you entered it correctly.');
113
- console.error(' Invite codes are 8 characters (e.g. A1B2C3D4).');
113
+ console.error(' Invite codes are 8 characters, letters and numbers (e.g. A1B2C3D4).');
114
+ console.error(' Ask the skill publisher if you need a new code.');
114
115
  }
115
- else if (err.message.includes('400') || err.message.includes('expired')) {
116
+ else if (response.status === 400 || err.message.toLowerCase().includes('expired') || err.message.toLowerCase().includes('redeemed')) {
116
117
  console.error(' This invite code has already been used or has expired.');
117
118
  console.error(' Ask the publisher for a new invite code.');
118
119
  }
119
120
  else {
120
- console.error(' Could not reach the SkillVault server. Check your internet connection.');
121
+ console.error(' Could not reach the SkillVault server or an unexpected error occurred.');
121
122
  console.error(` Server: ${API_URL}`);
122
123
  }
123
124
  process.exit(1);
@@ -506,7 +507,7 @@ async function installSkillStubs() {
506
507
  let frontmatter = '';
507
508
  let frontmatterFields = {};
508
509
  try {
509
- const { cek } = await fetchCEK(skillName, pub.token);
510
+ const { cek } = await fetchCEK(skillName, pub.token, config.api_url || API_URL);
510
511
  const vaultData = readFileSync(vaultPath);
511
512
  const vault = decryptVault(vaultData, cek);
512
513
  cek.fill(0);
@@ -532,17 +533,9 @@ async function installSkillStubs() {
532
533
  // Build frontmatter for stub — copy all fields except body-related ones
533
534
  let stubFrontmatter = `name: ${stubName}\n`;
534
535
  stubFrontmatter += `description: "${stubDescription.replace(/"/g, '\\"')}"\n`;
535
- // Preserve publisher's allowed-tools, trigger config, etc. but always include our load tool
536
- const publisherAllowedTools = frontmatterFields['allowed-tools'] || '';
537
- const loadTool = `"Bash(npx skillvault@${VERSION} --load *)"`;
538
- if (publisherAllowedTools && !publisherAllowedTools.includes('skillvault')) {
539
- // Merge publisher's allowed-tools with ours
540
- const merged = publisherAllowedTools.replace(/\]$/, `, ${loadTool}]`);
541
- stubFrontmatter += `allowed-tools: ${merged}\n`;
542
- }
543
- else {
544
- stubFrontmatter += `allowed-tools: [${loadTool}]\n`;
545
- }
536
+ // Only allow our specific load tool do NOT merge publisher-specified allowed-tools
537
+ const loadTool = `"Bash(npx skillvault@${VERSION} --load ${skillName})"`;
538
+ stubFrontmatter += `allowed-tools: [${loadTool}]\n`;
546
539
  // Copy through other frontmatter fields the publisher set (for Claude triggering)
547
540
  for (const [key, value] of Object.entries(frontmatterFields)) {
548
541
  if (!['name', 'description', 'allowed-tools'].includes(key)) {
@@ -632,10 +625,10 @@ function resolveSkillPublisher(skillName, config) {
632
625
  }
633
626
  return null;
634
627
  }
635
- async function fetchCEK(skillName, publisherToken) {
628
+ async function fetchCEK(skillName, publisherToken, apiUrl) {
636
629
  const kp = generateKeyPairSync('x25519');
637
630
  const pub = kp.publicKey.export({ type: 'spki', format: 'der' }).toString('base64');
638
- const res = await fetch(`${API_URL}/v1/skills/${skillName}/cek`, {
631
+ const res = await fetch(`${apiUrl}/v1/skills/${skillName}/cek`, {
639
632
  method: 'POST',
640
633
  headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${publisherToken}` },
641
634
  body: JSON.stringify({ companion_public_key: pub }),
@@ -688,8 +681,8 @@ function watermarkLayer2(content, id) {
688
681
  }
689
682
  /** Layer 3: Structural fingerprint — HMAC comment tag in code blocks */
690
683
  function watermarkLayer3(content, id) {
691
- const hmac = createHmac('sha256', 'skillvault-structural-v1');
692
- hmac.update(id);
684
+ const hmac = createHmac('sha256', id);
685
+ hmac.update('skillvault-structural-v1');
693
686
  const tag = `// sv:${hmac.digest('hex').slice(0, 12)}`;
694
687
  const lines = content.split('\n');
695
688
  const result = [];
@@ -903,7 +896,7 @@ async function loadSkill(skillName) {
903
896
  let cek;
904
897
  let licenseeId;
905
898
  try {
906
- const cekResult = await fetchCEK(skillName, resolved.publisher.token);
899
+ const cekResult = await fetchCEK(skillName, resolved.publisher.token, config.api_url || API_URL);
907
900
  cek = cekResult.cek;
908
901
  // Use server-provided watermark ID (includes grant ID, customer ID, timestamp)
909
902
  // Falls back to local composite if server didn't provide one
@@ -1015,15 +1008,21 @@ async function main() {
1015
1008
  process.exit(0);
1016
1009
  }
1017
1010
  // Default: show help
1018
- console.log(`🔐 SkillVault v${VERSION}\n`);
1011
+ console.log(`🔐 SkillVault v${VERSION} — Encrypted skill distribution for Claude Code\n`);
1019
1012
  const config = loadConfig();
1020
1013
  if (config) {
1021
1014
  console.log(` ${config.publishers.length} publisher${config.publishers.length !== 1 ? 's' : ''} configured`);
1022
1015
  console.log(' Run --status for details, --sync to update skills\n');
1023
1016
  }
1024
1017
  else {
1025
- console.log(' Not set up yet. Run:');
1018
+ console.log(' SkillVault delivers encrypted AI skills to your Claude Code agent.');
1019
+ console.log(' Skills are published by providers and installed via invite codes.\n');
1020
+ console.log(' To get started, you need an invite code from a skill publisher.');
1021
+ console.log(' Once you have one, run:\n');
1026
1022
  console.log(' npx skillvault --invite YOUR_CODE\n');
1023
+ console.log(' This will download your skills and install them into Claude Code.');
1024
+ console.log(' After setup, restart Claude Code and your skills will be available.\n');
1025
+ console.log(' Learn more: https://app.getskillvault.com\n');
1027
1026
  }
1028
1027
  }
1029
1028
  main().catch((err) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skillvault",
3
- "version": "0.7.3",
3
+ "version": "0.7.5",
4
4
  "description": "SkillVault — secure skill distribution for Claude Code",
5
5
  "type": "module",
6
6
  "bin": {