kramscan 0.1.1 → 0.3.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.
Files changed (91) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +419 -236
  3. package/dist/agent/confirmation.d.ts +5 -1
  4. package/dist/agent/confirmation.js +29 -9
  5. package/dist/agent/context.js +2 -3
  6. package/dist/agent/orchestrator.d.ts +2 -0
  7. package/dist/agent/orchestrator.js +50 -8
  8. package/dist/agent/prompts/system.d.ts +1 -1
  9. package/dist/agent/prompts/system.js +5 -7
  10. package/dist/agent/skills/health-check.js +22 -2
  11. package/dist/agent/skills/index.d.ts +1 -0
  12. package/dist/agent/skills/index.js +3 -1
  13. package/dist/agent/skills/verify-finding.d.ts +17 -0
  14. package/dist/agent/skills/verify-finding.js +91 -0
  15. package/dist/agent/skills/web-scan.js +46 -0
  16. package/dist/cli.js +156 -149
  17. package/dist/commands/agent.js +38 -38
  18. package/dist/commands/ai.d.ts +2 -0
  19. package/dist/commands/ai.js +112 -0
  20. package/dist/commands/analyze.js +103 -54
  21. package/dist/commands/config.js +55 -29
  22. package/dist/commands/dev.d.ts +2 -0
  23. package/dist/commands/dev.js +236 -0
  24. package/dist/commands/doctor.js +20 -15
  25. package/dist/commands/gate.d.ts +2 -0
  26. package/dist/commands/gate.js +109 -0
  27. package/dist/commands/onboard.js +188 -141
  28. package/dist/commands/report.js +68 -76
  29. package/dist/commands/scan.js +262 -81
  30. package/dist/commands/scans.d.ts +2 -0
  31. package/dist/commands/scans.js +55 -0
  32. package/dist/core/ai-client.d.ts +6 -1
  33. package/dist/core/ai-client.js +80 -12
  34. package/dist/core/ai-payloads.d.ts +17 -0
  35. package/dist/core/ai-payloads.js +54 -0
  36. package/dist/core/config-schema.d.ts +197 -0
  37. package/dist/core/config-schema.js +68 -0
  38. package/dist/core/config-schema.test.d.ts +1 -0
  39. package/dist/core/config-schema.test.js +151 -0
  40. package/dist/core/config.d.ts +8 -31
  41. package/dist/core/config.js +71 -14
  42. package/dist/core/diff-engine.d.ts +12 -0
  43. package/dist/core/diff-engine.js +47 -0
  44. package/dist/core/errors.d.ts +71 -0
  45. package/dist/core/errors.js +162 -0
  46. package/dist/core/scan-index.d.ts +20 -0
  47. package/dist/core/scan-index.js +52 -0
  48. package/dist/core/scan-storage.d.ts +11 -0
  49. package/dist/core/scan-storage.js +69 -0
  50. package/dist/core/scanner.d.ts +95 -13
  51. package/dist/core/scanner.js +342 -248
  52. package/dist/core/server-probe.d.ts +20 -0
  53. package/dist/core/server-probe.js +109 -0
  54. package/dist/core/vulnerability-detector.d.ts +9 -0
  55. package/dist/core/vulnerability-detector.js +46 -15
  56. package/dist/core/vulnerability-detector.test.d.ts +1 -0
  57. package/dist/core/vulnerability-detector.test.js +210 -0
  58. package/dist/index.js +3 -0
  59. package/dist/plugins/PluginManager.d.ts +27 -0
  60. package/dist/plugins/PluginManager.js +166 -0
  61. package/dist/plugins/index.d.ts +12 -0
  62. package/dist/plugins/index.js +29 -0
  63. package/dist/plugins/types.d.ts +55 -0
  64. package/dist/plugins/types.js +25 -0
  65. package/dist/plugins/vulnerabilities/CORSAnalyzerPlugin.d.ts +10 -0
  66. package/dist/plugins/vulnerabilities/CORSAnalyzerPlugin.js +67 -0
  67. package/dist/plugins/vulnerabilities/CSRFPlugin.d.ts +8 -0
  68. package/dist/plugins/vulnerabilities/CSRFPlugin.js +34 -0
  69. package/dist/plugins/vulnerabilities/CookieSecurityPlugin.d.ts +10 -0
  70. package/dist/plugins/vulnerabilities/CookieSecurityPlugin.js +91 -0
  71. package/dist/plugins/vulnerabilities/DebugEndpointPlugin.d.ts +15 -0
  72. package/dist/plugins/vulnerabilities/DebugEndpointPlugin.js +222 -0
  73. package/dist/plugins/vulnerabilities/DirectoryTraversalPlugin.d.ts +13 -0
  74. package/dist/plugins/vulnerabilities/DirectoryTraversalPlugin.js +110 -0
  75. package/dist/plugins/vulnerabilities/OpenRedirectPlugin.d.ts +10 -0
  76. package/dist/plugins/vulnerabilities/OpenRedirectPlugin.js +69 -0
  77. package/dist/plugins/vulnerabilities/SQLInjectionPlugin.d.ts +11 -0
  78. package/dist/plugins/vulnerabilities/SQLInjectionPlugin.js +109 -0
  79. package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.d.ts +11 -0
  80. package/dist/plugins/vulnerabilities/SecurityHeadersPlugin.js +63 -0
  81. package/dist/plugins/vulnerabilities/SensitiveDataPlugin.d.ts +9 -0
  82. package/dist/plugins/vulnerabilities/SensitiveDataPlugin.js +32 -0
  83. package/dist/plugins/vulnerabilities/XSSPlugin.d.ts +15 -0
  84. package/dist/plugins/vulnerabilities/XSSPlugin.js +81 -0
  85. package/dist/reports/PdfGenerator.d.ts +36 -0
  86. package/dist/reports/PdfGenerator.js +404 -0
  87. package/dist/utils/logger.d.ts +33 -1
  88. package/dist/utils/logger.js +127 -8
  89. package/dist/utils/theme.d.ts +56 -0
  90. package/dist/utils/theme.js +201 -0
  91. package/package.json +6 -3
