skillstore 0.0.1 → 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.
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +21 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/commands/install.d.ts +35 -0
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/commands/install.js +272 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/plugin/index.d.ts +3 -0
- package/dist/commands/plugin/index.d.ts.map +1 -0
- package/dist/commands/plugin/index.js +13 -0
- package/dist/commands/plugin/index.js.map +1 -0
- package/dist/commands/plugin/info.d.ts +9 -0
- package/dist/commands/plugin/info.d.ts.map +1 -0
- package/dist/commands/plugin/info.js +75 -0
- package/dist/commands/plugin/info.js.map +1 -0
- package/dist/commands/plugin/install.d.ts +29 -0
- package/dist/commands/plugin/install.d.ts.map +1 -0
- package/dist/commands/plugin/install.js +140 -0
- package/dist/commands/plugin/install.js.map +1 -0
- package/dist/commands/plugin/list.d.ts +22 -0
- package/dist/commands/plugin/list.d.ts.map +1 -0
- package/dist/commands/plugin/list.js +76 -0
- package/dist/commands/plugin/list.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/plugin-api.d.ts +155 -0
- package/dist/lib/plugin-api.d.ts.map +1 -0
- package/dist/lib/plugin-api.js +173 -0
- package/dist/lib/plugin-api.js.map +1 -0
- package/dist/lib/plugin-config.d.ts +56 -0
- package/dist/lib/plugin-config.d.ts.map +1 -0
- package/dist/lib/plugin-config.js +64 -0
- package/dist/lib/plugin-config.js.map +1 -0
- package/dist/lib/plugin-download.d.ts +36 -0
- package/dist/lib/plugin-download.d.ts.map +1 -0
- package/dist/lib/plugin-download.js +134 -0
- package/dist/lib/plugin-download.js.map +1 -0
- package/dist/lib/plugin-logger.d.ts +79 -0
- package/dist/lib/plugin-logger.d.ts.map +1 -0
- package/dist/lib/plugin-logger.js +173 -0
- package/dist/lib/plugin-logger.js.map +1 -0
- package/dist/lib/plugin-verify.d.ts +36 -0
- package/dist/lib/plugin-verify.d.ts.map +1 -0
- package/dist/lib/plugin-verify.js +103 -0
- package/dist/lib/plugin-verify.js.map +1 -0
- package/dist/lib/skill-api.d.ts +33 -0
- package/dist/lib/skill-api.d.ts.map +1 -0
- package/dist/lib/skill-api.js +64 -0
- package/dist/lib/skill-api.js.map +1 -0
- package/package.json +56 -17
- package/src/index.js +0 -16
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { PluginConfig } from './plugin-config.js';
|
|
2
|
+
import type { ManifestSkill } from './plugin-api.js';
|
|
3
|
+
/**
|
|
4
|
+
* Plugin Skill Downloader
|
|
5
|
+
*
|
|
6
|
+
* Downloads skills from the Skillstore API with concurrent downloads,
|
|
7
|
+
* progress tracking, and content hash verification.
|
|
8
|
+
*/
|
|
9
|
+
/** Download result for a single skill */
|
|
10
|
+
export interface SkillDownloadResult {
|
|
11
|
+
slug: string;
|
|
12
|
+
success: boolean;
|
|
13
|
+
path?: string;
|
|
14
|
+
error?: string;
|
|
15
|
+
skipped?: boolean;
|
|
16
|
+
}
|
|
17
|
+
/** Download summary */
|
|
18
|
+
export interface DownloadSummary {
|
|
19
|
+
total: number;
|
|
20
|
+
success: number;
|
|
21
|
+
failed: number;
|
|
22
|
+
skipped: number;
|
|
23
|
+
results: SkillDownloadResult[];
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Download all skills from a manifest with concurrent downloads
|
|
27
|
+
*/
|
|
28
|
+
export declare function downloadAllSkills(config: PluginConfig, skills: ManifestSkill[], options?: {
|
|
29
|
+
overwrite?: boolean;
|
|
30
|
+
verifyHash?: boolean;
|
|
31
|
+
}): Promise<DownloadSummary>;
|
|
32
|
+
/**
|
|
33
|
+
* Print download summary
|
|
34
|
+
*/
|
|
35
|
+
export declare function printDownloadSummary(summary: DownloadSummary): void;
|
|
36
|
+
//# sourceMappingURL=plugin-download.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-download.d.ts","sourceRoot":"","sources":["../../src/lib/plugin-download.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAKrD;;;;;GAKG;AAEH,yCAAyC;AACzC,MAAM,WAAW,mBAAmB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,uBAAuB;AACvB,MAAM,WAAW,eAAe;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,mBAAmB,EAAE,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACtC,MAAM,EAAE,YAAY,EACpB,MAAM,EAAE,aAAa,EAAE,EACvB,OAAO,GAAE;IACR,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;CAChB,GACJ,OAAO,CAAC,eAAe,CAAC,CA8C1B;AA0ED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI,CAuBnE"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { mkdir, writeFile, access } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { downloadSkill } from './plugin-api.js';
|
|
4
|
+
import { verifyContentHash } from './plugin-verify.js';
|
|
5
|
+
import { logger } from './plugin-logger.js';
|
|
6
|
+
/**
|
|
7
|
+
* Download all skills from a manifest with concurrent downloads
|
|
8
|
+
*/
|
|
9
|
+
export async function downloadAllSkills(config, skills, options = {}) {
|
|
10
|
+
const { overwrite = false, verifyHash = true } = options;
|
|
11
|
+
const results = [];
|
|
12
|
+
let success = 0;
|
|
13
|
+
let failed = 0;
|
|
14
|
+
let skipped = 0;
|
|
15
|
+
// Start progress tracking
|
|
16
|
+
logger.startProgress(skills.length, 'Downloading skills');
|
|
17
|
+
// Process skills in batches for concurrency
|
|
18
|
+
const batchSize = config.maxConcurrent;
|
|
19
|
+
for (let i = 0; i < skills.length; i += batchSize) {
|
|
20
|
+
const batch = skills.slice(i, i + batchSize);
|
|
21
|
+
const batchResults = await Promise.all(batch.map((skill) => downloadSingleSkill(config, skill, { overwrite, verifyHash })));
|
|
22
|
+
for (const result of batchResults) {
|
|
23
|
+
results.push(result);
|
|
24
|
+
if (result.success) {
|
|
25
|
+
if (result.skipped) {
|
|
26
|
+
skipped++;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
success++;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
failed++;
|
|
34
|
+
}
|
|
35
|
+
logger.incrementProgress();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
logger.completeProgress();
|
|
39
|
+
return {
|
|
40
|
+
total: skills.length,
|
|
41
|
+
success,
|
|
42
|
+
failed,
|
|
43
|
+
skipped,
|
|
44
|
+
results,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Download a single skill
|
|
49
|
+
*/
|
|
50
|
+
async function downloadSingleSkill(config, skill, options) {
|
|
51
|
+
const skillPath = join(config.installDir, `${skill.slug}.md`);
|
|
52
|
+
try {
|
|
53
|
+
// Check if skill already exists
|
|
54
|
+
if (!options.overwrite) {
|
|
55
|
+
try {
|
|
56
|
+
await access(skillPath);
|
|
57
|
+
// File exists, skip
|
|
58
|
+
return {
|
|
59
|
+
slug: skill.slug,
|
|
60
|
+
success: true,
|
|
61
|
+
path: skillPath,
|
|
62
|
+
skipped: true,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// File doesn't exist, continue with download
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Dry run mode - don't actually download
|
|
70
|
+
if (config.dryRun) {
|
|
71
|
+
return {
|
|
72
|
+
slug: skill.slug,
|
|
73
|
+
success: true,
|
|
74
|
+
path: skillPath,
|
|
75
|
+
skipped: true,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// Download skill content
|
|
79
|
+
const content = await downloadSkill(config, skill.downloadUrl);
|
|
80
|
+
// Verify content hash if enabled
|
|
81
|
+
if (options.verifyHash && skill.contentHash) {
|
|
82
|
+
const hashValid = verifyContentHash(content, skill.contentHash);
|
|
83
|
+
if (!hashValid) {
|
|
84
|
+
return {
|
|
85
|
+
slug: skill.slug,
|
|
86
|
+
success: false,
|
|
87
|
+
error: 'Content hash verification failed',
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Ensure directory exists
|
|
92
|
+
await mkdir(dirname(skillPath), { recursive: true });
|
|
93
|
+
// Write skill file
|
|
94
|
+
await writeFile(skillPath, content, 'utf-8');
|
|
95
|
+
return {
|
|
96
|
+
slug: skill.slug,
|
|
97
|
+
success: true,
|
|
98
|
+
path: skillPath,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
return {
|
|
103
|
+
slug: skill.slug,
|
|
104
|
+
success: false,
|
|
105
|
+
error: err instanceof Error ? err.message : 'Unknown error',
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Print download summary
|
|
111
|
+
*/
|
|
112
|
+
export function printDownloadSummary(summary) {
|
|
113
|
+
console.log('');
|
|
114
|
+
console.log('Download Summary:');
|
|
115
|
+
for (const result of summary.results) {
|
|
116
|
+
if (result.success) {
|
|
117
|
+
if (result.skipped) {
|
|
118
|
+
logger.skillSummary(result.slug, 'skipped');
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
logger.skillSummary(result.slug, 'installed');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
logger.skillSummary(result.slug, 'failed');
|
|
126
|
+
if (result.error) {
|
|
127
|
+
console.log(` Error: ${result.error}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
console.log('');
|
|
132
|
+
console.log(`Total: ${summary.total} | Installed: ${summary.success} | Skipped: ${summary.skipped} | Failed: ${summary.failed}`);
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=plugin-download.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-download.js","sourceRoot":"","sources":["../../src/lib/plugin-download.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export interface ProgressState {
|
|
2
|
+
current: number;
|
|
3
|
+
total: number;
|
|
4
|
+
label: string;
|
|
5
|
+
}
|
|
6
|
+
declare class PluginLogger {
|
|
7
|
+
private progressState;
|
|
8
|
+
private spinnerInterval;
|
|
9
|
+
private spinnerFrames;
|
|
10
|
+
private spinnerIndex;
|
|
11
|
+
/**
|
|
12
|
+
* Log info message
|
|
13
|
+
*/
|
|
14
|
+
info(message: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* Log success message
|
|
17
|
+
*/
|
|
18
|
+
success(message: string): void;
|
|
19
|
+
/**
|
|
20
|
+
* Log warning message
|
|
21
|
+
*/
|
|
22
|
+
warn(message: string): void;
|
|
23
|
+
/**
|
|
24
|
+
* Log error message
|
|
25
|
+
*/
|
|
26
|
+
error(message: string, err?: Error): void;
|
|
27
|
+
/**
|
|
28
|
+
* Log debug message (only in DEBUG mode)
|
|
29
|
+
*/
|
|
30
|
+
debug(message: string): void;
|
|
31
|
+
/**
|
|
32
|
+
* Start a spinner with message
|
|
33
|
+
*/
|
|
34
|
+
startSpinner(message: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* Stop the spinner
|
|
37
|
+
*/
|
|
38
|
+
stopSpinner(): void;
|
|
39
|
+
/**
|
|
40
|
+
* Complete spinner with success
|
|
41
|
+
*/
|
|
42
|
+
spinnerSuccess(message: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Complete spinner with error
|
|
45
|
+
*/
|
|
46
|
+
spinnerError(message: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* Start progress tracking
|
|
49
|
+
*/
|
|
50
|
+
startProgress(total: number, label: string): void;
|
|
51
|
+
/**
|
|
52
|
+
* Update progress
|
|
53
|
+
*/
|
|
54
|
+
updateProgress(current: number): void;
|
|
55
|
+
/**
|
|
56
|
+
* Increment progress by 1
|
|
57
|
+
*/
|
|
58
|
+
incrementProgress(): void;
|
|
59
|
+
/**
|
|
60
|
+
* Complete progress
|
|
61
|
+
*/
|
|
62
|
+
completeProgress(): void;
|
|
63
|
+
/**
|
|
64
|
+
* Render progress bar
|
|
65
|
+
*/
|
|
66
|
+
private renderProgress;
|
|
67
|
+
/**
|
|
68
|
+
* Print a box with content
|
|
69
|
+
*/
|
|
70
|
+
box(title: string, content: string[]): void;
|
|
71
|
+
/**
|
|
72
|
+
* Print skill installation summary
|
|
73
|
+
*/
|
|
74
|
+
skillSummary(slug: string, status: 'installed' | 'skipped' | 'failed'): void;
|
|
75
|
+
}
|
|
76
|
+
/** Singleton logger instance */
|
|
77
|
+
export declare const logger: PluginLogger;
|
|
78
|
+
export {};
|
|
79
|
+
//# sourceMappingURL=plugin-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-logger.d.ts","sourceRoot":"","sources":["../../src/lib/plugin-logger.ts"],"names":[],"mappings":"AAmBA,MAAM,WAAW,aAAa;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACd;AAED,cAAM,YAAY;IACjB,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,aAAa,CAAsD;IAC3E,OAAO,CAAC,YAAY,CAAK;IAEzB;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI3B;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI9B;;OAEG;IACH,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAI3B;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI;IAOzC;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAM5B;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAcnC;;OAEG;IACH,WAAW,IAAI,IAAI;IAQnB;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKrC;;OAEG;IACH,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAKnC;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IAKjD;;OAEG;IACH,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAOrC;;OAEG;IACH,iBAAiB,IAAI,IAAI;IAOzB;;OAEG;IACH,gBAAgB,IAAI,IAAI;IASxB;;OAEG;IACH,OAAO,CAAC,cAAc;IAetB;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI;IAe3C;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,IAAI;CAS5E;AAED,gCAAgC;AAChC,eAAO,MAAM,MAAM,cAAqB,CAAC"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import consola from 'consola';
|
|
2
|
+
/**
|
|
3
|
+
* Plugin CLI Logger
|
|
4
|
+
*
|
|
5
|
+
* Provides styled logging and progress indicators for plugin operations.
|
|
6
|
+
*/
|
|
7
|
+
/** Color codes for different log types */
|
|
8
|
+
const colors = {
|
|
9
|
+
info: '\x1b[36m', // Cyan
|
|
10
|
+
success: '\x1b[32m', // Green
|
|
11
|
+
warn: '\x1b[33m', // Yellow
|
|
12
|
+
error: '\x1b[31m', // Red
|
|
13
|
+
dim: '\x1b[90m', // Gray
|
|
14
|
+
reset: '\x1b[0m',
|
|
15
|
+
bold: '\x1b[1m',
|
|
16
|
+
};
|
|
17
|
+
class PluginLogger {
|
|
18
|
+
progressState = null;
|
|
19
|
+
spinnerInterval = null;
|
|
20
|
+
spinnerFrames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
21
|
+
spinnerIndex = 0;
|
|
22
|
+
/**
|
|
23
|
+
* Log info message
|
|
24
|
+
*/
|
|
25
|
+
info(message) {
|
|
26
|
+
consola.info(message);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Log success message
|
|
30
|
+
*/
|
|
31
|
+
success(message) {
|
|
32
|
+
consola.success(message);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Log warning message
|
|
36
|
+
*/
|
|
37
|
+
warn(message) {
|
|
38
|
+
consola.warn(message);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Log error message
|
|
42
|
+
*/
|
|
43
|
+
error(message, err) {
|
|
44
|
+
consola.error(message);
|
|
45
|
+
if (err && process.env.DEBUG) {
|
|
46
|
+
consola.error(err);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Log debug message (only in DEBUG mode)
|
|
51
|
+
*/
|
|
52
|
+
debug(message) {
|
|
53
|
+
if (process.env.DEBUG) {
|
|
54
|
+
consola.debug(message);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Start a spinner with message
|
|
59
|
+
*/
|
|
60
|
+
startSpinner(message) {
|
|
61
|
+
this.stopSpinner();
|
|
62
|
+
this.spinnerIndex = 0;
|
|
63
|
+
const spin = () => {
|
|
64
|
+
const frame = this.spinnerFrames[this.spinnerIndex];
|
|
65
|
+
process.stdout.write(`\r${colors.info}${frame}${colors.reset} ${message}`);
|
|
66
|
+
this.spinnerIndex = (this.spinnerIndex + 1) % this.spinnerFrames.length;
|
|
67
|
+
};
|
|
68
|
+
spin();
|
|
69
|
+
this.spinnerInterval = setInterval(spin, 80);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Stop the spinner
|
|
73
|
+
*/
|
|
74
|
+
stopSpinner() {
|
|
75
|
+
if (this.spinnerInterval) {
|
|
76
|
+
clearInterval(this.spinnerInterval);
|
|
77
|
+
this.spinnerInterval = null;
|
|
78
|
+
process.stdout.write('\r\x1b[K'); // Clear line
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Complete spinner with success
|
|
83
|
+
*/
|
|
84
|
+
spinnerSuccess(message) {
|
|
85
|
+
this.stopSpinner();
|
|
86
|
+
console.log(`${colors.success}✓${colors.reset} ${message}`);
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Complete spinner with error
|
|
90
|
+
*/
|
|
91
|
+
spinnerError(message) {
|
|
92
|
+
this.stopSpinner();
|
|
93
|
+
console.log(`${colors.error}✗${colors.reset} ${message}`);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Start progress tracking
|
|
97
|
+
*/
|
|
98
|
+
startProgress(total, label) {
|
|
99
|
+
this.progressState = { current: 0, total, label };
|
|
100
|
+
this.renderProgress();
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Update progress
|
|
104
|
+
*/
|
|
105
|
+
updateProgress(current) {
|
|
106
|
+
if (this.progressState) {
|
|
107
|
+
this.progressState.current = current;
|
|
108
|
+
this.renderProgress();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Increment progress by 1
|
|
113
|
+
*/
|
|
114
|
+
incrementProgress() {
|
|
115
|
+
if (this.progressState) {
|
|
116
|
+
this.progressState.current++;
|
|
117
|
+
this.renderProgress();
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Complete progress
|
|
122
|
+
*/
|
|
123
|
+
completeProgress() {
|
|
124
|
+
if (this.progressState) {
|
|
125
|
+
process.stdout.write('\r\x1b[K'); // Clear line
|
|
126
|
+
const { total, label } = this.progressState;
|
|
127
|
+
console.log(`${colors.success}✓${colors.reset} ${label} (${total}/${total})`);
|
|
128
|
+
this.progressState = null;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Render progress bar
|
|
133
|
+
*/
|
|
134
|
+
renderProgress() {
|
|
135
|
+
if (!this.progressState)
|
|
136
|
+
return;
|
|
137
|
+
const { current, total, label } = this.progressState;
|
|
138
|
+
const percent = Math.round((current / total) * 100);
|
|
139
|
+
const barWidth = 20;
|
|
140
|
+
const filled = Math.round((current / total) * barWidth);
|
|
141
|
+
const empty = barWidth - filled;
|
|
142
|
+
const bar = `${'█'.repeat(filled)}${'░'.repeat(empty)}`;
|
|
143
|
+
process.stdout.write(`\r${colors.info}↓${colors.reset} ${label} ${colors.dim}[${bar}]${colors.reset} ${current}/${total} (${percent}%)`);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Print a box with content
|
|
147
|
+
*/
|
|
148
|
+
box(title, content) {
|
|
149
|
+
const width = Math.max(title.length, ...content.map((c) => c.length)) + 4;
|
|
150
|
+
const border = '─'.repeat(width);
|
|
151
|
+
console.log(`${colors.dim}┌${border}┐${colors.reset}`);
|
|
152
|
+
console.log(`${colors.dim}│${colors.reset} ${colors.bold}${title.padEnd(width - 2)}${colors.reset} ${colors.dim}│${colors.reset}`);
|
|
153
|
+
console.log(`${colors.dim}├${border}┤${colors.reset}`);
|
|
154
|
+
for (const line of content) {
|
|
155
|
+
console.log(`${colors.dim}│${colors.reset} ${line.padEnd(width - 2)} ${colors.dim}│${colors.reset}`);
|
|
156
|
+
}
|
|
157
|
+
console.log(`${colors.dim}└${border}┘${colors.reset}`);
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Print skill installation summary
|
|
161
|
+
*/
|
|
162
|
+
skillSummary(slug, status) {
|
|
163
|
+
const icons = {
|
|
164
|
+
installed: `${colors.success}✓${colors.reset}`,
|
|
165
|
+
skipped: `${colors.warn}○${colors.reset}`,
|
|
166
|
+
failed: `${colors.error}✗${colors.reset}`,
|
|
167
|
+
};
|
|
168
|
+
console.log(` ${icons[status]} ${slug}`);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/** Singleton logger instance */
|
|
172
|
+
export const logger = new PluginLogger();
|
|
173
|
+
//# sourceMappingURL=plugin-logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-logger.js","sourceRoot":"","sources":["../../src/lib/plugin-logger.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { PluginManifest } from './plugin-api.js';
|
|
2
|
+
/**
|
|
3
|
+
* Plugin Manifest Verification
|
|
4
|
+
*
|
|
5
|
+
* Verifies HMAC-SHA256 signatures on plugin manifests to ensure integrity.
|
|
6
|
+
*/
|
|
7
|
+
/** Verification result */
|
|
8
|
+
export interface VerifyResult {
|
|
9
|
+
valid: boolean;
|
|
10
|
+
error?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Get the signing key from environment
|
|
14
|
+
* In production, this should be a public key or verification endpoint
|
|
15
|
+
* For CLI, we use a shared secret (configured by user or fetched from API)
|
|
16
|
+
*/
|
|
17
|
+
export declare function getVerificationKey(): string | null;
|
|
18
|
+
/**
|
|
19
|
+
* Verify manifest signature using HMAC-SHA256
|
|
20
|
+
*
|
|
21
|
+
* The signature is computed over the manifest JSON without the signature field.
|
|
22
|
+
*/
|
|
23
|
+
export declare function verifyManifestSignature(manifest: PluginManifest, key: string): VerifyResult;
|
|
24
|
+
/**
|
|
25
|
+
* Verify skill content hash
|
|
26
|
+
*
|
|
27
|
+
* Ensures downloaded skill content matches the hash in the manifest.
|
|
28
|
+
*/
|
|
29
|
+
export declare function verifyContentHash(content: string, expectedHash: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Verify entire manifest (signature + metadata)
|
|
32
|
+
*/
|
|
33
|
+
export declare function verifyManifest(manifest: PluginManifest, options?: {
|
|
34
|
+
skipSignature?: boolean;
|
|
35
|
+
}): Promise<VerifyResult>;
|
|
36
|
+
//# sourceMappingURL=plugin-verify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-verify.d.ts","sourceRoot":"","sources":["../../src/lib/plugin-verify.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;;;GAIG;AAEH,0BAA0B;AAC1B,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,IAAI,CAIlD;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CACtC,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,MAAM,GACT,YAAY,CA6Bd;AAgBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAMhF;AAED;;GAEG;AACH,wBAAsB,cAAc,CACnC,QAAQ,EAAE,cAAc,EACxB,OAAO,GAAE;IAAE,aAAa,CAAC,EAAE,OAAO,CAAA;CAAO,GACvC,OAAO,CAAC,YAAY,CAAC,CAyCvB"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { createHmac, createHash, timingSafeEqual as cryptoTimingSafeEqual } from 'node:crypto';
|
|
2
|
+
/**
|
|
3
|
+
* Get the signing key from environment
|
|
4
|
+
* In production, this should be a public key or verification endpoint
|
|
5
|
+
* For CLI, we use a shared secret (configured by user or fetched from API)
|
|
6
|
+
*/
|
|
7
|
+
export function getVerificationKey() {
|
|
8
|
+
// The verification key can be set via environment variable
|
|
9
|
+
// In production, this might be fetched from a public endpoint
|
|
10
|
+
return process.env.SKILLSTORE_VERIFY_KEY || null;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Verify manifest signature using HMAC-SHA256
|
|
14
|
+
*
|
|
15
|
+
* The signature is computed over the manifest JSON without the signature field.
|
|
16
|
+
*/
|
|
17
|
+
export function verifyManifestSignature(manifest, key) {
|
|
18
|
+
try {
|
|
19
|
+
// Extract signature and create unsigned manifest
|
|
20
|
+
const { signature, ...unsignedManifest } = manifest;
|
|
21
|
+
if (!signature) {
|
|
22
|
+
return { valid: false, error: 'Manifest has no signature' };
|
|
23
|
+
}
|
|
24
|
+
// Compute expected signature (matching server-side implementation)
|
|
25
|
+
const dataToSign = JSON.stringify(unsignedManifest, null, 0);
|
|
26
|
+
const expectedSignature = createHmac('sha256', key)
|
|
27
|
+
.update(dataToSign)
|
|
28
|
+
.digest('hex');
|
|
29
|
+
// Constant-time comparison to prevent timing attacks
|
|
30
|
+
const valid = timingSafeEqual(signature, expectedSignature);
|
|
31
|
+
if (!valid) {
|
|
32
|
+
return { valid: false, error: 'Signature verification failed' };
|
|
33
|
+
}
|
|
34
|
+
return { valid: true };
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
return {
|
|
38
|
+
valid: false,
|
|
39
|
+
error: `Verification error: ${err instanceof Error ? err.message : 'Unknown error'}`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Constant-time string comparison to prevent timing attacks
|
|
45
|
+
*/
|
|
46
|
+
function timingSafeEqual(a, b) {
|
|
47
|
+
if (a.length !== b.length) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
const bufA = Buffer.from(a, 'utf8');
|
|
51
|
+
const bufB = Buffer.from(b, 'utf8');
|
|
52
|
+
return cryptoTimingSafeEqual(bufA, bufB);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Verify skill content hash
|
|
56
|
+
*
|
|
57
|
+
* Ensures downloaded skill content matches the hash in the manifest.
|
|
58
|
+
*/
|
|
59
|
+
export function verifyContentHash(content, expectedHash) {
|
|
60
|
+
const actualHash = createHash('sha256').update(content).digest('hex');
|
|
61
|
+
// Content hash might be truncated, compare common length
|
|
62
|
+
const compareLength = Math.min(actualHash.length, expectedHash.length);
|
|
63
|
+
return actualHash.substring(0, compareLength) === expectedHash.substring(0, compareLength);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Verify entire manifest (signature + metadata)
|
|
67
|
+
*/
|
|
68
|
+
export async function verifyManifest(manifest, options = {}) {
|
|
69
|
+
// Validate manifest structure
|
|
70
|
+
if (!manifest.version || manifest.version !== '1.0') {
|
|
71
|
+
return { valid: false, error: 'Unsupported manifest version' };
|
|
72
|
+
}
|
|
73
|
+
if (!manifest.plugin?.slug) {
|
|
74
|
+
return { valid: false, error: 'Missing plugin slug in manifest' };
|
|
75
|
+
}
|
|
76
|
+
if (!Array.isArray(manifest.skills) || manifest.skills.length === 0) {
|
|
77
|
+
return { valid: false, error: 'Manifest contains no skills' };
|
|
78
|
+
}
|
|
79
|
+
// Validate skill entries
|
|
80
|
+
for (const skill of manifest.skills) {
|
|
81
|
+
if (!skill.slug || !skill.downloadUrl) {
|
|
82
|
+
return { valid: false, error: `Invalid skill entry: ${skill.slug || 'unknown'}` };
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Verify signature unless skipped
|
|
86
|
+
if (!options.skipSignature) {
|
|
87
|
+
const key = getVerificationKey();
|
|
88
|
+
if (!key) {
|
|
89
|
+
// If no key is configured, warn but don't fail
|
|
90
|
+
// This allows installation without signature verification
|
|
91
|
+
return {
|
|
92
|
+
valid: true,
|
|
93
|
+
error: 'Warning: No verification key configured, signature not verified',
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const signatureResult = verifyManifestSignature(manifest, key);
|
|
97
|
+
if (!signatureResult.valid) {
|
|
98
|
+
return signatureResult;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return { valid: true };
|
|
102
|
+
}
|
|
103
|
+
//# sourceMappingURL=plugin-verify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-verify.js","sourceRoot":"","sources":["../../src/lib/plugin-verify.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { PluginConfig } from './plugin-config.js';
|
|
2
|
+
/**
|
|
3
|
+
* Skill API Client
|
|
4
|
+
*
|
|
5
|
+
* Handles HTTP requests for single skill operations.
|
|
6
|
+
*/
|
|
7
|
+
/** Skill info response */
|
|
8
|
+
export interface SkillInfo {
|
|
9
|
+
slug: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string | null;
|
|
12
|
+
category: string | null;
|
|
13
|
+
version: string | null;
|
|
14
|
+
author: string | null;
|
|
15
|
+
riskLevel: string | null;
|
|
16
|
+
qualityScore: number | null;
|
|
17
|
+
pluginPath: string | null;
|
|
18
|
+
}
|
|
19
|
+
/** API Error */
|
|
20
|
+
export declare class SkillApiError extends Error {
|
|
21
|
+
statusCode: number;
|
|
22
|
+
code?: string | undefined;
|
|
23
|
+
constructor(message: string, statusCode: number, code?: string | undefined);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Fetch skill info/details
|
|
27
|
+
*/
|
|
28
|
+
export declare function fetchSkillInfo(config: PluginConfig, skillSlug: string): Promise<SkillInfo>;
|
|
29
|
+
/**
|
|
30
|
+
* Download skill as ZIP
|
|
31
|
+
*/
|
|
32
|
+
export declare function downloadSkillZip(config: PluginConfig, skillSlug: string): Promise<ArrayBuffer>;
|
|
33
|
+
//# sourceMappingURL=skill-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-api.d.ts","sourceRoot":"","sources":["../../src/lib/skill-api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;GAIG;AAEH,0BAA0B;AAC1B,MAAM,WAAW,SAAS;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,gBAAgB;AAChB,qBAAa,aAAc,SAAQ,KAAK;IAG/B,UAAU,EAAE,MAAM;IAClB,IAAI,CAAC,EAAE,MAAM;gBAFpB,OAAO,EAAE,MAAM,EACR,UAAU,EAAE,MAAM,EAClB,IAAI,CAAC,EAAE,MAAM,YAAA;CAKrB;AAgBD;;GAEG;AACH,wBAAsB,cAAc,CACnC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,SAAS,CAAC,CA6BpB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACrC,MAAM,EAAE,YAAY,EACpB,SAAS,EAAE,MAAM,GACf,OAAO,CAAC,WAAW,CAAC,CAgBtB"}
|