@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,282 @@
1
+ /**
2
+ * Progressive disclosure loader for skills
3
+ * Loads skills at different levels of detail
4
+ *
5
+ * @module skills/loader
6
+ */
7
+ import { readFile } from "node:fs/promises";
8
+ import { join, dirname } from "node:path";
9
+ import { SkillError, } from "./types.js";
10
+ // ============================================================================
11
+ // Token Estimation
12
+ // ============================================================================
13
+ /**
14
+ * Rough token estimation (4 chars ≈ 1 token for English text)
15
+ */
16
+ function estimateTokens(text) {
17
+ return Math.ceil(text.length / 4);
18
+ }
19
+ // ============================================================================
20
+ // Progressive Disclosure Loader
21
+ // ============================================================================
22
+ export class SkillLoader {
23
+ /**
24
+ * Load skill content at specified disclosure level
25
+ */
26
+ async loadSkill(skill, level = "full") {
27
+ switch (level) {
28
+ case "metadata":
29
+ return this.loadMetadataOnly(skill);
30
+ case "summary":
31
+ return this.loadSummary(skill);
32
+ case "full":
33
+ return this.loadFull(skill);
34
+ default:
35
+ throw new SkillError("LOAD_ERROR", `Unknown disclosure level: ${level}`, skill.metadata.id);
36
+ }
37
+ }
38
+ /**
39
+ * Load minimal metadata (no content)
40
+ */
41
+ loadMetadataOnly(skill) {
42
+ return {
43
+ usage: skill.metadata.description,
44
+ };
45
+ }
46
+ /**
47
+ * Load summary (quickstart + usage overview)
48
+ */
49
+ loadSummary(skill) {
50
+ return {
51
+ quickstart: skill.content.quickstart,
52
+ usage: skill.content.usage.slice(0, 2000), // First 2000 chars
53
+ };
54
+ }
55
+ /**
56
+ * Load full content
57
+ */
58
+ loadFull(skill) {
59
+ return { ...skill.content };
60
+ }
61
+ /**
62
+ * Load linked file content
63
+ */
64
+ async loadLinkedFile(skill, filePath) {
65
+ const linkedFile = skill.linkedFiles.find((f) => f.path === filePath);
66
+ if (!linkedFile) {
67
+ throw new SkillError("LOAD_ERROR", `Linked file not found: ${filePath}`, skill.metadata.id);
68
+ }
69
+ const fullPath = join(dirname(skill.sourcePath.toString()), filePath);
70
+ try {
71
+ const content = await readFile(fullPath, "utf-8");
72
+ return {
73
+ ...linkedFile,
74
+ content,
75
+ };
76
+ }
77
+ catch (error) {
78
+ throw new SkillError("LOAD_ERROR", `Failed to load linked file: ${error}`, skill.metadata.id, error);
79
+ }
80
+ }
81
+ /**
82
+ * Load all linked files for a skill
83
+ */
84
+ async loadAllLinkedFiles(skill) {
85
+ const results = [];
86
+ for (const linkedFile of skill.linkedFiles) {
87
+ try {
88
+ const loaded = await this.loadLinkedFile(skill, linkedFile.path);
89
+ results.push(loaded);
90
+ }
91
+ catch (error) {
92
+ // Skip files that fail to load
93
+ if (linkedFile.required) {
94
+ throw error;
95
+ }
96
+ }
97
+ }
98
+ return results;
99
+ }
100
+ // ========================================================================
101
+ // Context Engine Integration
102
+ // ========================================================================
103
+ /**
104
+ * Prepare skill content for context injection
105
+ * Respects token limits and disclosure levels
106
+ */
107
+ async prepareForContext(skill, config) {
108
+ const sections = [];
109
+ let content = "";
110
+ let currentTokens = 0;
111
+ // Load content at appropriate level
112
+ const skillContent = await this.loadSkill(skill, config.disclosureLevel);
113
+ // Add header
114
+ const header = `## Skill: ${skill.metadata.name}\n\n`;
115
+ content += header;
116
+ currentTokens += estimateTokens(header);
117
+ // Add sections in priority order
118
+ const sectionsToAdd = [
119
+ { name: "quickstart", content: skillContent.quickstart },
120
+ { name: "usage", content: skillContent.usage },
121
+ { name: "examples", content: skillContent.examples },
122
+ { name: "configuration", content: skillContent.configuration },
123
+ { name: "api", content: skillContent.api },
124
+ ];
125
+ for (const section of sectionsToAdd) {
126
+ if (!section.content)
127
+ continue;
128
+ const sectionHeader = `### ${section.name}\n\n`;
129
+ const sectionTokens = estimateTokens(sectionHeader + section.content);
130
+ if (currentTokens + sectionTokens > config.maxTokens) {
131
+ // Add truncated notice if we're out of tokens
132
+ if (currentTokens < config.maxTokens - 50) {
133
+ const notice = "\n*[Content truncated due to token limits]*\n";
134
+ content += notice;
135
+ }
136
+ break;
137
+ }
138
+ content += sectionHeader + section.content + "\n\n";
139
+ currentTokens += sectionTokens;
140
+ sections.push(section.name);
141
+ }
142
+ // Add linked files if requested and we have room
143
+ if (config.includeLinkedFiles && skill.linkedFiles.length > 0) {
144
+ const linkedHeader = "### Linked Files\n\n";
145
+ const linkedTokens = estimateTokens(linkedHeader);
146
+ if (currentTokens + linkedTokens < config.maxTokens) {
147
+ content += linkedHeader;
148
+ currentTokens += linkedTokens;
149
+ for (const linkedFile of skill.linkedFiles) {
150
+ try {
151
+ const loaded = await this.loadLinkedFile(skill, linkedFile.path);
152
+ const fileContent = `**${linkedFile.path}**:\n\n\`\`\`\n${loaded.content.slice(0, 500)}\n\`\`\`\n\n`;
153
+ const fileTokens = estimateTokens(fileContent);
154
+ if (currentTokens + fileTokens < config.maxTokens) {
155
+ content += fileContent;
156
+ currentTokens += fileTokens;
157
+ sections.push(`linked:${linkedFile.path}`);
158
+ }
159
+ else {
160
+ break;
161
+ }
162
+ }
163
+ catch {
164
+ // Skip files that fail to load
165
+ }
166
+ }
167
+ }
168
+ }
169
+ return {
170
+ skillId: skill.metadata.id,
171
+ content,
172
+ tokenCount: currentTokens,
173
+ sections,
174
+ };
175
+ }
176
+ /**
177
+ * Prepare multiple skills for context
178
+ */
179
+ async prepareMultipleForContext(skills, config) {
180
+ const results = [];
181
+ let remainingTokens = config.maxTokens;
182
+ for (const skill of skills) {
183
+ const skillConfig = {
184
+ ...config,
185
+ maxTokens: Math.floor(remainingTokens / (skills.length - results.length)),
186
+ };
187
+ try {
188
+ const prepared = await this.prepareForContext(skill, skillConfig);
189
+ results.push(prepared);
190
+ remainingTokens -= prepared.tokenCount;
191
+ }
192
+ catch (error) {
193
+ // Log error but continue with other skills
194
+ console.warn(`Failed to prepare skill ${skill.metadata.id} for context:`, error);
195
+ }
196
+ }
197
+ return results;
198
+ }
199
+ // ========================================================================
200
+ // Smart Loading
201
+ // ========================================================================
202
+ /**
203
+ * Intelligently load skill based on query context
204
+ */
205
+ async loadForQuery(skill, query) {
206
+ const queryLower = query.toLowerCase();
207
+ // Check if query matches specific sections
208
+ if (queryLower.includes("config") ||
209
+ queryLower.includes("setup") ||
210
+ queryLower.includes("env")) {
211
+ return {
212
+ usage: skill.content.usage,
213
+ quickstart: skill.content.quickstart,
214
+ examples: skill.content.examples,
215
+ configuration: skill.content.configuration,
216
+ environment: skill.content.environment,
217
+ api: skill.content.api,
218
+ troubleshooting: skill.content.troubleshooting,
219
+ };
220
+ }
221
+ if (queryLower.includes("example") ||
222
+ queryLower.includes("demo") ||
223
+ queryLower.includes("how to")) {
224
+ return {
225
+ usage: skill.content.usage,
226
+ quickstart: skill.content.quickstart,
227
+ examples: skill.content.examples,
228
+ configuration: skill.content.configuration,
229
+ environment: skill.content.environment,
230
+ api: skill.content.api,
231
+ troubleshooting: skill.content.troubleshooting,
232
+ };
233
+ }
234
+ if (queryLower.includes("api") ||
235
+ queryLower.includes("reference") ||
236
+ queryLower.includes("function")) {
237
+ return {
238
+ usage: skill.content.usage,
239
+ quickstart: skill.content.quickstart,
240
+ examples: skill.content.examples,
241
+ configuration: skill.content.configuration,
242
+ environment: skill.content.environment,
243
+ api: skill.content.api,
244
+ troubleshooting: skill.content.troubleshooting,
245
+ };
246
+ }
247
+ if (queryLower.includes("troubleshoot") ||
248
+ queryLower.includes("error") ||
249
+ queryLower.includes("fix")) {
250
+ return {
251
+ usage: skill.content.usage,
252
+ quickstart: skill.content.quickstart,
253
+ examples: skill.content.examples,
254
+ configuration: skill.content.configuration,
255
+ environment: skill.content.environment,
256
+ api: skill.content.api,
257
+ troubleshooting: skill.content.troubleshooting,
258
+ };
259
+ }
260
+ // Default to summary
261
+ return this.loadSummary(skill);
262
+ }
263
+ }
264
+ // ============================================================================
265
+ // Singleton Instance
266
+ // ============================================================================
267
+ let globalLoader = null;
268
+ /**
269
+ * Get or create global loader instance
270
+ */
271
+ export function getLoader() {
272
+ if (!globalLoader) {
273
+ globalLoader = new SkillLoader();
274
+ }
275
+ return globalLoader;
276
+ }
277
+ /**
278
+ * Reset global loader
279
+ */
280
+ export function resetLoader() {
281
+ globalLoader = null;
282
+ }