@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.
Files changed (44) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/.buildstamp +1 -1
  3. package/dist/agents/error-classifier.js +302 -0
  4. package/dist/agents/skills/security.js +217 -0
  5. package/dist/build-info.json +3 -3
  6. package/dist/cli/lazy-commands.example.js +113 -0
  7. package/dist/cli/lazy-commands.js +329 -0
  8. package/dist/cli/program/command-registry.js +13 -0
  9. package/dist/cli/program/register.skills.js +4 -0
  10. package/dist/config/config.js +1 -0
  11. package/dist/config/secrets-integration.js +88 -0
  12. package/dist/context-engine/index.js +33 -0
  13. package/dist/context-engine/legacy.js +181 -0
  14. package/dist/context-engine/registry.js +86 -0
  15. package/dist/context-engine/summarizing.js +293 -0
  16. package/dist/context-engine/types.js +7 -0
  17. package/dist/infra/abort-pattern.js +106 -0
  18. package/dist/infra/retry.js +94 -0
  19. package/dist/secrets/index.js +28 -0
  20. package/dist/secrets/resolver.js +185 -0
  21. package/dist/secrets/runtime.js +142 -0
  22. package/dist/secrets/types.js +11 -0
  23. package/dist/security/dangerous-tools.js +80 -0
  24. package/dist/security/types.js +12 -0
  25. package/dist/skills/commands.js +351 -0
  26. package/dist/skills/index.js +167 -0
  27. package/dist/skills/loader.js +282 -0
  28. package/dist/skills/parser.js +461 -0
  29. package/dist/skills/registry.js +397 -0
  30. package/dist/skills/security.js +318 -0
  31. package/dist/skills/types.js +21 -0
  32. package/dist/test-utils/index.js +219 -0
  33. package/dist/tui/index.js +595 -0
  34. package/docs/INTEGRATION_PLAN.md +475 -0
  35. package/docs/INTEGRATION_SUMMARY.md +215 -0
  36. package/docs/integrations/HEXSTRIKE_PLAN.md +796 -0
  37. package/docs/integrations/INTEGRATION_PLAN.md +424 -0
  38. package/docs/integrations/PAGE_AGENT_PLAN.md +370 -0
  39. package/docs/integrations/XYOPS_PLAN.md +978 -0
  40. package/docs/skills/IMPLEMENTATION_SUMMARY.md +145 -0
  41. package/docs/skills/SKILL.md +524 -0
  42. package/docs/skills.md +405 -0
  43. package/package.json +1 -1
  44. 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
+ }