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.
@@ -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 { stdout } = await execFileAsync(bin, ["sessions", "history", "--session-id", session, "--json"], { env: openclawEnv(stateDir) });
75
- json(res, JSON.parse(stdout));
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
- <div class="session-item">
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
- </div>`;
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([
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "leedab",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "LeedAB — Your enterprise AI agent. Local-first, private by default.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": "LeedAB <hello@leedab.com>",