blun-king-cli 5.3.7 → 6.0.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 (54) hide show
  1. package/bin/blun.js +100 -0
  2. package/lib/auth.js +162 -0
  3. package/lib/chat.js +82 -0
  4. package/lib/client.js +65 -0
  5. package/lib/ui.js +215 -0
  6. package/package.json +14 -18
  7. package/api.js +0 -965
  8. package/blun-cli.js +0 -3534
  9. package/blunking-api.js +0 -7
  10. package/bot.js +0 -188
  11. package/browser-controller.js +0 -102
  12. package/chat-memory.js +0 -103
  13. package/file-helper.js +0 -63
  14. package/fuzzy-match.js +0 -78
  15. package/identities.js +0 -106
  16. package/installer.js +0 -160
  17. package/job-manager.js +0 -146
  18. package/local-data.js +0 -71
  19. package/message-builder.js +0 -28
  20. package/noisy-evals.js +0 -38
  21. package/palace-memory.js +0 -246
  22. package/reference-inspector.js +0 -256
  23. package/runtime.js +0 -569
  24. package/task-executor.js +0 -104
  25. package/tests/browser-controller.test.js +0 -47
  26. package/tests/cli.test.js +0 -93
  27. package/tests/file-helper.test.js +0 -18
  28. package/tests/installer.test.js +0 -39
  29. package/tests/job-manager.test.js +0 -99
  30. package/tests/merge-compat.test.js +0 -77
  31. package/tests/messages.test.js +0 -23
  32. package/tests/noisy-evals.test.js +0 -12
  33. package/tests/noisy-intent-corpus.test.js +0 -45
  34. package/tests/reference-inspector.test.js +0 -42
  35. package/tests/runtime.test.js +0 -119
  36. package/tests/task-executor.test.js +0 -40
  37. package/tests/tools.test.js +0 -23
  38. package/tests/user-profile.test.js +0 -66
  39. package/tests/website-builder.test.js +0 -66
  40. package/tmp-build-smoke/nicrazy-landing/index.html +0 -53
  41. package/tmp-build-smoke/nicrazy-landing/style.css +0 -110
  42. package/tmp-shot-smoke/website-shot-1776006760424.png +0 -0
  43. package/tmp-shot-smoke/website-shot-1776007850007.png +0 -0
  44. package/tmp-shot-smoke/website-shot-1776007886209.png +0 -0
  45. package/tmp-shot-smoke/website-shot-1776007903766.png +0 -0
  46. package/tmp-shot-smoke/website-shot-1776008737117.png +0 -0
  47. package/tmp-shot-smoke/website-shot-1776008988859.png +0 -0
  48. package/tmp-smoke/nicrazy-landing/index.html +0 -66
  49. package/tmp-smoke/nicrazy-landing/style.css +0 -104
  50. package/tools.js +0 -177
  51. package/user-profile.js +0 -395
  52. package/website-builder.js +0 -394
  53. package/website-shot-1776010648230.png +0 -0
  54. package/website_builder.txt +0 -38
@@ -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
- };