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.
- package/dist/cli.js +23 -24
- 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.
|
|
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('
|
|
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('
|
|
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
|
|
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
|
-
//
|
|
536
|
-
const
|
|
537
|
-
|
|
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(`${
|
|
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',
|
|
692
|
-
hmac.update(
|
|
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('
|
|
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) => {
|