skillvault-publisher 0.1.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.
Files changed (65) hide show
  1. package/dist/commands/decrypt.d.ts +3 -0
  2. package/dist/commands/decrypt.d.ts.map +1 -0
  3. package/dist/commands/decrypt.js +152 -0
  4. package/dist/commands/decrypt.js.map +1 -0
  5. package/dist/commands/info.d.ts +3 -0
  6. package/dist/commands/info.d.ts.map +1 -0
  7. package/dist/commands/info.js +30 -0
  8. package/dist/commands/info.js.map +1 -0
  9. package/dist/commands/init.d.ts +3 -0
  10. package/dist/commands/init.d.ts.map +1 -0
  11. package/dist/commands/init.js +83 -0
  12. package/dist/commands/init.js.map +1 -0
  13. package/dist/commands/install.d.ts +3 -0
  14. package/dist/commands/install.d.ts.map +1 -0
  15. package/dist/commands/install.js +149 -0
  16. package/dist/commands/install.js.map +1 -0
  17. package/dist/commands/licenses.d.ts +3 -0
  18. package/dist/commands/licenses.d.ts.map +1 -0
  19. package/dist/commands/licenses.js +96 -0
  20. package/dist/commands/licenses.js.map +1 -0
  21. package/dist/commands/login.d.ts +3 -0
  22. package/dist/commands/login.d.ts.map +1 -0
  23. package/dist/commands/login.js +89 -0
  24. package/dist/commands/login.js.map +1 -0
  25. package/dist/commands/logout.d.ts +3 -0
  26. package/dist/commands/logout.d.ts.map +1 -0
  27. package/dist/commands/logout.js +11 -0
  28. package/dist/commands/logout.js.map +1 -0
  29. package/dist/commands/publish.d.ts +3 -0
  30. package/dist/commands/publish.d.ts.map +1 -0
  31. package/dist/commands/publish.js +215 -0
  32. package/dist/commands/publish.js.map +1 -0
  33. package/dist/commands/report.d.ts +3 -0
  34. package/dist/commands/report.d.ts.map +1 -0
  35. package/dist/commands/report.js +72 -0
  36. package/dist/commands/report.js.map +1 -0
  37. package/dist/commands/search.d.ts +3 -0
  38. package/dist/commands/search.d.ts.map +1 -0
  39. package/dist/commands/search.js +79 -0
  40. package/dist/commands/search.js.map +1 -0
  41. package/dist/commands/update.d.ts +3 -0
  42. package/dist/commands/update.d.ts.map +1 -0
  43. package/dist/commands/update.js +152 -0
  44. package/dist/commands/update.js.map +1 -0
  45. package/dist/commands/whoami.d.ts +3 -0
  46. package/dist/commands/whoami.d.ts.map +1 -0
  47. package/dist/commands/whoami.js +128 -0
  48. package/dist/commands/whoami.js.map +1 -0
  49. package/dist/credentials.d.ts +32 -0
  50. package/dist/credentials.d.ts.map +1 -0
  51. package/dist/credentials.js +106 -0
  52. package/dist/credentials.js.map +1 -0
  53. package/dist/fingerprint.d.ts +18 -0
  54. package/dist/fingerprint.d.ts.map +1 -0
  55. package/dist/fingerprint.js +51 -0
  56. package/dist/fingerprint.js.map +1 -0
  57. package/dist/grant-cache.d.ts +40 -0
  58. package/dist/grant-cache.d.ts.map +1 -0
  59. package/dist/grant-cache.js +112 -0
  60. package/dist/grant-cache.js.map +1 -0
  61. package/dist/index.d.ts +3 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +33 -0
  64. package/dist/index.js.map +1 -0
  65. package/package.json +35 -0
