@skilltap/core 0.5.5 → 0.5.7
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/package.json +1 -1
- package/src/git.ts +8 -0
- package/src/install.ts +10 -3
- package/src/security/semantic.ts +8 -2
package/package.json
CHANGED
package/src/git.ts
CHANGED
|
@@ -59,6 +59,14 @@ export async function clone(
|
|
|
59
59
|
),
|
|
60
60
|
);
|
|
61
61
|
}
|
|
62
|
+
if (stderr.includes("Permission denied") || stderr.includes("Could not read from remote repository")) {
|
|
63
|
+
return err(
|
|
64
|
+
new GitError(
|
|
65
|
+
`Repository not found or SSH access denied: '${url}'.`,
|
|
66
|
+
"Check that the repository exists and your SSH key is configured correctly.",
|
|
67
|
+
),
|
|
68
|
+
);
|
|
69
|
+
}
|
|
62
70
|
if (stderr.includes("not found") || stderr.includes("does not exist")) {
|
|
63
71
|
return err(new GitError(`Repository not found: '${url}'.`));
|
|
64
72
|
}
|
package/src/install.ts
CHANGED
|
@@ -63,8 +63,12 @@ export type InstallOptions = {
|
|
|
63
63
|
) => Promise<boolean>;
|
|
64
64
|
/** Called after static scan finds warnings — "Run semantic scan?" prompt. */
|
|
65
65
|
onOfferSemantic?: () => Promise<boolean>;
|
|
66
|
-
/** Called
|
|
67
|
-
|
|
66
|
+
/** Called when static scan begins for a skill. */
|
|
67
|
+
onStaticScanStart?: (skillName: string) => void;
|
|
68
|
+
/** Called when semantic scan begins for a skill. */
|
|
69
|
+
onSemanticScanStart?: (skillName: string) => void;
|
|
70
|
+
/** Called after each chunk is evaluated during semantic scan. */
|
|
71
|
+
onSemanticProgress?: (completed: number, total: number, score: number, reason: string) => void;
|
|
68
72
|
/** Called after all scans pass cleanly, before placement. Return false to cancel. */
|
|
69
73
|
onConfirmInstall?: (skillNames: string[]) => Promise<boolean>;
|
|
70
74
|
/** Called when a skill is already installed. Return "update" to update it instead, or "abort" to cancel. */
|
|
@@ -159,9 +163,11 @@ async function resolveTapName(
|
|
|
159
163
|
async function runSecurityScan(
|
|
160
164
|
selected: ScannedSkill[],
|
|
161
165
|
onWarnings?: InstallOptions["onWarnings"],
|
|
166
|
+
onStaticScanStart?: InstallOptions["onStaticScanStart"],
|
|
162
167
|
): Promise<Result<StaticWarning[], ScanError | UserError>> {
|
|
163
168
|
const allWarnings: StaticWarning[] = [];
|
|
164
169
|
for (const skill of selected) {
|
|
170
|
+
onStaticScanStart?.(skill.name);
|
|
165
171
|
const scanResult = await scanStatic(skill.path);
|
|
166
172
|
if (!scanResult.ok) return scanResult;
|
|
167
173
|
if (scanResult.value.length > 0) {
|
|
@@ -501,7 +507,7 @@ export async function installSkill(
|
|
|
501
507
|
|
|
502
508
|
// 6.5. Security scan (unless skipped)
|
|
503
509
|
if (!options.skipScan) {
|
|
504
|
-
const scanResult = await runSecurityScan(selected, options.onWarnings);
|
|
510
|
+
const scanResult = await runSecurityScan(selected, options.onWarnings, options.onStaticScanStart);
|
|
505
511
|
if (!scanResult.ok) return scanResult;
|
|
506
512
|
allWarnings.push(...scanResult.value);
|
|
507
513
|
}
|
|
@@ -515,6 +521,7 @@ export async function installSkill(
|
|
|
515
521
|
|
|
516
522
|
if (shouldRunSemantic && !options.skipScan && options.agent) {
|
|
517
523
|
for (const skill of selected) {
|
|
524
|
+
options.onSemanticScanStart?.(skill.name);
|
|
518
525
|
const semResult = await scanSemantic(skill.path, options.agent, {
|
|
519
526
|
threshold: options.threshold,
|
|
520
527
|
onProgress: options.onSemanticProgress,
|
package/src/security/semantic.ts
CHANGED
|
@@ -18,7 +18,8 @@ export type SemanticWarning = {
|
|
|
18
18
|
|
|
19
19
|
export type SemanticScanOptions = {
|
|
20
20
|
threshold?: number;
|
|
21
|
-
|
|
21
|
+
onScanStart?: (total: number) => void;
|
|
22
|
+
onProgress?: (completed: number, total: number, score: number, reason: string) => void;
|
|
22
23
|
};
|
|
23
24
|
|
|
24
25
|
// ── Constants ──
|
|
@@ -141,6 +142,8 @@ export async function scanSemantic(
|
|
|
141
142
|
const chunks = await chunkSkillDir(dir);
|
|
142
143
|
if (chunks.length === 0) return ok([]);
|
|
143
144
|
|
|
145
|
+
opts?.onScanStart?.(chunks.length);
|
|
146
|
+
|
|
144
147
|
const randomSuffix = randomBytes(4).toString("hex");
|
|
145
148
|
const warnings: SemanticWarning[] = [];
|
|
146
149
|
|
|
@@ -175,10 +178,10 @@ export async function scanSemantic(
|
|
|
175
178
|
const result = await adapter.invoke(prompt);
|
|
176
179
|
|
|
177
180
|
completed++;
|
|
178
|
-
opts?.onProgress?.(completed, chunks.length);
|
|
179
181
|
|
|
180
182
|
if (result.ok) {
|
|
181
183
|
const { score, reason } = result.value;
|
|
184
|
+
opts?.onProgress?.(completed, chunks.length, score, reason);
|
|
182
185
|
if (score >= threshold) {
|
|
183
186
|
warnings.push({
|
|
184
187
|
file: chunk.file,
|
|
@@ -189,6 +192,9 @@ export async function scanSemantic(
|
|
|
189
192
|
raw: truncateRaw(chunk.content),
|
|
190
193
|
});
|
|
191
194
|
}
|
|
195
|
+
} else {
|
|
196
|
+
// Invoke failed — advance progress with score 0
|
|
197
|
+
opts?.onProgress?.(completed, chunks.length, 0, "");
|
|
192
198
|
}
|
|
193
199
|
// If invoke fails, treat as score 0 — skip (fail open)
|
|
194
200
|
},
|