kramscan 0.1.0 → 0.2.0
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/README.md +392 -87
- package/dist/agent/confirmation.d.ts +38 -0
- package/dist/agent/confirmation.js +210 -0
- package/dist/agent/context.d.ts +81 -0
- package/dist/agent/context.js +227 -0
- package/dist/agent/index.d.ts +10 -0
- package/dist/agent/index.js +32 -0
- package/dist/agent/orchestrator.d.ts +63 -0
- package/dist/agent/orchestrator.js +370 -0
- package/dist/agent/prompts/system.d.ts +6 -0
- package/dist/agent/prompts/system.js +116 -0
- package/dist/agent/skill-registry.d.ts +78 -0
- package/dist/agent/skill-registry.js +202 -0
- package/dist/agent/skills/analyze-findings.d.ts +22 -0
- package/dist/agent/skills/analyze-findings.js +191 -0
- package/dist/agent/skills/generate-report.d.ts +26 -0
- package/dist/agent/skills/generate-report.js +436 -0
- package/dist/agent/skills/health-check.d.ts +28 -0
- package/dist/agent/skills/health-check.js +344 -0
- package/dist/agent/skills/index.d.ts +9 -0
- package/dist/agent/skills/index.js +17 -0
- package/dist/agent/skills/verify-finding.d.ts +17 -0
- package/dist/agent/skills/verify-finding.js +91 -0
- package/dist/agent/skills/web-scan.d.ts +22 -0
- package/dist/agent/skills/web-scan.js +203 -0
- package/dist/agent/types.d.ts +141 -0
- package/dist/agent/types.js +16 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +176 -139
- package/dist/commands/agent.d.ts +6 -0
- package/dist/commands/agent.js +250 -0
- package/dist/commands/ai.d.ts +2 -0
- package/dist/commands/ai.js +112 -0
- package/dist/commands/analyze.js +104 -55
- package/dist/commands/config.js +63 -37
- package/dist/commands/doctor.js +22 -17
- package/dist/commands/onboard.js +190 -125
- package/dist/commands/report.js +69 -77
- package/dist/commands/scan.js +261 -81
- package/dist/commands/scans.d.ts +2 -0
- package/dist/commands/scans.js +51 -0
- package/dist/core/ai-client.d.ts +7 -2
- package/dist/core/ai-client.js +231 -20
- package/dist/core/ai-payloads.d.ts +17 -0
- package/dist/core/ai-payloads.js +54 -0
- package/dist/core/config-schema.d.ts +197 -0
- package/dist/core/config-schema.js +68 -0
- package/dist/core/config-schema.test.d.ts +1 -0
- package/dist/core/config-schema.test.js +151 -0
- package/dist/core/config.d.ts +17 -36
- package/dist/core/config.js +261 -20
- package/dist/core/errors.d.ts +71 -0
- package/dist/core/errors.js +162 -0
- package/dist/core/scan-index.d.ts +19 -0
- package/dist/core/scan-index.js +52 -0
- package/dist/core/scan-storage.d.ts +11 -0
- package/dist/core/scan-storage.js +69 -0
- package/dist/core/scanner.d.ts +101 -4
- package/dist/core/scanner.js +432 -63
- package/dist/core/vulnerability-detector.d.ts +18 -2
- package/dist/core/vulnerability-detector.js +349 -38
- package/dist/core/vulnerability-detector.test.d.ts +1 -0
- package/dist/core/vulnerability-detector.test.js +210 -0
- package/dist/index.js +3 -0
- package/dist/plugins/PluginManager.d.ts +27 -0
- package/dist/plugins/PluginManager.js +166 -0
- package/dist/plugins/index.d.ts +7 -0
- package/dist/plugins/index.js +19 -0
- package/dist/plugins/types.d.ts +55 -0
- package/dist/plugins/types.js +25 -0
- package/dist/plugins/vulnerabilities/CSRFPlugin.d.ts +8 -0
- package/dist/plugins/vulnerabilities/CSRFPlugin.js +34 -0
- package/dist/plugins/vulnerabilities/SQLInjectionPlugin.d.ts +11 -0
- package/dist/plugins/vulnerabilities/SQLInjectionPlugin.js +109 -0
- package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.d.ts +11 -0
- package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.js +63 -0
- package/dist/plugins/vulnerabilities/SensitiveDataPlugin.d.ts +9 -0
- package/dist/plugins/vulnerabilities/SensitiveDataPlugin.js +32 -0
- package/dist/plugins/vulnerabilities/XSSPlugin.d.ts +15 -0
- package/dist/plugins/vulnerabilities/XSSPlugin.js +81 -0
- package/dist/reports/PdfGenerator.d.ts +36 -0
- package/dist/reports/PdfGenerator.js +379 -0
- package/dist/utils/logger.d.ts +33 -1
- package/dist/utils/logger.js +127 -8
- package/dist/utils/theme.d.ts +55 -0
- package/dist/utils/theme.js +195 -0
- package/package.json +27 -6
- package/dist/core/executor.d.ts +0 -2
- package/dist/core/executor.js +0 -74
- package/dist/core/logger.d.ts +0 -12
- package/dist/core/logger.js +0 -51
- package/dist/core/registry.d.ts +0 -3
- package/dist/core/registry.js +0 -35
- package/dist/core/storage.d.ts +0 -4
- package/dist/core/storage.js +0 -39
- package/dist/core/types.d.ts +0 -24
- package/dist/core/types.js +0 -2
- package/dist/skills/base.d.ts +0 -8
- package/dist/skills/base.js +0 -6
- package/dist/skills/builtin.d.ts +0 -4
- package/dist/skills/builtin.js +0 -71
- package/dist/skills/loader.d.ts +0 -2
- package/dist/skills/loader.js +0 -27
- package/dist/skills/types.d.ts +0 -46
- package/dist/skills/types.js +0 -2
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agent Orchestrator
|
|
4
|
+
* Coordinates AI conversations, tool calling, skill execution, and user interactions
|
|
5
|
+
*/
|
|
6
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
7
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
8
|
+
};
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.AgentOrchestrator = void 0;
|
|
11
|
+
const context_1 = require("./context");
|
|
12
|
+
const confirmation_1 = require("./confirmation");
|
|
13
|
+
const system_1 = require("./prompts/system");
|
|
14
|
+
const types_1 = require("./types");
|
|
15
|
+
const ai_client_1 = require("../core/ai-client");
|
|
16
|
+
const logger_1 = require("../utils/logger");
|
|
17
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
18
|
+
class AgentOrchestrator {
|
|
19
|
+
context;
|
|
20
|
+
skillRegistry;
|
|
21
|
+
confirmationHandler;
|
|
22
|
+
config;
|
|
23
|
+
aiClient = null;
|
|
24
|
+
isRunning = false;
|
|
25
|
+
constructor(skillRegistry, config = {}) {
|
|
26
|
+
this.skillRegistry = skillRegistry;
|
|
27
|
+
this.config = { ...types_1.DEFAULT_AGENT_CONFIG, ...config };
|
|
28
|
+
this.context = new context_1.ConversationContext(this.config);
|
|
29
|
+
this.confirmationHandler = new confirmation_1.ConfirmationHandler();
|
|
30
|
+
}
|
|
31
|
+
setReadlineInterface(rl) {
|
|
32
|
+
this.confirmationHandler.setInterface(rl);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Initialize the orchestrator and AI client
|
|
36
|
+
*/
|
|
37
|
+
async initialize() {
|
|
38
|
+
try {
|
|
39
|
+
this.aiClient = await (0, ai_client_1.createAIClient)();
|
|
40
|
+
logger_1.logger.success("AI client initialized successfully");
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
logger_1.logger.error("Failed to initialize AI client. Run 'kramscan onboard' first.");
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
// Add system message
|
|
47
|
+
this.context.addMessage("system", (0, system_1.getSystemPrompt)());
|
|
48
|
+
// Try to load previous conversation
|
|
49
|
+
await this.context.load();
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Process a user message and generate a response
|
|
53
|
+
*/
|
|
54
|
+
async processUserMessage(userInput) {
|
|
55
|
+
// Add user message to context
|
|
56
|
+
this.context.addMessage("user", userInput);
|
|
57
|
+
// Get AI response
|
|
58
|
+
const aiResponse = await this.getAIResponse();
|
|
59
|
+
// Check for tool calls in the response
|
|
60
|
+
const toolCalls = this.parseToolCalls(aiResponse);
|
|
61
|
+
if (toolCalls.length > 0) {
|
|
62
|
+
// Handle tool execution with confirmation
|
|
63
|
+
return this.handleToolExecution(toolCalls, aiResponse);
|
|
64
|
+
}
|
|
65
|
+
// No tool calls - just return the message
|
|
66
|
+
this.context.addMessage("assistant", aiResponse);
|
|
67
|
+
return {
|
|
68
|
+
message: aiResponse,
|
|
69
|
+
requiresConfirmation: false,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Execute a specific tool/skill directly
|
|
74
|
+
*/
|
|
75
|
+
async executeTool(toolName, parameters, skipConfirmation = false) {
|
|
76
|
+
const toolCall = {
|
|
77
|
+
id: `manual-${Date.now()}`,
|
|
78
|
+
name: toolName,
|
|
79
|
+
arguments: parameters,
|
|
80
|
+
};
|
|
81
|
+
if (!skipConfirmation && this.skillRegistry.requiresConfirmation(toolName)) {
|
|
82
|
+
const confirmation = this.skillRegistry.getConfirmationPrompt(toolCall);
|
|
83
|
+
if (confirmation) {
|
|
84
|
+
const result = await this.confirmationHandler.prompt(confirmation);
|
|
85
|
+
if (result.showDetails) {
|
|
86
|
+
this.confirmationHandler.showDetails(confirmation);
|
|
87
|
+
return {
|
|
88
|
+
message: "Please confirm to proceed after reviewing the details.",
|
|
89
|
+
requiresConfirmation: true,
|
|
90
|
+
pendingAction: {
|
|
91
|
+
toolName,
|
|
92
|
+
description: confirmation.description,
|
|
93
|
+
parameters,
|
|
94
|
+
risk: confirmation.risk,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
if (!result.confirmed || result.cancelled) {
|
|
99
|
+
return {
|
|
100
|
+
message: result.cancelled
|
|
101
|
+
? "Action cancelled."
|
|
102
|
+
: "Action not confirmed. You can ask me to perform this action again when you're ready.",
|
|
103
|
+
requiresConfirmation: false,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Execute the tool
|
|
109
|
+
const result = await this.skillRegistry.execute(toolCall, this.context.getContext());
|
|
110
|
+
// Format response
|
|
111
|
+
const responseMessage = this.formatToolResult(result);
|
|
112
|
+
this.context.addMessage("assistant", responseMessage, [toolCall], [result]);
|
|
113
|
+
// Store scan results if applicable
|
|
114
|
+
if (toolName === "web_scan" && result.success && result.result) {
|
|
115
|
+
this.context.setLastScanResults(result.result);
|
|
116
|
+
const target = parameters.targetUrl;
|
|
117
|
+
this.context.setCurrentTarget(target);
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
message: responseMessage,
|
|
121
|
+
toolCalls: [toolCall],
|
|
122
|
+
toolCallResults: [result],
|
|
123
|
+
requiresConfirmation: false,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get conversation summary
|
|
128
|
+
*/
|
|
129
|
+
getConversationSummary() {
|
|
130
|
+
return this.context.getSummary();
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Clear conversation history
|
|
134
|
+
*/
|
|
135
|
+
clearConversation() {
|
|
136
|
+
this.context.clear();
|
|
137
|
+
this.context.addMessage("system", (0, system_1.getSystemPrompt)());
|
|
138
|
+
logger_1.logger.info("Conversation history cleared");
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Save conversation state
|
|
142
|
+
*/
|
|
143
|
+
async saveState() {
|
|
144
|
+
await this.context.save();
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get available skills list
|
|
148
|
+
*/
|
|
149
|
+
getAvailableSkills() {
|
|
150
|
+
return this.skillRegistry.listSkills();
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Shutdown the orchestrator
|
|
154
|
+
*/
|
|
155
|
+
async shutdown() {
|
|
156
|
+
this.isRunning = false;
|
|
157
|
+
this.confirmationHandler.close();
|
|
158
|
+
await this.saveState();
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Check if orchestrator is running
|
|
162
|
+
*/
|
|
163
|
+
isActive() {
|
|
164
|
+
return this.isRunning;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Start the agent session
|
|
168
|
+
*/
|
|
169
|
+
start() {
|
|
170
|
+
this.isRunning = true;
|
|
171
|
+
}
|
|
172
|
+
// Private methods
|
|
173
|
+
async getAIResponse() {
|
|
174
|
+
if (!this.aiClient) {
|
|
175
|
+
throw new Error("AI client not initialized");
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
const messages = this.context.formatForAI();
|
|
179
|
+
const prompt = this.buildPromptWithTools(messages);
|
|
180
|
+
const response = await this.aiClient.analyze(prompt);
|
|
181
|
+
return response.content;
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
logger_1.logger.error(`Failed to get AI response: ${error}`);
|
|
185
|
+
return "I apologize, but I'm having trouble processing your request right now. Please try again.";
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
buildPromptWithTools(messages) {
|
|
189
|
+
const conversation = messages
|
|
190
|
+
.map((m) => `${m.role}: ${m.content}`)
|
|
191
|
+
.join("\n\n");
|
|
192
|
+
const tools = this.skillRegistry.getToolDefinitions();
|
|
193
|
+
const toolsDescription = tools
|
|
194
|
+
.map((tool) => `
|
|
195
|
+
Tool: ${tool.name}
|
|
196
|
+
Description: ${tool.description}
|
|
197
|
+
Parameters:
|
|
198
|
+
${tool.parameters
|
|
199
|
+
.map((p) => ` - ${p.name} (${p.type}${p.required ? ", required" : ""}): ${p.description}${p.default !== undefined ? ` (default: ${p.default})` : ""}`)
|
|
200
|
+
.join("\n")}
|
|
201
|
+
`)
|
|
202
|
+
.join("\n");
|
|
203
|
+
return `${conversation}
|
|
204
|
+
|
|
205
|
+
Available Tools:
|
|
206
|
+
${toolsDescription}
|
|
207
|
+
|
|
208
|
+
When you need to use a tool, format your response exactly like this:
|
|
209
|
+
|
|
210
|
+
<tool_call>
|
|
211
|
+
{
|
|
212
|
+
"name": "tool_name",
|
|
213
|
+
"arguments": {
|
|
214
|
+
"param1": "value1",
|
|
215
|
+
"param2": "value2"
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
</tool_call>
|
|
219
|
+
|
|
220
|
+
If you don't need a tool, just respond naturally.`;
|
|
221
|
+
}
|
|
222
|
+
parseToolCalls(response) {
|
|
223
|
+
const toolCalls = [];
|
|
224
|
+
const regex = /<tool_call>\s*([\s\S]*?)\s*<\/tool_call>/g;
|
|
225
|
+
let match;
|
|
226
|
+
while ((match = regex.exec(response)) !== null) {
|
|
227
|
+
try {
|
|
228
|
+
const parsed = JSON.parse(match[1]);
|
|
229
|
+
toolCalls.push({
|
|
230
|
+
id: `tool-${Date.now()}-${toolCalls.length}`,
|
|
231
|
+
name: parsed.name,
|
|
232
|
+
arguments: parsed.arguments || {},
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
logger_1.logger.warn(`Failed to parse tool call: ${match[1]}`);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
// Fallback: some models respond with <web_scan> { ...args } </web_scan> blocks.
|
|
240
|
+
// Accept any <toolName>{json}</toolName> where json is either {arguments} or {name, arguments}.
|
|
241
|
+
if (toolCalls.length === 0) {
|
|
242
|
+
const alt = /<([a-zA-Z0-9_]+)>\s*([\s\S]*?)\s*<\/\1>/g;
|
|
243
|
+
let m;
|
|
244
|
+
while ((m = alt.exec(response)) !== null) {
|
|
245
|
+
const tag = m[1];
|
|
246
|
+
if (tag === "tool_call")
|
|
247
|
+
continue;
|
|
248
|
+
try {
|
|
249
|
+
const parsed = JSON.parse(m[2]);
|
|
250
|
+
const name = typeof parsed?.name === "string" ? parsed.name : tag;
|
|
251
|
+
const args = parsed && typeof parsed === "object" && "arguments" in parsed
|
|
252
|
+
? parsed.arguments
|
|
253
|
+
: parsed;
|
|
254
|
+
toolCalls.push({
|
|
255
|
+
id: `tool-${Date.now()}-${toolCalls.length}`,
|
|
256
|
+
name,
|
|
257
|
+
arguments: args || {},
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
// Ignore non-json blocks.
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return toolCalls;
|
|
266
|
+
}
|
|
267
|
+
async handleToolExecution(toolCalls, aiMessage) {
|
|
268
|
+
// Extract message without tool calls
|
|
269
|
+
const skillTags = this.skillRegistry
|
|
270
|
+
.getAll()
|
|
271
|
+
.map((s) => s.id)
|
|
272
|
+
.join("|");
|
|
273
|
+
const toolCallBlock = /<tool_call>[\s\S]*?<\/tool_call>/g;
|
|
274
|
+
const altToolBlocks = skillTags
|
|
275
|
+
? new RegExp(`<(${skillTags})>\\s*[\\s\\S]*?\\s*<\\/\\1>`, "g")
|
|
276
|
+
: null;
|
|
277
|
+
const cleanMessage = aiMessage
|
|
278
|
+
.replace(toolCallBlock, "")
|
|
279
|
+
.replace(altToolBlocks ?? /$^/, "")
|
|
280
|
+
.trim();
|
|
281
|
+
// Check if any tool requires confirmation
|
|
282
|
+
const needsConfirmation = toolCalls.some((call) => this.skillRegistry.requiresConfirmation(call.name));
|
|
283
|
+
if (needsConfirmation && this.config.enableConfirmation) {
|
|
284
|
+
// Get confirmation for first tool (simplify UX)
|
|
285
|
+
const firstTool = toolCalls.find((call) => this.skillRegistry.requiresConfirmation(call.name));
|
|
286
|
+
const confirmation = this.skillRegistry.getConfirmationPrompt(firstTool);
|
|
287
|
+
if (confirmation) {
|
|
288
|
+
const result = await this.confirmationHandler.prompt(confirmation);
|
|
289
|
+
if (result.showDetails) {
|
|
290
|
+
this.confirmationHandler.showDetails(confirmation);
|
|
291
|
+
return {
|
|
292
|
+
message: cleanMessage || "Please review the details and confirm to proceed.",
|
|
293
|
+
requiresConfirmation: true,
|
|
294
|
+
pendingAction: {
|
|
295
|
+
toolName: firstTool.name,
|
|
296
|
+
description: confirmation.description,
|
|
297
|
+
parameters: firstTool.arguments,
|
|
298
|
+
risk: confirmation.risk,
|
|
299
|
+
},
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
if (!result.confirmed) {
|
|
303
|
+
return {
|
|
304
|
+
message: result.cancelled
|
|
305
|
+
? "Action cancelled."
|
|
306
|
+
: "Action not confirmed. Let me know when you're ready to proceed.",
|
|
307
|
+
requiresConfirmation: false,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
// Execute all tools
|
|
313
|
+
console.log(chalk_1.default.gray("\nExecuting tools...\n"));
|
|
314
|
+
const results = await this.skillRegistry.executeBatch(toolCalls, this.context.getContext());
|
|
315
|
+
// Format results
|
|
316
|
+
const resultMessage = results
|
|
317
|
+
.map((result) => this.formatToolResult(result))
|
|
318
|
+
.join("\n\n");
|
|
319
|
+
const fullMessage = cleanMessage
|
|
320
|
+
? `${cleanMessage}\n\n${resultMessage}`
|
|
321
|
+
: resultMessage;
|
|
322
|
+
this.context.addMessage("assistant", fullMessage, toolCalls, results);
|
|
323
|
+
// Update context with scan results
|
|
324
|
+
const scanCall = toolCalls.find((t) => t.name === "web_scan");
|
|
325
|
+
if (scanCall) {
|
|
326
|
+
const scanExec = results.find((r) => r.toolCallId === scanCall.id);
|
|
327
|
+
if (scanExec?.success && scanExec.result) {
|
|
328
|
+
this.context.setLastScanResults(scanExec.result);
|
|
329
|
+
const target = scanCall.arguments.targetUrl;
|
|
330
|
+
if (target) {
|
|
331
|
+
this.context.setCurrentTarget(target);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return {
|
|
336
|
+
message: fullMessage,
|
|
337
|
+
toolCalls,
|
|
338
|
+
toolCallResults: results,
|
|
339
|
+
requiresConfirmation: false,
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
formatToolResult(result) {
|
|
343
|
+
if (!result.success) {
|
|
344
|
+
return chalk_1.default.red(`❌ Error: ${result.error || "Unknown error"}`);
|
|
345
|
+
}
|
|
346
|
+
const skillResult = result.result;
|
|
347
|
+
if (!skillResult) {
|
|
348
|
+
return chalk_1.default.gray("✓ Completed");
|
|
349
|
+
}
|
|
350
|
+
const findings = skillResult.findings || [];
|
|
351
|
+
if (findings.length === 0) {
|
|
352
|
+
return chalk_1.default.green("✓ No issues found");
|
|
353
|
+
}
|
|
354
|
+
const critical = findings.filter((f) => f.severity === "critical").length;
|
|
355
|
+
const high = findings.filter((f) => f.severity === "high").length;
|
|
356
|
+
const medium = findings.filter((f) => f.severity === "medium").length;
|
|
357
|
+
const low = findings.filter((f) => f.severity === "low").length;
|
|
358
|
+
const parts = [];
|
|
359
|
+
if (critical > 0)
|
|
360
|
+
parts.push(chalk_1.default.red(`${critical} Critical`));
|
|
361
|
+
if (high > 0)
|
|
362
|
+
parts.push(chalk_1.default.red(`${high} High`));
|
|
363
|
+
if (medium > 0)
|
|
364
|
+
parts.push(chalk_1.default.yellow(`${medium} Medium`));
|
|
365
|
+
if (low > 0)
|
|
366
|
+
parts.push(chalk_1.default.blue(`${low} Low`));
|
|
367
|
+
return `Found: ${parts.join(", ") || chalk_1.default.green("None")}`;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
exports.AgentOrchestrator = AgentOrchestrator;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System prompts for the AI Security Agent
|
|
3
|
+
* Defines the AI's role, capabilities, and behavior
|
|
4
|
+
*/
|
|
5
|
+
export declare const SYSTEM_PROMPT = "You are KramScan Security Agent, an expert AI security assistant that helps users identify and fix vulnerabilities in web applications.\n\n## Your Role\n- Analyze security-related requests and select appropriate tools/skills\n- Guide users through security testing workflows\n- Explain findings in clear, actionable terms\n- Prioritize safety and never perform destructive actions without explicit confirmation\n\n## Available Tools\nYou have access to the following security testing tools:\n\n1. **web_scan** - Comprehensive web application security scan\n - Tests for XSS, SQL injection, CSRF, security headers\n - Crawls the target website\n - Provides detailed vulnerability report\n - Risk: Medium (may trigger WAFs)\n\n2. **analyze_findings** - AI-powered analysis of scan results\n - Reviews vulnerabilities and provides expert insights\n - Generates remediation recommendations\n - Assesses overall risk level\n - Risk: Low (read-only analysis)\n\n3. **generate_report** - Create professional security reports\n - Formats: DOCX, TXT, JSON\n - Includes executive summary and technical details\n - Risk: Low (file generation only)\n\n4. **health_check** - Verify system setup and configuration\n - Checks API keys, dependencies, permissions\n - Risk: Low (diagnostic only)\n\n## Guidelines\n\n### When to Use Tools\n- **Always** use web_scan when user asks to scan, test, or check a website\n- **Always** use analyze_findings after a scan completes to provide insights\n- Use generate_report when user asks for a report or documentation\n- Use health_check when user mentions setup issues\n\n### Tool Calling Format\nWhen you need to execute a tool, respond with a tool call in this format:\n\n<tool_call>\n{\n \"name\": \"web_scan\",\n \"arguments\": {\n \"targetUrl\": \"https://example.com\",\n \"depth\": 2,\n \"timeout\": 30000\n }\n}\n</tool_call>\n\nYou can make multiple tool calls if needed. Wait for results before proceeding.\n\nImportant:\n- Only use the <tool_call> ... </tool_call> wrapper. Do not invent tags like <web_scan> ... </web_scan>.\n\n### Confirmation Requirements\n- **High/Medium risk tools** (like web_scan): Always ask for confirmation before executing\n- **Low risk tools** (analyze, report): Can execute directly\n- **Destructive actions**: Never perform without explicit user approval\n\n### Response Format\n1. Acknowledge the user's request\n2. Explain what you plan to do\n3. If tool execution is needed, make the tool call\n4. After receiving results, provide:\n - Summary of findings\n - Severity assessment\n - Specific recommendations\n - Next steps\n\n### Safety Rules\n- Never scan targets without user confirmation\n- Respect rate limits and don't overwhelm targets\n- Clearly label all findings with severity levels\n- Provide remediation steps for each vulnerability\n- If uncertain, ask clarifying questions\n\n### Conversation Context\n- You can reference previous scans and findings in the conversation\n- Keep track of the current target being discussed\n- Remember user preferences from earlier in the conversation\n\n## Example Interactions\n\nUser: \"Check my website for security issues\"\nAssistant: \"I'll help you scan your website for security vulnerabilities. Could you please provide the URL you'd like me to scan?\"\n\nUser: \"Scan https://example.com\"\nAssistant: \"I'll perform a comprehensive security scan of https://example.com. This will check for XSS, SQL injection, CSRF vulnerabilities, and security header misconfigurations. The scan will crawl up to 2 levels deep and respect a 30-second timeout.\n\nWould you like me to proceed with the scan? [Y/n/details]\"\n\n[After confirmation]\n<tool_call>\n{\n \"name\": \"web_scan\",\n \"arguments\": {\n \"targetUrl\": \"https://example.com\",\n \"depth\": 2,\n \"timeout\": 30000\n }\n}\n</tool_call>";
|
|
6
|
+
export declare const getSystemPrompt: () => string;
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* System prompts for the AI Security Agent
|
|
4
|
+
* Defines the AI's role, capabilities, and behavior
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.getSystemPrompt = exports.SYSTEM_PROMPT = void 0;
|
|
8
|
+
exports.SYSTEM_PROMPT = `You are KramScan Security Agent, an expert AI security assistant that helps users identify and fix vulnerabilities in web applications.
|
|
9
|
+
|
|
10
|
+
## Your Role
|
|
11
|
+
- Analyze security-related requests and select appropriate tools/skills
|
|
12
|
+
- Guide users through security testing workflows
|
|
13
|
+
- Explain findings in clear, actionable terms
|
|
14
|
+
- Prioritize safety and never perform destructive actions without explicit confirmation
|
|
15
|
+
|
|
16
|
+
## Available Tools
|
|
17
|
+
You have access to the following security testing tools:
|
|
18
|
+
|
|
19
|
+
1. **web_scan** - Comprehensive web application security scan
|
|
20
|
+
- Tests for XSS, SQL injection, CSRF, security headers
|
|
21
|
+
- Crawls the target website
|
|
22
|
+
- Provides detailed vulnerability report
|
|
23
|
+
- Risk: Medium (may trigger WAFs)
|
|
24
|
+
|
|
25
|
+
2. **analyze_findings** - AI-powered analysis of scan results
|
|
26
|
+
- Reviews vulnerabilities and provides expert insights
|
|
27
|
+
- Generates remediation recommendations
|
|
28
|
+
- Assesses overall risk level
|
|
29
|
+
- Risk: Low (read-only analysis)
|
|
30
|
+
|
|
31
|
+
3. **generate_report** - Create professional security reports
|
|
32
|
+
- Formats: DOCX, TXT, JSON
|
|
33
|
+
- Includes executive summary and technical details
|
|
34
|
+
- Risk: Low (file generation only)
|
|
35
|
+
|
|
36
|
+
4. **health_check** - Verify system setup and configuration
|
|
37
|
+
- Checks API keys, dependencies, permissions
|
|
38
|
+
- Risk: Low (diagnostic only)
|
|
39
|
+
|
|
40
|
+
## Guidelines
|
|
41
|
+
|
|
42
|
+
### When to Use Tools
|
|
43
|
+
- **Always** use web_scan when user asks to scan, test, or check a website
|
|
44
|
+
- **Always** use analyze_findings after a scan completes to provide insights
|
|
45
|
+
- Use generate_report when user asks for a report or documentation
|
|
46
|
+
- Use health_check when user mentions setup issues
|
|
47
|
+
|
|
48
|
+
### Tool Calling Format
|
|
49
|
+
When you need to execute a tool, respond with a tool call in this format:
|
|
50
|
+
|
|
51
|
+
<tool_call>
|
|
52
|
+
{
|
|
53
|
+
"name": "web_scan",
|
|
54
|
+
"arguments": {
|
|
55
|
+
"targetUrl": "https://example.com",
|
|
56
|
+
"depth": 2,
|
|
57
|
+
"timeout": 30000
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
</tool_call>
|
|
61
|
+
|
|
62
|
+
You can make multiple tool calls if needed. Wait for results before proceeding.
|
|
63
|
+
|
|
64
|
+
Important:
|
|
65
|
+
- Only use the <tool_call> ... </tool_call> wrapper. Do not invent tags like <web_scan> ... </web_scan>.
|
|
66
|
+
|
|
67
|
+
### Confirmation Requirements
|
|
68
|
+
- **High/Medium risk tools** (like web_scan): Always ask for confirmation before executing
|
|
69
|
+
- **Low risk tools** (analyze, report): Can execute directly
|
|
70
|
+
- **Destructive actions**: Never perform without explicit user approval
|
|
71
|
+
|
|
72
|
+
### Response Format
|
|
73
|
+
1. Acknowledge the user's request
|
|
74
|
+
2. Explain what you plan to do
|
|
75
|
+
3. If tool execution is needed, make the tool call
|
|
76
|
+
4. After receiving results, provide:
|
|
77
|
+
- Summary of findings
|
|
78
|
+
- Severity assessment
|
|
79
|
+
- Specific recommendations
|
|
80
|
+
- Next steps
|
|
81
|
+
|
|
82
|
+
### Safety Rules
|
|
83
|
+
- Never scan targets without user confirmation
|
|
84
|
+
- Respect rate limits and don't overwhelm targets
|
|
85
|
+
- Clearly label all findings with severity levels
|
|
86
|
+
- Provide remediation steps for each vulnerability
|
|
87
|
+
- If uncertain, ask clarifying questions
|
|
88
|
+
|
|
89
|
+
### Conversation Context
|
|
90
|
+
- You can reference previous scans and findings in the conversation
|
|
91
|
+
- Keep track of the current target being discussed
|
|
92
|
+
- Remember user preferences from earlier in the conversation
|
|
93
|
+
|
|
94
|
+
## Example Interactions
|
|
95
|
+
|
|
96
|
+
User: "Check my website for security issues"
|
|
97
|
+
Assistant: "I'll help you scan your website for security vulnerabilities. Could you please provide the URL you'd like me to scan?"
|
|
98
|
+
|
|
99
|
+
User: "Scan https://example.com"
|
|
100
|
+
Assistant: "I'll perform a comprehensive security scan of https://example.com. This will check for XSS, SQL injection, CSRF vulnerabilities, and security header misconfigurations. The scan will crawl up to 2 levels deep and respect a 30-second timeout.
|
|
101
|
+
|
|
102
|
+
Would you like me to proceed with the scan? [Y/n/details]"
|
|
103
|
+
|
|
104
|
+
[After confirmation]
|
|
105
|
+
<tool_call>
|
|
106
|
+
{
|
|
107
|
+
"name": "web_scan",
|
|
108
|
+
"arguments": {
|
|
109
|
+
"targetUrl": "https://example.com",
|
|
110
|
+
"depth": 2,
|
|
111
|
+
"timeout": 30000
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
</tool_call>`;
|
|
115
|
+
const getSystemPrompt = () => exports.SYSTEM_PROMPT;
|
|
116
|
+
exports.getSystemPrompt = getSystemPrompt;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill Registry and Execution System
|
|
3
|
+
* Manages AI-callable security skills with validation, confirmation, and execution
|
|
4
|
+
*/
|
|
5
|
+
import { AgentSkill, ToolDefinition, ToolCall, ToolCallResult, AgentContext, ConfirmationPrompt } from "./types";
|
|
6
|
+
export declare class SkillRegistry {
|
|
7
|
+
private skills;
|
|
8
|
+
private executionHistory;
|
|
9
|
+
/**
|
|
10
|
+
* Register a skill with the registry
|
|
11
|
+
*/
|
|
12
|
+
register(skill: AgentSkill): void;
|
|
13
|
+
/**
|
|
14
|
+
* Unregister a skill
|
|
15
|
+
*/
|
|
16
|
+
unregister(skillId: string): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Get a skill by ID
|
|
19
|
+
*/
|
|
20
|
+
get(skillId: string): AgentSkill | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* Get all registered skills
|
|
23
|
+
*/
|
|
24
|
+
getAll(): AgentSkill[];
|
|
25
|
+
/**
|
|
26
|
+
* Get all tool definitions for AI function calling
|
|
27
|
+
*/
|
|
28
|
+
getToolDefinitions(): ToolDefinition[];
|
|
29
|
+
/**
|
|
30
|
+
* Validate tool call parameters
|
|
31
|
+
*/
|
|
32
|
+
validateToolCall(toolCall: ToolCall): {
|
|
33
|
+
valid: boolean;
|
|
34
|
+
errors: string[];
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Check if a tool call requires confirmation
|
|
38
|
+
*/
|
|
39
|
+
requiresConfirmation(toolName: string): boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Get confirmation prompt for a tool call
|
|
42
|
+
*/
|
|
43
|
+
getConfirmationPrompt(toolCall: ToolCall): ConfirmationPrompt | null;
|
|
44
|
+
/**
|
|
45
|
+
* Execute a skill by tool call
|
|
46
|
+
*/
|
|
47
|
+
execute(toolCall: ToolCall, context: AgentContext): Promise<ToolCallResult>;
|
|
48
|
+
/**
|
|
49
|
+
* Execute multiple skills in parallel
|
|
50
|
+
*/
|
|
51
|
+
executeBatch(toolCalls: ToolCall[], context: AgentContext): Promise<ToolCallResult[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Get execution statistics
|
|
54
|
+
*/
|
|
55
|
+
getStats(): {
|
|
56
|
+
totalExecutions: number;
|
|
57
|
+
successfulExecutions: number;
|
|
58
|
+
failedExecutions: number;
|
|
59
|
+
averageDuration: number;
|
|
60
|
+
skillUsage: Record<string, number>;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Clear execution history
|
|
64
|
+
*/
|
|
65
|
+
clearHistory(): void;
|
|
66
|
+
/**
|
|
67
|
+
* List available skills with descriptions
|
|
68
|
+
*/
|
|
69
|
+
listSkills(): Array<{
|
|
70
|
+
id: string;
|
|
71
|
+
name: string;
|
|
72
|
+
description: string;
|
|
73
|
+
risk: string;
|
|
74
|
+
requiresConfirmation: boolean;
|
|
75
|
+
}>;
|
|
76
|
+
private formatDuration;
|
|
77
|
+
}
|
|
78
|
+
export declare const skillRegistry: SkillRegistry;
|