@serendb/serendesktop 0.1.3 → 0.1.5
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/server.js +125 -38
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -4,9 +4,10 @@ import { exec as exec2 } from "child_process";
|
|
|
4
4
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, statSync as statSync2 } from "fs";
|
|
5
5
|
import { createServer as createServer2 } from "http";
|
|
6
6
|
import { request as httpsRequest } from "https";
|
|
7
|
-
import { homedir as
|
|
7
|
+
import { homedir as homedir6, platform as platform4 } from "os";
|
|
8
8
|
import { join as join7, extname as extname2 } from "path";
|
|
9
9
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
10
|
+
import { createRequire as createRequire2 } from "module";
|
|
10
11
|
import { WebSocketServer } from "ws";
|
|
11
12
|
|
|
12
13
|
// src/events.ts
|
|
@@ -232,8 +233,8 @@ function createClient(sessionId) {
|
|
|
232
233
|
toolCall: params.toolCall,
|
|
233
234
|
options: params.options
|
|
234
235
|
});
|
|
235
|
-
const optionId = await new Promise((
|
|
236
|
-
session.pendingPermissions.set(requestId,
|
|
236
|
+
const optionId = await new Promise((resolve4, reject) => {
|
|
237
|
+
session.pendingPermissions.set(requestId, resolve4);
|
|
237
238
|
setTimeout(() => {
|
|
238
239
|
session.pendingPermissions.delete(requestId);
|
|
239
240
|
reject(new Error("Permission request timed out"));
|
|
@@ -266,8 +267,8 @@ function createClient(sessionId) {
|
|
|
266
267
|
oldText,
|
|
267
268
|
newText: params.content
|
|
268
269
|
});
|
|
269
|
-
const accepted = await new Promise((
|
|
270
|
-
session.pendingDiffProposals.set(proposalId,
|
|
270
|
+
const accepted = await new Promise((resolve4, reject) => {
|
|
271
|
+
session.pendingDiffProposals.set(proposalId, resolve4);
|
|
271
272
|
setTimeout(() => {
|
|
272
273
|
session.pendingDiffProposals.delete(proposalId);
|
|
273
274
|
reject(new Error("Diff proposal timed out"));
|
|
@@ -386,8 +387,8 @@ ${candidates.map((p) => ` - ${p}`).join("\n")}`
|
|
|
386
387
|
}
|
|
387
388
|
async function isCommandAvailable(command) {
|
|
388
389
|
const which = platform() === "win32" ? "where" : "which";
|
|
389
|
-
return new Promise((
|
|
390
|
-
execFile(which, [command], (err) =>
|
|
390
|
+
return new Promise((resolve4) => {
|
|
391
|
+
execFile(which, [command], (err) => resolve4(!err));
|
|
391
392
|
});
|
|
392
393
|
}
|
|
393
394
|
async function acpSpawn(params) {
|
|
@@ -622,7 +623,7 @@ async function acpEnsureClaudeCli() {
|
|
|
622
623
|
return "claude";
|
|
623
624
|
}
|
|
624
625
|
const npmCmd = platform() === "win32" ? "npm.cmd" : "npm";
|
|
625
|
-
return new Promise((
|
|
626
|
+
return new Promise((resolve4, reject) => {
|
|
626
627
|
const proc = execFile(
|
|
627
628
|
npmCmd,
|
|
628
629
|
["install", "-g", "@anthropic-ai/claude-code"],
|
|
@@ -636,7 +637,7 @@ async function acpEnsureClaudeCli() {
|
|
|
636
637
|
return;
|
|
637
638
|
}
|
|
638
639
|
console.log(`[ACP] Claude Code CLI installed: ${stdout}`);
|
|
639
|
-
|
|
640
|
+
resolve4("claude");
|
|
640
641
|
}
|
|
641
642
|
);
|
|
642
643
|
});
|
|
@@ -648,17 +649,17 @@ import { platform as platform2 } from "os";
|
|
|
648
649
|
import { dirname } from "path";
|
|
649
650
|
var os = platform2();
|
|
650
651
|
function exec(cmd, args) {
|
|
651
|
-
return new Promise((
|
|
652
|
+
return new Promise((resolve4, reject) => {
|
|
652
653
|
execFile2(cmd, args, { timeout: 6e4 }, (err, stdout) => {
|
|
653
654
|
if (err) {
|
|
654
655
|
if (err.code === 1 || err.killed) {
|
|
655
|
-
|
|
656
|
+
resolve4("");
|
|
656
657
|
return;
|
|
657
658
|
}
|
|
658
659
|
reject(err);
|
|
659
660
|
return;
|
|
660
661
|
}
|
|
661
|
-
|
|
662
|
+
resolve4(stdout.trim());
|
|
662
663
|
});
|
|
663
664
|
});
|
|
664
665
|
}
|
|
@@ -1417,7 +1418,7 @@ import { randomUUID as randomUUID2 } from "crypto";
|
|
|
1417
1418
|
var processes = /* @__PURE__ */ new Map();
|
|
1418
1419
|
function sendRequest(proc, method, params) {
|
|
1419
1420
|
const id = randomUUID2();
|
|
1420
|
-
return new Promise((
|
|
1421
|
+
return new Promise((resolve4, reject) => {
|
|
1421
1422
|
const timeout = setTimeout(() => {
|
|
1422
1423
|
proc.pendingRequests.delete(id);
|
|
1423
1424
|
reject(new Error(`MCP request timeout: ${method}`));
|
|
@@ -1425,7 +1426,7 @@ function sendRequest(proc, method, params) {
|
|
|
1425
1426
|
proc.pendingRequests.set(id, {
|
|
1426
1427
|
resolve: (v) => {
|
|
1427
1428
|
clearTimeout(timeout);
|
|
1428
|
-
|
|
1429
|
+
resolve4(v);
|
|
1429
1430
|
},
|
|
1430
1431
|
reject: (e) => {
|
|
1431
1432
|
clearTimeout(timeout);
|
|
@@ -1503,13 +1504,13 @@ async function setSetting(params) {
|
|
|
1503
1504
|
await saveSettings(settings);
|
|
1504
1505
|
}
|
|
1505
1506
|
function findAvailablePort() {
|
|
1506
|
-
return new Promise((
|
|
1507
|
+
return new Promise((resolve4, reject) => {
|
|
1507
1508
|
const server = createServer();
|
|
1508
1509
|
server.listen(0, "127.0.0.1", () => {
|
|
1509
1510
|
const addr = server.address();
|
|
1510
1511
|
if (addr && typeof addr === "object") {
|
|
1511
1512
|
const p = addr.port;
|
|
1512
|
-
server.close(() =>
|
|
1513
|
+
server.close(() => resolve4(p));
|
|
1513
1514
|
} else {
|
|
1514
1515
|
server.close(() => reject(new Error("Failed to get port")));
|
|
1515
1516
|
}
|
|
@@ -1549,10 +1550,10 @@ async function findOpenClawEntrypoint() {
|
|
|
1549
1550
|
];
|
|
1550
1551
|
try {
|
|
1551
1552
|
const cmd = process.platform === "win32" ? "where" : "which";
|
|
1552
|
-
const path = await new Promise((
|
|
1553
|
+
const path = await new Promise((resolve4, reject) => {
|
|
1553
1554
|
execFile3(cmd, ["openclaw"], (err, stdout) => {
|
|
1554
1555
|
if (err) reject(err);
|
|
1555
|
-
else
|
|
1556
|
+
else resolve4(stdout.trim());
|
|
1556
1557
|
});
|
|
1557
1558
|
});
|
|
1558
1559
|
if (path) candidates.unshift(path);
|
|
@@ -1681,7 +1682,7 @@ async function openclawStart(_params) {
|
|
|
1681
1682
|
emit("openclaw://status-changed", { status: "crashed" });
|
|
1682
1683
|
}
|
|
1683
1684
|
});
|
|
1684
|
-
await new Promise((
|
|
1685
|
+
await new Promise((resolve4) => setTimeout(resolve4, 1e3));
|
|
1685
1686
|
if (childProcess && !childProcess.killed) {
|
|
1686
1687
|
processStatus = "running";
|
|
1687
1688
|
startedAt = Date.now();
|
|
@@ -1722,7 +1723,7 @@ async function openclawStop(_params) {
|
|
|
1722
1723
|
}
|
|
1723
1724
|
async function openclawRestart(_params) {
|
|
1724
1725
|
await openclawStop({});
|
|
1725
|
-
await new Promise((
|
|
1726
|
+
await new Promise((resolve4) => setTimeout(resolve4, 500));
|
|
1726
1727
|
await openclawStart({});
|
|
1727
1728
|
}
|
|
1728
1729
|
async function openclawStatus(_params) {
|
|
@@ -1737,7 +1738,7 @@ async function openclawStatus(_params) {
|
|
|
1737
1738
|
async function openclawListChannels(_params) {
|
|
1738
1739
|
if (processStatus !== "running") return [];
|
|
1739
1740
|
const entrypoint = await findOpenClawEntrypoint();
|
|
1740
|
-
return new Promise((
|
|
1741
|
+
return new Promise((resolve4) => {
|
|
1741
1742
|
execFile3(
|
|
1742
1743
|
"node",
|
|
1743
1744
|
[entrypoint, "channels", "status", "--json"],
|
|
@@ -1745,7 +1746,7 @@ async function openclawListChannels(_params) {
|
|
|
1745
1746
|
(err, stdout) => {
|
|
1746
1747
|
if (err) {
|
|
1747
1748
|
console.error("[OpenClaw] Failed to list channels:", err);
|
|
1748
|
-
|
|
1749
|
+
resolve4([]);
|
|
1749
1750
|
return;
|
|
1750
1751
|
}
|
|
1751
1752
|
try {
|
|
@@ -1764,9 +1765,9 @@ async function openclawListChannels(_params) {
|
|
|
1764
1765
|
}
|
|
1765
1766
|
channels.length = 0;
|
|
1766
1767
|
channels.push(...result);
|
|
1767
|
-
|
|
1768
|
+
resolve4(result);
|
|
1768
1769
|
} catch {
|
|
1769
|
-
|
|
1770
|
+
resolve4([]);
|
|
1770
1771
|
}
|
|
1771
1772
|
}
|
|
1772
1773
|
);
|
|
@@ -1837,14 +1838,14 @@ async function openclawConnectChannel(params) {
|
|
|
1837
1838
|
async function openclawDisconnectChannel(params) {
|
|
1838
1839
|
const { channelId } = params;
|
|
1839
1840
|
const entrypoint = await findOpenClawEntrypoint();
|
|
1840
|
-
return new Promise((
|
|
1841
|
+
return new Promise((resolve4, reject) => {
|
|
1841
1842
|
execFile3(
|
|
1842
1843
|
"node",
|
|
1843
1844
|
[entrypoint, "channels", "remove", "--channel", channelId, "--delete"],
|
|
1844
1845
|
{ cwd: OPENCLAW_DIR, timeout: 1e4 },
|
|
1845
1846
|
(err) => {
|
|
1846
1847
|
if (err) reject(new Error(`Failed to disconnect: ${err.message}`));
|
|
1847
|
-
else
|
|
1848
|
+
else resolve4();
|
|
1848
1849
|
}
|
|
1849
1850
|
);
|
|
1850
1851
|
});
|
|
@@ -1899,7 +1900,7 @@ async function openclawGrantApproval(params) {
|
|
|
1899
1900
|
async function openclawGetQr(params) {
|
|
1900
1901
|
const { platform: plat } = params;
|
|
1901
1902
|
const entrypoint = await findOpenClawEntrypoint();
|
|
1902
|
-
return new Promise((
|
|
1903
|
+
return new Promise((resolve4, reject) => {
|
|
1903
1904
|
execFile3(
|
|
1904
1905
|
"node",
|
|
1905
1906
|
[entrypoint, "channels", "qr", "--platform", plat, "--json"],
|
|
@@ -1909,9 +1910,9 @@ async function openclawGetQr(params) {
|
|
|
1909
1910
|
else {
|
|
1910
1911
|
try {
|
|
1911
1912
|
const data = JSON.parse(stdout);
|
|
1912
|
-
|
|
1913
|
+
resolve4(data.qr || data.qrCode || stdout.trim());
|
|
1913
1914
|
} catch {
|
|
1914
|
-
|
|
1915
|
+
resolve4(stdout.trim());
|
|
1915
1916
|
}
|
|
1916
1917
|
}
|
|
1917
1918
|
}
|
|
@@ -1983,11 +1984,93 @@ async function stopWatching() {
|
|
|
1983
1984
|
});
|
|
1984
1985
|
}
|
|
1985
1986
|
|
|
1987
|
+
// src/handlers/updater.ts
|
|
1988
|
+
import { spawn as spawn3 } from "child_process";
|
|
1989
|
+
import { platform as platform3, homedir as homedir4 } from "os";
|
|
1990
|
+
import { resolve as resolve3 } from "path";
|
|
1991
|
+
import { createRequire } from "module";
|
|
1992
|
+
var require2 = createRequire(import.meta.url);
|
|
1993
|
+
var pkg = require2("../package.json");
|
|
1994
|
+
var CURRENT_VERSION = pkg.version;
|
|
1995
|
+
var PACKAGE_NAME = "@serendb/serendesktop";
|
|
1996
|
+
var REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
|
|
1997
|
+
async function checkForUpdate() {
|
|
1998
|
+
try {
|
|
1999
|
+
const controller = new AbortController();
|
|
2000
|
+
const timeout = setTimeout(() => controller.abort(), 1e4);
|
|
2001
|
+
const res = await fetch(REGISTRY_URL, {
|
|
2002
|
+
signal: controller.signal,
|
|
2003
|
+
headers: { Accept: "application/json" }
|
|
2004
|
+
});
|
|
2005
|
+
clearTimeout(timeout);
|
|
2006
|
+
if (!res.ok) {
|
|
2007
|
+
console.warn(`[Updater] Registry returned ${res.status}`);
|
|
2008
|
+
return { currentVersion: CURRENT_VERSION, latestVersion: null, updateAvailable: false };
|
|
2009
|
+
}
|
|
2010
|
+
const data = await res.json();
|
|
2011
|
+
const latestVersion = data.version ?? null;
|
|
2012
|
+
const updateAvailable = latestVersion !== null && latestVersion !== CURRENT_VERSION && isNewer(latestVersion, CURRENT_VERSION);
|
|
2013
|
+
console.log(`[Updater] Current: ${CURRENT_VERSION}, Latest: ${latestVersion}, Update: ${updateAvailable}`);
|
|
2014
|
+
return { currentVersion: CURRENT_VERSION, latestVersion, updateAvailable };
|
|
2015
|
+
} catch (err) {
|
|
2016
|
+
console.warn("[Updater] Failed to check for updates:", err);
|
|
2017
|
+
return { currentVersion: CURRENT_VERSION, latestVersion: null, updateAvailable: false };
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
async function installUpdate() {
|
|
2021
|
+
const home2 = homedir4();
|
|
2022
|
+
const serenDir = resolve3(home2, ".seren-local");
|
|
2023
|
+
const nodeDir = resolve3(serenDir, "node");
|
|
2024
|
+
const binDir = resolve3(serenDir, "bin");
|
|
2025
|
+
const isWin = platform3() === "win32";
|
|
2026
|
+
const nodeBinDir = isWin ? nodeDir : resolve3(nodeDir, "bin");
|
|
2027
|
+
const npmCmd = isWin ? resolve3(nodeBinDir, "npm.cmd") : resolve3(nodeBinDir, "npm");
|
|
2028
|
+
const serendesktopCmd = isWin ? "serendesktop.cmd" : "serendesktop";
|
|
2029
|
+
if (isWin) {
|
|
2030
|
+
const script = [
|
|
2031
|
+
`timeout /t 2 /nobreak >nul`,
|
|
2032
|
+
`set "PATH=${nodeBinDir};${binDir};%PATH%"`,
|
|
2033
|
+
`"${npmCmd}" install -g ${PACKAGE_NAME} --prefix "${serenDir}"`,
|
|
2034
|
+
`"${serendesktopCmd}"`
|
|
2035
|
+
].join(" && ");
|
|
2036
|
+
const child = spawn3("cmd", ["/c", script], {
|
|
2037
|
+
detached: true,
|
|
2038
|
+
stdio: "ignore",
|
|
2039
|
+
windowsHide: true
|
|
2040
|
+
});
|
|
2041
|
+
child.unref();
|
|
2042
|
+
} else {
|
|
2043
|
+
const script = [
|
|
2044
|
+
`sleep 2`,
|
|
2045
|
+
`export PATH="${nodeBinDir}:${binDir}:$PATH"`,
|
|
2046
|
+
`"${npmCmd}" install -g ${PACKAGE_NAME} --prefix "${serenDir}"`,
|
|
2047
|
+
`"${serendesktopCmd}"`
|
|
2048
|
+
].join(" && ");
|
|
2049
|
+
const child = spawn3("bash", ["-c", script], {
|
|
2050
|
+
detached: true,
|
|
2051
|
+
stdio: "ignore"
|
|
2052
|
+
});
|
|
2053
|
+
child.unref();
|
|
2054
|
+
}
|
|
2055
|
+
console.log("[Updater] Detached updater spawned, exiting server...");
|
|
2056
|
+
setTimeout(() => process.exit(0), 500);
|
|
2057
|
+
return { started: true };
|
|
2058
|
+
}
|
|
2059
|
+
function isNewer(a, b) {
|
|
2060
|
+
const pa = a.split(".").map(Number);
|
|
2061
|
+
const pb = b.split(".").map(Number);
|
|
2062
|
+
for (let i = 0; i < 3; i++) {
|
|
2063
|
+
if ((pa[i] ?? 0) > (pb[i] ?? 0)) return true;
|
|
2064
|
+
if ((pa[i] ?? 0) < (pb[i] ?? 0)) return false;
|
|
2065
|
+
}
|
|
2066
|
+
return false;
|
|
2067
|
+
}
|
|
2068
|
+
|
|
1986
2069
|
// src/handlers/wallet.ts
|
|
1987
2070
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
1988
2071
|
import { readFile as readFile4, writeFile as writeFile4, mkdir as mkdir3 } from "fs/promises";
|
|
1989
2072
|
import { join as join5 } from "path";
|
|
1990
|
-
import { homedir as
|
|
2073
|
+
import { homedir as homedir5 } from "os";
|
|
1991
2074
|
import {
|
|
1992
2075
|
privateKeyToAccount
|
|
1993
2076
|
} from "viem/accounts";
|
|
@@ -2000,7 +2083,7 @@ import {
|
|
|
2000
2083
|
getAddress
|
|
2001
2084
|
} from "viem";
|
|
2002
2085
|
import { base } from "viem/chains";
|
|
2003
|
-
var SEREN_DIR = join5(
|
|
2086
|
+
var SEREN_DIR = join5(homedir5(), ".seren-local");
|
|
2004
2087
|
var WALLET_FILE = join5(SEREN_DIR, "data", "crypto-wallet.json");
|
|
2005
2088
|
var USDC_CONTRACT_BASE = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913";
|
|
2006
2089
|
var BASE_RPC_URL = "https://mainnet.base.org";
|
|
@@ -2316,6 +2399,8 @@ function registerAllHandlers() {
|
|
|
2316
2399
|
registerHandler("get_embedding_dimension", getEmbeddingDimension);
|
|
2317
2400
|
registerHandler("mcp_disconnect", mcpDisconnect);
|
|
2318
2401
|
registerHandler("mcp_read_resource", mcpReadResource);
|
|
2402
|
+
registerHandler("check_for_update", checkForUpdate);
|
|
2403
|
+
registerHandler("install_update", installUpdate);
|
|
2319
2404
|
registerHandler("create_conversation", createConversation);
|
|
2320
2405
|
registerHandler("get_conversations", getConversations);
|
|
2321
2406
|
registerHandler("get_conversation", getConversation);
|
|
@@ -2333,10 +2418,10 @@ import { fileURLToPath } from "url";
|
|
|
2333
2418
|
var __dirname = dirname2(fileURLToPath(import.meta.url));
|
|
2334
2419
|
function getInstalledVersion() {
|
|
2335
2420
|
try {
|
|
2336
|
-
const
|
|
2421
|
+
const pkg2 = JSON.parse(
|
|
2337
2422
|
readFileSync2(join6(__dirname, "..", "package.json"), "utf-8")
|
|
2338
2423
|
);
|
|
2339
|
-
return
|
|
2424
|
+
return pkg2.version ?? "0.0.0";
|
|
2340
2425
|
} catch {
|
|
2341
2426
|
return "0.0.0";
|
|
2342
2427
|
}
|
|
@@ -2356,7 +2441,7 @@ async function getLatestVersion() {
|
|
|
2356
2441
|
return null;
|
|
2357
2442
|
}
|
|
2358
2443
|
}
|
|
2359
|
-
function
|
|
2444
|
+
function isNewer2(latest, current) {
|
|
2360
2445
|
const l = latest.split(".").map(Number);
|
|
2361
2446
|
const c = current.split(".").map(Number);
|
|
2362
2447
|
for (let i = 0; i < 3; i++) {
|
|
@@ -2368,7 +2453,7 @@ function isNewer(latest, current) {
|
|
|
2368
2453
|
function checkForUpdates() {
|
|
2369
2454
|
const current = getInstalledVersion();
|
|
2370
2455
|
getLatestVersion().then((latest) => {
|
|
2371
|
-
if (latest &&
|
|
2456
|
+
if (latest && isNewer2(latest, current)) {
|
|
2372
2457
|
console.log("");
|
|
2373
2458
|
console.log(` \u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557`);
|
|
2374
2459
|
console.log(` \u2551 Update available: v${current} \u2192 v${latest.padEnd(10)} \u2551`);
|
|
@@ -2381,6 +2466,8 @@ function checkForUpdates() {
|
|
|
2381
2466
|
}
|
|
2382
2467
|
|
|
2383
2468
|
// src/server.ts
|
|
2469
|
+
var require3 = createRequire2(import.meta.url);
|
|
2470
|
+
var APP_VERSION = require3("../package.json").version;
|
|
2384
2471
|
var PORT = Number(process.env.SEREN_PORT) || 19420;
|
|
2385
2472
|
var NO_OPEN = process.argv.includes("--no-open");
|
|
2386
2473
|
var AUTH_TOKEN = process.env.SEREN_RUNTIME_TOKEN || randomBytes3(32).toString("hex");
|
|
@@ -2459,7 +2546,7 @@ function serveSpaFallback(res) {
|
|
|
2459
2546
|
return serveHtml(res);
|
|
2460
2547
|
}
|
|
2461
2548
|
function openBrowser(url) {
|
|
2462
|
-
const cmd =
|
|
2549
|
+
const cmd = platform4() === "darwin" ? `open "${url}"` : platform4() === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
|
|
2463
2550
|
exec2(cmd, (err) => {
|
|
2464
2551
|
if (err) console.log(`[Seren Local] Could not open browser: ${err.message}`);
|
|
2465
2552
|
});
|
|
@@ -2534,7 +2621,7 @@ var httpServer = createServer2((req, res) => {
|
|
|
2534
2621
|
}
|
|
2535
2622
|
if (req.url === "/health") {
|
|
2536
2623
|
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2537
|
-
res.end(JSON.stringify({ status: "ok", version:
|
|
2624
|
+
res.end(JSON.stringify({ status: "ok", version: APP_VERSION, token: AUTH_TOKEN, buildHash: BUILD_HASH }));
|
|
2538
2625
|
return;
|
|
2539
2626
|
}
|
|
2540
2627
|
const urlPath = req.url || "/";
|
|
@@ -2588,7 +2675,7 @@ wss.on("connection", (ws, req) => {
|
|
|
2588
2675
|
console.log("[Seren Local] Browser disconnected");
|
|
2589
2676
|
});
|
|
2590
2677
|
});
|
|
2591
|
-
var dataDir = join7(
|
|
2678
|
+
var dataDir = join7(homedir6(), ".seren-local");
|
|
2592
2679
|
mkdirSync2(dataDir, { recursive: true });
|
|
2593
2680
|
initChatDb(join7(dataDir, "conversations.db"));
|
|
2594
2681
|
registerAllHandlers();
|