@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,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
|
+
}
|