@@ -3,25 +3,97 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.logger = void 0;
6
+ exports.structuredLogger = exports.logger = exports.LogLevel = void 0;
7
+ exports.createChildLogger = createChildLogger;
7
8
  const chalk_1 = __importDefault(require("chalk"));
8
9
  const ora_1 = __importDefault(require("ora"));
10
+ var LogLevel;
11
+ (function (LogLevel) {
12
+ LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
13
+ LogLevel[LogLevel["INFO"] = 1] = "INFO";
14
+ LogLevel[LogLevel["SUCCESS"] = 2] = "SUCCESS";
15
+ LogLevel[LogLevel["WARN"] = 3] = "WARN";
16
+ LogLevel[LogLevel["ERROR"] = 4] = "ERROR";
17
+ })(LogLevel || (exports.LogLevel = LogLevel = {}));
18
+ function getLogLevel() {
19
+ const envLevel = process.env.LOG_LEVEL?.toUpperCase();
20
+ switch (envLevel) {
21
+ case "DEBUG":
22
+ return LogLevel.DEBUG;
23
+ case "INFO":
24
+ return LogLevel.INFO;
25
+ case "WARN":
26
+ case "WARNING":
27
+ return LogLevel.WARN;
28
+ case "ERROR":
29
+ return LogLevel.ERROR;
30
+ default:
31
+ return process.env.KRAMSCAN_DEBUG === "1" || process.env.KRAMSCAN_DEBUG === "true"
32
+ ? LogLevel.DEBUG
33
+ : LogLevel.INFO;
34
+ }
35
+ }
36
+ function debugEnabled() {
37
+ return getLogLevel() <= LogLevel.DEBUG;
38
+ }
39
+ function isJsonOutput() {
40
+ return process.env.LOG_JSON === "1" || process.env.LOG_JSON === "true";
41
+ }
42
+ function shouldLog(level) {
43
+ return level >= getLogLevel();
44
+ }
45
+ function formatLogEntry(level, message, context) {
46
+ return {
47
+ timestamp: new Date().toISOString(),
48
+ level,
49
+ message,
50
+ context,
51
+ };
52
+ }
53
+ function outputLog(entry) {
54
+ if (isJsonOutput()) {
55
+ console.log(JSON.stringify(entry));
56
+ }
57
+ else {
58
+ const { timestamp, level, message, ...rest } = entry;
59
+ let output = message;
60
+ if (process.env.LOG_INCLUDE_CONTEXT === "true" && Object.keys(rest).length > 0) {
61
+ output += ` ${JSON.stringify(rest)}`;
62
+ }
63
+ console.log(output);
64
+ }
65
+ }
66
+ // Simple human-readable logger (original behavior)
9
67
  exports.logger = {
10
68
  info: (message) => {
11
- console.log(chalk_1.default.blue("ℹ"), message);
69
+ if (shouldLog(LogLevel.INFO)) {
70
+ console.log(chalk_1.default.blue("i"), message);
71
+ }
12
72
  },
13
73
  success: (message) => {
14
- console.log(chalk_1.default.green("✓"), message);
74
+ if (shouldLog(LogLevel.SUCCESS)) {
75
+ console.log(chalk_1.default.green("✓"), message);
76
+ }
15
77
  },
16
78
  warn: (message) => {
17
- console.log(chalk_1.default.yellow("⚠"), message);
79
+ if (shouldLog(LogLevel.WARN)) {
80
+ console.log(chalk_1.default.yellow("⚠"), message);
81
+ }
18
82
  },
19
83
  error: (message) => {
20
- console.log(chalk_1.default.red("✗"), message);
84
+ if (shouldLog(LogLevel.ERROR)) {
85
+ console.log(chalk_1.default.red("✗"), message);
86
+ }
21
87
  },
22
- debug: (message) => {
23
- if (process.env.DEBUG) {
24
- console.log(chalk_1.default.gray("→"), message);
88
+ debug: (message, context) => {
89
+ if (debugEnabled()) {
90
+ if (isJsonOutput()) {
91
+ const entry = formatLogEntry("DEBUG", message, context);
92
+ console.log(JSON.stringify(entry));
93
+ }
94
+ else {
95
+ console.log(chalk_1.default.gray("→"), message, context ? JSON.stringify(context) : "");
96
+ }
25
97
  }
26
98
  },
27
99
  spinner: (text) => {
@@ -32,3 +104,50 @@ exports.logger = {
32
104
  }).start();
33
105
  },
34
106
  };
107
+ // Structured JSON logger for log aggregation systems
108
+ exports.structuredLogger = {
109
+ debug: (message, context) => {
110
+ if (shouldLog(LogLevel.DEBUG)) {
111
+ outputLog(formatLogEntry("DEBUG", message, context));
112
+ }
113
+ },
114
+ info: (message, context) => {
115
+ if (shouldLog(LogLevel.INFO)) {
116
+ outputLog(formatLogEntry("INFO", message, context));
117
+ }
118
+ },
119
+ warn: (message, context) => {
120
+ if (shouldLog(LogLevel.WARN)) {
121
+ outputLog(formatLogEntry("WARN", message, context));
122
+ }
123
+ },
124
+ error: (message, context) => {
125
+ if (shouldLog(LogLevel.ERROR)) {
126
+ outputLog(formatLogEntry("ERROR", message, context));
127
+ }
128
+ },
129
+ // Log with custom level
130
+ log: (level, message, context) => {
131
+ if (shouldLog(level)) {
132
+ const levelName = LogLevel[level];
133
+ outputLog(formatLogEntry(levelName, message, context));
134
+ }
135
+ },
136
+ };
137
+ // Convenience function to create a child logger with additional context
138
+ function createChildLogger(defaultContext) {
139
+ return {
140
+ debug: (message, context) => {
141
+ exports.structuredLogger.debug(message, { ...defaultContext, ...context });
142
+ },
143
+ info: (message, context) => {
144
+ exports.structuredLogger.info(message, { ...defaultContext, ...context });
145
+ },
146
+ warn: (message, context) => {
147
+ exports.structuredLogger.warn(message, { ...defaultContext, ...context });
148
+ },
149
+ error: (message, context) => {
150
+ exports.structuredLogger.error(message, { ...defaultContext, ...context });
151
+ },
152
+ };
153
+ }
@@ -0,0 +1,56 @@
1
+ export declare const CLI_VERSION: string;
2
+ export declare const theme: {
3
+ brand: import("chalk").ChalkInstance;
4
+ error: import("chalk").ChalkInstance;
5
+ success: import("chalk").ChalkInstance;
6
+ warning: import("chalk").ChalkInstance;
7
+ info: import("chalk").ChalkInstance;
8
+ dim: import("chalk").ChalkInstance;
9
+ gray: import("chalk").ChalkInstance;
10
+ white: import("chalk").ChalkInstance;
11
+ cyan: import("chalk").ChalkInstance;
12
+ brightWhite: import("chalk").ChalkInstance;
13
+ brightCyan: import("chalk").ChalkInstance;
14
+ brightMagenta: import("chalk").ChalkInstance;
15
+ brightBlue: import("chalk").ChalkInstance;
16
+ brightGreen: import("chalk").ChalkInstance;
17
+ brightYellow: import("chalk").ChalkInstance;
18
+ brightRed: import("chalk").ChalkInstance;
19
+ critical: import("chalk").ChalkInstance;
20
+ high: import("chalk").ChalkInstance;
21
+ medium: import("chalk").ChalkInstance;
22
+ low: import("chalk").ChalkInstance;
23
+ infoSeverity: import("chalk").ChalkInstance;
24
+ yellow: import("chalk").ChalkInstance;
25
+ green: import("chalk").ChalkInstance;
26
+ };
27
+ export declare function printBanner(): void;
28
+ export declare function printInfo(): void;
29
+ export declare function getSeverityColor(severity: string): (text: string) => string;
30
+ export declare function displayScanSummary(result: {
31
+ target: string;
32
+ duration: number;
33
+ metadata: {
34
+ crawledUrls: number;
35
+ testedForms: number;
36
+ requestsMade: number;
37
+ };
38
+ summary: {
39
+ total: number;
40
+ critical: number;
41
+ high: number;
42
+ medium: number;
43
+ low: number;
44
+ info: number;
45
+ };
46
+ score: number;
47
+ vulnerabilities: Array<{
48
+ severity: string;
49
+ title: string;
50
+ url: string;
51
+ description: string;
52
+ }>;
53
+ filepath: string;
54
+ pdfPath?: string | null;
55
+ }): void;
56
+ export default theme;
@@ -0,0 +1,201 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.theme = exports.CLI_VERSION = void 0;
40
+ exports.printBanner = printBanner;
41
+ exports.printInfo = printInfo;
42
+ exports.getSeverityColor = getSeverityColor;
43
+ exports.displayScanSummary = displayScanSummary;
44
+ const chalk_1 = __importDefault(require("chalk"));
45
+ const path = __importStar(require("path"));
46
+ const fs = __importStar(require("fs"));
47
+ // Read version from package.json (single source of truth)
48
+ function getPackageVersion() {
49
+ try {
50
+ const pkgPath = path.resolve(__dirname, "..", "..", "package.json");
51
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
52
+ return pkg.version || "0.0.0";
53
+ }
54
+ catch {
55
+ return "0.0.0";
56
+ }
57
+ }
58
+ exports.CLI_VERSION = getPackageVersion();
59
+ exports.theme = {
60
+ // Colors
61
+ brand: chalk_1.default.hex("#00D1FF"),
62
+ error: chalk_1.default.red.bold,
63
+ success: chalk_1.default.green,
64
+ warning: chalk_1.default.yellow,
65
+ info: chalk_1.default.blue,
66
+ dim: chalk_1.default.gray,
67
+ gray: chalk_1.default.gray,
68
+ white: chalk_1.default.white,
69
+ cyan: chalk_1.default.cyan,
70
+ brightWhite: chalk_1.default.white.bold,
71
+ brightCyan: chalk_1.default.cyan.bold,
72
+ brightMagenta: chalk_1.default.magenta.bold,
73
+ brightBlue: chalk_1.default.blue.bold,
74
+ brightGreen: chalk_1.default.green.bold,
75
+ brightYellow: chalk_1.default.yellow.bold,
76
+ brightRed: chalk_1.default.red.bold,
77
+ // Severity colors
78
+ critical: chalk_1.default.red.bold,
79
+ high: chalk_1.default.red,
80
+ medium: chalk_1.default.yellow,
81
+ low: chalk_1.default.blue,
82
+ infoSeverity: chalk_1.default.gray,
83
+ yellow: chalk_1.default.yellow,
84
+ green: chalk_1.default.green,
85
+ };
86
+ // ─── ASCII Art Banner ──────────────────────────────────────────────
87
+ function printBanner() {
88
+ const lines = [
89
+ `██╗ ██╗██████╗ █████╗ ███╗ ███╗███████╗ ██████╗ █████╗ ███╗ ██╗`,
90
+ `██║ ██╔╝██╔══██╗██╔══██╗████╗ ████║██╔════╝██╔════╝██╔══██╗████╗ ██║`,
91
+ `█████╔╝ ██████╔╝███████║██╔████╔██║███████╗██║ ███████║██╔██╗ ██║`,
92
+ `██╔═██╗ ██╔══██╗██╔══██║██║╚██╔╝██║╚════██║██║ ██╔══██║██║╚██╗██║`,
93
+ `██║ ██╗██║ ██║██║ ██║██║ ╚═╝ ██║███████║╚██████╗██║ ██║██║ ╚████║`,
94
+ `╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝╚══════╝ ╚═════╝╚═╝ ╚═╝╚═╝ ╚═══╝`,
95
+ ];
96
+ console.log("");
97
+ lines.forEach((line, i) => {
98
+ const shade = i % 2 === 0 ? exports.theme.brightWhite : exports.theme.dim;
99
+ console.log(` ${shade(line)}`);
100
+ });
101
+ console.log("");
102
+ }
103
+ // ─── Dashboard Info ────────────────────────────────────────────────
104
+ function printInfo() {
105
+ console.log(` ${exports.theme.dim("───────────────────────────────────────────────────────")}`);
106
+ console.log(` ${exports.theme.brightWhite(" KramScan")} ${exports.theme.gray(`v${exports.CLI_VERSION}`)} ${exports.theme.dim("|")} ${exports.theme.cyan("AI-Powered Web Security Scanner")}`);
107
+ console.log(` ${exports.theme.dim("───────────────────────────────────────────────────────")}`);
108
+ console.log("");
109
+ console.log(` ${exports.theme.brightYellow("Tips for getting started:")}`);
110
+ console.log(` ${exports.theme.white("1.")} ${exports.theme.gray("Run")} ${exports.theme.cyan("kramscan onboard")} ${exports.theme.gray("to configure your API keys.")}`);
111
+ console.log(` ${exports.theme.white("2.")} ${exports.theme.gray("Run")} ${exports.theme.cyan("kramscan scan <url>")} ${exports.theme.gray("to scan a target.")}`);
112
+ console.log(` ${exports.theme.white("3.")} ${exports.theme.gray("Run")} ${exports.theme.cyan("kramscan --help")} ${exports.theme.gray("for all commands.")}`);
113
+ console.log("");
114
+ }
115
+ // ─── Severity Color Helper ─────────────────────────────────────────
116
+ function getSeverityColor(severity) {
117
+ const s = severity.toLowerCase();
118
+ if (s === "critical")
119
+ return exports.theme.critical;
120
+ if (s === "high")
121
+ return exports.theme.high;
122
+ if (s === "medium")
123
+ return exports.theme.medium;
124
+ if (s === "low")
125
+ return exports.theme.low;
126
+ return exports.theme.infoSeverity;
127
+ }
128
+ // ─── Scan Summary Display ──────────────────────────────────────────
129
+ function displayScanSummary(result) {
130
+ const { target, duration, metadata, summary, vulnerabilities, filepath, pdfPath, score } = result;
131
+ // Scan Summary
132
+ console.log("");
133
+ console.log(exports.theme.brightWhite.bold("📊 Scan Summary"));
134
+ console.log(exports.theme.gray("─".repeat(50)));
135
+ console.log("");
136
+ console.log(exports.theme.white("Target:"), exports.theme.cyan(target));
137
+ console.log(exports.theme.white("Duration:"), exports.theme.cyan(`${(duration / 1000).toFixed(2)}s`));
138
+ console.log(exports.theme.white("URLs Crawled:"), exports.theme.cyan(metadata.crawledUrls));
139
+ console.log(exports.theme.white("Forms Tested:"), exports.theme.cyan(metadata.testedForms));
140
+ console.log(exports.theme.white("Requests Made:"), exports.theme.cyan(metadata.requestsMade));
141
+ // Security Score Display
142
+ const scoreColor = score > 80 ? exports.theme.success : (score > 50 ? exports.theme.warning : exports.theme.error);
143
+ const scoreLabel = score > 80 ? "EXCELLENT" : (score > 50 ? "FAIR" : "POOR");
144
+ console.log("");
145
+ console.log(` ${exports.theme.white("Security Score:")} ${scoreColor.bold(score + "/100")} ${exports.theme.gray(`(${scoreLabel})`)}`);
146
+ console.log(` ${scoreColor("█".repeat(Math.round(score / 5)) + exports.theme.dim("█".repeat(20 - Math.round(score / 5))))}`);
147
+ console.log("");
148
+ // Vulnerability summary
149
+ console.log(exports.theme.brightWhite.bold("🛡️ Vulnerabilities Found"));
150
+ console.log(exports.theme.gray("─".repeat(50)));
151
+ console.log("");
152
+ if (summary.total === 0) {
153
+ console.log(exports.theme.success("✓ No vulnerabilities found!"));
154
+ }
155
+ else {
156
+ if (summary.critical > 0)
157
+ console.log(exports.theme.critical(` ${summary.critical} Critical`), exports.theme.gray("- Immediate action required"));
158
+ if (summary.high > 0)
159
+ console.log(exports.theme.high(` ${summary.high} High`), exports.theme.gray("- Should be fixed soon"));
160
+ if (summary.medium > 0)
161
+ console.log(exports.theme.medium(` ${summary.medium} Medium`), exports.theme.gray("- Fix when possible"));
162
+ if (summary.low > 0)
163
+ console.log(exports.theme.low(` ${summary.low} Low`), exports.theme.gray("- Minor issues"));
164
+ if (summary.info > 0)
165
+ console.log(exports.theme.infoSeverity(` ${summary.info} Info`), exports.theme.gray("- Informational"));
166
+ }
167
+ console.log("");
168
+ console.log(exports.theme.gray("Results saved to:"), exports.theme.white(filepath));
169
+ if (pdfPath) {
170
+ console.log(exports.theme.gray("PDF report saved to:"), exports.theme.white(pdfPath));
171
+ }
172
+ console.log("");
173
+ // Show top vulnerabilities
174
+ if (vulnerabilities.length > 0) {
175
+ console.log(exports.theme.brightWhite.bold("🔴 Top Findings"));
176
+ console.log(exports.theme.gray("─".repeat(50)));
177
+ console.log("");
178
+ const topVulns = vulnerabilities
179
+ .sort((a, b) => {
180
+ const severityOrder = { critical: 0, high: 1, medium: 2, low: 3, info: 4 };
181
+ return severityOrder[a.severity] - severityOrder[b.severity];
182
+ })
183
+ .slice(0, 5);
184
+ for (const vuln of topVulns) {
185
+ const severityColor = getSeverityColor(vuln.severity);
186
+ console.log(severityColor(`[${vuln.severity.toUpperCase()}]`), exports.theme.brightWhite.bold(vuln.title));
187
+ console.log(exports.theme.gray(` ${vuln.url}`));
188
+ console.log(exports.theme.white(` ${vuln.description}`));
189
+ console.log("");
190
+ }
191
+ if (vulnerabilities.length > 5) {
192
+ console.log(exports.theme.gray(` ... and ${vulnerabilities.length - 5} more`));
193
+ console.log("");
194
+ }
195
+ }
196
+ console.log(exports.theme.cyan("💡 Next steps:"));
197
+ console.log(exports.theme.white(` 1. Run ${exports.theme.cyan(`kramscan analyze ${filepath}`)} for AI-powered insights`));
198
+ console.log(exports.theme.white(" 2. PDF report is generated automatically after the scan"));
199
+ console.log("");
200
+ }
201
+ exports.default = exports.theme;
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "kramscan",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "description": "KramScan CLI — AI-powered web app security testing",
5
- "author": "Akram Shaikh <akramshaikh.me>",
5
+ "author": "Akram Shaikh (https://akramshaikh.me)",
6
6
  "license": "MIT",
7
7
  "keywords": [
8
8
  "security",
@@ -13,6 +13,9 @@
13
13
  "web-security",
14
14
  "analysis"
15
15
  ],
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
16
19
  "repository": {
17
20
  "type": "git",
18
21
  "url": "https://github.com/shaikhakramshakil/kramscan.git"
@@ -45,7 +48,7 @@
45
48
  "lint": "eslint src --ext .ts",
46
49
  "lint:fix": "eslint src --ext .ts --fix",
47
50
  "format": "prettier --write \"src/**/*.ts\"",
48
- "prepublishOnly": "npm run clean && npm run build"
51
+ "prepublishOnly": "npm test && npm run clean && npm run build"
49
52
  },
50
53
  "dependencies": {
51
54
  "@anthropic-ai/sdk": "^0.31.0",