craftclose 0.1.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/LICENSE +21 -0
- package/README.md +176 -0
- package/SKILL.md +139 -0
- package/craftclose.example.yml +84 -0
- package/dist/ai-analyzer.d.ts +96 -0
- package/dist/ai-analyzer.d.ts.map +1 -0
- package/dist/ai-analyzer.js +275 -0
- package/dist/ai-analyzer.js.map +1 -0
- package/dist/alerts/discord.d.ts +23 -0
- package/dist/alerts/discord.d.ts.map +1 -0
- package/dist/alerts/discord.js +95 -0
- package/dist/alerts/discord.js.map +1 -0
- package/dist/alerts/index.d.ts +5 -0
- package/dist/alerts/index.d.ts.map +1 -0
- package/dist/alerts/index.js +8 -0
- package/dist/alerts/index.js.map +1 -0
- package/dist/alerts/telegram.d.ts +25 -0
- package/dist/alerts/telegram.d.ts.map +1 -0
- package/dist/alerts/telegram.js +72 -0
- package/dist/alerts/telegram.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +410 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +36 -0
- package/dist/config.js.map +1 -0
- package/dist/connectors/index.d.ts +8 -0
- package/dist/connectors/index.d.ts.map +1 -0
- package/dist/connectors/index.js +14 -0
- package/dist/connectors/index.js.map +1 -0
- package/dist/connectors/parsers.d.ts +24 -0
- package/dist/connectors/parsers.d.ts.map +1 -0
- package/dist/connectors/parsers.js +64 -0
- package/dist/connectors/parsers.js.map +1 -0
- package/dist/connectors/pterodactyl.d.ts +90 -0
- package/dist/connectors/pterodactyl.d.ts.map +1 -0
- package/dist/connectors/pterodactyl.js +221 -0
- package/dist/connectors/pterodactyl.js.map +1 -0
- package/dist/connectors/rcon.d.ts +51 -0
- package/dist/connectors/rcon.d.ts.map +1 -0
- package/dist/connectors/rcon.js +95 -0
- package/dist/connectors/rcon.js.map +1 -0
- package/dist/connectors/ssh.d.ts +65 -0
- package/dist/connectors/ssh.d.ts.map +1 -0
- package/dist/connectors/ssh.js +273 -0
- package/dist/connectors/ssh.js.map +1 -0
- package/dist/craft-close-skill.d.ts +106 -0
- package/dist/craft-close-skill.d.ts.map +1 -0
- package/dist/craft-close-skill.js +604 -0
- package/dist/craft-close-skill.js.map +1 -0
- package/dist/history.d.ts +32 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +194 -0
- package/dist/history.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +28 -0
- package/dist/index.js.map +1 -0
- package/dist/openclaw-entry.d.ts +29 -0
- package/dist/openclaw-entry.d.ts.map +1 -0
- package/dist/openclaw-entry.js +45 -0
- package/dist/openclaw-entry.js.map +1 -0
- package/dist/patterns/index.d.ts +32 -0
- package/dist/patterns/index.d.ts.map +1 -0
- package/dist/patterns/index.js +248 -0
- package/dist/patterns/index.js.map +1 -0
- package/dist/security/action-allowlist.d.ts +21 -0
- package/dist/security/action-allowlist.d.ts.map +1 -0
- package/dist/security/action-allowlist.js +54 -0
- package/dist/security/action-allowlist.js.map +1 -0
- package/dist/security/audit-log.d.ts +22 -0
- package/dist/security/audit-log.d.ts.map +1 -0
- package/dist/security/audit-log.js +49 -0
- package/dist/security/audit-log.js.map +1 -0
- package/dist/security/index.d.ts +10 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js +20 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/input-sanitizer.d.ts +32 -0
- package/dist/security/input-sanitizer.d.ts.map +1 -0
- package/dist/security/input-sanitizer.js +81 -0
- package/dist/security/input-sanitizer.js.map +1 -0
- package/dist/security/path-jail.d.ts +25 -0
- package/dist/security/path-jail.d.ts.map +1 -0
- package/dist/security/path-jail.js +73 -0
- package/dist/security/path-jail.js.map +1 -0
- package/dist/security/rcon-filter.d.ts +24 -0
- package/dist/security/rcon-filter.d.ts.map +1 -0
- package/dist/security/rcon-filter.js +76 -0
- package/dist/security/rcon-filter.js.map +1 -0
- package/dist/types.d.ts +154 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CraftClose ā BYOK AI Crash Analyzer
|
|
4
|
+
*
|
|
5
|
+
* Uses the user's own Gemini API key for crash log analysis.
|
|
6
|
+
* No backend, no paid tier ā direct Gemini API calls.
|
|
7
|
+
* AI analysis is always best-effort: returns null on failure, never blocks monitoring.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.AIAnalyzer = void 0;
|
|
11
|
+
const node_crypto_1 = require("node:crypto");
|
|
12
|
+
const API_BASE = "https://generativelanguage.googleapis.com/v1beta/models";
|
|
13
|
+
class AIAnalyzer {
|
|
14
|
+
apiKey;
|
|
15
|
+
model;
|
|
16
|
+
maxCallsPerHour;
|
|
17
|
+
cacheTtlMs;
|
|
18
|
+
timeout;
|
|
19
|
+
crashCache = new Map();
|
|
20
|
+
callTimestamps = [];
|
|
21
|
+
constructor(options) {
|
|
22
|
+
this.apiKey = options.geminiKey;
|
|
23
|
+
this.model = options.model ?? "gemini-2.5-flash";
|
|
24
|
+
this.maxCallsPerHour = options.maxCallsPerHour ?? 10;
|
|
25
|
+
this.cacheTtlMs = options.cacheTtlMs ?? 24 * 60 * 60 * 1000;
|
|
26
|
+
this.timeout = options.timeout ?? 30_000;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Analyze a crash log. Returns null if rate-limited, cached, or on error.
|
|
30
|
+
*/
|
|
31
|
+
async analyzeCrash(request) {
|
|
32
|
+
const cacheKey = this.hashLog(request.log);
|
|
33
|
+
const cached = this.getCached(cacheKey);
|
|
34
|
+
if (cached)
|
|
35
|
+
return cached;
|
|
36
|
+
if (!this.checkRateLimit())
|
|
37
|
+
return null;
|
|
38
|
+
try {
|
|
39
|
+
const prompt = this.buildCrashAnalysisPrompt(request);
|
|
40
|
+
const raw = await this.callGemini(prompt);
|
|
41
|
+
const parsed = this.parseJsonResponse(raw, ["root_cause", "severity", "fix_suggestion", "confidence"]);
|
|
42
|
+
const result = {
|
|
43
|
+
root_cause: parsed.root_cause,
|
|
44
|
+
severity: parsed.severity,
|
|
45
|
+
fix_suggestion: parsed.fix_suggestion,
|
|
46
|
+
confidence: parsed.confidence,
|
|
47
|
+
model: this.model,
|
|
48
|
+
cached: false,
|
|
49
|
+
};
|
|
50
|
+
this.crashCache.set(cacheKey, { result, timestamp: Date.now() });
|
|
51
|
+
return result;
|
|
52
|
+
}
|
|
53
|
+
catch (err) {
|
|
54
|
+
console.error(`[CraftClose] AI crash analysis failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Optimize server configs. Returns null on failure.
|
|
60
|
+
*/
|
|
61
|
+
async optimizeConfig(request) {
|
|
62
|
+
if (!this.checkRateLimit())
|
|
63
|
+
return null;
|
|
64
|
+
try {
|
|
65
|
+
const prompt = this.buildConfigOptimizePrompt(request);
|
|
66
|
+
const raw = await this.callGemini(prompt);
|
|
67
|
+
const parsed = this.parseJsonResponse(raw, []);
|
|
68
|
+
if (!Array.isArray(parsed)) {
|
|
69
|
+
throw new TypeError("Expected array of config recommendations");
|
|
70
|
+
}
|
|
71
|
+
return parsed;
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
console.error(`[CraftClose] AI config optimization failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Detect plugin conflicts. Returns null on failure.
|
|
80
|
+
*/
|
|
81
|
+
async detectConflicts(request) {
|
|
82
|
+
if (!this.checkRateLimit())
|
|
83
|
+
return null;
|
|
84
|
+
try {
|
|
85
|
+
const prompt = this.buildConflictDetectionPrompt(request);
|
|
86
|
+
const raw = await this.callGemini(prompt);
|
|
87
|
+
const parsed = this.parseJsonResponse(raw, []);
|
|
88
|
+
if (!Array.isArray(parsed)) {
|
|
89
|
+
throw new TypeError("Expected array of plugin conflicts");
|
|
90
|
+
}
|
|
91
|
+
return parsed;
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
console.error(`[CraftClose] AI conflict detection failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/** Hash the first 2000 chars of a log for cache lookup. */
|
|
99
|
+
hashLog(log) {
|
|
100
|
+
return (0, node_crypto_1.createHash)("sha256").update(log.slice(0, 2000)).digest("hex");
|
|
101
|
+
}
|
|
102
|
+
/** Check cache for a previous analysis result. */
|
|
103
|
+
getCached(key) {
|
|
104
|
+
const entry = this.crashCache.get(key);
|
|
105
|
+
if (!entry)
|
|
106
|
+
return null;
|
|
107
|
+
if (Date.now() - entry.timestamp > this.cacheTtlMs) {
|
|
108
|
+
this.crashCache.delete(key);
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
return { ...entry.result, cached: true };
|
|
112
|
+
}
|
|
113
|
+
/** Sliding-window rate limiter. Returns false if limit exceeded. */
|
|
114
|
+
checkRateLimit() {
|
|
115
|
+
const oneHourAgo = Date.now() - 60 * 60 * 1000;
|
|
116
|
+
while (this.callTimestamps.length > 0 && this.callTimestamps[0] <= oneHourAgo) {
|
|
117
|
+
this.callTimestamps.shift();
|
|
118
|
+
}
|
|
119
|
+
if (this.callTimestamps.length >= this.maxCallsPerHour) {
|
|
120
|
+
console.warn("[CraftClose] AI rate limit reached ā skipping analysis");
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
this.callTimestamps.push(Date.now());
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
/** Call Gemini generateContent API. */
|
|
127
|
+
async callGemini(prompt) {
|
|
128
|
+
const url = `${API_BASE}/${this.model}:generateContent?key=${this.apiKey}`;
|
|
129
|
+
const controller = new AbortController();
|
|
130
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
131
|
+
try {
|
|
132
|
+
const response = await fetch(url, {
|
|
133
|
+
method: "POST",
|
|
134
|
+
headers: { "Content-Type": "application/json" },
|
|
135
|
+
body: JSON.stringify({
|
|
136
|
+
contents: [{ parts: [{ text: prompt }] }],
|
|
137
|
+
generationConfig: { temperature: 0.2, maxOutputTokens: 2048 },
|
|
138
|
+
}),
|
|
139
|
+
signal: controller.signal,
|
|
140
|
+
});
|
|
141
|
+
if (!response.ok) {
|
|
142
|
+
const body = await response.text();
|
|
143
|
+
throw new Error(`Gemini API error ${response.status}: ${body.slice(0, 500)}`);
|
|
144
|
+
}
|
|
145
|
+
const data = (await response.json());
|
|
146
|
+
const text = data.candidates?.[0]?.content?.parts?.[0]?.text;
|
|
147
|
+
if (!text) {
|
|
148
|
+
throw new Error("Gemini returned empty response");
|
|
149
|
+
}
|
|
150
|
+
return text;
|
|
151
|
+
}
|
|
152
|
+
finally {
|
|
153
|
+
clearTimeout(timer);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** Parse JSON from model response, with retry on parse failure. */
|
|
157
|
+
parseJsonResponse(raw, requiredFields) {
|
|
158
|
+
const cleaned = raw.replaceAll(/```json\s*/g, "").replaceAll(/```\s*/g, "").trim();
|
|
159
|
+
try {
|
|
160
|
+
return this.validateJson(cleaned, requiredFields);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
const jsonMatch = /\{[\s\S]*\}|\[[\s\S]*\]/u.exec(cleaned);
|
|
164
|
+
if (!jsonMatch) {
|
|
165
|
+
throw new Error(`Failed to parse Gemini response as JSON: ${cleaned.slice(0, 200)}`);
|
|
166
|
+
}
|
|
167
|
+
return this.validateJson(jsonMatch[0], requiredFields);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
validateJson(text, requiredFields) {
|
|
171
|
+
const parsed = JSON.parse(text);
|
|
172
|
+
for (const field of requiredFields) {
|
|
173
|
+
if (parsed[field] === undefined) {
|
|
174
|
+
throw new Error(`Missing required field '${field}' in Gemini response`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
return parsed;
|
|
178
|
+
}
|
|
179
|
+
/** Build crash analysis prompt with few-shot examples and guardrails. */
|
|
180
|
+
buildCrashAnalysisPrompt(request) {
|
|
181
|
+
const ctx = request.context;
|
|
182
|
+
return `You are CraftClose, an expert Minecraft server diagnostician. Analyze the following crash log and provide a diagnosis.
|
|
183
|
+
|
|
184
|
+
## Rules (STRICT)
|
|
185
|
+
- Be specific and actionable. Say WHICH plugin and WHY, not "check your plugins".
|
|
186
|
+
- Include confidence as a 0-100 integer.
|
|
187
|
+
- NEVER suggest destructive actions: no "delete your world", no "remove all plugins", no "reinstall the server".
|
|
188
|
+
- ALWAYS suggest backups before any configuration change.
|
|
189
|
+
- Only reference plugins that appear in the provided plugin list.
|
|
190
|
+
- If you're not confident, say so. Low confidence is better than wrong confidence.
|
|
191
|
+
- Respond with ONLY valid JSON, no markdown, no explanation.
|
|
192
|
+
|
|
193
|
+
## Server Context
|
|
194
|
+
- Version: ${ctx.version ?? "Unknown"}
|
|
195
|
+
- Server type: ${ctx.server_type ?? "Unknown"}
|
|
196
|
+
- Plugins: ${ctx.plugins?.join(", ") ?? "Unknown"}
|
|
197
|
+
- RAM: ${ctx.ram_mb ? `${ctx.ram_mb}MB` : "Unknown"}
|
|
198
|
+
- Players at crash: ${ctx.player_count ?? "Unknown"}
|
|
199
|
+
|
|
200
|
+
## Few-Shot Examples
|
|
201
|
+
|
|
202
|
+
### Example 1
|
|
203
|
+
Log: "java.lang.OutOfMemoryError: Java heap space\\n at com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard.<init>"
|
|
204
|
+
Response:
|
|
205
|
+
{"root_cause": "WorldEdit clipboard operation exceeded heap memory. A large //copy or //paste operation loaded too many blocks into RAM.", "severity": "critical", "fix_suggestion": "1. Back up your server. 2. Increase -Xmx to at least 8GB using Aikar flags. 3. Install FAWE (Fast Async WorldEdit) for large operations. 4. Set //limit 50000 to cap block changes.", "confidence": 95}
|
|
206
|
+
|
|
207
|
+
### Example 2
|
|
208
|
+
Log: "Could not pass event PlayerJoinEvent to EssentialsX v2.20.1\\norg.bukkit.event.EventException\\n Caused by: java.lang.NullPointerException"
|
|
209
|
+
Response:
|
|
210
|
+
{"root_cause": "EssentialsX threw a NullPointerException during PlayerJoinEvent. Likely a corrupted player data file in plugins/Essentials/userdata/.", "severity": "warning", "fix_suggestion": "1. Back up plugins/Essentials/userdata/. 2. Delete the affected player's yml file to reset their Essentials data. 3. Update EssentialsX to the latest version.", "confidence": 82}
|
|
211
|
+
|
|
212
|
+
### Example 3
|
|
213
|
+
Log: "java.net.BindException: Address already in use: bind\\n at sun.nio.ch.Net.bind0(Native Method)\\n at net.minecraft.server.dedicated.DedicatedServer.init"
|
|
214
|
+
Response:
|
|
215
|
+
{"root_cause": "Port 25565 is already in use by another process. A previous server instance may still be running.", "severity": "critical", "fix_suggestion": "1. Run 'netstat -tlnp | grep 25565' to find the process using the port. 2. Kill the old process or wait for it to shut down. 3. Then start the server.", "confidence": 97}
|
|
216
|
+
|
|
217
|
+
## Crash Log (last 200 lines)
|
|
218
|
+
\`\`\`
|
|
219
|
+
${request.log.slice(0, 8000)}
|
|
220
|
+
\`\`\`
|
|
221
|
+
|
|
222
|
+
## Your Analysis (respond with ONLY this JSON format)
|
|
223
|
+
{"root_cause": "...", "severity": "critical|warning|info", "fix_suggestion": "...", "confidence": 0-100}`;
|
|
224
|
+
}
|
|
225
|
+
/** Build config optimization prompt. */
|
|
226
|
+
buildConfigOptimizePrompt(request) {
|
|
227
|
+
const configEntries = Object.entries(request.configs)
|
|
228
|
+
.map(([file, content]) => `### ${file}\n\`\`\`\n${content.slice(0, 3000)}\n\`\`\``)
|
|
229
|
+
.join("\n\n");
|
|
230
|
+
return `You are CraftClose, a Minecraft server performance optimization expert. Analyze the server configuration files and suggest improvements.
|
|
231
|
+
|
|
232
|
+
## Rules (STRICT)
|
|
233
|
+
- Only suggest changes with risk level "safe", "low", or "medium". Never suggest "high" risk changes.
|
|
234
|
+
- Always explain WHY each change helps.
|
|
235
|
+
- Always recommend backing up before making changes.
|
|
236
|
+
- Focus on: view-distance, simulation-distance, entity limits, chunk loading, network compression, mob spawning, JVM flags (Aikar).
|
|
237
|
+
- Respond with ONLY a valid JSON array, no markdown, no explanation.
|
|
238
|
+
|
|
239
|
+
## Server Info
|
|
240
|
+
- Server type: ${request.server_type}
|
|
241
|
+
- RAM: ${request.ram_mb}MB
|
|
242
|
+
- Target player count: ${request.player_target}
|
|
243
|
+
|
|
244
|
+
## Config Files
|
|
245
|
+
${configEntries}
|
|
246
|
+
|
|
247
|
+
## Your Recommendations (respond with ONLY a JSON array)
|
|
248
|
+
[{"file": "...", "setting": "...", "current_value": "...", "recommended_value": "...", "reason": "...", "risk": "safe|low|medium"}, ...]`;
|
|
249
|
+
}
|
|
250
|
+
/** Build plugin conflict detection prompt. */
|
|
251
|
+
buildConflictDetectionPrompt(request) {
|
|
252
|
+
const pluginList = request.plugins
|
|
253
|
+
.map(p => `- ${p.name} v${p.version}`)
|
|
254
|
+
.join("\n");
|
|
255
|
+
const crashSection = request.crash_log
|
|
256
|
+
? `\n## Recent Crash Log\n\`\`\`\n${request.crash_log.slice(0, 4000)}\n\`\`\``
|
|
257
|
+
: "";
|
|
258
|
+
return `You are CraftClose, a Minecraft plugin compatibility expert. Analyze the installed plugins for known conflicts or incompatibilities.
|
|
259
|
+
|
|
260
|
+
## Rules (STRICT)
|
|
261
|
+
- Only report REAL conflicts. Do not fabricate conflicts.
|
|
262
|
+
- Mark as "known" if it's a well-documented incompatibility, "suspected" if the crash log suggests it.
|
|
263
|
+
- If there are NO conflicts, return an empty array [].
|
|
264
|
+
- Respond with ONLY a valid JSON array, no markdown, no explanation.
|
|
265
|
+
|
|
266
|
+
## Installed Plugins
|
|
267
|
+
${pluginList}
|
|
268
|
+
${crashSection}
|
|
269
|
+
|
|
270
|
+
## Your Analysis (respond with ONLY a JSON array)
|
|
271
|
+
[{"plugins": [...], "type": "known|suspected", "description": "...", "resolution": "..."}, ...]`;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
exports.AIAnalyzer = AIAnalyzer;
|
|
275
|
+
//# sourceMappingURL=ai-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-analyzer.js","sourceRoot":"","sources":["../src/ai-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discord Alert Channel
|
|
3
|
+
*
|
|
4
|
+
* Sends crash alerts via Discord webhook embeds.
|
|
5
|
+
*/
|
|
6
|
+
import type { AlertPayload } from "../types.js";
|
|
7
|
+
export interface DiscordAlertOptions {
|
|
8
|
+
webhook_url: string;
|
|
9
|
+
}
|
|
10
|
+
export declare class DiscordAlert {
|
|
11
|
+
private options;
|
|
12
|
+
constructor(options: DiscordAlertOptions);
|
|
13
|
+
/**
|
|
14
|
+
* Send an alert as a Discord webhook embed.
|
|
15
|
+
*/
|
|
16
|
+
send(payload: AlertPayload): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Build a Discord embed from the alert payload.
|
|
19
|
+
*/
|
|
20
|
+
private buildEmbed;
|
|
21
|
+
private getSeverityColor;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=discord.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord.d.ts","sourceRoot":"","sources":["../../src/alerts/discord.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,YAAY;IACvB,OAAO,CAAC,OAAO,CAAsB;gBAEzB,OAAO,EAAE,mBAAmB;IAIxC;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBhD;;OAEG;IACH,OAAO,CAAC,UAAU;IAsDlB,OAAO,CAAC,gBAAgB;CASzB"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Discord Alert Channel
|
|
4
|
+
*
|
|
5
|
+
* Sends crash alerts via Discord webhook embeds.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.DiscordAlert = void 0;
|
|
9
|
+
class DiscordAlert {
|
|
10
|
+
options;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.options = options;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Send an alert as a Discord webhook embed.
|
|
16
|
+
*/
|
|
17
|
+
async send(payload) {
|
|
18
|
+
const embed = this.buildEmbed(payload);
|
|
19
|
+
const response = await fetch(this.options.webhook_url, {
|
|
20
|
+
method: "POST",
|
|
21
|
+
headers: { "Content-Type": "application/json" },
|
|
22
|
+
body: JSON.stringify({
|
|
23
|
+
username: "CraftClose",
|
|
24
|
+
avatar_url: "https://craftclose.dev/icon.png",
|
|
25
|
+
embeds: [embed],
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
if (!response.ok) {
|
|
29
|
+
throw new Error(`Discord webhook error: ${response.status} ${await response.text()}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Build a Discord embed from the alert payload.
|
|
34
|
+
*/
|
|
35
|
+
buildEmbed(payload) {
|
|
36
|
+
const color = this.getSeverityColor(payload.severity);
|
|
37
|
+
const fields = [];
|
|
38
|
+
if (payload.pattern_match) {
|
|
39
|
+
fields.push({
|
|
40
|
+
name: "š Known Issue",
|
|
41
|
+
value: payload.pattern_match.title,
|
|
42
|
+
inline: true,
|
|
43
|
+
});
|
|
44
|
+
fields.push({
|
|
45
|
+
name: "š” Fix",
|
|
46
|
+
value: payload.pattern_match.fix.slice(0, 1024),
|
|
47
|
+
inline: false,
|
|
48
|
+
});
|
|
49
|
+
fields.push({
|
|
50
|
+
name: "šÆ Confidence",
|
|
51
|
+
value: `${Math.round(payload.pattern_match.confidence * 100)}%`,
|
|
52
|
+
inline: true,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
if (payload.ai_analysis) {
|
|
56
|
+
fields.push({
|
|
57
|
+
name: "š¤ AI Analysis",
|
|
58
|
+
value: payload.ai_analysis.root_cause.slice(0, 1024),
|
|
59
|
+
inline: false,
|
|
60
|
+
});
|
|
61
|
+
fields.push({
|
|
62
|
+
name: "š” AI Suggestion",
|
|
63
|
+
value: payload.ai_analysis.fix_suggestion.slice(0, 1024),
|
|
64
|
+
inline: false,
|
|
65
|
+
});
|
|
66
|
+
fields.push({
|
|
67
|
+
name: "šÆ Confidence",
|
|
68
|
+
value: `${Math.round(payload.ai_analysis.confidence * 100)}%${payload.ai_analysis.cached ? " (cached)" : ""}`,
|
|
69
|
+
inline: true,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
title: payload.title,
|
|
74
|
+
description: payload.description,
|
|
75
|
+
color,
|
|
76
|
+
fields,
|
|
77
|
+
footer: {
|
|
78
|
+
text: `CraftClose Ā· ${payload.server}`,
|
|
79
|
+
icon_url: "https://craftclose.dev/icon.png",
|
|
80
|
+
},
|
|
81
|
+
timestamp: payload.timestamp.toISOString(),
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
getSeverityColor(severity) {
|
|
85
|
+
switch (severity) {
|
|
86
|
+
case "critical": return 0xff0000; // Red
|
|
87
|
+
case "warning": return 0xff9900; // Orange
|
|
88
|
+
case "info": return 0x3498db; // Blue
|
|
89
|
+
case "recovery": return 0x2ecc71; // Green
|
|
90
|
+
default: return 0x95a5a6; // Gray
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.DiscordAlert = DiscordAlert;
|
|
95
|
+
//# sourceMappingURL=discord.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discord.js","sourceRoot":"","sources":["../../src/alerts/discord.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/alerts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,YAAY,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DiscordAlert = exports.TelegramAlert = void 0;
|
|
4
|
+
var telegram_js_1 = require("./telegram.js");
|
|
5
|
+
Object.defineProperty(exports, "TelegramAlert", { enumerable: true, get: function () { return telegram_js_1.TelegramAlert; } });
|
|
6
|
+
var discord_js_1 = require("./discord.js");
|
|
7
|
+
Object.defineProperty(exports, "DiscordAlert", { enumerable: true, get: function () { return discord_js_1.DiscordAlert; } });
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/alerts/index.ts"],"names":[],"mappings":";;;AAAA,6CAA8C;AAArC,4GAAA,aAAa,OAAA;AAEtB,2CAA4C;AAAnC,0GAAA,YAAY,OAAA"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram Alert Channel
|
|
3
|
+
*
|
|
4
|
+
* Sends crash alerts, recovery notifications, and status updates via Telegram Bot API.
|
|
5
|
+
*/
|
|
6
|
+
import type { AlertPayload } from "../types.js";
|
|
7
|
+
export interface TelegramAlertOptions {
|
|
8
|
+
bot_token: string;
|
|
9
|
+
chat_id: string;
|
|
10
|
+
}
|
|
11
|
+
export declare class TelegramAlert {
|
|
12
|
+
private options;
|
|
13
|
+
private apiBase;
|
|
14
|
+
constructor(options: TelegramAlertOptions);
|
|
15
|
+
/**
|
|
16
|
+
* Send an alert message to Telegram.
|
|
17
|
+
*/
|
|
18
|
+
send(payload: AlertPayload): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Format alert payload into a Telegram message.
|
|
21
|
+
*/
|
|
22
|
+
private formatMessage;
|
|
23
|
+
private getSeverityEmoji;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=telegram.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.d.ts","sourceRoot":"","sources":["../../src/alerts/telegram.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEhD,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,OAAO,CAAS;gBAEZ,OAAO,EAAE,oBAAoB;IAKzC;;OAEG;IACG,IAAI,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBhD;;OAEG;IACH,OAAO,CAAC,aAAa;IA4BrB,OAAO,CAAC,gBAAgB;CASzB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Telegram Alert Channel
|
|
4
|
+
*
|
|
5
|
+
* Sends crash alerts, recovery notifications, and status updates via Telegram Bot API.
|
|
6
|
+
*/
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.TelegramAlert = void 0;
|
|
9
|
+
class TelegramAlert {
|
|
10
|
+
options;
|
|
11
|
+
apiBase;
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.options = options;
|
|
14
|
+
this.apiBase = `https://api.telegram.org/bot${options.bot_token}`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Send an alert message to Telegram.
|
|
18
|
+
*/
|
|
19
|
+
async send(payload) {
|
|
20
|
+
const message = this.formatMessage(payload);
|
|
21
|
+
const response = await fetch(`${this.apiBase}/sendMessage`, {
|
|
22
|
+
method: "POST",
|
|
23
|
+
headers: { "Content-Type": "application/json" },
|
|
24
|
+
body: JSON.stringify({
|
|
25
|
+
chat_id: this.options.chat_id,
|
|
26
|
+
text: message,
|
|
27
|
+
parse_mode: "Markdown",
|
|
28
|
+
disable_web_page_preview: true,
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
if (!response.ok) {
|
|
32
|
+
throw new Error(`Telegram API error: ${response.status} ${await response.text()}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Format alert payload into a Telegram message.
|
|
37
|
+
*/
|
|
38
|
+
formatMessage(payload) {
|
|
39
|
+
const emoji = this.getSeverityEmoji(payload.severity);
|
|
40
|
+
const time = payload.timestamp.toLocaleTimeString("en-US", { hour12: false });
|
|
41
|
+
let message = `${emoji} *CraftClose ā ${payload.server}*\n`;
|
|
42
|
+
message += `${payload.title}\n\n`;
|
|
43
|
+
message += `${payload.description}\n`;
|
|
44
|
+
message += `\nā° ${time}`;
|
|
45
|
+
if (payload.pattern_match) {
|
|
46
|
+
message += `\n\nš *Known Issue:* ${payload.pattern_match.title}`;
|
|
47
|
+
message += `\nš” *Fix:* ${payload.pattern_match.fix}`;
|
|
48
|
+
message += `\nšÆ Confidence: ${Math.round(payload.pattern_match.confidence * 100)}%`;
|
|
49
|
+
}
|
|
50
|
+
if (payload.ai_analysis) {
|
|
51
|
+
message += `\n\nš¤ *AI Analysis:*`;
|
|
52
|
+
message += `\n${payload.ai_analysis.root_cause}`;
|
|
53
|
+
message += `\nš” *Suggestion:* ${payload.ai_analysis.fix_suggestion}`;
|
|
54
|
+
message += `\nšÆ Confidence: ${Math.round(payload.ai_analysis.confidence * 100)}%`;
|
|
55
|
+
if (payload.ai_analysis.cached) {
|
|
56
|
+
message += ` (cached)`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return message;
|
|
60
|
+
}
|
|
61
|
+
getSeverityEmoji(severity) {
|
|
62
|
+
switch (severity) {
|
|
63
|
+
case "critical": return "š“";
|
|
64
|
+
case "warning": return "š”";
|
|
65
|
+
case "info": return "šµ";
|
|
66
|
+
case "recovery": return "š¢";
|
|
67
|
+
default: return "āŖ";
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.TelegramAlert = TelegramAlert;
|
|
72
|
+
//# sourceMappingURL=telegram.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"telegram.js","sourceRoot":"","sources":["../../src/alerts/telegram.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;GAEG"}
|