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.
- package/bin/blun.js +100 -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/package.json +14 -18
- package/api.js +0 -965
- package/blun-cli.js +0 -3534
- package/blunking-api.js +0 -7
- package/bot.js +0 -188
- package/browser-controller.js +0 -102
- 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 -569
- 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
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
const fs = require("node:fs");
|
|
4
|
-
const os = require("node:os");
|
|
5
|
-
const path = require("node:path");
|
|
6
|
-
|
|
7
|
-
const browser = require("../browser-controller");
|
|
8
|
-
|
|
9
|
-
test("browser controller can open, type, click and inspect a page", async () => {
|
|
10
|
-
const html = [
|
|
11
|
-
"<!doctype html>",
|
|
12
|
-
"<html><body>",
|
|
13
|
-
'<input id="name" />',
|
|
14
|
-
'<button id="run" onclick="document.querySelector(\'#output\').textContent = document.querySelector(\'#name\').value">Run</button>',
|
|
15
|
-
'<div id="output"></div>',
|
|
16
|
-
"</body></html>"
|
|
17
|
-
].join("");
|
|
18
|
-
const url = `data:text/html,${encodeURIComponent(html)}`;
|
|
19
|
-
|
|
20
|
-
await browser.open(url);
|
|
21
|
-
await browser.type("#name", "browser-ok");
|
|
22
|
-
await browser.click("#run");
|
|
23
|
-
const snapshot = await browser.snapshot();
|
|
24
|
-
|
|
25
|
-
assert.equal(snapshot.url.startsWith("data:text/html"), true);
|
|
26
|
-
assert.equal(snapshot.text.includes("browser-ok"), true);
|
|
27
|
-
|
|
28
|
-
await browser.close();
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
test("browser controller can save a screenshot file", async () => {
|
|
32
|
-
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "blun-browser-"));
|
|
33
|
-
const target = path.join(dir, "page.png");
|
|
34
|
-
|
|
35
|
-
await browser.open("data:text/html,%3C!doctype%20html%3E%3Chtml%3E%3Cbody%3Escreenshot-ok%3C%2Fbody%3E%3C%2Fhtml%3E");
|
|
36
|
-
const shot = await browser.screenshot(target);
|
|
37
|
-
|
|
38
|
-
assert.equal(fs.existsSync(target), true);
|
|
39
|
-
assert.equal(shot.path, target);
|
|
40
|
-
|
|
41
|
-
await browser.close();
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test("browser controller normalizes bracketed hostnames into valid urls", () => {
|
|
45
|
-
assert.equal(browser.normalizeUrl("<www.autofiles.de>"), "https://www.autofiles.de/");
|
|
46
|
-
assert.equal(browser.normalizeUrl("autofiles.de"), "https://autofiles.de/");
|
|
47
|
-
});
|
package/tests/cli.test.js
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
const fs = require("node:fs");
|
|
4
|
-
const os = require("node:os");
|
|
5
|
-
const path = require("node:path");
|
|
6
|
-
|
|
7
|
-
test("cli saveReturnedFiles skips empty placeholder payloads", () => {
|
|
8
|
-
const cli = require("../blun-cli");
|
|
9
|
-
const workdir = fs.mkdtempSync(path.join(os.tmpdir(), "blun-cli-"));
|
|
10
|
-
const target = path.join(workdir, "shot.png");
|
|
11
|
-
fs.writeFileSync(target, Buffer.from([1, 2, 3]));
|
|
12
|
-
|
|
13
|
-
const written = cli.saveReturnedFiles(workdir, [{ path: "shot.png", content: "" }]);
|
|
14
|
-
const content = fs.readFileSync(target);
|
|
15
|
-
|
|
16
|
-
assert.deepEqual(written, []);
|
|
17
|
-
assert.deepEqual([...content], [1, 2, 3]);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test("cli parseLearnCommand extracts category and content", () => {
|
|
21
|
-
const cli = require("../blun-cli");
|
|
22
|
-
const parsed = cli.parseLearnCommand('/learn system: Ich nutze immer Node fuer Bots.');
|
|
23
|
-
|
|
24
|
-
assert.equal(parsed.category, "system");
|
|
25
|
-
assert.equal(parsed.content, "Ich nutze immer Node fuer Bots.");
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
test("cli parseLearnCommand supports alias shorthand", () => {
|
|
29
|
-
const cli = require("../blun-cli");
|
|
30
|
-
const parsed = cli.parseLearnCommand("/learn alias shipit=playwright");
|
|
31
|
-
|
|
32
|
-
assert.equal(parsed.category, "system");
|
|
33
|
-
assert.equal(parsed.content, "shipit = playwright");
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
test("cli parseLearnCommand supports workflow shorthand", () => {
|
|
37
|
-
const cli = require("../blun-cli");
|
|
38
|
-
const parsed = cli.parseLearnCommand("/learn workflow deploy=ssh root@host");
|
|
39
|
-
|
|
40
|
-
assert.equal(parsed.category, "system");
|
|
41
|
-
assert.equal(parsed.content, "Wenn ich deploy sage, meine ich ssh root@host.");
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test("cli parseLearnCommand supports prefer and forbid shorthands", () => {
|
|
45
|
-
const cli = require("../blun-cli");
|
|
46
|
-
const prefer = cli.parseLearnCommand("/learn prefer node fuer bots");
|
|
47
|
-
const forbid = cli.parseLearnCommand("/learn forbid landingpages bei install");
|
|
48
|
-
|
|
49
|
-
assert.equal(prefer.content, "Ich bevorzuge node fuer bots.");
|
|
50
|
-
assert.equal(forbid.content, "Mach niemals landingpages bei install.");
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test("cli buildQueueSnapshot reports running and pending jobs", () => {
|
|
54
|
-
const cli = require("../blun-cli");
|
|
55
|
-
const lines = cli.buildQueueSnapshot({
|
|
56
|
-
mode: "agent",
|
|
57
|
-
selectedIdentity: "installer",
|
|
58
|
-
currentJob: { id: 2, message: "installier playwright" },
|
|
59
|
-
queue: [{ id: 3, message: "mach screenshot" }, { id: 4, message: "analysier das" }]
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
const joined = lines.join("\n");
|
|
63
|
-
assert.match(joined, /running: #2 installier playwright/);
|
|
64
|
-
assert.match(joined, /pending: 2/);
|
|
65
|
-
assert.match(joined, /#3 mach screenshot/);
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
test("cli parseResumeCommand extracts a job id", () => {
|
|
69
|
-
const cli = require("../blun-cli");
|
|
70
|
-
assert.equal(cli.parseResumeCommand("/resume job_123"), "job_123");
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
test("cli parseWatchCommand extracts a job id", () => {
|
|
74
|
-
const cli = require("../blun-cli");
|
|
75
|
-
assert.equal(cli.parseWatchCommand("/watch job_999"), "job_999");
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
test("cli taskboard includes remote jobs and artifacts", () => {
|
|
79
|
-
const cli = require("../blun-cli");
|
|
80
|
-
const lines = cli.buildTaskboard({
|
|
81
|
-
mode: "agent",
|
|
82
|
-
selectedIdentity: "installer",
|
|
83
|
-
currentJob: null,
|
|
84
|
-
queue: [],
|
|
85
|
-
jobs: [{ id: "job_1", status: "completed", endpoint: "/agent" }],
|
|
86
|
-
lastArtifacts: ["index.html"]
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
const joined = lines.join("\n");
|
|
90
|
-
assert.match(joined, /remote jobs: 1/);
|
|
91
|
-
assert.match(joined, /job_1 completed \/agent/);
|
|
92
|
-
assert.match(joined, /index\.html/);
|
|
93
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
const path = require("node:path");
|
|
4
|
-
|
|
5
|
-
const fileHelper = require("../file-helper");
|
|
6
|
-
|
|
7
|
-
test("ensureInside allows safe paths within the workspace", () => {
|
|
8
|
-
const root = path.resolve("C:/tmp/root");
|
|
9
|
-
const target = fileHelper.ensureInside(root, "nested/file.txt");
|
|
10
|
-
|
|
11
|
-
assert.equal(target, path.join(root, "nested", "file.txt"));
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
test("ensureInside blocks sibling-prefix escapes", () => {
|
|
15
|
-
const root = path.resolve("C:/tmp/root");
|
|
16
|
-
|
|
17
|
-
assert.throws(() => fileHelper.ensureInside(root, "../root2/evil.txt"), /Path escapes workdir/);
|
|
18
|
-
});
|
package/tests/installer.test.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
|
|
4
|
-
const installer = require("../installer");
|
|
5
|
-
|
|
6
|
-
test("maps natural language telegram bot install request to node-telegram-bot-api", () => {
|
|
7
|
-
const request = installer.resolveInstallRequest("installier dir den telegram bot");
|
|
8
|
-
|
|
9
|
-
assert.equal(request.source, "node-telegram-bot-api");
|
|
10
|
-
assert.equal(request.kind, "npm");
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test("maps telegramm spelling variant to node-telegram-bot-api", () => {
|
|
14
|
-
const request = installer.resolveInstallRequest("Okay willst du dir den telegramm bot einmal installieren");
|
|
15
|
-
|
|
16
|
-
assert.equal(request.source, "node-telegram-bot-api");
|
|
17
|
-
assert.equal(request.kind, "npm");
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test("maps typo-heavy install request to node-telegram-bot-api", () => {
|
|
21
|
-
const request = installer.resolveInstallRequest("instaliier dir den telegramm bot");
|
|
22
|
-
|
|
23
|
-
assert.equal(request.source, "node-telegram-bot-api");
|
|
24
|
-
assert.equal(request.kind, "npm");
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test("maps telegarm typo to node-telegram-bot-api", () => {
|
|
28
|
-
const request = installer.resolveInstallRequest("insalieren den telegarm bot");
|
|
29
|
-
|
|
30
|
-
assert.equal(request.source, "node-telegram-bot-api");
|
|
31
|
-
assert.equal(request.kind, "npm");
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test("maps playwrigth typo to playwright", () => {
|
|
35
|
-
const request = installer.resolveInstallRequest("insalieren playwrigth");
|
|
36
|
-
|
|
37
|
-
assert.equal(request.source, "playwright");
|
|
38
|
-
assert.equal(request.kind, "npm");
|
|
39
|
-
});
|
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
const fs = require("node:fs");
|
|
4
|
-
const os = require("node:os");
|
|
5
|
-
const path = require("node:path");
|
|
6
|
-
|
|
7
|
-
test("job manager can create update and list jobs", () => {
|
|
8
|
-
const base = fs.mkdtempSync(path.join(os.tmpdir(), "blun-jobs-"));
|
|
9
|
-
process.env.BLUN_HOME = base;
|
|
10
|
-
delete require.cache[require.resolve("../job-manager")];
|
|
11
|
-
const jobs = require("../job-manager");
|
|
12
|
-
|
|
13
|
-
const job = jobs.createJob({
|
|
14
|
-
endpoint: "/agent",
|
|
15
|
-
sessionId: "sess-1",
|
|
16
|
-
payload: { goal: "installier playwright" }
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
jobs.updateJob(job.id, {
|
|
20
|
-
status: "completed",
|
|
21
|
-
result: { answer: "Installiert: playwright" }
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
const stored = jobs.getJob(job.id);
|
|
25
|
-
const listed = jobs.listJobs({ sessionId: "sess-1" });
|
|
26
|
-
|
|
27
|
-
assert.equal(stored.status, "completed");
|
|
28
|
-
assert.equal(stored.result.answer, "Installiert: playwright");
|
|
29
|
-
assert.equal(listed[0].id, job.id);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("job manager can create a resume job from an older one", () => {
|
|
33
|
-
const base = fs.mkdtempSync(path.join(os.tmpdir(), "blun-jobs-"));
|
|
34
|
-
process.env.BLUN_HOME = base;
|
|
35
|
-
delete require.cache[require.resolve("../job-manager")];
|
|
36
|
-
const jobs = require("../job-manager");
|
|
37
|
-
|
|
38
|
-
const job = jobs.createJob({
|
|
39
|
-
endpoint: "/agent",
|
|
40
|
-
sessionId: "sess-2",
|
|
41
|
-
payload: { goal: "mach screenshot von https://example.com" }
|
|
42
|
-
});
|
|
43
|
-
jobs.updateJob(job.id, { status: "failed", error: "network", result: { answer: "step 2 failed" } });
|
|
44
|
-
jobs.appendJobLog(job.id, "started", { step: 1 });
|
|
45
|
-
jobs.appendJobLog(job.id, "failed", { step: 2, error: "network" });
|
|
46
|
-
|
|
47
|
-
const resumed = jobs.cloneJobForResume(job.id);
|
|
48
|
-
|
|
49
|
-
assert.equal(resumed.status, "queued");
|
|
50
|
-
assert.equal(resumed.resumedFrom, job.id);
|
|
51
|
-
assert.equal(resumed.payload.goal, "mach screenshot von https://example.com");
|
|
52
|
-
assert.match(resumed.payload.resume_context.previousError, /network/);
|
|
53
|
-
assert.equal(resumed.payload.resume_context.previousLogs.length, 2);
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
test("job manager keeps append-only logs per job", () => {
|
|
57
|
-
const base = fs.mkdtempSync(path.join(os.tmpdir(), "blun-jobs-"));
|
|
58
|
-
process.env.BLUN_HOME = base;
|
|
59
|
-
delete require.cache[require.resolve("../job-manager")];
|
|
60
|
-
const jobs = require("../job-manager");
|
|
61
|
-
|
|
62
|
-
const job = jobs.createJob({
|
|
63
|
-
endpoint: "/chat",
|
|
64
|
-
sessionId: "sess-3",
|
|
65
|
-
payload: { message: "hi" }
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
jobs.appendJobLog(job.id, "started", { step: 1 });
|
|
69
|
-
jobs.appendJobLog(job.id, "completed", { ok: true });
|
|
70
|
-
const logs = jobs.getJobLogs(job.id);
|
|
71
|
-
|
|
72
|
-
assert.equal(logs.length, 2);
|
|
73
|
-
assert.equal(logs[0].event, "started");
|
|
74
|
-
assert.equal(logs[1].payload.ok, true);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test("job manager can summarize a completed job", () => {
|
|
78
|
-
const base = fs.mkdtempSync(path.join(os.tmpdir(), "blun-jobs-"));
|
|
79
|
-
process.env.BLUN_HOME = base;
|
|
80
|
-
delete require.cache[require.resolve("../job-manager")];
|
|
81
|
-
const jobs = require("../job-manager");
|
|
82
|
-
|
|
83
|
-
const job = jobs.createJob({
|
|
84
|
-
endpoint: "/agent",
|
|
85
|
-
sessionId: "sess-4",
|
|
86
|
-
payload: { goal: "build site" }
|
|
87
|
-
});
|
|
88
|
-
jobs.updateJob(job.id, {
|
|
89
|
-
status: "completed",
|
|
90
|
-
startedAt: Date.now() - 1000,
|
|
91
|
-
finishedAt: Date.now(),
|
|
92
|
-
result: { task_type: "website_builder", files: [{ path: "index.html" }], references: [{ url: "https://example.com" }] }
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const summary = jobs.summarizeJob(jobs.getJob(job.id));
|
|
96
|
-
assert.equal(summary.taskType, "website_builder");
|
|
97
|
-
assert.equal(summary.fileCount, 1);
|
|
98
|
-
assert.equal(summary.referenceCount, 1);
|
|
99
|
-
});
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
const { execFileSync } = require("node:child_process");
|
|
4
|
-
const fs = require("node:fs");
|
|
5
|
-
const os = require("node:os");
|
|
6
|
-
const path = require("node:path");
|
|
7
|
-
|
|
8
|
-
test("runtime exposes v8 compatibility prompt helpers", () => {
|
|
9
|
-
const runtime = require("../runtime");
|
|
10
|
-
const task = { type: "analysis", role: "research", output: "analysis" };
|
|
11
|
-
|
|
12
|
-
const prompt = runtime.composePrompt(task, "[extra]", "[tools]");
|
|
13
|
-
const retry = runtime.buildRetryPrompt(["bot_phrasing", "no_real_build_output"]);
|
|
14
|
-
|
|
15
|
-
assert.equal(typeof prompt, "string");
|
|
16
|
-
assert.equal(prompt.includes("[extra]"), true);
|
|
17
|
-
assert.equal(prompt.includes("[tools]"), true);
|
|
18
|
-
assert.equal(typeof retry, "string");
|
|
19
|
-
assert.equal(retry.includes("Bot-Floskeln") || retry.includes("Bot-Floskeln".toLowerCase()), true);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test("tools can parse a fenced tool call block", () => {
|
|
23
|
-
const tools = require("../tools");
|
|
24
|
-
const parsed = tools.parseToolCall('```tool\n{"tool":"write_file","args":{"path":"index.html","content":"ok"}}\n```');
|
|
25
|
-
|
|
26
|
-
assert.deepEqual(parsed, {
|
|
27
|
-
tool: "write_file",
|
|
28
|
-
args: { path: "index.html", content: "ok" }
|
|
29
|
-
});
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("palace memory isolates users and works without external mempalace binary", () => {
|
|
33
|
-
const base = fs.mkdtempSync(path.join(os.tmpdir(), "blun-palace-"));
|
|
34
|
-
process.env.BLUN_HOME = base;
|
|
35
|
-
delete require.cache[require.resolve("../palace-memory")];
|
|
36
|
-
const palace = require("../palace-memory");
|
|
37
|
-
|
|
38
|
-
const storedA = palace.palaceStore("Nicrazy ist eine Fashion-Brand.", "user-note", "chat-1:user-1");
|
|
39
|
-
const storedB = palace.palaceStore("Flora und Glueck ist ein Blumenladen.", "user-note", "chat-1:user-2");
|
|
40
|
-
const searchA = palace.palaceSearch("Fashion", 5, "chat-1:user-1");
|
|
41
|
-
const searchB = palace.palaceSearch("Fashion", 5, "chat-1:user-2");
|
|
42
|
-
const wake = palace.palaceWakeUp("chat-1:user-1");
|
|
43
|
-
|
|
44
|
-
assert.equal(storedA, true);
|
|
45
|
-
assert.equal(storedB, true);
|
|
46
|
-
assert.equal(searchA.includes("Fashion-Brand"), true);
|
|
47
|
-
assert.equal(searchB.includes("Keine") || searchB.includes("keine"), true);
|
|
48
|
-
assert.equal(wake.includes("Fashion-Brand"), true);
|
|
49
|
-
assert.equal(fs.existsSync(palace.getUserPalace("chat-1:user-1")), true);
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
test("bot resolves per-user sessions for group chats", () => {
|
|
53
|
-
const output = execFileSync(
|
|
54
|
-
process.execPath,
|
|
55
|
-
[
|
|
56
|
-
"-e",
|
|
57
|
-
[
|
|
58
|
-
"const bot = require('./bot');",
|
|
59
|
-
"const privateKey = bot.resolveSessionId({ chat: { id: 11, type: 'private' }, from: { id: 22 } });",
|
|
60
|
-
"const groupKey = bot.resolveSessionId({ chat: { id: -1001, type: 'group' }, from: { id: 22 } });",
|
|
61
|
-
"const palace = bot.parsePalaceCommand('/palace search nicrazy');",
|
|
62
|
-
"console.log(JSON.stringify({ privateKey, groupKey, palace }));"
|
|
63
|
-
].join(" ")
|
|
64
|
-
],
|
|
65
|
-
{
|
|
66
|
-
cwd: path.resolve(__dirname, ".."),
|
|
67
|
-
encoding: "utf8",
|
|
68
|
-
env: { ...process.env, BLUN_TELEGRAM_TOKEN: "" }
|
|
69
|
-
}
|
|
70
|
-
).trim();
|
|
71
|
-
const lastLine = output.split(/\r?\n/).at(-1);
|
|
72
|
-
const parsed = JSON.parse(lastLine);
|
|
73
|
-
|
|
74
|
-
assert.equal(parsed.privateKey, "11");
|
|
75
|
-
assert.equal(parsed.groupKey, "-1001::22");
|
|
76
|
-
assert.deepEqual(parsed.palace, { action: "search", value: "nicrazy" });
|
|
77
|
-
});
|
package/tests/messages.test.js
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
|
|
4
|
-
const { buildConversationMessages } = require("../message-builder");
|
|
5
|
-
|
|
6
|
-
test("includes recent session history before the current user message", () => {
|
|
7
|
-
const session = {
|
|
8
|
-
history: [
|
|
9
|
-
{ role: "user", content: "erstes problem" },
|
|
10
|
-
{ role: "assistant", content: "erste antwort" },
|
|
11
|
-
{ role: "user", content: "zweites problem" }
|
|
12
|
-
]
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
const messages = buildConversationMessages({
|
|
16
|
-
prompt: "system prompt",
|
|
17
|
-
session,
|
|
18
|
-
message: "aktuelles problem"
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
assert.deepEqual(messages.map((item) => item.role), ["system", "user", "assistant", "user", "user"]);
|
|
22
|
-
assert.equal(messages.at(-1).content, "aktuelles problem");
|
|
23
|
-
});
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
|
|
4
|
-
const { evaluateNoisyIntentCorpus } = require("../noisy-evals");
|
|
5
|
-
|
|
6
|
-
test("noisy intent evaluation report passes current corpus", () => {
|
|
7
|
-
const report = evaluateNoisyIntentCorpus();
|
|
8
|
-
|
|
9
|
-
assert.equal(report.total > 0, true);
|
|
10
|
-
assert.equal(report.failed, 0);
|
|
11
|
-
assert.equal(report.passed, report.total);
|
|
12
|
-
});
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
|
|
4
|
-
const runtime = require("../runtime");
|
|
5
|
-
|
|
6
|
-
test("noisy install corpus stays in installation lane", () => {
|
|
7
|
-
const cases = [
|
|
8
|
-
"instaliier dir den telegarm bot",
|
|
9
|
-
"insalieren telegramm bot",
|
|
10
|
-
"kanst du playwrigth instalieren",
|
|
11
|
-
"hol dir den telegrm bot bitte",
|
|
12
|
-
"mach plugin instalation fuer playwrigth"
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
for (const sample of cases) {
|
|
16
|
-
const task = runtime.classifyTask(sample, null);
|
|
17
|
-
assert.equal(task.type, "installation", sample);
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
|
-
|
|
21
|
-
test("noisy screenshot corpus stays in browser capture lane", () => {
|
|
22
|
-
const cases = [
|
|
23
|
-
"mach ein screenshoot von der websiete https://example.com",
|
|
24
|
-
"brauch ein screnshot von der website https://example.com",
|
|
25
|
-
"mach n bild von der websiete https://example.com"
|
|
26
|
-
];
|
|
27
|
-
|
|
28
|
-
for (const sample of cases) {
|
|
29
|
-
const task = runtime.classifyTask(sample, null);
|
|
30
|
-
assert.equal(task.type, "browser_capture", sample);
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test("noisy website build corpus stays in website builder lane", () => {
|
|
35
|
-
const cases = [
|
|
36
|
-
"baue mir eine websiete fuer mein studio",
|
|
37
|
-
"erstell mir ne webseite fuer ein tattoo shop",
|
|
38
|
-
"mach landingpgae fuer nicrazy style"
|
|
39
|
-
];
|
|
40
|
-
|
|
41
|
-
for (const sample of cases) {
|
|
42
|
-
const task = runtime.classifyTask(sample, null);
|
|
43
|
-
assert.equal(task.type, "website_builder", sample);
|
|
44
|
-
}
|
|
45
|
-
});
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
|
|
4
|
-
const inspector = require("../reference-inspector");
|
|
5
|
-
|
|
6
|
-
test("reference helper detects when automatic reference chain should run", () => {
|
|
7
|
-
assert.equal(
|
|
8
|
-
inspector.shouldAutoReference("bau mir eine seite mit referenz https://example.com", { type: "website_builder" }),
|
|
9
|
-
true
|
|
10
|
-
);
|
|
11
|
-
|
|
12
|
-
assert.equal(
|
|
13
|
-
inspector.shouldAutoReference("installier playwright", { type: "installation" }),
|
|
14
|
-
false
|
|
15
|
-
);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test("reference helper builds a prompt block from inspected references", () => {
|
|
19
|
-
const block = inspector.buildReferencePromptBlock([
|
|
20
|
-
{
|
|
21
|
-
url: "https://example.com",
|
|
22
|
-
summary: {
|
|
23
|
-
title: "Example",
|
|
24
|
-
h1s: ["Hero"],
|
|
25
|
-
text: "Strong headline and clear CTA",
|
|
26
|
-
links: 5,
|
|
27
|
-
images: 2
|
|
28
|
-
},
|
|
29
|
-
screenshotPath: "C:\\shots\\example.png"
|
|
30
|
-
}
|
|
31
|
-
]);
|
|
32
|
-
|
|
33
|
-
assert.match(block, /Referenz 1/);
|
|
34
|
-
assert.match(block, /Example/);
|
|
35
|
-
assert.match(block, /example\.png/);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test("reference helper extracts and normalizes bare domains and bracketed urls", () => {
|
|
39
|
-
const urls = inspector.extractUrls("mach einen screenshot von <www.autofiles.de> und vielleicht auch autofiles.de");
|
|
40
|
-
|
|
41
|
-
assert.deepEqual(urls, ["https://www.autofiles.de/", "https://autofiles.de/"]);
|
|
42
|
-
});
|
package/tests/runtime.test.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
|
|
4
|
-
const runtime = require("../runtime");
|
|
5
|
-
|
|
6
|
-
test("classifies AI system review as analysis instead of website build", () => {
|
|
7
|
-
const task = runtime.classifyTask("ich baue gerade eine eigene KI auf. das system ist ganz gut aber er macht noch viel falsch kannst du dir das anschauen?", null);
|
|
8
|
-
|
|
9
|
-
assert.equal(task.type, "analysis");
|
|
10
|
-
assert.equal(task.role, "research");
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
test("routes website requests to website builder", () => {
|
|
14
|
-
const task = runtime.classifyTask("mach mir eine website fuer nicrazy.com", null);
|
|
15
|
-
|
|
16
|
-
assert.equal(task.type, "website_builder");
|
|
17
|
-
assert.equal(task.output, "file");
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test("keeps active task only for explicit continuation prompts", () => {
|
|
21
|
-
const session = {
|
|
22
|
-
activeTask: { type: "website_builder", role: "website_builder", output: "file" }
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
const followupTask = runtime.classifyTask("weiter", session);
|
|
26
|
-
const unrelatedTask = runtime.classifyTask("das ist schlecht", session);
|
|
27
|
-
|
|
28
|
-
assert.equal(followupTask.followup, true);
|
|
29
|
-
assert.equal(unrelatedTask.type, "chat");
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test("picks an explicit identity from the user message", () => {
|
|
33
|
-
const selection = runtime.resolveIdentity("antworte als debugger und analysiere den fehler", { type: "debugging", role: "dev" });
|
|
34
|
-
|
|
35
|
-
assert.equal(selection.id, "debugger");
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
test("recommends installer identity for installation tasks", () => {
|
|
39
|
-
const selection = runtime.resolveIdentity("installier dir den telegram bot", { type: "installation", role: "installer" });
|
|
40
|
-
|
|
41
|
-
assert.equal(selection.id, "installer");
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
test("classifies screenshot requests for websites as browser capture", () => {
|
|
45
|
-
const task = runtime.classifyTask("mach ein bild von der website https://example.com", null);
|
|
46
|
-
|
|
47
|
-
assert.equal(task.type, "browser_capture");
|
|
48
|
-
assert.equal(task.output, "file");
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
test("classifies install commands as installation instead of generic chat or build", () => {
|
|
52
|
-
const task = runtime.classifyTask("installier dir den telegram bot", null);
|
|
53
|
-
|
|
54
|
-
assert.equal(task.type, "installation");
|
|
55
|
-
assert.equal(task.reason, "install");
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
test("classifies typo-heavy install commands as installation", () => {
|
|
59
|
-
const task = runtime.classifyTask("instaliier dir den telegramm bot", null);
|
|
60
|
-
|
|
61
|
-
assert.equal(task.type, "installation");
|
|
62
|
-
assert.equal(task.reason, "install");
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test("classifies typo-heavy screenshot website commands as browser capture", () => {
|
|
66
|
-
const task = runtime.classifyTask("mach ein screenshoot von der websiete https://example.com", null);
|
|
67
|
-
|
|
68
|
-
assert.equal(task.type, "browser_capture");
|
|
69
|
-
assert.equal(task.reason, "browser_capture");
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test("classifies typo-heavy website build requests as website builder", () => {
|
|
73
|
-
const task = runtime.classifyTask("baue mir eine websiete fuer mein studio", null);
|
|
74
|
-
|
|
75
|
-
assert.equal(task.type, "website_builder");
|
|
76
|
-
assert.equal(task.reason, "build_intent");
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
test("keeps installation follow-ups in the installation task lane", () => {
|
|
80
|
-
const session = {
|
|
81
|
-
activeTask: { type: "installation", role: "installer", output: "action" }
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
const task = runtime.classifyTask("findest du auch selbst", session);
|
|
85
|
-
|
|
86
|
-
assert.equal(task.type, "installation");
|
|
87
|
-
assert.equal(task.followup, true);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
test("returns routing scores with installation clearly above website builder", () => {
|
|
91
|
-
const details = runtime.classifyTaskDetailed("installier dir den telegram bot", null);
|
|
92
|
-
|
|
93
|
-
assert.equal(details.task.type, "installation");
|
|
94
|
-
assert.equal(details.scores.installation > details.scores.website_builder, true);
|
|
95
|
-
assert.equal(details.confidence >= 0.5, true);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
test("penalizes installation answers that drift into landingpage or scaffold output", () => {
|
|
99
|
-
const result = runtime.scoreResponse(
|
|
100
|
-
"<!DOCTYPE html><html><body>landingpage</body></html>",
|
|
101
|
-
{ type: "installation", role: "installer", output: "action" },
|
|
102
|
-
"installier dir den telegram bot"
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
assert.equal(result.score < 60, true);
|
|
106
|
-
assert.equal(result.reasons.includes("action_mismatch"), true);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
test("self-check blocks critical installation drift before output", () => {
|
|
110
|
-
const result = runtime.selfCheckResponse(
|
|
111
|
-
"Welche Sprache nutzt du? Ich kann dir dann ein bot.py bauen.",
|
|
112
|
-
{ type: "installation", role: "installer", output: "action" },
|
|
113
|
-
"installier dir den telegram bot"
|
|
114
|
-
);
|
|
115
|
-
|
|
116
|
-
assert.equal(result.blocked, true);
|
|
117
|
-
assert.equal(result.critical, true);
|
|
118
|
-
assert.equal(result.reasons.includes("refusal_or_detour"), true);
|
|
119
|
-
});
|
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
const test = require("node:test");
|
|
2
|
-
const assert = require("node:assert/strict");
|
|
3
|
-
|
|
4
|
-
const executor = require("../task-executor");
|
|
5
|
-
|
|
6
|
-
test("direct action helper recognizes installation and browser capture tasks", () => {
|
|
7
|
-
assert.equal(executor.isDirectActionTask({ type: "installation" }), true);
|
|
8
|
-
assert.equal(executor.isDirectActionTask({ type: "browser_capture" }), true);
|
|
9
|
-
assert.equal(executor.isDirectActionTask({ type: "website_builder" }), false);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
test("installation resolution falls back to active task intent", () => {
|
|
13
|
-
const request = executor.resolveInstallRequestWithSession("findest du auch selbst", {
|
|
14
|
-
activeTask: { lastUserIntent: "installier dir den telegram bot" }
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
assert.equal(request.source, "node-telegram-bot-api");
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test("installation resolution can use learned per-user aliases", () => {
|
|
21
|
-
const base = require("node:fs").mkdtempSync(require("node:path").join(require("node:os").tmpdir(), "blun-task-exec-"));
|
|
22
|
-
process.env.BLUN_HOME = base;
|
|
23
|
-
delete require.cache[require.resolve("../user-profile")];
|
|
24
|
-
delete require.cache[require.resolve("../task-executor")];
|
|
25
|
-
const profile = require("../user-profile");
|
|
26
|
-
const localExecutor = require("../task-executor");
|
|
27
|
-
|
|
28
|
-
profile.learnInstallAlias("user-77", "telegarm bot", "node-telegram-bot-api");
|
|
29
|
-
const request = localExecutor.resolveInstallRequestWithSession("mach mal telegarm bot", {}, "user-77");
|
|
30
|
-
|
|
31
|
-
assert.equal(request.source, "node-telegram-bot-api");
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
test("capture url resolution falls back to active task intent", () => {
|
|
35
|
-
const url = executor.resolveCaptureUrl("mach einfach", {
|
|
36
|
-
activeTask: { lastUserIntent: "mach ein screenshot von https://example.com" }
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
assert.equal(url, "https://example.com");
|
|
40
|
-
});
|