leedab 0.1.1 → 0.1.2
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 +15 -0
- package/dist/dashboard/static/index.html +28 -2
- package/dist/onboard/index.js +27 -12
- package/package.json +1 -1
package/dist/dashboard/routes.js
CHANGED
|
@@ -2,6 +2,7 @@ import { execFile, spawn } from "node:child_process";
|
|
|
2
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
|
+
import { userInfo } from "node:os";
|
|
5
6
|
import { resolveOpenClawBin, openclawEnv } from "../openclaw.js";
|
|
6
7
|
import { addEntry, removeEntry, listEntries } from "../vault.js";
|
|
7
8
|
import { readAuditLog } from "../audit.js";
|
|
@@ -130,6 +131,20 @@ export function createRoutes(config) {
|
|
|
130
131
|
json(res, []);
|
|
131
132
|
}
|
|
132
133
|
},
|
|
134
|
+
/**
|
|
135
|
+
* GET /api/whoami — current OS user's first name
|
|
136
|
+
*/
|
|
137
|
+
"GET /api/whoami": async (_req, res) => {
|
|
138
|
+
let firstName = userInfo().username;
|
|
139
|
+
try {
|
|
140
|
+
const { stdout } = await execFileAsync("id", ["-F"], { timeout: 2000 });
|
|
141
|
+
const fullName = stdout.trim();
|
|
142
|
+
if (fullName)
|
|
143
|
+
firstName = fullName.split(/\s+/)[0];
|
|
144
|
+
}
|
|
145
|
+
catch { }
|
|
146
|
+
json(res, { name: firstName });
|
|
147
|
+
},
|
|
133
148
|
/**
|
|
134
149
|
* GET /api/status — channel health status
|
|
135
150
|
*/
|
|
@@ -297,6 +297,10 @@
|
|
|
297
297
|
.msg-bubble.agent strong { font-weight: 600; }
|
|
298
298
|
.msg-bubble.agent em { font-style: italic; }
|
|
299
299
|
.msg-bubble.agent blockquote { border-left: 3px solid var(--accent); padding-left: 10px; color: var(--text-dim); margin: 6px 0; }
|
|
300
|
+
.msg-bubble.agent table { width: 100%; border-collapse: collapse; margin: 8px 0; font-size: 13px; }
|
|
301
|
+
.msg-bubble.agent th, .msg-bubble.agent td { text-align: left; padding: 6px 10px; border: 1px solid var(--border); }
|
|
302
|
+
.msg-bubble.agent th { background: var(--surface-raised); font-weight: 600; color: var(--text-secondary); font-size: 12px; }
|
|
303
|
+
.msg-bubble.agent td { color: var(--text); }
|
|
300
304
|
|
|
301
305
|
/* Thinking */
|
|
302
306
|
.thinking-row {
|
|
@@ -635,6 +639,15 @@
|
|
|
635
639
|
const params = new URLSearchParams(window.location.search);
|
|
636
640
|
let sessionId = params.get("session") || "console";
|
|
637
641
|
|
|
642
|
+
let userName = "You";
|
|
643
|
+
let userInitial = "Y";
|
|
644
|
+
fetch("/api/whoami").then(r => r.json()).then(d => {
|
|
645
|
+
if (d.name) {
|
|
646
|
+
userName = d.name;
|
|
647
|
+
userInitial = d.name.charAt(0).toUpperCase();
|
|
648
|
+
}
|
|
649
|
+
}).catch(() => {});
|
|
650
|
+
|
|
638
651
|
input.addEventListener("input", () => {
|
|
639
652
|
input.style.height = "auto";
|
|
640
653
|
input.style.height = Math.min(input.scrollHeight, 120) + "px";
|
|
@@ -727,7 +740,7 @@
|
|
|
727
740
|
img.alt = "LeedAB";
|
|
728
741
|
avatar.appendChild(img);
|
|
729
742
|
} else {
|
|
730
|
-
avatar.textContent =
|
|
743
|
+
avatar.textContent = userInitial;
|
|
731
744
|
}
|
|
732
745
|
|
|
733
746
|
const content = document.createElement("div");
|
|
@@ -735,7 +748,7 @@
|
|
|
735
748
|
|
|
736
749
|
const meta = document.createElement("div");
|
|
737
750
|
meta.className = "msg-meta";
|
|
738
|
-
meta.innerHTML = `<span class="msg-name">${type === "agent" ? "LeedAB" :
|
|
751
|
+
meta.innerHTML = `<span class="msg-name">${type === "agent" ? "LeedAB" : userName}</span><span class="msg-time">${now()}</span>`;
|
|
739
752
|
|
|
740
753
|
const bubble = document.createElement("div");
|
|
741
754
|
bubble.className = `msg-bubble ${type}`;
|
|
@@ -760,6 +773,19 @@
|
|
|
760
773
|
let h = text.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">");
|
|
761
774
|
// Code blocks
|
|
762
775
|
h = h.replace(/```(\w*)\n([\s\S]*?)```/g, (_,lang,code) => `<pre><code>${code.trim()}</code></pre>`);
|
|
776
|
+
// Tables (must run before inline formatting)
|
|
777
|
+
h = h.replace(/(\n|^)(\|[^\n]+\|\n\|[\s\-:|]+\|\n(?:\|[^\n]+\|\n?)+)/g, function(_, prefix, block) {
|
|
778
|
+
const rows = block.trim().split("\n");
|
|
779
|
+
const parseRow = r => r.replace(/^\|/, "").replace(/\|$/, "").split("|").map(c => c.trim());
|
|
780
|
+
const headers = parseRow(rows[0]);
|
|
781
|
+
const body = rows.slice(2).map(parseRow);
|
|
782
|
+
let t = "<table><thead><tr>" + headers.map(h => `<th>${h}</th>`).join("") + "</tr></thead><tbody>";
|
|
783
|
+
for (const cells of body) {
|
|
784
|
+
t += "<tr>" + cells.map(c => `<td>${c}</td>`).join("") + "</tr>";
|
|
785
|
+
}
|
|
786
|
+
t += "</tbody></table>";
|
|
787
|
+
return prefix + t;
|
|
788
|
+
});
|
|
763
789
|
// Inline code
|
|
764
790
|
h = h.replace(/`([^`]+)`/g, "<code>$1</code>");
|
|
765
791
|
// Bold
|
package/dist/onboard/index.js
CHANGED
|
@@ -27,15 +27,23 @@ export async function runOnboard() {
|
|
|
27
27
|
console.log(chalk.dim(" Get your key at ") + chalk.cyan("https://leedab.com") + "\n");
|
|
28
28
|
let licensed = false;
|
|
29
29
|
while (!licensed) {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
let licenseKey;
|
|
31
|
+
try {
|
|
32
|
+
const answers = await inquirer.prompt([
|
|
33
|
+
{
|
|
34
|
+
type: "password",
|
|
35
|
+
name: "licenseKey",
|
|
36
|
+
message: "License key:",
|
|
37
|
+
mask: "*",
|
|
38
|
+
validate: (v) => v.trim().startsWith("am_live_") || "Key should start with am_live_",
|
|
39
|
+
},
|
|
40
|
+
]);
|
|
41
|
+
licenseKey = answers.licenseKey;
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
console.log(chalk.dim("\n\n Exiting. Run `leedab onboard` when you have your key.\n"));
|
|
45
|
+
process.exit(0);
|
|
46
|
+
}
|
|
39
47
|
process.stdout.write(chalk.dim(" Validating..."));
|
|
40
48
|
const result = await validateLicenseKey(licenseKey.trim());
|
|
41
49
|
if (result.valid) {
|
|
@@ -45,9 +53,16 @@ export async function runOnboard() {
|
|
|
45
53
|
}
|
|
46
54
|
else {
|
|
47
55
|
console.log(chalk.red(" invalid key."));
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
56
|
+
let retry = true;
|
|
57
|
+
try {
|
|
58
|
+
const answers = await inquirer.prompt([
|
|
59
|
+
{ type: "confirm", name: "retry", message: "Try again?", default: true },
|
|
60
|
+
]);
|
|
61
|
+
retry = answers.retry;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
retry = false;
|
|
65
|
+
}
|
|
51
66
|
if (!retry) {
|
|
52
67
|
console.log(chalk.red("\n A valid license key is required to use LeedAB."));
|
|
53
68
|
console.log(chalk.dim(" Get one at ") + chalk.cyan("https://leedab.com\n"));
|