@poolzin/pool-bot 2026.3.7 → 2026.3.9
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/CHANGELOG.md +16 -0
- package/dist/.buildstamp +1 -1
- package/dist/agents/error-classifier.js +302 -0
- package/dist/agents/skills/security.js +217 -0
- package/dist/build-info.json +3 -3
- package/dist/cli/lazy-commands.example.js +113 -0
- package/dist/cli/lazy-commands.js +329 -0
- package/dist/cli/program/command-registry.js +13 -0
- package/dist/cli/program/register.skills.js +4 -0
- package/dist/config/config.js +1 -0
- package/dist/config/secrets-integration.js +88 -0
- package/dist/context-engine/index.js +33 -0
- package/dist/context-engine/legacy.js +181 -0
- package/dist/context-engine/registry.js +86 -0
- package/dist/context-engine/summarizing.js +293 -0
- package/dist/context-engine/types.js +7 -0
- package/dist/infra/abort-pattern.js +106 -0
- package/dist/infra/retry.js +94 -0
- package/dist/secrets/index.js +28 -0
- package/dist/secrets/resolver.js +185 -0
- package/dist/secrets/runtime.js +142 -0
- package/dist/secrets/types.js +11 -0
- package/dist/security/dangerous-tools.js +80 -0
- package/dist/security/types.js +12 -0
- package/dist/skills/commands.js +351 -0
- package/dist/skills/index.js +167 -0
- package/dist/skills/loader.js +282 -0
- package/dist/skills/parser.js +461 -0
- package/dist/skills/registry.js +397 -0
- package/dist/skills/security.js +318 -0
- package/dist/skills/types.js +21 -0
- package/dist/test-utils/index.js +219 -0
- package/dist/tui/index.js +595 -0
- package/docs/INTEGRATION_PLAN.md +475 -0
- package/docs/INTEGRATION_SUMMARY.md +215 -0
- package/docs/integrations/HEXSTRIKE_PLAN.md +796 -0
- package/docs/integrations/INTEGRATION_PLAN.md +424 -0
- package/docs/integrations/PAGE_AGENT_PLAN.md +370 -0
- package/docs/integrations/XYOPS_PLAN.md +978 -0
- package/docs/skills/IMPLEMENTATION_SUMMARY.md +145 -0
- package/docs/skills/SKILL.md +524 -0
- package/docs/skills.md +405 -0
- package/package.json +1 -1
- package/skills/example-skill/SKILL.md +195 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI commands for skills management
|
|
3
|
+
* Provides poolbot skills subcommands
|
|
4
|
+
*
|
|
5
|
+
* @module skills/commands
|
|
6
|
+
*/
|
|
7
|
+
import { SkillError, } from "./types.js";
|
|
8
|
+
import { getRegistry } from "./registry.js";
|
|
9
|
+
import { getLoader } from "./loader.js";
|
|
10
|
+
import { formatFindings, getSecuritySummary } from "./security.js";
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// Command Registration
|
|
13
|
+
// ============================================================================
|
|
14
|
+
/**
|
|
15
|
+
* Register skills commands with CLI
|
|
16
|
+
*/
|
|
17
|
+
export function registerSkillsCommands(program) {
|
|
18
|
+
const mods = program
|
|
19
|
+
.command("mods")
|
|
20
|
+
.description("Manage capability modules (SKILL.md files)");
|
|
21
|
+
// List command
|
|
22
|
+
mods
|
|
23
|
+
.command("list")
|
|
24
|
+
.description("List all available skills")
|
|
25
|
+
.option("-c, --category <category>", "Filter by category")
|
|
26
|
+
.option("-t, --tag <tag>", "Filter by tag")
|
|
27
|
+
.option("-e, --enabled", "Show only enabled skills")
|
|
28
|
+
.option("--disabled", "Show only disabled skills")
|
|
29
|
+
.option("-j, --json", "Output as JSON")
|
|
30
|
+
.action(listCommand);
|
|
31
|
+
// View command
|
|
32
|
+
mods
|
|
33
|
+
.command("view <id>")
|
|
34
|
+
.description("View skill details")
|
|
35
|
+
.option("-l, --level <level>", "Disclosure level (metadata|summary|full)", "full")
|
|
36
|
+
.option("--no-linked", "Skip linked files")
|
|
37
|
+
.option("--security", "Include security report")
|
|
38
|
+
.action(viewCommand);
|
|
39
|
+
// Search command
|
|
40
|
+
mods
|
|
41
|
+
.command("search <query>")
|
|
42
|
+
.description("Search skills by name, description, or tags")
|
|
43
|
+
.option("-c, --category <category>", "Filter by category")
|
|
44
|
+
.action(searchCommand);
|
|
45
|
+
// Enable/disable commands
|
|
46
|
+
mods
|
|
47
|
+
.command("enable <id>")
|
|
48
|
+
.description("Enable a skill")
|
|
49
|
+
.action(enableCommand);
|
|
50
|
+
mods
|
|
51
|
+
.command("disable <id>")
|
|
52
|
+
.description("Disable a skill")
|
|
53
|
+
.action(disableCommand);
|
|
54
|
+
// Scan command
|
|
55
|
+
mods
|
|
56
|
+
.command("scan [path]")
|
|
57
|
+
.description("Scan for skills in directory")
|
|
58
|
+
.action(scanCommand);
|
|
59
|
+
// Stats command
|
|
60
|
+
mods
|
|
61
|
+
.command("stats")
|
|
62
|
+
.description("Show skill statistics")
|
|
63
|
+
.action(statsCommand);
|
|
64
|
+
}
|
|
65
|
+
// ============================================================================
|
|
66
|
+
// Command Implementations
|
|
67
|
+
// ============================================================================
|
|
68
|
+
/**
|
|
69
|
+
* Ensure registry is initialized with default paths
|
|
70
|
+
*/
|
|
71
|
+
async function ensureRegistry() {
|
|
72
|
+
const registry = getRegistry({
|
|
73
|
+
localPaths: ["./skills", "./src/skills"],
|
|
74
|
+
autoScan: true,
|
|
75
|
+
});
|
|
76
|
+
// Auto-scan if empty
|
|
77
|
+
if (registry.getStats().total === 0) {
|
|
78
|
+
await registry.scan();
|
|
79
|
+
}
|
|
80
|
+
return registry;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* List skills command
|
|
84
|
+
*/
|
|
85
|
+
async function listCommand(options) {
|
|
86
|
+
const registry = await ensureRegistry();
|
|
87
|
+
const filters = {};
|
|
88
|
+
if (options.category)
|
|
89
|
+
filters.category = options.category;
|
|
90
|
+
if (options.tag)
|
|
91
|
+
filters.tags = [options.tag];
|
|
92
|
+
if (options.enabled)
|
|
93
|
+
filters.enabledOnly = true;
|
|
94
|
+
if (options.disabled) {
|
|
95
|
+
// Invert - show only disabled
|
|
96
|
+
const all = registry.getAllRefs();
|
|
97
|
+
const disabled = all.filter((s) => !s.enabled);
|
|
98
|
+
if (options.json) {
|
|
99
|
+
console.log(JSON.stringify(disabled, null, 2));
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
printSkillTable(disabled);
|
|
103
|
+
}
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const result = registry.search(filters);
|
|
107
|
+
if (options.json) {
|
|
108
|
+
console.log(JSON.stringify(result.skills, null, 2));
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
printSkillTable(result.skills);
|
|
112
|
+
if (result.total > result.skills.length) {
|
|
113
|
+
console.log(`\nShowing ${result.skills.length} of ${result.total} skills`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* View skill command
|
|
119
|
+
*/
|
|
120
|
+
async function viewCommand(id, options) {
|
|
121
|
+
const registry = await ensureRegistry();
|
|
122
|
+
const loader = getLoader();
|
|
123
|
+
const skill = registry.get(id);
|
|
124
|
+
if (!skill) {
|
|
125
|
+
console.error(`Error: Skill '${id}' not found`);
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
const level = options.level;
|
|
129
|
+
// Print header
|
|
130
|
+
console.log(`\n${"=".repeat(60)}`);
|
|
131
|
+
console.log(` ${skill.metadata.name}`);
|
|
132
|
+
console.log(` ${skill.metadata.description}`);
|
|
133
|
+
console.log(`${"=".repeat(60)}\n`);
|
|
134
|
+
// Print metadata
|
|
135
|
+
console.log("Metadata:");
|
|
136
|
+
console.log(` ID: ${skill.metadata.id}`);
|
|
137
|
+
console.log(` Version: ${skill.metadata.version}`);
|
|
138
|
+
console.log(` Category: ${skill.metadata.category}`);
|
|
139
|
+
console.log(` Author: ${skill.metadata.author || "Unknown"}`);
|
|
140
|
+
console.log(` Tags: ${skill.metadata.tags.join(", ") || "None"}`);
|
|
141
|
+
console.log(` Status: ${skill.enabled ? "Enabled" : "Disabled"}`);
|
|
142
|
+
// Print security status
|
|
143
|
+
const secSummary = skill.securityReport
|
|
144
|
+
? getSecuritySummary(skill.securityReport)
|
|
145
|
+
: { status: "Not scanned", color: "gray", summary: "", counts: {} };
|
|
146
|
+
console.log(` Security: ${secSummary.status}`);
|
|
147
|
+
// Print content based on level
|
|
148
|
+
console.log("\n" + "-".repeat(40));
|
|
149
|
+
if (level === "metadata") {
|
|
150
|
+
console.log("\n[Metadata only - use --level summary or full for content]");
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const content = await loader.loadSkill(skill, level);
|
|
154
|
+
if (content.quickstart) {
|
|
155
|
+
console.log("\n## Quick Start\n");
|
|
156
|
+
console.log(content.quickstart);
|
|
157
|
+
}
|
|
158
|
+
if (content.usage) {
|
|
159
|
+
console.log("\n## Usage\n");
|
|
160
|
+
console.log(content.usage);
|
|
161
|
+
}
|
|
162
|
+
if (level === "full") {
|
|
163
|
+
if (content.examples) {
|
|
164
|
+
console.log("\n## Examples\n");
|
|
165
|
+
console.log(content.examples);
|
|
166
|
+
}
|
|
167
|
+
if (content.configuration) {
|
|
168
|
+
console.log("\n## Configuration\n");
|
|
169
|
+
console.log(content.configuration);
|
|
170
|
+
}
|
|
171
|
+
if (content.environment) {
|
|
172
|
+
console.log("\n## Environment Variables\n");
|
|
173
|
+
console.log(content.environment);
|
|
174
|
+
}
|
|
175
|
+
if (content.api) {
|
|
176
|
+
console.log("\n## API Reference\n");
|
|
177
|
+
console.log(content.api);
|
|
178
|
+
}
|
|
179
|
+
if (content.troubleshooting) {
|
|
180
|
+
console.log("\n## Troubleshooting\n");
|
|
181
|
+
console.log(content.troubleshooting);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// Print linked files
|
|
185
|
+
if (options.linked !== false && skill.linkedFiles.length > 0) {
|
|
186
|
+
console.log("\n## Linked Files\n");
|
|
187
|
+
for (const file of skill.linkedFiles) {
|
|
188
|
+
console.log(` - ${file.path}${file.required ? " (required)" : ""}`);
|
|
189
|
+
if (options.linked && level === "full") {
|
|
190
|
+
try {
|
|
191
|
+
const loaded = await loader.loadLinkedFile(skill, file.path);
|
|
192
|
+
console.log("\n```");
|
|
193
|
+
console.log(loaded.content.slice(0, 500));
|
|
194
|
+
if (loaded.content.length > 500) {
|
|
195
|
+
console.log("\n... [truncated]");
|
|
196
|
+
}
|
|
197
|
+
console.log("```\n");
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
console.log(` [Error loading: ${error}]`);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Print security report
|
|
206
|
+
if (options.security && skill.securityReport) {
|
|
207
|
+
console.log("\n## Security Report\n");
|
|
208
|
+
console.log(`Scanner: ${skill.securityReport.scannerVersion}`);
|
|
209
|
+
console.log(`Scanned: ${skill.securityReport.scannedAt.toISOString()}`);
|
|
210
|
+
console.log(`Result: ${getSecuritySummary(skill.securityReport).status}\n`);
|
|
211
|
+
const findings = formatFindings(skill.securityReport.findings);
|
|
212
|
+
for (const line of findings) {
|
|
213
|
+
console.log(line);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Search skills command
|
|
219
|
+
*/
|
|
220
|
+
async function searchCommand(query, options) {
|
|
221
|
+
const registry = await ensureRegistry();
|
|
222
|
+
const filters = {
|
|
223
|
+
query,
|
|
224
|
+
};
|
|
225
|
+
if (options.category)
|
|
226
|
+
filters.category = options.category;
|
|
227
|
+
const result = registry.search(filters);
|
|
228
|
+
if (result.skills.length === 0) {
|
|
229
|
+
console.log(`No skills found matching '${query}'`);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
console.log(`\nFound ${result.total} skill(s) matching '${query}':\n`);
|
|
233
|
+
printSkillTable(result.skills);
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Enable skill command
|
|
237
|
+
*/
|
|
238
|
+
async function enableCommand(id) {
|
|
239
|
+
const registry = await ensureRegistry();
|
|
240
|
+
try {
|
|
241
|
+
const success = registry.enable(id);
|
|
242
|
+
if (success) {
|
|
243
|
+
console.log(`✓ Skill '${id}' enabled`);
|
|
244
|
+
}
|
|
245
|
+
else {
|
|
246
|
+
console.error(`Error: Skill '${id}' not found`);
|
|
247
|
+
process.exit(1);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
catch (error) {
|
|
251
|
+
if (error instanceof SkillError) {
|
|
252
|
+
console.error(`Error: ${error.message}`);
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
throw error;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Disable skill command
|
|
260
|
+
*/
|
|
261
|
+
async function disableCommand(id) {
|
|
262
|
+
const registry = await ensureRegistry();
|
|
263
|
+
const success = registry.disable(id);
|
|
264
|
+
if (success) {
|
|
265
|
+
console.log(`✓ Skill '${id}' disabled`);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
console.error(`Error: Skill '${id}' not found`);
|
|
269
|
+
process.exit(1);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Scan directory for skills
|
|
274
|
+
*/
|
|
275
|
+
async function scanCommand(path) {
|
|
276
|
+
const registry = await ensureRegistry();
|
|
277
|
+
const scanPath = path || "./skills";
|
|
278
|
+
console.log(`Scanning ${scanPath} for skills...\n`);
|
|
279
|
+
try {
|
|
280
|
+
const { loaded, errors } = await registry.scan();
|
|
281
|
+
console.log(`Loaded ${loaded} skill(s)`);
|
|
282
|
+
if (errors.length > 0) {
|
|
283
|
+
console.log(`\n${errors.length} error(s):`);
|
|
284
|
+
for (const error of errors) {
|
|
285
|
+
console.log(` - ${error.message}`);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
catch (error) {
|
|
290
|
+
console.error(`Scan failed: ${error}`);
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Show skill statistics
|
|
296
|
+
*/
|
|
297
|
+
async function statsCommand() {
|
|
298
|
+
const registry = await ensureRegistry();
|
|
299
|
+
const stats = registry.getStats();
|
|
300
|
+
console.log("\nSkill Statistics");
|
|
301
|
+
console.log("=".repeat(40));
|
|
302
|
+
console.log(`\nTotal Skills: ${stats.total}`);
|
|
303
|
+
console.log(`Enabled: ${stats.enabled}`);
|
|
304
|
+
console.log(`Disabled: ${stats.disabled}`);
|
|
305
|
+
console.log("\nBy Category:");
|
|
306
|
+
for (const [category, count] of Object.entries(stats.byCategory)) {
|
|
307
|
+
console.log(` ${category.padEnd(15)} ${count}`);
|
|
308
|
+
}
|
|
309
|
+
console.log("\nBy Verification:");
|
|
310
|
+
for (const [status, count] of Object.entries(stats.byVerification)) {
|
|
311
|
+
console.log(` ${status.padEnd(15)} ${count}`);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// ============================================================================
|
|
315
|
+
// Helpers
|
|
316
|
+
// ============================================================================
|
|
317
|
+
/**
|
|
318
|
+
* Print skills as formatted table
|
|
319
|
+
*/
|
|
320
|
+
function printSkillTable(skills) {
|
|
321
|
+
if (skills.length === 0) {
|
|
322
|
+
console.log("No skills found.");
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
// Calculate column widths
|
|
326
|
+
const idWidth = Math.max(10, ...skills.map((s) => s.id.length));
|
|
327
|
+
const nameWidth = Math.max(15, ...skills.map((s) => s.name.length));
|
|
328
|
+
const catWidth = Math.max(10, ...skills.map((s) => s.category.length));
|
|
329
|
+
const verWidth = 8;
|
|
330
|
+
// Header
|
|
331
|
+
console.log(`${"ID".padEnd(idWidth)} ${"Name".padEnd(nameWidth)} ${"Category".padEnd(catWidth)} ${"Version".padEnd(verWidth)} Status`);
|
|
332
|
+
console.log("-".repeat(idWidth + nameWidth + catWidth + verWidth + 20));
|
|
333
|
+
// Rows
|
|
334
|
+
for (const skill of skills) {
|
|
335
|
+
const status = skill.enabled ? "✓" : "○";
|
|
336
|
+
const secIcon = skill.verification === "failed"
|
|
337
|
+
? "⚠"
|
|
338
|
+
: skill.verification === "warning"
|
|
339
|
+
? "!"
|
|
340
|
+
: " ";
|
|
341
|
+
console.log(`${skill.id.slice(0, idWidth).padEnd(idWidth)} ` +
|
|
342
|
+
`${skill.name.slice(0, nameWidth).padEnd(nameWidth)} ` +
|
|
343
|
+
`${skill.category.padEnd(catWidth)} ` +
|
|
344
|
+
`${skill.version.padEnd(verWidth)} ` +
|
|
345
|
+
`${status}${secIcon}`);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// ============================================================================
|
|
349
|
+
// Export for testing
|
|
350
|
+
// ============================================================================
|
|
351
|
+
export { listCommand, viewCommand, searchCommand, enableCommand, disableCommand, scanCommand, statsCommand, };
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PoolBot Skills System
|
|
3
|
+
*
|
|
4
|
+
* A modular skill management system compatible with agentskills.io.
|
|
5
|
+
* Provides progressive disclosure, security scanning, and context engine integration.
|
|
6
|
+
*
|
|
7
|
+
* @module skills
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { getRegistry, getLoader, scanSkill } from './skills/index.js';
|
|
11
|
+
*
|
|
12
|
+
* // Scan for skills
|
|
13
|
+
* const registry = getRegistry({ localPaths: ['./skills'] });
|
|
14
|
+
* await registry.scan();
|
|
15
|
+
*
|
|
16
|
+
* // Load a skill with progressive disclosure
|
|
17
|
+
* const loader = getLoader();
|
|
18
|
+
* const skill = registry.get('my-skill');
|
|
19
|
+
* const content = await loader.loadSkill(skill, 'summary');
|
|
20
|
+
*
|
|
21
|
+
* // Security scan
|
|
22
|
+
* const report = await scanSkill(skill);
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Types
|
|
27
|
+
// ============================================================================
|
|
28
|
+
export {
|
|
29
|
+
// Errors
|
|
30
|
+
SkillError, } from './types.js';
|
|
31
|
+
// ============================================================================
|
|
32
|
+
// Parser
|
|
33
|
+
// ============================================================================
|
|
34
|
+
export { parseSkill, parseSkillFile, parseSkills, isSkillFile, extractSkillId, parseYaml, parseSections, validateMetadata, extractContent, } from './parser.js';
|
|
35
|
+
// ============================================================================
|
|
36
|
+
// Registry
|
|
37
|
+
// ============================================================================
|
|
38
|
+
export { SkillsRegistry, getRegistry, resetRegistry, } from './registry.js';
|
|
39
|
+
// ============================================================================
|
|
40
|
+
// Loader
|
|
41
|
+
// ============================================================================
|
|
42
|
+
export { SkillLoader, getLoader, resetLoader, } from './loader.js';
|
|
43
|
+
// ============================================================================
|
|
44
|
+
// Security
|
|
45
|
+
// ============================================================================
|
|
46
|
+
export { scanSkill, quickSecurityCheck, getSecuritySummary, formatFindings, PATTERNS, } from './security.js';
|
|
47
|
+
// ============================================================================
|
|
48
|
+
// Commands
|
|
49
|
+
// ============================================================================
|
|
50
|
+
export { registerSkillsCommands, listCommand, viewCommand, searchCommand, enableCommand, disableCommand, scanCommand, statsCommand, } from './commands.js';
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Context Integration (Future Enhancement)
|
|
53
|
+
// ============================================================================
|
|
54
|
+
// Note: Context engine integration will be implemented in a future phase
|
|
55
|
+
// to avoid circular dependencies with the context-engine module.
|
|
56
|
+
// ============================================================================
|
|
57
|
+
// Constants
|
|
58
|
+
// ============================================================================
|
|
59
|
+
/**
|
|
60
|
+
* Current skills system version
|
|
61
|
+
*/
|
|
62
|
+
export const SKILLS_VERSION = '1.0.0';
|
|
63
|
+
/**
|
|
64
|
+
* Default skill directories
|
|
65
|
+
*/
|
|
66
|
+
export const DEFAULT_SKILL_PATHS = [
|
|
67
|
+
'./skills',
|
|
68
|
+
'~/.poolbot/skills',
|
|
69
|
+
];
|
|
70
|
+
// ============================================================================
|
|
71
|
+
// Convenience Functions
|
|
72
|
+
// ============================================================================
|
|
73
|
+
import { getRegistry } from './registry.js';
|
|
74
|
+
import { getLoader } from './loader.js';
|
|
75
|
+
import { scanSkill } from './security.js';
|
|
76
|
+
/**
|
|
77
|
+
* Quick skill lookup by ID
|
|
78
|
+
*/
|
|
79
|
+
export function getSkill(id) {
|
|
80
|
+
return getRegistry().get(id);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* List all available skills
|
|
84
|
+
*/
|
|
85
|
+
export function listSkills() {
|
|
86
|
+
return getRegistry().getAllRefs();
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Search skills
|
|
90
|
+
*/
|
|
91
|
+
export function searchSkills(query) {
|
|
92
|
+
return getRegistry().search({ query });
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Enable a skill
|
|
96
|
+
*/
|
|
97
|
+
export function enableSkill(id) {
|
|
98
|
+
return getRegistry().enable(id);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Disable a skill
|
|
102
|
+
*/
|
|
103
|
+
export function disableSkill(id) {
|
|
104
|
+
return getRegistry().disable(id);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Get skill content for context injection
|
|
108
|
+
*/
|
|
109
|
+
export async function getSkillForContext(skillId, config = {}) {
|
|
110
|
+
const registry = getRegistry();
|
|
111
|
+
const loader = getLoader();
|
|
112
|
+
const skill = registry.get(skillId);
|
|
113
|
+
if (!skill || !skill.enabled)
|
|
114
|
+
return null;
|
|
115
|
+
const fullConfig = {
|
|
116
|
+
skillIds: [skillId],
|
|
117
|
+
maxTokens: 4000,
|
|
118
|
+
disclosureLevel: 'summary',
|
|
119
|
+
includeLinkedFiles: false,
|
|
120
|
+
...config,
|
|
121
|
+
};
|
|
122
|
+
return loader.prepareForContext(skill, fullConfig);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Run security scan on a skill
|
|
126
|
+
*/
|
|
127
|
+
export async function securityScanSkill(skillId) {
|
|
128
|
+
const registry = getRegistry();
|
|
129
|
+
const skill = registry.get(skillId);
|
|
130
|
+
if (!skill)
|
|
131
|
+
return null;
|
|
132
|
+
const report = await scanSkill(skill);
|
|
133
|
+
skill.securityReport = report;
|
|
134
|
+
skill.verification = report.result;
|
|
135
|
+
return report;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Initialize the skills system
|
|
139
|
+
*
|
|
140
|
+
* @param config - Registry configuration
|
|
141
|
+
* @returns Promise that resolves when initialization is complete
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* import { initSkills } from './skills/index.js';
|
|
146
|
+
*
|
|
147
|
+
* await initSkills({
|
|
148
|
+
* localPaths: ['./my-skills'],
|
|
149
|
+
* autoScan: true,
|
|
150
|
+
* });
|
|
151
|
+
* ```
|
|
152
|
+
*/
|
|
153
|
+
export async function initSkills(config) {
|
|
154
|
+
const registry = getRegistry(config);
|
|
155
|
+
if (config?.localPaths?.length) {
|
|
156
|
+
await registry.scan();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Reset the skills system (useful for testing)
|
|
161
|
+
*/
|
|
162
|
+
export function resetSkills() {
|
|
163
|
+
const { resetRegistry } = require('./registry.js');
|
|
164
|
+
const { resetLoader } = require('./loader.js');
|
|
165
|
+
resetRegistry();
|
|
166
|
+
resetLoader();
|
|
167
|
+
}
|