leedab 0.1.0 → 0.1.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/routes.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { execFile, spawn } from "node:child_process";
|
|
2
|
-
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
2
|
+
import { readFile, writeFile, mkdir, readdir } from "node:fs/promises";
|
|
3
3
|
import { resolve } from "node:path";
|
|
4
4
|
import { promisify } from "node:util";
|
|
5
5
|
import { resolveOpenClawBin, openclawEnv } from "../openclaw.js";
|
|
@@ -66,13 +66,65 @@ export function createRoutes(config) {
|
|
|
66
66
|
}
|
|
67
67
|
},
|
|
68
68
|
/**
|
|
69
|
-
* GET /api/chat/history — get conversation history
|
|
69
|
+
* GET /api/chat/history — get conversation history from JSONL logs
|
|
70
70
|
*/
|
|
71
71
|
"GET /api/chat/history": async (_req, res, url) => {
|
|
72
72
|
const session = url.searchParams.get("session") ?? "console";
|
|
73
73
|
try {
|
|
74
|
-
const
|
|
75
|
-
|
|
74
|
+
const sessionsDir = resolve(stateDir, "agents", "main", "sessions");
|
|
75
|
+
// If session is a UUID, use it directly; otherwise search by key
|
|
76
|
+
let jsonlPath = resolve(sessionsDir, `${session}.jsonl`);
|
|
77
|
+
// Try to find the file — if not found by direct name, scan directory
|
|
78
|
+
try {
|
|
79
|
+
await readFile(jsonlPath);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
// Session param might be the key rather than the UUID filename
|
|
83
|
+
// List files and try to match
|
|
84
|
+
const files = await readdir(sessionsDir);
|
|
85
|
+
const match = files.find(f => f.endsWith(".jsonl"));
|
|
86
|
+
if (!match) {
|
|
87
|
+
json(res, []);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
// Fall back to direct path — if it doesn't exist, we'll catch below
|
|
91
|
+
}
|
|
92
|
+
const raw = await readFile(jsonlPath, "utf-8");
|
|
93
|
+
const messages = [];
|
|
94
|
+
for (const line of raw.split("\n")) {
|
|
95
|
+
if (!line.trim())
|
|
96
|
+
continue;
|
|
97
|
+
try {
|
|
98
|
+
const entry = JSON.parse(line);
|
|
99
|
+
if (entry.type !== "message")
|
|
100
|
+
continue;
|
|
101
|
+
const msg = entry.message;
|
|
102
|
+
if (!msg || (msg.role !== "user" && msg.role !== "assistant"))
|
|
103
|
+
continue;
|
|
104
|
+
let text = "";
|
|
105
|
+
if (Array.isArray(msg.content)) {
|
|
106
|
+
text = msg.content
|
|
107
|
+
.filter((b) => b.type === "text")
|
|
108
|
+
.map((b) => b.text)
|
|
109
|
+
.join("\n");
|
|
110
|
+
}
|
|
111
|
+
else if (typeof msg.content === "string") {
|
|
112
|
+
text = msg.content;
|
|
113
|
+
}
|
|
114
|
+
// Strip all OpenClaw "(untrusted metadata)" blocks and timestamp prefix
|
|
115
|
+
text = text.replace(/^(\w[\w\s]*\(untrusted metadata\):\n```json\n[\s\S]*?\n```\n\n)+/, "");
|
|
116
|
+
text = text.replace(/^\[[\w]{3} \d{4}-\d{2}-\d{2} \d{2}:\d{2} \w+\] /, "");
|
|
117
|
+
if (text) {
|
|
118
|
+
messages.push({
|
|
119
|
+
role: msg.role,
|
|
120
|
+
text,
|
|
121
|
+
timestamp: entry.timestamp,
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch { }
|
|
126
|
+
}
|
|
127
|
+
json(res, messages);
|
|
76
128
|
}
|
|
77
129
|
catch {
|
|
78
130
|
json(res, []);
|
|
@@ -157,8 +157,9 @@
|
|
|
157
157
|
label = parts.slice(2).join(":");
|
|
158
158
|
}
|
|
159
159
|
const tokens = s.totalTokens != null ? `${(s.totalTokens / 1000).toFixed(1)}k tokens` : "";
|
|
160
|
+
const sid = s.sessionId || s.key || "";
|
|
160
161
|
return `
|
|
161
|
-
<
|
|
162
|
+
<a class="session-item" href="/?session=${encodeURIComponent(sid)}">
|
|
162
163
|
<div class="session-info">
|
|
163
164
|
<h3>${escapeHtml(label)}</h3>
|
|
164
165
|
<p>${escapeHtml(s.model || "")} ${tokens ? "· " + tokens : ""}</p>
|
|
@@ -167,7 +168,7 @@
|
|
|
167
168
|
<div class="channel">${channel}</div>
|
|
168
169
|
<div>${date}</div>
|
|
169
170
|
</div>
|
|
170
|
-
</
|
|
171
|
+
</a>`;
|
|
171
172
|
}).join("");
|
|
172
173
|
} catch {
|
|
173
174
|
list.innerHTML = '<div style="text-align:center;padding:48px 0;color:var(--text-dim);font-size:14px">Could not load sessions. Is the gateway running?</div>';
|
|
@@ -42,8 +42,7 @@ export async function onboardTelegram() {
|
|
|
42
42
|
}
|
|
43
43
|
console.log(chalk.green(`\n Connected to @${data.result.username}\n`));
|
|
44
44
|
// Prompt for first allowlist user
|
|
45
|
-
console.log(chalk.dim(" By default, only allowlisted users can message the bot
|
|
46
|
-
console.log(chalk.dim(" To find your Telegram user ID, message @userinfobot on Telegram.\n"));
|
|
45
|
+
console.log(chalk.dim(" By default, only allowlisted users can message the bot.\n"));
|
|
47
46
|
const { addUser } = await inquirer.prompt([
|
|
48
47
|
{
|
|
49
48
|
type: "confirm",
|
|
@@ -54,6 +53,7 @@ export async function onboardTelegram() {
|
|
|
54
53
|
]);
|
|
55
54
|
const allowlist = [];
|
|
56
55
|
if (addUser) {
|
|
56
|
+
console.log(chalk.dim("\n Tip: Message @userinfobot on Telegram to get any user's ID.\n"));
|
|
57
57
|
let more = true;
|
|
58
58
|
while (more) {
|
|
59
59
|
const { userId } = await inquirer.prompt([
|