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,210 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Confirmation Prompt System
|
|
4
|
+
* Handles user confirmation for skill execution with detailed risk assessment
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
40
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
41
|
+
};
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.ConfirmationHandler = void 0;
|
|
44
|
+
const readline = __importStar(require("readline"));
|
|
45
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
46
|
+
class ConfirmationHandler {
|
|
47
|
+
rl = null;
|
|
48
|
+
ownsRl = false;
|
|
49
|
+
constructor(rl) {
|
|
50
|
+
if (rl) {
|
|
51
|
+
this.rl = rl;
|
|
52
|
+
this.ownsRl = false;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
setInterface(rl) {
|
|
56
|
+
// Prefer sharing a single readline interface to avoid double-reading stdin.
|
|
57
|
+
this.rl = rl;
|
|
58
|
+
this.ownsRl = false;
|
|
59
|
+
}
|
|
60
|
+
getInterface() {
|
|
61
|
+
if (!this.rl) {
|
|
62
|
+
this.rl = readline.createInterface({
|
|
63
|
+
input: process.stdin,
|
|
64
|
+
output: process.stdout,
|
|
65
|
+
});
|
|
66
|
+
this.ownsRl = true;
|
|
67
|
+
}
|
|
68
|
+
return this.rl;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Display confirmation prompt and get user response
|
|
72
|
+
*/
|
|
73
|
+
async prompt(confirmation) {
|
|
74
|
+
console.log("");
|
|
75
|
+
console.log(chalk_1.default.bold.yellow("⚠️ Action Requires Confirmation"));
|
|
76
|
+
console.log(chalk_1.default.gray("─".repeat(50)));
|
|
77
|
+
console.log("");
|
|
78
|
+
// Display action details
|
|
79
|
+
console.log(chalk_1.default.white("Action:"), chalk_1.default.cyan(confirmation.action));
|
|
80
|
+
console.log(chalk_1.default.white("Description:"), confirmation.description);
|
|
81
|
+
console.log("");
|
|
82
|
+
// Display risk level with color coding
|
|
83
|
+
const riskColor = this.getRiskColor(confirmation.risk);
|
|
84
|
+
console.log(chalk_1.default.white("Risk Level:"), riskColor(confirmation.risk.toUpperCase()));
|
|
85
|
+
console.log(chalk_1.default.white("Estimated Time:"), confirmation.estimatedTime);
|
|
86
|
+
console.log("");
|
|
87
|
+
// Display parameters
|
|
88
|
+
console.log(chalk_1.default.white("Parameters:"));
|
|
89
|
+
Object.entries(confirmation.parameters).forEach(([key, value]) => {
|
|
90
|
+
const displayValue = typeof value === "object" ? JSON.stringify(value) : String(value);
|
|
91
|
+
console.log(` ${chalk_1.default.gray(key)}: ${chalk_1.default.white(displayValue)}`);
|
|
92
|
+
});
|
|
93
|
+
console.log("");
|
|
94
|
+
// Risk warnings
|
|
95
|
+
if (confirmation.risk === "high") {
|
|
96
|
+
console.log(chalk_1.default.red.bold("⚠️ WARNING: This action may have significant impact."));
|
|
97
|
+
}
|
|
98
|
+
else if (confirmation.risk === "medium") {
|
|
99
|
+
console.log(chalk_1.default.yellow("⚠️ This action will interact with external systems."));
|
|
100
|
+
}
|
|
101
|
+
console.log("");
|
|
102
|
+
// Get user input
|
|
103
|
+
return this.getUserInput();
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Quick confirmation for low-risk actions
|
|
107
|
+
*/
|
|
108
|
+
async quickConfirm(action) {
|
|
109
|
+
const rl = this.getInterface();
|
|
110
|
+
return new Promise((resolve) => {
|
|
111
|
+
rl.question(chalk_1.default.gray(`${action} [Y/n]: `), (answer) => {
|
|
112
|
+
const normalized = answer.trim().toLowerCase();
|
|
113
|
+
resolve(normalized === "" || normalized === "y" || normalized === "yes");
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Display detailed information about the action
|
|
119
|
+
*/
|
|
120
|
+
showDetails(confirmation) {
|
|
121
|
+
console.log("");
|
|
122
|
+
console.log(chalk_1.default.bold.cyan("📋 Action Details"));
|
|
123
|
+
console.log(chalk_1.default.gray("─".repeat(50)));
|
|
124
|
+
console.log("");
|
|
125
|
+
console.log(chalk_1.default.white("What will happen:"));
|
|
126
|
+
console.log(chalk_1.default.gray(this.getDetailedDescription(confirmation.action)));
|
|
127
|
+
console.log("");
|
|
128
|
+
console.log(chalk_1.default.white("Safety considerations:"));
|
|
129
|
+
console.log(chalk_1.default.gray(this.getSafetyInfo(confirmation.risk)));
|
|
130
|
+
console.log("");
|
|
131
|
+
if (confirmation.risk === "high") {
|
|
132
|
+
console.log(chalk_1.default.yellow("Recommendations:"));
|
|
133
|
+
console.log(chalk_1.default.gray("• Ensure you have proper authorization"));
|
|
134
|
+
console.log(chalk_1.default.gray("• Verify the target is correct"));
|
|
135
|
+
console.log(chalk_1.default.gray("• Consider testing in a safe environment first"));
|
|
136
|
+
console.log("");
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Close the readline interface
|
|
141
|
+
*/
|
|
142
|
+
close() {
|
|
143
|
+
if (this.rl && this.ownsRl) {
|
|
144
|
+
this.rl.close();
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
async getUserInput() {
|
|
148
|
+
const rl = this.getInterface();
|
|
149
|
+
return new Promise((resolve) => {
|
|
150
|
+
const askQuestion = () => {
|
|
151
|
+
rl.question(chalk_1.default.gray("Proceed? [Y/n/details/cancel]: "), (answer) => {
|
|
152
|
+
const normalized = answer.trim().toLowerCase();
|
|
153
|
+
if (normalized === "" || normalized === "y" || normalized === "yes") {
|
|
154
|
+
resolve({ confirmed: true, showDetails: false, cancelled: false });
|
|
155
|
+
}
|
|
156
|
+
else if (normalized === "n" || normalized === "no") {
|
|
157
|
+
resolve({ confirmed: false, showDetails: false, cancelled: false });
|
|
158
|
+
}
|
|
159
|
+
else if (normalized === "details" || normalized === "d") {
|
|
160
|
+
resolve({ confirmed: false, showDetails: true, cancelled: false });
|
|
161
|
+
}
|
|
162
|
+
else if (normalized === "cancel" || normalized === "c") {
|
|
163
|
+
resolve({ confirmed: false, showDetails: false, cancelled: true });
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
console.log(chalk_1.default.gray("Please enter: Y, n, details, or cancel"));
|
|
167
|
+
askQuestion();
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
askQuestion();
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
getRiskColor(risk) {
|
|
175
|
+
switch (risk) {
|
|
176
|
+
case "high":
|
|
177
|
+
return chalk_1.default.red.bold;
|
|
178
|
+
case "medium":
|
|
179
|
+
return chalk_1.default.yellow;
|
|
180
|
+
case "low":
|
|
181
|
+
return chalk_1.default.green;
|
|
182
|
+
default:
|
|
183
|
+
return chalk_1.default.gray;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
getDetailedDescription(action) {
|
|
187
|
+
const descriptions = {
|
|
188
|
+
"Web Scan": "This will crawl the target website and test for common vulnerabilities including XSS, SQL injection, CSRF, and security header misconfigurations. The scan sends HTTP requests to the target.",
|
|
189
|
+
"Analyze Findings": "This will use AI to analyze previously discovered vulnerabilities and provide detailed remediation recommendations.",
|
|
190
|
+
"Generate Report": "This will create a professional security report document based on scan results.",
|
|
191
|
+
"Check Environment": "This will verify your system configuration, API keys, and dependencies.",
|
|
192
|
+
"View Configuration": "This will display your current KramScan configuration settings.",
|
|
193
|
+
};
|
|
194
|
+
return (descriptions[action] ||
|
|
195
|
+
"This action will execute the requested security operation.");
|
|
196
|
+
}
|
|
197
|
+
getSafetyInfo(risk) {
|
|
198
|
+
switch (risk) {
|
|
199
|
+
case "high":
|
|
200
|
+
return "This action may trigger security systems, generate significant network traffic, or have other notable effects. Use with caution.";
|
|
201
|
+
case "medium":
|
|
202
|
+
return "This action will make network requests to external systems. Ensure you have permission to test the target.";
|
|
203
|
+
case "low":
|
|
204
|
+
return "This is a safe, read-only operation that won't modify any external systems.";
|
|
205
|
+
default:
|
|
206
|
+
return "Please review the action details carefully before proceeding.";
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
exports.ConfirmationHandler = ConfirmationHandler;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conversation Context Manager
|
|
3
|
+
* Manages conversation history, user context, and session state
|
|
4
|
+
*/
|
|
5
|
+
import { ConversationMessage, AgentContext, AgentConfig } from "./types";
|
|
6
|
+
export declare class ConversationContext {
|
|
7
|
+
private messages;
|
|
8
|
+
private context;
|
|
9
|
+
private config;
|
|
10
|
+
private historyFile;
|
|
11
|
+
constructor(config?: Partial<AgentConfig>);
|
|
12
|
+
private initializeContext;
|
|
13
|
+
/**
|
|
14
|
+
* Get the current agent context
|
|
15
|
+
*/
|
|
16
|
+
getContext(): AgentContext;
|
|
17
|
+
/**
|
|
18
|
+
* Update the current target URL
|
|
19
|
+
*/
|
|
20
|
+
setCurrentTarget(target: string): void;
|
|
21
|
+
/**
|
|
22
|
+
* Get the current target URL
|
|
23
|
+
*/
|
|
24
|
+
getCurrentTarget(): string | undefined;
|
|
25
|
+
/**
|
|
26
|
+
* Store last scan results
|
|
27
|
+
*/
|
|
28
|
+
setLastScanResults(results: unknown): void;
|
|
29
|
+
/**
|
|
30
|
+
* Get last scan results
|
|
31
|
+
*/
|
|
32
|
+
getLastScanResults(): unknown | undefined;
|
|
33
|
+
/**
|
|
34
|
+
* Add a message to the conversation
|
|
35
|
+
*/
|
|
36
|
+
addMessage(role: ConversationMessage["role"], content: string, toolCalls?: any[], toolCallResults?: any[]): ConversationMessage;
|
|
37
|
+
/**
|
|
38
|
+
* Get all conversation messages
|
|
39
|
+
*/
|
|
40
|
+
getMessages(): ConversationMessage[];
|
|
41
|
+
/**
|
|
42
|
+
* Get recent messages (for AI context)
|
|
43
|
+
*/
|
|
44
|
+
getRecentMessages(count?: number): ConversationMessage[];
|
|
45
|
+
/**
|
|
46
|
+
* Get the last message
|
|
47
|
+
*/
|
|
48
|
+
getLastMessage(): ConversationMessage | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Get conversation summary for display
|
|
51
|
+
*/
|
|
52
|
+
getSummary(): {
|
|
53
|
+
totalMessages: number;
|
|
54
|
+
sessionDuration: string;
|
|
55
|
+
currentTarget?: string;
|
|
56
|
+
hasScanResults: boolean;
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Clear conversation history
|
|
60
|
+
*/
|
|
61
|
+
clear(): void;
|
|
62
|
+
/**
|
|
63
|
+
* Trim history to max length
|
|
64
|
+
*/
|
|
65
|
+
private trimHistory;
|
|
66
|
+
/**
|
|
67
|
+
* Persist conversation to disk
|
|
68
|
+
*/
|
|
69
|
+
save(): Promise<void>;
|
|
70
|
+
/**
|
|
71
|
+
* Load conversation from disk
|
|
72
|
+
*/
|
|
73
|
+
load(): Promise<boolean>;
|
|
74
|
+
/**
|
|
75
|
+
* Format messages for AI provider (OpenAI/Anthropic format)
|
|
76
|
+
*/
|
|
77
|
+
formatForAI(): Array<{
|
|
78
|
+
role: string;
|
|
79
|
+
content: string;
|
|
80
|
+
}>;
|
|
81
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Conversation Context Manager
|
|
4
|
+
* Manages conversation history, user context, and session state
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.ConversationContext = void 0;
|
|
41
|
+
const types_1 = require("./types");
|
|
42
|
+
const uuid_1 = require("uuid");
|
|
43
|
+
const os = __importStar(require("os"));
|
|
44
|
+
const path = __importStar(require("path"));
|
|
45
|
+
const fs = __importStar(require("fs/promises"));
|
|
46
|
+
class ConversationContext {
|
|
47
|
+
messages = [];
|
|
48
|
+
context;
|
|
49
|
+
config;
|
|
50
|
+
historyFile;
|
|
51
|
+
constructor(config = {}) {
|
|
52
|
+
this.config = { ...types_1.DEFAULT_AGENT_CONFIG, ...config };
|
|
53
|
+
this.context = this.initializeContext();
|
|
54
|
+
this.historyFile = path.join(os.homedir(), ".kramscan", "agent-history.json");
|
|
55
|
+
}
|
|
56
|
+
initializeContext() {
|
|
57
|
+
return {
|
|
58
|
+
sessionId: (0, uuid_1.v4)(),
|
|
59
|
+
userId: os.userInfo().username,
|
|
60
|
+
startTime: new Date(),
|
|
61
|
+
workingDirectory: process.cwd(),
|
|
62
|
+
environment: {
|
|
63
|
+
nodeVersion: process.version,
|
|
64
|
+
platform: process.platform,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Get the current agent context
|
|
70
|
+
*/
|
|
71
|
+
getContext() {
|
|
72
|
+
return { ...this.context };
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Update the current target URL
|
|
76
|
+
*/
|
|
77
|
+
setCurrentTarget(target) {
|
|
78
|
+
this.context.currentTarget = target;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Get the current target URL
|
|
82
|
+
*/
|
|
83
|
+
getCurrentTarget() {
|
|
84
|
+
return this.context.currentTarget;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Store last scan results
|
|
88
|
+
*/
|
|
89
|
+
setLastScanResults(results) {
|
|
90
|
+
this.context.lastScanResults = results;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Get last scan results
|
|
94
|
+
*/
|
|
95
|
+
getLastScanResults() {
|
|
96
|
+
return this.context.lastScanResults;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Add a message to the conversation
|
|
100
|
+
*/
|
|
101
|
+
addMessage(role, content, toolCalls, toolCallResults) {
|
|
102
|
+
const message = {
|
|
103
|
+
id: (0, uuid_1.v4)(),
|
|
104
|
+
role,
|
|
105
|
+
content,
|
|
106
|
+
timestamp: new Date(),
|
|
107
|
+
toolCalls,
|
|
108
|
+
toolCallResults,
|
|
109
|
+
};
|
|
110
|
+
this.messages.push(message);
|
|
111
|
+
this.trimHistory();
|
|
112
|
+
return message;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get all conversation messages
|
|
116
|
+
*/
|
|
117
|
+
getMessages() {
|
|
118
|
+
return [...this.messages];
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get recent messages (for AI context)
|
|
122
|
+
*/
|
|
123
|
+
getRecentMessages(count = this.config.maxConversationHistory) {
|
|
124
|
+
return this.messages.slice(-count);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Get the last message
|
|
128
|
+
*/
|
|
129
|
+
getLastMessage() {
|
|
130
|
+
return this.messages[this.messages.length - 1];
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Get conversation summary for display
|
|
134
|
+
*/
|
|
135
|
+
getSummary() {
|
|
136
|
+
const duration = Date.now() - this.context.startTime.getTime();
|
|
137
|
+
const hours = Math.floor(duration / (1000 * 60 * 60));
|
|
138
|
+
const minutes = Math.floor((duration % (1000 * 60 * 60)) / (1000 * 60));
|
|
139
|
+
const seconds = Math.floor((duration % (1000 * 60)) / 1000);
|
|
140
|
+
let sessionDuration;
|
|
141
|
+
if (hours > 0) {
|
|
142
|
+
sessionDuration = `${hours}h ${minutes}m ${seconds}s`;
|
|
143
|
+
}
|
|
144
|
+
else if (minutes > 0) {
|
|
145
|
+
sessionDuration = `${minutes}m ${seconds}s`;
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
sessionDuration = `${seconds}s`;
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
totalMessages: this.messages.length,
|
|
152
|
+
sessionDuration,
|
|
153
|
+
currentTarget: this.context.currentTarget,
|
|
154
|
+
hasScanResults: !!this.context.lastScanResults,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Clear conversation history
|
|
159
|
+
*/
|
|
160
|
+
clear() {
|
|
161
|
+
this.messages = [];
|
|
162
|
+
this.context.currentTarget = undefined;
|
|
163
|
+
this.context.lastScanResults = undefined;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Trim history to max length
|
|
167
|
+
*/
|
|
168
|
+
trimHistory() {
|
|
169
|
+
if (this.messages.length > this.config.maxConversationHistory * 2) {
|
|
170
|
+
// Keep system message if present, then last N messages
|
|
171
|
+
const systemMessages = this.messages.filter((m) => m.role === "system");
|
|
172
|
+
const recentMessages = this.messages.slice(-this.config.maxConversationHistory);
|
|
173
|
+
this.messages = [...systemMessages, ...recentMessages];
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Persist conversation to disk
|
|
178
|
+
*/
|
|
179
|
+
async save() {
|
|
180
|
+
try {
|
|
181
|
+
const data = {
|
|
182
|
+
context: this.context,
|
|
183
|
+
messages: this.messages,
|
|
184
|
+
timestamp: new Date().toISOString(),
|
|
185
|
+
};
|
|
186
|
+
const dir = path.dirname(this.historyFile);
|
|
187
|
+
await fs.mkdir(dir, { recursive: true });
|
|
188
|
+
await fs.writeFile(this.historyFile, JSON.stringify(data, null, 2));
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
console.error("Failed to save conversation history:", error);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Load conversation from disk
|
|
196
|
+
*/
|
|
197
|
+
async load() {
|
|
198
|
+
try {
|
|
199
|
+
const data = await fs.readFile(this.historyFile, "utf-8");
|
|
200
|
+
const parsed = JSON.parse(data);
|
|
201
|
+
if (parsed.context) {
|
|
202
|
+
this.context = { ...this.context, ...parsed.context };
|
|
203
|
+
}
|
|
204
|
+
if (parsed.messages) {
|
|
205
|
+
this.messages = parsed.messages.map((m) => ({
|
|
206
|
+
...m,
|
|
207
|
+
timestamp: new Date(m.timestamp),
|
|
208
|
+
}));
|
|
209
|
+
}
|
|
210
|
+
return true;
|
|
211
|
+
}
|
|
212
|
+
catch {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Format messages for AI provider (OpenAI/Anthropic format)
|
|
218
|
+
*/
|
|
219
|
+
formatForAI() {
|
|
220
|
+
// Include system messages so the model receives core constraints and tool format instructions.
|
|
221
|
+
return this.messages.map((m) => ({
|
|
222
|
+
role: m.role,
|
|
223
|
+
content: m.content,
|
|
224
|
+
}));
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
exports.ConversationContext = ConversationContext;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Module Index
|
|
3
|
+
* Main exports for the AI Agent system
|
|
4
|
+
*/
|
|
5
|
+
export { AgentOrchestrator } from "./orchestrator";
|
|
6
|
+
export { ConversationContext } from "./context";
|
|
7
|
+
export { SkillRegistry, skillRegistry } from "./skill-registry";
|
|
8
|
+
export { ConfirmationHandler } from "./confirmation";
|
|
9
|
+
export * from "./types";
|
|
10
|
+
export * from "./skills";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agent Module Index
|
|
4
|
+
* Main exports for the AI Agent system
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
18
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
exports.ConfirmationHandler = exports.skillRegistry = exports.SkillRegistry = exports.ConversationContext = exports.AgentOrchestrator = void 0;
|
|
22
|
+
var orchestrator_1 = require("./orchestrator");
|
|
23
|
+
Object.defineProperty(exports, "AgentOrchestrator", { enumerable: true, get: function () { return orchestrator_1.AgentOrchestrator; } });
|
|
24
|
+
var context_1 = require("./context");
|
|
25
|
+
Object.defineProperty(exports, "ConversationContext", { enumerable: true, get: function () { return context_1.ConversationContext; } });
|
|
26
|
+
var skill_registry_1 = require("./skill-registry");
|
|
27
|
+
Object.defineProperty(exports, "SkillRegistry", { enumerable: true, get: function () { return skill_registry_1.SkillRegistry; } });
|
|
28
|
+
Object.defineProperty(exports, "skillRegistry", { enumerable: true, get: function () { return skill_registry_1.skillRegistry; } });
|
|
29
|
+
var confirmation_1 = require("./confirmation");
|
|
30
|
+
Object.defineProperty(exports, "ConfirmationHandler", { enumerable: true, get: function () { return confirmation_1.ConfirmationHandler; } });
|
|
31
|
+
__exportStar(require("./types"), exports);
|
|
32
|
+
__exportStar(require("./skills"), exports);
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent Orchestrator
|
|
3
|
+
* Coordinates AI conversations, tool calling, skill execution, and user interactions
|
|
4
|
+
*/
|
|
5
|
+
import { ConversationContext } from "./context";
|
|
6
|
+
import { SkillRegistry } from "./skill-registry";
|
|
7
|
+
import { AgentConfig, AgentResponse } from "./types";
|
|
8
|
+
import type * as readline from "readline";
|
|
9
|
+
export declare class AgentOrchestrator {
|
|
10
|
+
private context;
|
|
11
|
+
private skillRegistry;
|
|
12
|
+
private confirmationHandler;
|
|
13
|
+
private config;
|
|
14
|
+
private aiClient;
|
|
15
|
+
private isRunning;
|
|
16
|
+
constructor(skillRegistry: SkillRegistry, config?: Partial<AgentConfig>);
|
|
17
|
+
setReadlineInterface(rl: readline.Interface): void;
|
|
18
|
+
/**
|
|
19
|
+
* Initialize the orchestrator and AI client
|
|
20
|
+
*/
|
|
21
|
+
initialize(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Process a user message and generate a response
|
|
24
|
+
*/
|
|
25
|
+
processUserMessage(userInput: string): Promise<AgentResponse>;
|
|
26
|
+
/**
|
|
27
|
+
* Execute a specific tool/skill directly
|
|
28
|
+
*/
|
|
29
|
+
executeTool(toolName: string, parameters: Record<string, unknown>, skipConfirmation?: boolean): Promise<AgentResponse>;
|
|
30
|
+
/**
|
|
31
|
+
* Get conversation summary
|
|
32
|
+
*/
|
|
33
|
+
getConversationSummary(): ReturnType<ConversationContext["getSummary"]>;
|
|
34
|
+
/**
|
|
35
|
+
* Clear conversation history
|
|
36
|
+
*/
|
|
37
|
+
clearConversation(): void;
|
|
38
|
+
/**
|
|
39
|
+
* Save conversation state
|
|
40
|
+
*/
|
|
41
|
+
saveState(): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Get available skills list
|
|
44
|
+
*/
|
|
45
|
+
getAvailableSkills(): ReturnType<SkillRegistry["listSkills"]>;
|
|
46
|
+
/**
|
|
47
|
+
* Shutdown the orchestrator
|
|
48
|
+
*/
|
|
49
|
+
shutdown(): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* Check if orchestrator is running
|
|
52
|
+
*/
|
|
53
|
+
isActive(): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Start the agent session
|
|
56
|
+
*/
|
|
57
|
+
start(): void;
|
|
58
|
+
private getAIResponse;
|
|
59
|
+
private buildPromptWithTools;
|
|
60
|
+
private parseToolCalls;
|
|
61
|
+
private handleToolExecution;
|
|
62
|
+
private formatToolResult;
|
|
63
|
+
}
|