blun-king-cli 5.4.0 → 6.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/bin/blun.js +134 -0
- package/lib/auth.js +162 -0
- package/lib/chat.js +82 -0
- package/lib/client.js +65 -0
- package/lib/ui.js +215 -0
- package/lib/workspace.js +110 -0
- package/package.json +14 -18
- package/api.js +0 -965
- package/blun-cli.js +0 -3726
- package/blun-cli.js.claude +0 -3578
- package/blunking-api.js +0 -7
- package/bot.js +0 -188
- package/browser-controller.js +0 -116
- package/chat-memory.js +0 -103
- package/file-helper.js +0 -63
- package/fuzzy-match.js +0 -78
- package/identities.js +0 -106
- package/installer.js +0 -160
- package/job-manager.js +0 -146
- package/local-data.js +0 -71
- package/message-builder.js +0 -28
- package/noisy-evals.js +0 -38
- package/palace-memory.js +0 -246
- package/reference-inspector.js +0 -256
- package/runtime.js +0 -570
- package/task-executor.js +0 -104
- package/tests/browser-controller.test.js +0 -47
- package/tests/cli.test.js +0 -93
- package/tests/file-helper.test.js +0 -18
- package/tests/installer.test.js +0 -39
- package/tests/job-manager.test.js +0 -99
- package/tests/merge-compat.test.js +0 -77
- package/tests/messages.test.js +0 -23
- package/tests/noisy-evals.test.js +0 -12
- package/tests/noisy-intent-corpus.test.js +0 -45
- package/tests/reference-inspector.test.js +0 -42
- package/tests/runtime.test.js +0 -119
- package/tests/task-executor.test.js +0 -40
- package/tests/tools.test.js +0 -23
- package/tests/user-profile.test.js +0 -66
- package/tests/website-builder.test.js +0 -66
- package/tmp-build-smoke/nicrazy-landing/index.html +0 -53
- package/tmp-build-smoke/nicrazy-landing/style.css +0 -110
- package/tmp-shot-smoke/website-shot-1776006760424.png +0 -0
- package/tmp-shot-smoke/website-shot-1776007850007.png +0 -0
- package/tmp-shot-smoke/website-shot-1776007886209.png +0 -0
- package/tmp-shot-smoke/website-shot-1776007903766.png +0 -0
- package/tmp-shot-smoke/website-shot-1776008737117.png +0 -0
- package/tmp-shot-smoke/website-shot-1776008988859.png +0 -0
- package/tmp-smoke/nicrazy-landing/index.html +0 -66
- package/tmp-smoke/nicrazy-landing/style.css +0 -104
- package/tools.js +0 -177
- package/user-profile.js +0 -395
- package/website-builder.js +0 -394
- package/website-shot-1776010648230.png +0 -0
- package/website_builder.txt +0 -38
package/reference-inspector.js
DELETED
|
@@ -1,256 +0,0 @@
|
|
|
1
|
-
const path = require("path");
|
|
2
|
-
const { execFile } = require("child_process");
|
|
3
|
-
const { storeReference } = require("./local-data");
|
|
4
|
-
|
|
5
|
-
let chromiumLoader = null;
|
|
6
|
-
|
|
7
|
-
function normalizeDetectedUrl(input) {
|
|
8
|
-
const raw = String(input || "").trim();
|
|
9
|
-
if (!raw) return null;
|
|
10
|
-
|
|
11
|
-
let cleaned = raw
|
|
12
|
-
.replace(/^[<\s"'`(]+/, "")
|
|
13
|
-
.replace(/[>\s"'`),.;:!?]+$/, "");
|
|
14
|
-
|
|
15
|
-
if (!cleaned) return null;
|
|
16
|
-
if (/^www\./i.test(cleaned)) cleaned = `https://${cleaned}`;
|
|
17
|
-
if (/^[a-z0-9.-]+\.[a-z]{2,}(\/|$)/i.test(cleaned) && !/^[a-z][a-z0-9+.-]*:/i.test(cleaned)) {
|
|
18
|
-
cleaned = `https://${cleaned}`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
const parsed = new URL(cleaned);
|
|
23
|
-
if (!/^https?:$/i.test(parsed.protocol) && !/^data:$/i.test(parsed.protocol)) return null;
|
|
24
|
-
return parsed.toString();
|
|
25
|
-
} catch {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function extractUrls(text) {
|
|
31
|
-
const matches = [
|
|
32
|
-
...Array.from(String(text || "").matchAll(/https?:\/\/[^\s)>"']+/gi)).map((match) => match[0]),
|
|
33
|
-
...Array.from(String(text || "").matchAll(/(?:^|[\s<(])((?:www\.)?[a-z0-9.-]+\.[a-z]{2,}(?:\/[^\s)>"']*)?)/gi)).map((match) => match[1])
|
|
34
|
-
];
|
|
35
|
-
|
|
36
|
-
return [...new Set(matches.map(normalizeDetectedUrl).filter(Boolean))];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function summarizeHtml(source) {
|
|
40
|
-
const title = (source.match(/<title[^>]*>([\s\S]*?)<\/title>/i) || [, ""])[1].trim();
|
|
41
|
-
const h1s = [...source.matchAll(/<h1[^>]*>([\s\S]*?)<\/h1>/ig)]
|
|
42
|
-
.map((match) => match[1].replace(/<[^>]+>/g, "").trim())
|
|
43
|
-
.filter(Boolean);
|
|
44
|
-
const links = [...source.matchAll(/<a\b/ig)].length;
|
|
45
|
-
const images = [...source.matchAll(/<img\b/ig)].length;
|
|
46
|
-
const text = cleanText((source.match(/<body[^>]*>([\s\S]*?)<\/body>/i) || [, source])[1]).slice(0, 3000);
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
title,
|
|
50
|
-
h1s,
|
|
51
|
-
links,
|
|
52
|
-
images,
|
|
53
|
-
text,
|
|
54
|
-
responsive: /<meta[^>]+name=["']viewport["']/i.test(source)
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function cleanText(source) {
|
|
59
|
-
return String(source || "")
|
|
60
|
-
.replace(/<script[\s\S]*?<\/script>/gi, " ")
|
|
61
|
-
.replace(/<style[\s\S]*?<\/style>/gi, " ")
|
|
62
|
-
.replace(/<[^>]+>/g, " ")
|
|
63
|
-
.replace(/\s+/g, " ")
|
|
64
|
-
.trim();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function shouldAutoReference(input, task = {}) {
|
|
68
|
-
const text = String(input || "");
|
|
69
|
-
if (!extractUrls(text).length) return false;
|
|
70
|
-
if (["installation", "browser_capture"].includes(task?.type)) return false;
|
|
71
|
-
if (task?.type === "website_builder" || task?.type === "analysis") return true;
|
|
72
|
-
return /\b(referenz|vorlage|inspiriert|angelehnt|wie diese|wie die|schau dir|analysier.*https?:\/\/|bau.*https?:\/\/)\b/i.test(text);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function buildReferencePromptBlock(references = []) {
|
|
76
|
-
if (!Array.isArray(references) || references.length === 0) return "";
|
|
77
|
-
|
|
78
|
-
const lines = ["[Auto Reference Chain]"];
|
|
79
|
-
references.forEach((ref, index) => {
|
|
80
|
-
const summary = ref.summary || ref;
|
|
81
|
-
lines.push(`Referenz ${index + 1}: ${ref.url || "-"}`);
|
|
82
|
-
if (summary.title) lines.push(`Titel: ${summary.title}`);
|
|
83
|
-
if (Array.isArray(summary.h1s) && summary.h1s.length) lines.push(`H1: ${summary.h1s.join(" | ")}`);
|
|
84
|
-
if (summary.text) lines.push(`Text: ${String(summary.text).slice(0, 500)}`);
|
|
85
|
-
if (typeof summary.links === "number") lines.push(`Links: ${summary.links}`);
|
|
86
|
-
if (typeof summary.images === "number") lines.push(`Bilder: ${summary.images}`);
|
|
87
|
-
if (ref.screenshotPath) lines.push(`Screenshot: ${ref.screenshotPath}`);
|
|
88
|
-
if (ref.error) lines.push(`Fehler: ${ref.error}`);
|
|
89
|
-
});
|
|
90
|
-
|
|
91
|
-
return lines.join("\n");
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async function loadChromium() {
|
|
95
|
-
if (chromiumLoader !== null) return chromiumLoader;
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
const playwright = require("playwright");
|
|
99
|
-
chromiumLoader = playwright.chromium;
|
|
100
|
-
} catch {
|
|
101
|
-
chromiumLoader = false;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
return chromiumLoader;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function execFileAsync(command, args) {
|
|
108
|
-
return new Promise((resolve, reject) => {
|
|
109
|
-
execFile(command, args, { maxBuffer: 20 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
110
|
-
if (error) reject(new Error(stderr || error.message));
|
|
111
|
-
else resolve(stdout);
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
async function fetchHtml(url, options = {}) {
|
|
117
|
-
try {
|
|
118
|
-
const resp = await fetch(url, {
|
|
119
|
-
headers: {
|
|
120
|
-
"User-Agent": options.userAgent || "BLUN-King/5.0 (+reference-inspector)"
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
if (!resp.ok) throw new Error(`Reference fetch failed with HTTP ${resp.status}`);
|
|
124
|
-
return await resp.text();
|
|
125
|
-
} catch {
|
|
126
|
-
try {
|
|
127
|
-
const curlBinary = process.platform === "win32" ? "curl.exe" : "curl";
|
|
128
|
-
return await execFileAsync(curlBinary, [
|
|
129
|
-
"-L",
|
|
130
|
-
"-A",
|
|
131
|
-
options.userAgent || "BLUN-King/5.0 (+reference-inspector)",
|
|
132
|
-
url
|
|
133
|
-
]);
|
|
134
|
-
} catch {
|
|
135
|
-
if (process.platform === "win32") {
|
|
136
|
-
const script = [
|
|
137
|
-
`$ProgressPreference='SilentlyContinue'`,
|
|
138
|
-
`$resp = Invoke-WebRequest -UseBasicParsing -Headers @{'User-Agent'='${options.userAgent || "BLUN-King/5.0 (+reference-inspector)"}'} -Uri '${url}'`,
|
|
139
|
-
`[Console]::Out.Write($resp.Content)`
|
|
140
|
-
].join("; ");
|
|
141
|
-
return await execFileAsync("powershell.exe", ["-NoProfile", "-Command", script]);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
throw new Error("Reference fetch failed");
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async function inspectReference(url, options = {}) {
|
|
150
|
-
let html = "";
|
|
151
|
-
let summary = {
|
|
152
|
-
title: "",
|
|
153
|
-
h1s: [],
|
|
154
|
-
links: 0,
|
|
155
|
-
images: 0,
|
|
156
|
-
responsive: false
|
|
157
|
-
};
|
|
158
|
-
const result = {
|
|
159
|
-
url,
|
|
160
|
-
fetchedAt: Date.now(),
|
|
161
|
-
summary,
|
|
162
|
-
html,
|
|
163
|
-
screenshotPath: null,
|
|
164
|
-
screenshotAvailable: false,
|
|
165
|
-
error: null
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
try {
|
|
169
|
-
html = await fetchHtml(url, options);
|
|
170
|
-
summary = summarizeHtml(html);
|
|
171
|
-
result.html = html;
|
|
172
|
-
result.summary = summary;
|
|
173
|
-
} catch (error) {
|
|
174
|
-
result.error = error.message;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
if (!result.error && options.screenshot !== false) {
|
|
178
|
-
const chromium = await loadChromium();
|
|
179
|
-
if (chromium) {
|
|
180
|
-
try {
|
|
181
|
-
const browser = await chromium.launch({ headless: true });
|
|
182
|
-
try {
|
|
183
|
-
const page = await browser.newPage({ viewport: { width: 1440, height: 1024 } });
|
|
184
|
-
await page.goto(url, { waitUntil: "networkidle", timeout: options.timeout || 30000 });
|
|
185
|
-
const stored = storeReference(url, {
|
|
186
|
-
type: "reference",
|
|
187
|
-
mode: "html+screenshot",
|
|
188
|
-
summary
|
|
189
|
-
});
|
|
190
|
-
const screenshotPath = path.join(path.dirname(stored.filePath), `${stored.id}.png`);
|
|
191
|
-
await page.screenshot({ path: screenshotPath, fullPage: true });
|
|
192
|
-
result.screenshotPath = screenshotPath;
|
|
193
|
-
result.screenshotAvailable = true;
|
|
194
|
-
result.storage = stored.filePath;
|
|
195
|
-
} finally {
|
|
196
|
-
await browser.close();
|
|
197
|
-
}
|
|
198
|
-
} catch {
|
|
199
|
-
result.screenshotAvailable = false;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (!result.storage) {
|
|
205
|
-
const stored = storeReference(url, {
|
|
206
|
-
type: "reference",
|
|
207
|
-
mode: result.error ? "error" : "html",
|
|
208
|
-
summary,
|
|
209
|
-
error: result.error
|
|
210
|
-
});
|
|
211
|
-
result.storage = stored.filePath;
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
return result;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async function screenshotUrl(url, options = {}) {
|
|
218
|
-
const result = await inspectReference(url, { ...options, screenshot: true });
|
|
219
|
-
return {
|
|
220
|
-
url: result.url,
|
|
221
|
-
screenshotPath: result.screenshotPath,
|
|
222
|
-
screenshotAvailable: result.screenshotAvailable,
|
|
223
|
-
summary: result.summary,
|
|
224
|
-
storage: result.storage,
|
|
225
|
-
error: result.error
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
async function autoReferenceChain(input, options = {}) {
|
|
230
|
-
const urls = extractUrls(input).slice(0, options.limit || 2);
|
|
231
|
-
const references = [];
|
|
232
|
-
|
|
233
|
-
for (const url of urls) {
|
|
234
|
-
try {
|
|
235
|
-
references.push(await inspectReference(url, { screenshot: options.screenshot !== false }));
|
|
236
|
-
} catch (error) {
|
|
237
|
-
references.push({
|
|
238
|
-
url,
|
|
239
|
-
error: error.message,
|
|
240
|
-
summary: { title: "", h1s: [], links: 0, images: 0, text: "", responsive: false }
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
return references;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
module.exports = {
|
|
249
|
-
extractUrls,
|
|
250
|
-
inspectReference,
|
|
251
|
-
summarizeHtml,
|
|
252
|
-
shouldAutoReference,
|
|
253
|
-
buildReferencePromptBlock,
|
|
254
|
-
screenshotUrl,
|
|
255
|
-
autoReferenceChain
|
|
256
|
-
};
|