@nettee/beacon 0.2.0 → 0.2.1
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/dist/dashboard/export.js
CHANGED
|
@@ -3,6 +3,7 @@ import { mkdtemp, readdir, readFile, realpath, rm } from "node:fs/promises";
|
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { basename, dirname, isAbsolute, join, sep } from "node:path";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
|
+
import { fillExportedHtmlSystemPrompt, systemPromptFromJsonl, } from "./session-prompt.js";
|
|
6
7
|
const execFileAsync = promisify(execFile);
|
|
7
8
|
function isInside(root, candidate) {
|
|
8
9
|
return candidate === root || candidate.startsWith(`${root}${sep}`);
|
|
@@ -42,7 +43,11 @@ export async function exportSessionHtml(request) {
|
|
|
42
43
|
timeout: request.timeoutMs ?? 60_000,
|
|
43
44
|
windowsHide: true,
|
|
44
45
|
});
|
|
45
|
-
|
|
46
|
+
const html = await readFile(outputPath, "utf8");
|
|
47
|
+
const systemPrompt = systemPromptFromJsonl(await readFile(jsonlPath, "utf8"));
|
|
48
|
+
return systemPrompt
|
|
49
|
+
? fillExportedHtmlSystemPrompt(html, systemPrompt)
|
|
50
|
+
: html;
|
|
46
51
|
}
|
|
47
52
|
finally {
|
|
48
53
|
await rm(directory, { recursive: true, force: true });
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
function asRecord(value) {
|
|
2
|
+
return typeof value === "object" && value !== null
|
|
3
|
+
? value
|
|
4
|
+
: undefined;
|
|
5
|
+
}
|
|
6
|
+
function contentText(content) {
|
|
7
|
+
if (typeof content === "string")
|
|
8
|
+
return content;
|
|
9
|
+
if (!Array.isArray(content))
|
|
10
|
+
return "";
|
|
11
|
+
return content
|
|
12
|
+
.map((block) => {
|
|
13
|
+
const record = asRecord(block);
|
|
14
|
+
return record?.type === "text" && typeof record.text === "string"
|
|
15
|
+
? record.text
|
|
16
|
+
: "";
|
|
17
|
+
})
|
|
18
|
+
.filter((part) => part.length > 0)
|
|
19
|
+
.join("\n");
|
|
20
|
+
}
|
|
21
|
+
function systemMessageText(content, sections) {
|
|
22
|
+
return [content, ...sections.values()]
|
|
23
|
+
.filter((part) => part.length > 0)
|
|
24
|
+
.join("\n\n");
|
|
25
|
+
}
|
|
26
|
+
export function systemPromptFromJsonl(jsonl) {
|
|
27
|
+
const contents = [];
|
|
28
|
+
const sections = new Map();
|
|
29
|
+
let seen = false;
|
|
30
|
+
for (const line of jsonl.split(/\r?\n/)) {
|
|
31
|
+
if (line.trim().length === 0)
|
|
32
|
+
continue;
|
|
33
|
+
let parsed;
|
|
34
|
+
try {
|
|
35
|
+
parsed = JSON.parse(line);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
const entry = asRecord(parsed);
|
|
41
|
+
const message = asRecord(entry?.message);
|
|
42
|
+
if (entry?.type !== "message" || message?.role !== "system")
|
|
43
|
+
continue;
|
|
44
|
+
seen = true;
|
|
45
|
+
const text = contentText(message.content);
|
|
46
|
+
if (text.length > 0)
|
|
47
|
+
contents.push(text);
|
|
48
|
+
const named = asRecord(message.sections);
|
|
49
|
+
if (!named)
|
|
50
|
+
continue;
|
|
51
|
+
for (const [name, value] of Object.entries(named)) {
|
|
52
|
+
if (value === null)
|
|
53
|
+
sections.delete(name);
|
|
54
|
+
else if (typeof value === "string")
|
|
55
|
+
sections.set(name, value);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!seen)
|
|
59
|
+
return undefined;
|
|
60
|
+
const prompt = systemMessageText(contents.join("\n\n"), sections);
|
|
61
|
+
return prompt.length > 0 ? prompt : undefined;
|
|
62
|
+
}
|
|
63
|
+
const sessionDataScript = /<script\s+id="session-data"(?:\s+[^>]*)?>([A-Za-z0-9+/=\s]*)<\/script>/i;
|
|
64
|
+
export function fillExportedHtmlSystemPrompt(html, systemPrompt) {
|
|
65
|
+
if (systemPrompt.length === 0)
|
|
66
|
+
return html;
|
|
67
|
+
const match = sessionDataScript.exec(html);
|
|
68
|
+
if (!match || match.index === undefined)
|
|
69
|
+
return html;
|
|
70
|
+
const raw = match[1] ?? "";
|
|
71
|
+
const encoded = raw.replace(/\s+/g, "");
|
|
72
|
+
if (encoded.length === 0)
|
|
73
|
+
return html;
|
|
74
|
+
let data;
|
|
75
|
+
try {
|
|
76
|
+
const parsed = JSON.parse(Buffer.from(encoded, "base64").toString("utf8"));
|
|
77
|
+
const record = asRecord(parsed);
|
|
78
|
+
if (!record)
|
|
79
|
+
return html;
|
|
80
|
+
data = record;
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return html;
|
|
84
|
+
}
|
|
85
|
+
const existing = data.systemPrompt;
|
|
86
|
+
if (typeof existing === "string" && existing.length > 0)
|
|
87
|
+
return html;
|
|
88
|
+
data.systemPrompt = systemPrompt;
|
|
89
|
+
const next = Buffer.from(JSON.stringify(data), "utf8").toString("base64");
|
|
90
|
+
return (html.slice(0, match.index) +
|
|
91
|
+
match[0].replace(raw, next) +
|
|
92
|
+
html.slice(match.index + match[0].length));
|
|
93
|
+
}
|