@@ -0,0 +1,152 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import * as jose from 'jose';
4
+ import { readdirSync, readFileSync, writeFileSync, existsSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { homedir } from 'node:os';
7
+ import { getConfig, getKeypair } from '../credentials.js';
8
+ const SKILLS_DIR = join(homedir(), '.claude', 'skills');
9
+ export const updateCommand = new Command('update')
10
+ .description('Update installed skills to latest versions')
11
+ .argument('[skill]', 'Specific skill to update (or all if omitted)')
12
+ .action(async (skill) => {
13
+ try {
14
+ const config = getConfig();
15
+ if (!config) {
16
+ process.stderr.write(chalk.red('Not logged in. Run `skillvault login` first.\n'));
17
+ process.exit(1);
18
+ }
19
+ const keypair = getKeypair();
20
+ if (!keypair) {
21
+ process.stderr.write(chalk.red('Credentials not found. Run `skillvault login` first.\n'));
22
+ process.exit(1);
23
+ }
24
+ // Sign host JWT
25
+ const hostPrivJWK = keypair.privateKey.host;
26
+ const hostPubJWK = keypair.publicKey.host;
27
+ const hostPrivKey = await jose.importJWK(hostPrivJWK, 'EdDSA');
28
+ const hostJWT = await new jose.SignJWT({
29
+ iss: config.host_thumbprint,
30
+ aud: config.server_url,
31
+ host_public_key: hostPubJWK,
32
+ jti: crypto.randomUUID(),
33
+ })
34
+ .setProtectedHeader({ alg: 'EdDSA', typ: 'host+jwt' })
35
+ .setIssuedAt()
36
+ .setExpirationTime('60s')
37
+ .sign(hostPrivKey);
38
+ // Scan for installed skills
39
+ if (!existsSync(SKILLS_DIR)) {
40
+ console.log('No skills installed.');
41
+ return;
42
+ }
43
+ const skillDirs = readdirSync(SKILLS_DIR, { withFileTypes: true })
44
+ .filter((d) => d.isDirectory())
45
+ .map((d) => d.name);
46
+ if (skillDirs.length === 0) {
47
+ console.log('No skills installed.');
48
+ return;
49
+ }
50
+ // Filter to specific skill if provided
51
+ const toCheck = skill
52
+ ? skillDirs.filter((d) => d === skill)
53
+ : skillDirs;
54
+ if (toCheck.length === 0) {
55
+ process.stderr.write(chalk.red(`Skill "${skill}" is not installed.\n`));
56
+ process.exit(1);
57
+ }
58
+ let updatedCount = 0;
59
+ let upToDateCount = 0;
60
+ let errorCount = 0;
61
+ for (const skillDir of toCheck) {
62
+ const manifestPath = join(SKILLS_DIR, skillDir, 'manifest.json');
63
+ if (!existsSync(manifestPath)) {
64
+ continue;
65
+ }
66
+ let manifest;
67
+ try {
68
+ manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
69
+ }
70
+ catch {
71
+ process.stderr.write(chalk.dim(`Skipping ${skillDir}: invalid manifest\n`));
72
+ errorCount++;
73
+ continue;
74
+ }
75
+ // Check for newer version
76
+ try {
77
+ const checkRes = await fetch(`${config.server_url}/skills/check-update?name=${encodeURIComponent(manifest.capability_name)}&current_version=${encodeURIComponent(manifest.version)}`, {
78
+ headers: { Authorization: `Bearer ${hostJWT}` },
79
+ });
80
+ if (!checkRes.ok) {
81
+ process.stderr.write(chalk.dim(` ${skillDir}: update check failed (${checkRes.status})\n`));
82
+ errorCount++;
83
+ continue;
84
+ }
85
+ const checkData = (await checkRes.json());
86
+ if (!checkData.update_available) {
87
+ upToDateCount++;
88
+ continue;
89
+ }
90
+ // Download and replace vault
91
+ if (checkData.vault_data) {
92
+ const vaultData = Buffer.from(checkData.vault_data, 'base64');
93
+ const vaultPath = join(SKILLS_DIR, skillDir, 'skill.vault');
94
+ writeFileSync(vaultPath, vaultData);
95
+ // Update manifest
96
+ manifest.version = checkData.latest_version;
97
+ manifest.vault_hash = checkData.vault_hash || '';
98
+ manifest.installed_at = new Date().toISOString();
99
+ writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
100
+ console.log(chalk.green(` ${skillDir}: ${checkData.current_version} -> ${checkData.latest_version}`));
101
+ updatedCount++;
102
+ }
103
+ else {
104
+ // Version available but no vault data in response — fetch separately
105
+ const dlRes = await fetch(`${config.server_url}/skills/download?name=${encodeURIComponent(manifest.capability_name)}`, {
106
+ headers: { Authorization: `Bearer ${hostJWT}` },
107
+ });
108
+ if (dlRes.ok) {
109
+ const dlData = (await dlRes.json());
110
+ const vaultData = Buffer.from(dlData.vault_data, 'base64');
111
+ writeFileSync(join(SKILLS_DIR, skillDir, 'skill.vault'), vaultData);
112
+ manifest.version = dlData.version;
113
+ manifest.vault_hash = dlData.vault_hash;
114
+ manifest.installed_at = new Date().toISOString();
115
+ writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
116
+ console.log(chalk.green(` ${skillDir}: ${checkData.current_version} -> ${dlData.version}`));
117
+ updatedCount++;
118
+ }
119
+ else {
120
+ process.stderr.write(chalk.dim(` ${skillDir}: download failed\n`));
121
+ errorCount++;
122
+ }
123
+ }
124
+ }
125
+ catch (err) {
126
+ const msg = err instanceof Error ? err.message : String(err);
127
+ process.stderr.write(chalk.dim(` ${skillDir}: ${msg}\n`));
128
+ errorCount++;
129
+ }
130
+ }
131
+ // Print summary
132
+ console.log();
133
+ if (updatedCount > 0) {
134
+ console.log(chalk.green(`Updated ${updatedCount} skill${updatedCount === 1 ? '' : 's'}.`));
135
+ }
136
+ if (upToDateCount > 0) {
137
+ console.log(chalk.dim(`${upToDateCount} skill${upToDateCount === 1 ? '' : 's'} already up to date.`));
138
+ }
139
+ if (errorCount > 0) {
140
+ console.log(chalk.yellow(`${errorCount} skill${errorCount === 1 ? '' : 's'} had errors.`));
141
+ }
142
+ if (updatedCount === 0 && upToDateCount === 0 && errorCount === 0) {
143
+ console.log('No skills to update.');
144
+ }
145
+ }
146
+ catch (err) {
147
+ const message = err instanceof Error ? err.message : String(err);
148
+ process.stderr.write(chalk.red(`Update failed: ${message}\n`));
149
+ process.exit(1);
150
+ }
151
+ });
152
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const whoamiCommand: Command;
3
+ //# sourceMappingURL=whoami.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmBpC,eAAO,MAAM,aAAa,SAsItB,CAAC"}
@@ -0,0 +1,128 @@
1
+ import { Command } from 'commander';
2
+ import chalk from 'chalk';
3
+ import * as jose from 'jose';
4
+ import { getConfig, getKeypair } from '../credentials.js';
5
+ import { getDeviceFingerprint } from '../fingerprint.js';
6
+ export const whoamiCommand = new Command('whoami')
7
+ .description('Show current user, active grants, and device fingerprint')
8
+ .option('--json', 'Output as JSON')
9
+ .action(async (options) => {
10
+ try {
11
+ const config = getConfig();
12
+ if (!config) {
13
+ console.log(chalk.yellow('\n Not logged in.'));
14
+ console.log(chalk.dim(' Run `skillvault login` to authenticate.\n'));
15
+ return;
16
+ }
17
+ const keypair = getKeypair();
18
+ if (!keypair) {
19
+ console.log(chalk.yellow('\n Keypair not found. Please log in again.'));
20
+ console.log(chalk.dim(' Run `skillvault login` to authenticate.\n'));
21
+ return;
22
+ }
23
+ const fingerprint = getDeviceFingerprint();
24
+ // Sign a host JWT for the status endpoint
25
+ const hostPrivateKeyJWK = keypair.privateKey.host;
26
+ const privateKey = await jose.importJWK(hostPrivateKeyJWK, 'EdDSA');
27
+ const hostJWT = await new jose.SignJWT({
28
+ iss: config.host_thumbprint,
29
+ aud: config.server_url,
30
+ fingerprint,
31
+ jti: crypto.randomUUID(),
32
+ })
33
+ .setProtectedHeader({ alg: 'EdDSA', typ: 'host+jwt' })
34
+ .setIssuedAt()
35
+ .setExpirationTime('60s')
36
+ .sign(privateKey);
37
+ // Call server status endpoint
38
+ const response = await fetch(`${config.server_url}/agent/status`, {
39
+ headers: {
40
+ Authorization: `Bearer ${hostJWT}`,
41
+ },
42
+ });
43
+ if (!response.ok) {
44
+ // Show local info even if server is unreachable
45
+ if (options.json) {
46
+ console.log(JSON.stringify({
47
+ host_id: config.host_id,
48
+ agent_id: config.agent_id,
49
+ device_fingerprint: fingerprint,
50
+ server_url: config.server_url,
51
+ server_status: 'unreachable',
52
+ }, null, 2));
53
+ return;
54
+ }
55
+ console.log();
56
+ console.log(chalk.bold(' Skill Vault Identity'));
57
+ console.log();
58
+ console.log(` ${'Host ID:'.padEnd(22)} ${config.host_id}`);
59
+ console.log(` ${'Agent ID:'.padEnd(22)} ${config.agent_id}`);
60
+ console.log(` ${'Device Fingerprint:'.padEnd(22)} ${fingerprint}`);
61
+ console.log(` ${'Server:'.padEnd(22)} ${config.server_url}`);
62
+ console.log();
63
+ console.log(chalk.yellow(` Server unreachable (${response.status}). Showing local config only.`));
64
+ console.log();
65
+ return;
66
+ }
67
+ const data = await response.json();
68
+ // JSON output mode
69
+ if (options.json) {
70
+ console.log(JSON.stringify({
71
+ host_id: data.host_id ?? config.host_id,
72
+ agent_id: data.agent_id ?? config.agent_id,
73
+ device_fingerprint: fingerprint,
74
+ server_url: config.server_url,
75
+ status: data.status,
76
+ grants: data.grants ?? [],
77
+ }, null, 2));
78
+ return;
79
+ }
80
+ // Formatted output
81
+ console.log();
82
+ console.log(chalk.bold(' Skill Vault Identity'));
83
+ console.log();
84
+ console.log(` ${'Host ID:'.padEnd(22)} ${data.host_id ?? config.host_id}`);
85
+ console.log(` ${'Agent ID:'.padEnd(22)} ${data.agent_id ?? config.agent_id}`);
86
+ console.log(` ${'Device Fingerprint:'.padEnd(22)} ${fingerprint}`);
87
+ console.log(` ${'Server:'.padEnd(22)} ${config.server_url}`);
88
+ console.log(` ${'Status:'.padEnd(22)} ${chalk.green(data.status)}`);
89
+ // Grants table
90
+ if (data.grants && data.grants.length > 0) {
91
+ console.log();
92
+ console.log(chalk.bold(' Active Grants'));
93
+ console.log();
94
+ const capWidth = Math.max(20, ...data.grants.map((g) => g.capability.length + 2));
95
+ const statusWidth = 12;
96
+ const header = [
97
+ chalk.dim('Capability'.padEnd(capWidth)),
98
+ chalk.dim('Status'.padEnd(statusWidth)),
99
+ chalk.dim('Expires'),
100
+ ].join(' ');
101
+ console.log(` ${header}`);
102
+ console.log(` ${chalk.dim('-'.repeat(capWidth + statusWidth + 24))}`);
103
+ for (const grant of data.grants) {
104
+ const statusColor = grant.status === 'active' ? chalk.green : chalk.yellow;
105
+ const expiresAt = grant.expires_at
106
+ ? new Date(grant.expires_at).toLocaleString()
107
+ : '-';
108
+ const row = [
109
+ chalk.cyan(grant.capability.padEnd(capWidth)),
110
+ statusColor(grant.status.padEnd(statusWidth)),
111
+ chalk.dim(expiresAt),
112
+ ].join(' ');
113
+ console.log(` ${row}`);
114
+ }
115
+ }
116
+ else {
117
+ console.log();
118
+ console.log(chalk.dim(' No active grants.'));
119
+ }
120
+ console.log();
121
+ }
122
+ catch (err) {
123
+ const message = err instanceof Error ? err.message : String(err);
124
+ console.error(chalk.red(`Error: ${message}`));
125
+ process.exit(1);
126
+ }
127
+ });
128
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Cross-platform credential storage.
3
+ * Stores config in ~/.skillvault/ and uses macOS Keychain where available.
4
+ */
5
+ export interface SkillVaultConfig {
6
+ server_url: string;
7
+ host_id: string;
8
+ agent_id: string;
9
+ email?: string;
10
+ publisher_id?: string;
11
+ host_thumbprint: string;
12
+ }
13
+ export declare function getConfig(): SkillVaultConfig | null;
14
+ export declare function saveConfig(config: SkillVaultConfig): void;
15
+ export declare function removeConfig(): void;
16
+ /**
17
+ * Store host keypair in macOS Keychain (or fallback to file).
18
+ */
19
+ export declare function storeKeypair(privateKeyJWK: object, publicKeyJWK: object): void;
20
+ /**
21
+ * Retrieve host keypair from macOS Keychain (or fallback to file).
22
+ */
23
+ export declare function getKeypair(): {
24
+ privateKey: object;
25
+ publicKey: object;
26
+ } | null;
27
+ /**
28
+ * Remove host keypair from storage.
29
+ */
30
+ export declare function removeKeypair(): void;
31
+ export declare function getConfigDir(): string;
32
+ //# sourceMappingURL=credentials.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.d.ts","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAaH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAMD,wBAAgB,SAAS,IAAI,gBAAgB,GAAG,IAAI,CAOnD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAGzD;AAED,wBAAgB,YAAY,IAAI,IAAI,CAGnC;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI,CA2B9E;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAoB7E;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAWpC;AAED,wBAAgB,YAAY,IAAI,MAAM,CAErC"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Cross-platform credential storage.
3
+ * Stores config in ~/.skillvault/ and uses macOS Keychain where available.
4
+ */
5
+ import { mkdirSync, readFileSync, writeFileSync, rmSync, existsSync } from 'node:fs';
6
+ import { join } from 'node:path';
7
+ import { homedir } from 'node:os';
8
+ import { execSync } from 'node:child_process';
9
+ const CONFIG_DIR = join(homedir(), '.skillvault');
10
+ const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
11
+ const GRANTS_CACHE_FILE = join(CONFIG_DIR, 'grants-cache.json');
12
+ const KEYCHAIN_SERVICE = 'com.skillvault.cli';
13
+ const KEYCHAIN_ACCOUNT = 'host-keypair';
14
+ function ensureConfigDir() {
15
+ mkdirSync(CONFIG_DIR, { recursive: true });
16
+ }
17
+ export function getConfig() {
18
+ try {
19
+ if (!existsSync(CONFIG_FILE))
20
+ return null;
21
+ return JSON.parse(readFileSync(CONFIG_FILE, 'utf8'));
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ }
27
+ export function saveConfig(config) {
28
+ ensureConfigDir();
29
+ writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
30
+ }
31
+ export function removeConfig() {
32
+ try {
33
+ rmSync(CONFIG_FILE);
34
+ }
35
+ catch { /* ok if missing */ }
36
+ try {
37
+ rmSync(GRANTS_CACHE_FILE);
38
+ }
39
+ catch { /* ok if missing */ }
40
+ }
41
+ /**
42
+ * Store host keypair in macOS Keychain (or fallback to file).
43
+ */
44
+ export function storeKeypair(privateKeyJWK, publicKeyJWK) {
45
+ ensureConfigDir();
46
+ const data = JSON.stringify({ privateKey: privateKeyJWK, publicKey: publicKeyJWK });
47
+ if (process.platform === 'darwin') {
48
+ try {
49
+ // Delete existing entry silently
50
+ try {
51
+ execSync(`security delete-generic-password -s "${KEYCHAIN_SERVICE}" -a "${KEYCHAIN_ACCOUNT}" 2>/dev/null`, { stdio: 'pipe' });
52
+ }
53
+ catch { /* ok if missing */ }
54
+ // Add new entry
55
+ execSync(`security add-generic-password -s "${KEYCHAIN_SERVICE}" -a "${KEYCHAIN_ACCOUNT}" -w "${data.replace(/"/g, '\\"')}" -U`, { stdio: 'pipe' });
56
+ return;
57
+ }
58
+ catch {
59
+ // Fall through to file storage
60
+ }
61
+ }
62
+ // Fallback: store in config directory
63
+ writeFileSync(join(CONFIG_DIR, 'keypair.json'), data, { mode: 0o600 });
64
+ }
65
+ /**
66
+ * Retrieve host keypair from macOS Keychain (or fallback to file).
67
+ */
68
+ export function getKeypair() {
69
+ if (process.platform === 'darwin') {
70
+ try {
71
+ const result = execSync(`security find-generic-password -s "${KEYCHAIN_SERVICE}" -a "${KEYCHAIN_ACCOUNT}" -w`, { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
72
+ return JSON.parse(result);
73
+ }
74
+ catch {
75
+ // Fall through to file
76
+ }
77
+ }
78
+ try {
79
+ const filePath = join(CONFIG_DIR, 'keypair.json');
80
+ if (!existsSync(filePath))
81
+ return null;
82
+ return JSON.parse(readFileSync(filePath, 'utf8'));
83
+ }
84
+ catch {
85
+ return null;
86
+ }
87
+ }
88
+ /**
89
+ * Remove host keypair from storage.
90
+ */
91
+ export function removeKeypair() {
92
+ if (process.platform === 'darwin') {
93
+ try {
94
+ execSync(`security delete-generic-password -s "${KEYCHAIN_SERVICE}" -a "${KEYCHAIN_ACCOUNT}" 2>/dev/null`, { stdio: 'pipe' });
95
+ }
96
+ catch { /* ok if missing */ }
97
+ }
98
+ try {
99
+ rmSync(join(CONFIG_DIR, 'keypair.json'));
100
+ }
101
+ catch { /* ok */ }
102
+ }
103
+ export function getConfigDir() {
104
+ return CONFIG_DIR;
105
+ }
106
+ //# sourceMappingURL=credentials.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Device fingerprinting for host identification.
3
+ * Generates a stable 16-char hex fingerprint from hardware/OS attributes.
4
+ */
5
+ /**
6
+ * Generate a stable 16-character hex device fingerprint.
7
+ *
8
+ * Components hashed:
9
+ * - hostname
10
+ * - username
11
+ * - platform (e.g. 'darwin', 'linux')
12
+ * - arch (e.g. 'arm64', 'x64')
13
+ * - macOS hardware UUID (when available)
14
+ *
15
+ * The result is cached in-memory for the lifetime of the process.
16
+ */
17
+ export declare function getDeviceFingerprint(): string;
18
+ //# sourceMappingURL=fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA0BH;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAc7C"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Device fingerprinting for host identification.
3
+ * Generates a stable 16-char hex fingerprint from hardware/OS attributes.
4
+ */
5
+ import { createHash } from 'node:crypto';
6
+ import { hostname, userInfo, platform, arch } from 'node:os';
7
+ import { execSync } from 'node:child_process';
8
+ let cachedFingerprint = null;
9
+ /**
10
+ * Retrieve macOS hardware UUID via ioreg.
11
+ * Returns empty string on non-macOS or if command fails.
12
+ */
13
+ function getMacHardwareUUID() {
14
+ if (platform() !== 'darwin')
15
+ return '';
16
+ try {
17
+ const output = execSync('ioreg -rd1 -c IOPlatformExpertDevice', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
18
+ const match = output.match(/"IOPlatformUUID"\s*=\s*"([^"]+)"/);
19
+ return match ? match[1] : '';
20
+ }
21
+ catch {
22
+ return '';
23
+ }
24
+ }
25
+ /**
26
+ * Generate a stable 16-character hex device fingerprint.
27
+ *
28
+ * Components hashed:
29
+ * - hostname
30
+ * - username
31
+ * - platform (e.g. 'darwin', 'linux')
32
+ * - arch (e.g. 'arm64', 'x64')
33
+ * - macOS hardware UUID (when available)
34
+ *
35
+ * The result is cached in-memory for the lifetime of the process.
36
+ */
37
+ export function getDeviceFingerprint() {
38
+ if (cachedFingerprint !== null)
39
+ return cachedFingerprint;
40
+ const components = [
41
+ hostname(),
42
+ userInfo().username,
43
+ platform(),
44
+ arch(),
45
+ getMacHardwareUUID(),
46
+ ].join(':');
47
+ const hash = createHash('sha256').update(components).digest('hex');
48
+ cachedFingerprint = hash.substring(0, 16);
49
+ return cachedFingerprint;
50
+ }
51
+ //# sourceMappingURL=fingerprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../src/fingerprint.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,IAAI,iBAAiB,GAAkB,IAAI,CAAC;AAE5C;;;GAGG;AACH,SAAS,kBAAkB;IACzB,IAAI,QAAQ,EAAE,KAAK,QAAQ;QAAE,OAAO,EAAE,CAAC;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CACrB,sCAAsC,EACtC,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CACtD,CAAC;QACF,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,kCAAkC,CAAC,CAAC;QAC/D,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,oBAAoB;IAClC,IAAI,iBAAiB,KAAK,IAAI;QAAE,OAAO,iBAAiB,CAAC;IAEzD,MAAM,UAAU,GAAG;QACjB,QAAQ,EAAE;QACV,QAAQ,EAAE,CAAC,QAAQ;QACnB,QAAQ,EAAE;QACV,IAAI,EAAE;QACN,kBAAkB,EAAE;KACrB,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEZ,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACnE,iBAAiB,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,iBAAiB,CAAC;AAC3B,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Offline grant caching with TTL and grace periods.
3
+ * Cache file: ~/.skillvault/grants-cache.json
4
+ */
5
+ export interface CachedGrantEntry {
6
+ capability: string;
7
+ grant: unknown;
8
+ cached_at: string;
9
+ }
10
+ /**
11
+ * Store a grant in the cache with a timestamp.
12
+ */
13
+ export declare function cacheGrant(capability: string, grant: unknown): void;
14
+ /**
15
+ * Retrieve a cached grant if it exists and is within TTL.
16
+ * Returns null if missing or expired.
17
+ */
18
+ export declare function getCachedGrant(capability: string): unknown | null;
19
+ /**
20
+ * Check if a cached grant is within the soft grace period (TTL + 10 min).
21
+ * Returns true if the grant exists and is within soft grace, even if past TTL.
22
+ */
23
+ export declare function isWithinSoftGrace(capability: string): boolean;
24
+ /**
25
+ * Check if a cached grant is within the hard grace period (TTL + 30 min).
26
+ * Returns true if the grant exists and is within hard grace, even if past TTL.
27
+ */
28
+ export declare function isWithinHardGrace(capability: string): boolean;
29
+ /**
30
+ * Remove the cache file entirely.
31
+ */
32
+ export declare function clearCache(): void;
33
+ /** Exported for testing */
34
+ export declare const _internals: {
35
+ CACHE_FILE: string;
36
+ DEFAULT_TTL_MS: number;
37
+ SOFT_GRACE_MS: number;
38
+ HARD_GRACE_MS: number;
39
+ };
40
+ //# sourceMappingURL=grant-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"grant-cache.d.ts","sourceRoot":"","sources":["../src/grant-cache.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmBH,MAAM,WAAW,gBAAgB;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAgCD;;GAEG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAQnE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI,CASjE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAO7D;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAO7D;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAMjC;AAED,2BAA2B;AAC3B,eAAO,MAAM,UAAU;;;;;CAKtB,CAAC"}