@rubytech/create-realagent 1.0.721 → 1.0.736
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/package.json +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +2 -3
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +0 -1
- package/payload/platform/plugins/docs/PLUGIN.md +1 -1
- package/payload/platform/plugins/docs/references/settings.md +0 -13
- package/payload/platform/templates/account.json +0 -1
- package/payload/server/chunk-3KDVGWPQ.js +2920 -0
- package/payload/server/chunk-BIOIXN5A.js +12165 -0
- package/payload/server/chunk-D53LK5YC.js +12171 -0
- package/payload/server/chunk-FM5JMRED.js +12033 -0
- package/payload/server/chunk-HPU24BXP.js +12173 -0
- package/payload/server/chunk-HU5FSQYA.js +12186 -0
- package/payload/server/chunk-JDT3MGUY.js +12165 -0
- package/payload/server/chunk-K7GQ5RMN.js +12172 -0
- package/payload/server/chunk-ULVR2RRY.js +9439 -0
- package/payload/server/client-pool-I5TCP7WI.js +28 -0
- package/payload/server/maxy-edge.js +2 -1
- package/payload/server/package.json +1 -0
- package/payload/server/public/assets/admin-BKdSPr9G.js +352 -0
- package/payload/server/public/index.html +1 -1
- package/payload/server/server.js +338 -260
- package/payload/server/public/assets/admin-yP0pMsyg.js +0 -352
package/payload/server/server.js
CHANGED
|
@@ -1,35 +1,65 @@
|
|
|
1
1
|
import {
|
|
2
|
-
GREETING_DIRECTIVE,
|
|
3
|
-
HAIKU_MODEL,
|
|
4
2
|
Hono,
|
|
5
3
|
LOG_DIR,
|
|
6
4
|
MAXY_DIR,
|
|
7
5
|
TELEGRAM_ADMIN_WEBHOOK_SECRET_FILE,
|
|
8
6
|
TELEGRAM_WEBHOOK_SECRET_FILE,
|
|
9
7
|
USERS_FILE,
|
|
10
|
-
__commonJS,
|
|
11
|
-
__toESM,
|
|
12
|
-
agentLogStream,
|
|
13
|
-
backfillNullUserIdConversations,
|
|
14
|
-
bindVisitorToGroup,
|
|
15
8
|
buildX11Env,
|
|
16
9
|
callOauthLlm,
|
|
17
10
|
canAccessAdmin,
|
|
18
|
-
checkGroupMembership,
|
|
19
11
|
checkRateLimit,
|
|
20
12
|
clearRateLimit,
|
|
21
|
-
clearSessionHistory,
|
|
22
13
|
clientIpMiddleware,
|
|
23
14
|
compactSession,
|
|
24
|
-
completeGrantSetup,
|
|
25
15
|
computeConstraints,
|
|
26
16
|
createRemoteSession,
|
|
27
|
-
deleteConversation,
|
|
28
|
-
embed,
|
|
29
17
|
ensureAuth,
|
|
30
18
|
ensureCdp,
|
|
31
19
|
ensureLogDir,
|
|
32
20
|
ensureVnc,
|
|
21
|
+
hashPassword,
|
|
22
|
+
invokeAgent,
|
|
23
|
+
isActionActive,
|
|
24
|
+
isPasswordValid,
|
|
25
|
+
isRemoteAuthConfigured,
|
|
26
|
+
keyFilePath,
|
|
27
|
+
launchAction,
|
|
28
|
+
load,
|
|
29
|
+
logPath,
|
|
30
|
+
recordFailedAttempt,
|
|
31
|
+
render,
|
|
32
|
+
renderLoginPage,
|
|
33
|
+
requireAdminSession,
|
|
34
|
+
resolveBrowserTransport,
|
|
35
|
+
resolveClientIp,
|
|
36
|
+
safeJson,
|
|
37
|
+
sanitizeClientCorrId,
|
|
38
|
+
serve,
|
|
39
|
+
setRemotePassword,
|
|
40
|
+
sleep,
|
|
41
|
+
streamLogPathFor,
|
|
42
|
+
validateKey,
|
|
43
|
+
validatePasswordStrength,
|
|
44
|
+
verifyPassword,
|
|
45
|
+
verifyRemotePassword,
|
|
46
|
+
vncLog,
|
|
47
|
+
waitForExit,
|
|
48
|
+
writeChromiumWrapper
|
|
49
|
+
} from "./chunk-ULVR2RRY.js";
|
|
50
|
+
import {
|
|
51
|
+
GREETING_DIRECTIVE,
|
|
52
|
+
HAIKU_MODEL,
|
|
53
|
+
__commonJS,
|
|
54
|
+
__toESM,
|
|
55
|
+
agentLogStream,
|
|
56
|
+
backfillNullUserIdConversations,
|
|
57
|
+
bindVisitorToGroup,
|
|
58
|
+
checkGroupMembership,
|
|
59
|
+
clearSessionHistory,
|
|
60
|
+
completeGrantSetup,
|
|
61
|
+
deleteConversation,
|
|
62
|
+
embed,
|
|
33
63
|
fetchBranding,
|
|
34
64
|
findGroupBySlug,
|
|
35
65
|
findRecentConversation,
|
|
@@ -49,56 +79,30 @@ import {
|
|
|
49
79
|
getUserNameForSession,
|
|
50
80
|
getUserTimezone,
|
|
51
81
|
getVisitorIdForSession,
|
|
52
|
-
|
|
53
|
-
invokeAgent,
|
|
54
|
-
isActionActive,
|
|
55
|
-
isPasswordValid,
|
|
56
|
-
isRemoteAuthConfigured,
|
|
57
|
-
keyFilePath,
|
|
58
|
-
launchAction,
|
|
82
|
+
interruptClient,
|
|
59
83
|
listAdminSessions,
|
|
60
84
|
listAdminSessionsInProgress,
|
|
61
|
-
load,
|
|
62
85
|
loadOnboardingStep,
|
|
63
|
-
logPath,
|
|
64
86
|
preConversationLogStream,
|
|
65
|
-
|
|
87
|
+
preflushStreamLogKey,
|
|
66
88
|
registerGrantSession,
|
|
67
89
|
registerResumedSession,
|
|
68
90
|
registerSession,
|
|
69
91
|
renameConversation,
|
|
70
|
-
render,
|
|
71
|
-
renderLoginPage,
|
|
72
|
-
requireAdminSession,
|
|
73
92
|
resolveAccount,
|
|
74
93
|
resolveAgentConfig,
|
|
75
|
-
resolveBrowserTransport,
|
|
76
|
-
resolveClientIp,
|
|
77
94
|
resolveDefaultAgentSlug,
|
|
78
95
|
resolveUserAccounts,
|
|
79
|
-
safeJson,
|
|
80
|
-
sanitizeClientCorrId,
|
|
81
96
|
seedSessionHistory,
|
|
82
|
-
serve,
|
|
83
97
|
setConversationIdForSession,
|
|
84
98
|
setGroupContextForSession,
|
|
85
|
-
setRemotePassword,
|
|
86
99
|
sigtermFlushStreamLogs,
|
|
87
|
-
sleep,
|
|
88
|
-
streamLogPathFor,
|
|
89
100
|
unregisterSession,
|
|
90
101
|
validateAgentSlug,
|
|
91
|
-
validateKey,
|
|
92
|
-
validatePasswordStrength,
|
|
93
102
|
validateSession,
|
|
94
103
|
verifyAndGetConversationUpdatedAt,
|
|
95
|
-
verifyConversationOwnership
|
|
96
|
-
|
|
97
|
-
verifyRemotePassword,
|
|
98
|
-
vncLog,
|
|
99
|
-
waitForExit,
|
|
100
|
-
writeChromiumWrapper
|
|
101
|
-
} from "./chunk-7ODDM7L4.js";
|
|
104
|
+
verifyConversationOwnership
|
|
105
|
+
} from "./chunk-3KDVGWPQ.js";
|
|
102
106
|
|
|
103
107
|
// ../lib/graph-trash/dist/index.js
|
|
104
108
|
var require_dist = __commonJS({
|
|
@@ -597,8 +601,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
597
601
|
};
|
|
598
602
|
|
|
599
603
|
// server/index.ts
|
|
600
|
-
import { readFileSync as
|
|
601
|
-
import { resolve as
|
|
604
|
+
import { readFileSync as readFileSync16, existsSync as existsSync19, watchFile } from "fs";
|
|
605
|
+
import { resolve as resolve20, join as join10, basename as basename7 } from "path";
|
|
602
606
|
import { homedir as homedir2 } from "os";
|
|
603
607
|
|
|
604
608
|
// app/lib/agent-slug-pattern.ts
|
|
@@ -2683,7 +2687,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
2683
2687
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
2684
2688
|
console.error(`${TAG3} draining credential save queue\u2026`);
|
|
2685
2689
|
const timer2 = new Promise(
|
|
2686
|
-
(
|
|
2690
|
+
(resolve21) => setTimeout(() => resolve21("timeout"), timeoutMs)
|
|
2687
2691
|
);
|
|
2688
2692
|
const result = await Promise.race([
|
|
2689
2693
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -2811,11 +2815,11 @@ async function createWaSocket(opts) {
|
|
|
2811
2815
|
return sock;
|
|
2812
2816
|
}
|
|
2813
2817
|
async function waitForConnection(sock) {
|
|
2814
|
-
return new Promise((
|
|
2818
|
+
return new Promise((resolve21, reject) => {
|
|
2815
2819
|
const handler = (update) => {
|
|
2816
2820
|
if (update.connection === "open") {
|
|
2817
2821
|
sock.ev.off("connection.update", handler);
|
|
2818
|
-
|
|
2822
|
+
resolve21();
|
|
2819
2823
|
}
|
|
2820
2824
|
if (update.connection === "close") {
|
|
2821
2825
|
sock.ev.off("connection.update", handler);
|
|
@@ -2929,14 +2933,14 @@ ${inspected}`;
|
|
|
2929
2933
|
return inspect2(err, INSPECT_OPTS2);
|
|
2930
2934
|
}
|
|
2931
2935
|
function withTimeout(label, promise, timeoutMs) {
|
|
2932
|
-
return new Promise((
|
|
2936
|
+
return new Promise((resolve21, reject) => {
|
|
2933
2937
|
const timer2 = setTimeout(() => {
|
|
2934
2938
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
2935
2939
|
}, timeoutMs);
|
|
2936
2940
|
promise.then(
|
|
2937
2941
|
(value) => {
|
|
2938
2942
|
clearTimeout(timer2);
|
|
2939
|
-
|
|
2943
|
+
resolve21(value);
|
|
2940
2944
|
},
|
|
2941
2945
|
(err) => {
|
|
2942
2946
|
clearTimeout(timer2);
|
|
@@ -4150,11 +4154,11 @@ async function connectWithReconnect(conn) {
|
|
|
4150
4154
|
console.error(
|
|
4151
4155
|
`${TAG11} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
4152
4156
|
);
|
|
4153
|
-
await new Promise((
|
|
4154
|
-
const timer2 = setTimeout(
|
|
4157
|
+
await new Promise((resolve21) => {
|
|
4158
|
+
const timer2 = setTimeout(resolve21, delay);
|
|
4155
4159
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
4156
4160
|
clearTimeout(timer2);
|
|
4157
|
-
|
|
4161
|
+
resolve21();
|
|
4158
4162
|
}, { once: true });
|
|
4159
4163
|
});
|
|
4160
4164
|
}
|
|
@@ -4162,16 +4166,16 @@ async function connectWithReconnect(conn) {
|
|
|
4162
4166
|
}
|
|
4163
4167
|
}
|
|
4164
4168
|
function waitForDisconnectEvent(conn) {
|
|
4165
|
-
return new Promise((
|
|
4169
|
+
return new Promise((resolve21) => {
|
|
4166
4170
|
if (!conn.sock) {
|
|
4167
|
-
|
|
4171
|
+
resolve21();
|
|
4168
4172
|
return;
|
|
4169
4173
|
}
|
|
4170
4174
|
const sock = conn.sock;
|
|
4171
4175
|
const handler = (update) => {
|
|
4172
4176
|
if (update.connection === "close") {
|
|
4173
4177
|
sock.ev.off("connection.update", handler);
|
|
4174
|
-
|
|
4178
|
+
resolve21();
|
|
4175
4179
|
}
|
|
4176
4180
|
};
|
|
4177
4181
|
sock.ev.on("connection.update", handler);
|
|
@@ -4388,8 +4392,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4388
4392
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
4389
4393
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
4390
4394
|
let resolvePending;
|
|
4391
|
-
const sttPending = new Promise((
|
|
4392
|
-
resolvePending =
|
|
4395
|
+
const sttPending = new Promise((resolve21) => {
|
|
4396
|
+
resolvePending = resolve21;
|
|
4393
4397
|
});
|
|
4394
4398
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
4395
4399
|
try {
|
|
@@ -4502,20 +4506,20 @@ async function probeApiKey() {
|
|
|
4502
4506
|
return result.status;
|
|
4503
4507
|
}
|
|
4504
4508
|
function checkPort(port2, timeoutMs = 500) {
|
|
4505
|
-
return new Promise((
|
|
4509
|
+
return new Promise((resolve21) => {
|
|
4506
4510
|
const socket = createConnection(port2, "127.0.0.1");
|
|
4507
4511
|
socket.setTimeout(timeoutMs);
|
|
4508
4512
|
socket.once("connect", () => {
|
|
4509
4513
|
socket.destroy();
|
|
4510
|
-
|
|
4514
|
+
resolve21(true);
|
|
4511
4515
|
});
|
|
4512
4516
|
socket.once("error", () => {
|
|
4513
4517
|
socket.destroy();
|
|
4514
|
-
|
|
4518
|
+
resolve21(false);
|
|
4515
4519
|
});
|
|
4516
4520
|
socket.once("timeout", () => {
|
|
4517
4521
|
socket.destroy();
|
|
4518
|
-
|
|
4522
|
+
resolve21(false);
|
|
4519
4523
|
});
|
|
4520
4524
|
});
|
|
4521
4525
|
}
|
|
@@ -6717,8 +6721,8 @@ async function startLogin(opts) {
|
|
|
6717
6721
|
resetActiveLogin(accountId);
|
|
6718
6722
|
let resolveQr = null;
|
|
6719
6723
|
let rejectQr = null;
|
|
6720
|
-
const qrPromise = new Promise((
|
|
6721
|
-
resolveQr =
|
|
6724
|
+
const qrPromise = new Promise((resolve21, reject) => {
|
|
6725
|
+
resolveQr = resolve21;
|
|
6722
6726
|
rejectQr = reject;
|
|
6723
6727
|
});
|
|
6724
6728
|
const qrTimer = setTimeout(
|
|
@@ -7820,6 +7824,7 @@ var session_default2 = app10;
|
|
|
7820
7824
|
|
|
7821
7825
|
// server/routes/admin/chat.ts
|
|
7822
7826
|
import { resolve as resolve12 } from "path";
|
|
7827
|
+
import { appendFileSync as appendFileSync4 } from "fs";
|
|
7823
7828
|
|
|
7824
7829
|
// app/lib/script-stream-tailer.ts
|
|
7825
7830
|
import * as childProcess from "child_process";
|
|
@@ -8106,6 +8111,16 @@ function chatReject(status, error, sk) {
|
|
|
8106
8111
|
});
|
|
8107
8112
|
}
|
|
8108
8113
|
var app11 = new Hono();
|
|
8114
|
+
app11.post("/cancel", requireAdminSession, async (c) => {
|
|
8115
|
+
const session_key = c.var.sessionKey;
|
|
8116
|
+
try {
|
|
8117
|
+
const { interruptClient: interruptClient2 } = await import("./client-pool-I5TCP7WI.js");
|
|
8118
|
+
await interruptClient2(session_key);
|
|
8119
|
+
return c.json({ ok: true });
|
|
8120
|
+
} catch (err) {
|
|
8121
|
+
return c.json({ ok: false, error: err instanceof Error ? err.message : String(err) }, 500);
|
|
8122
|
+
}
|
|
8123
|
+
});
|
|
8109
8124
|
app11.post("/", requireAdminSession, async (c) => {
|
|
8110
8125
|
const session_key = c.var.sessionKey;
|
|
8111
8126
|
const contentType = c.req.header("content-type") ?? "";
|
|
@@ -8254,13 +8269,107 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
8254
8269
|
}
|
|
8255
8270
|
const encoder = new TextEncoder();
|
|
8256
8271
|
const sseConvId = getConversationIdForSession(session_key);
|
|
8257
|
-
const
|
|
8272
|
+
const sseLogStream = sseConvId ? agentLogStream("sse-events", account.accountDir, sseConvId) : preConversationLogStream("sse-events", account.accountDir);
|
|
8258
8273
|
const sk = sseConvId?.slice(0, 8) ?? session_key.slice(0, 8);
|
|
8274
|
+
const teeStreamLogKey = sseConvId ?? preflushStreamLogKey(session_key);
|
|
8275
|
+
const teeStreamLogPath = resolve12(account.accountDir, "logs", `claude-agent-stream-${teeStreamLogKey}.log`);
|
|
8276
|
+
try {
|
|
8277
|
+
appendFileSync4(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [chat-route-version=task606-incoming-close] sessionKey=${session_key.slice(0, 12)}\u2026
|
|
8278
|
+
`);
|
|
8279
|
+
} catch {
|
|
8280
|
+
}
|
|
8281
|
+
const incoming = c.env?.incoming;
|
|
8282
|
+
if (incoming && typeof incoming.on === "function") {
|
|
8283
|
+
incoming.on("close", () => {
|
|
8284
|
+
const tsClose = (/* @__PURE__ */ new Date()).toISOString();
|
|
8285
|
+
try {
|
|
8286
|
+
appendFileSync4(teeStreamLogPath, `[${tsClose}] [incoming-close] sessionKey=${session_key.slice(0, 12)}\u2026 complete=${incoming.complete}
|
|
8287
|
+
`);
|
|
8288
|
+
} catch {
|
|
8289
|
+
}
|
|
8290
|
+
if (incoming.complete === false) {
|
|
8291
|
+
console.error(`[${tsClose}] [incoming-close] DISCONNECT sessionKey=${session_key.slice(0, 12)}\u2026`);
|
|
8292
|
+
interruptClient(session_key).catch((err) => {
|
|
8293
|
+
try {
|
|
8294
|
+
appendFileSync4(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [incoming-close] interrupt-failed: ${err instanceof Error ? err.message : String(err)}
|
|
8295
|
+
`);
|
|
8296
|
+
} catch {
|
|
8297
|
+
}
|
|
8298
|
+
});
|
|
8299
|
+
}
|
|
8300
|
+
});
|
|
8301
|
+
} else {
|
|
8302
|
+
try {
|
|
8303
|
+
appendFileSync4(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [incoming-close] UNAVAILABLE \u2014 c.env.incoming is not an EventEmitter
|
|
8304
|
+
`);
|
|
8305
|
+
} catch {
|
|
8306
|
+
}
|
|
8307
|
+
}
|
|
8308
|
+
const sseLog = {
|
|
8309
|
+
write(line) {
|
|
8310
|
+
try {
|
|
8311
|
+
sseLogStream.write(line);
|
|
8312
|
+
} catch {
|
|
8313
|
+
}
|
|
8314
|
+
try {
|
|
8315
|
+
appendFileSync4(teeStreamLogPath, line);
|
|
8316
|
+
} catch {
|
|
8317
|
+
}
|
|
8318
|
+
return true;
|
|
8319
|
+
},
|
|
8320
|
+
end() {
|
|
8321
|
+
try {
|
|
8322
|
+
sseLogStream.end();
|
|
8323
|
+
} catch {
|
|
8324
|
+
}
|
|
8325
|
+
}
|
|
8326
|
+
};
|
|
8259
8327
|
let tailer = null;
|
|
8260
8328
|
const readable = new ReadableStream({
|
|
8329
|
+
// Task 606 — fires when the consumer (Hono's response writer / Node
|
|
8330
|
+
// adapter) cancels the stream because the client disconnected. This is
|
|
8331
|
+
// the only signal that arrives WHILE start()'s for-await is blocked
|
|
8332
|
+
// awaiting the SDK's next message — c.req.raw.signal didn't propagate
|
|
8333
|
+
// under @hono/node-server, and controller.enqueue throwing only
|
|
8334
|
+
// surfaces on the next yielded event (which never comes if the model
|
|
8335
|
+
// is mid-response when Cancel is pressed). cancel() is the load-bearing
|
|
8336
|
+
// hook for operator abort.
|
|
8337
|
+
//
|
|
8338
|
+
// Synchronous trace writes go to BOTH the per-conv stream log (where
|
|
8339
|
+
// operators read) AND console.error (server.log backstop). This lets
|
|
8340
|
+
// us prove definitively whether this callback is even being invoked
|
|
8341
|
+
// by @hono/node-server on disconnect.
|
|
8342
|
+
cancel(reason) {
|
|
8343
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
8344
|
+
const reasonStr = typeof reason === "string" ? reason : reason instanceof Error ? reason.message : "consumer-cancelled";
|
|
8345
|
+
sseLog.write(`[${ts}] [${sk}] admin: CANCEL [stream-cancel] reason=${reasonStr}
|
|
8346
|
+
`);
|
|
8347
|
+
console.error(`[${(/* @__PURE__ */ new Date()).toISOString()}] [stream-cancel-callback] sessionKey=${session_key.slice(0, 12)}\u2026 reason=${JSON.stringify(reasonStr)}`);
|
|
8348
|
+
interruptClient(session_key).catch((err) => {
|
|
8349
|
+
sseLog.write(`[${ts}] [${sk}] admin: ABORT [interrupt-failed] ${err instanceof Error ? err.message : String(err)}
|
|
8350
|
+
`);
|
|
8351
|
+
});
|
|
8352
|
+
},
|
|
8261
8353
|
async start(controller) {
|
|
8262
8354
|
let controllerOpen = true;
|
|
8263
8355
|
const sseEntry = { controller, conversationId: sseConvId ?? null, sessionKey: session_key };
|
|
8356
|
+
try {
|
|
8357
|
+
const reqSignal = c.req.raw?.signal;
|
|
8358
|
+
if (reqSignal) {
|
|
8359
|
+
reqSignal.addEventListener("abort", () => {
|
|
8360
|
+
const abortLogKey = sseConvId ?? preflushStreamLogKey(session_key);
|
|
8361
|
+
const abortStreamLog = agentLogStream("claude-agent-stream", account.accountDir, abortLogKey);
|
|
8362
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
8363
|
+
sseLog.write(`[${ts}] [${sk}] admin: ABORT [operator-cancel] interrupting pool client
|
|
8364
|
+
`);
|
|
8365
|
+
interruptClient(session_key, abortStreamLog).catch((err) => {
|
|
8366
|
+
sseLog.write(`[${ts}] [${sk}] admin: ABORT [interrupt-failed] ${err instanceof Error ? err.message : String(err)}
|
|
8367
|
+
`);
|
|
8368
|
+
});
|
|
8369
|
+
}, { once: true });
|
|
8370
|
+
}
|
|
8371
|
+
} catch {
|
|
8372
|
+
}
|
|
8264
8373
|
try {
|
|
8265
8374
|
registerAdminSSE(sseEntry);
|
|
8266
8375
|
if (sseConvId) {
|
|
@@ -8308,6 +8417,10 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
8308
8417
|
if (controllerClosed) {
|
|
8309
8418
|
sseLog.write(`[${ts}] [${sk}] admin: DISCONNECT [client_disconnect] ${rawMessage}
|
|
8310
8419
|
`);
|
|
8420
|
+
interruptClient(session_key).catch((interruptErr) => {
|
|
8421
|
+
sseLog.write(`[${ts}] [${sk}] admin: ABORT [interrupt-failed] ${interruptErr instanceof Error ? interruptErr.message : String(interruptErr)}
|
|
8422
|
+
`);
|
|
8423
|
+
});
|
|
8311
8424
|
} else {
|
|
8312
8425
|
const category = classifyAgentError(err);
|
|
8313
8426
|
const errEvent = JSON.stringify({ type: "text", content: friendlyAgentError(err) });
|
|
@@ -8595,9 +8708,8 @@ app14.get("/", (c) => {
|
|
|
8595
8708
|
}
|
|
8596
8709
|
const resolvedAccount = resolveAccount();
|
|
8597
8710
|
const model = resolvedAccount?.config.adminModel ?? "unknown";
|
|
8598
|
-
const contextMode = resolvedAccount?.config.contextMode ?? "managed";
|
|
8599
8711
|
const thinkingView = resolvedAccount?.config.thinkingView ?? "default";
|
|
8600
|
-
return c.json({ version, account, model,
|
|
8712
|
+
return c.json({ version, account, model, thinkingView });
|
|
8601
8713
|
});
|
|
8602
8714
|
var claude_info_default = app14;
|
|
8603
8715
|
|
|
@@ -8647,47 +8759,14 @@ app15.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
8647
8759
|
});
|
|
8648
8760
|
var attachment_default = app15;
|
|
8649
8761
|
|
|
8650
|
-
// server/routes/admin/
|
|
8651
|
-
import { readFileSync as readFileSync13, writeFileSync as writeFileSync8 } from "fs";
|
|
8762
|
+
// server/routes/admin/agents.ts
|
|
8652
8763
|
import { resolve as resolve15 } from "path";
|
|
8653
|
-
|
|
8764
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync13, existsSync as existsSync17, rmSync } from "fs";
|
|
8654
8765
|
var app16 = new Hono();
|
|
8655
|
-
app16.
|
|
8656
|
-
let body;
|
|
8657
|
-
try {
|
|
8658
|
-
body = await c.req.json();
|
|
8659
|
-
} catch {
|
|
8660
|
-
return c.json({ error: "Invalid request" }, 400);
|
|
8661
|
-
}
|
|
8662
|
-
const { contextMode } = body;
|
|
8663
|
-
if (!contextMode || !VALID_CONTEXT_MODES.includes(contextMode)) {
|
|
8664
|
-
return c.json({ error: `Invalid contextMode. Valid values: ${VALID_CONTEXT_MODES.join(", ")}` }, 400);
|
|
8665
|
-
}
|
|
8666
|
-
const account = resolveAccount();
|
|
8667
|
-
if (!account) return c.json({ error: "No account configured" }, 500);
|
|
8668
|
-
const configPath2 = resolve15(account.accountDir, "account.json");
|
|
8669
|
-
try {
|
|
8670
|
-
const raw = readFileSync13(configPath2, "utf-8");
|
|
8671
|
-
const config = JSON.parse(raw);
|
|
8672
|
-
config.contextMode = contextMode;
|
|
8673
|
-
writeFileSync8(configPath2, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
8674
|
-
console.error(`[account-update] contextMode=${contextMode}`);
|
|
8675
|
-
return c.json({ ok: true, contextMode });
|
|
8676
|
-
} catch (err) {
|
|
8677
|
-
console.error(`[account-update] failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
8678
|
-
return c.json({ error: "Failed to update account" }, 500);
|
|
8679
|
-
}
|
|
8680
|
-
});
|
|
8681
|
-
var account_default = app16;
|
|
8682
|
-
|
|
8683
|
-
// server/routes/admin/agents.ts
|
|
8684
|
-
import { resolve as resolve16 } from "path";
|
|
8685
|
-
import { readdirSync as readdirSync4, readFileSync as readFileSync14, existsSync as existsSync17, rmSync } from "fs";
|
|
8686
|
-
var app17 = new Hono();
|
|
8687
|
-
app17.get("/", (c) => {
|
|
8766
|
+
app16.get("/", (c) => {
|
|
8688
8767
|
const account = resolveAccount();
|
|
8689
8768
|
if (!account) return c.json({ agents: [] });
|
|
8690
|
-
const agentsDir =
|
|
8769
|
+
const agentsDir = resolve15(account.accountDir, "agents");
|
|
8691
8770
|
if (!existsSync17(agentsDir)) return c.json({ agents: [] });
|
|
8692
8771
|
const agents = [];
|
|
8693
8772
|
try {
|
|
@@ -8695,10 +8774,10 @@ app17.get("/", (c) => {
|
|
|
8695
8774
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
8696
8775
|
if (!entry.isDirectory()) continue;
|
|
8697
8776
|
if (entry.name === "admin") continue;
|
|
8698
|
-
const configPath2 =
|
|
8777
|
+
const configPath2 = resolve15(agentsDir, entry.name, "config.json");
|
|
8699
8778
|
if (!existsSync17(configPath2)) continue;
|
|
8700
8779
|
try {
|
|
8701
|
-
const config = JSON.parse(
|
|
8780
|
+
const config = JSON.parse(readFileSync13(configPath2, "utf-8"));
|
|
8702
8781
|
agents.push({
|
|
8703
8782
|
slug: entry.name,
|
|
8704
8783
|
displayName: config.displayName ?? entry.name,
|
|
@@ -8714,7 +8793,7 @@ app17.get("/", (c) => {
|
|
|
8714
8793
|
}
|
|
8715
8794
|
return c.json({ agents });
|
|
8716
8795
|
});
|
|
8717
|
-
|
|
8796
|
+
app16.delete("/:slug", (c) => {
|
|
8718
8797
|
const slug = c.req.param("slug");
|
|
8719
8798
|
const account = resolveAccount();
|
|
8720
8799
|
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
@@ -8724,7 +8803,7 @@ app17.delete("/:slug", (c) => {
|
|
|
8724
8803
|
if (slug.includes("/") || slug.includes("..") || slug.includes("\\")) {
|
|
8725
8804
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
8726
8805
|
}
|
|
8727
|
-
const agentDir =
|
|
8806
|
+
const agentDir = resolve15(account.accountDir, "agents", slug);
|
|
8728
8807
|
if (!existsSync17(agentDir)) {
|
|
8729
8808
|
return c.json({ error: "Agent not found" }, 404);
|
|
8730
8809
|
}
|
|
@@ -8737,7 +8816,7 @@ app17.delete("/:slug", (c) => {
|
|
|
8737
8816
|
return c.json({ error: "Failed to delete agent" }, 500);
|
|
8738
8817
|
}
|
|
8739
8818
|
});
|
|
8740
|
-
var agents_default =
|
|
8819
|
+
var agents_default = app16;
|
|
8741
8820
|
|
|
8742
8821
|
// server/routes/admin/sessions.ts
|
|
8743
8822
|
import crypto2 from "crypto";
|
|
@@ -8759,8 +8838,8 @@ function formatAge(updatedAtStr) {
|
|
|
8759
8838
|
return "unknown";
|
|
8760
8839
|
}
|
|
8761
8840
|
}
|
|
8762
|
-
var
|
|
8763
|
-
|
|
8841
|
+
var app17 = new Hono();
|
|
8842
|
+
app17.get("/", requireAdminSession, async (c) => {
|
|
8764
8843
|
const sessionKey = c.var.sessionKey;
|
|
8765
8844
|
const accountId = getAccountIdForSession(sessionKey);
|
|
8766
8845
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -8790,7 +8869,7 @@ app18.get("/", requireAdminSession, async (c) => {
|
|
|
8790
8869
|
return c.json({ error: "Failed to fetch sessions" }, 500);
|
|
8791
8870
|
}
|
|
8792
8871
|
});
|
|
8793
|
-
|
|
8872
|
+
app17.post("/new", requireAdminSession, async (c) => {
|
|
8794
8873
|
const oldSessionKey = c.var.sessionKey;
|
|
8795
8874
|
const accountId = getAccountIdForSession(oldSessionKey);
|
|
8796
8875
|
const userId = getUserIdForSession(oldSessionKey);
|
|
@@ -8805,7 +8884,7 @@ app18.post("/new", requireAdminSession, async (c) => {
|
|
|
8805
8884
|
console.log(`[session] ${(/* @__PURE__ */ new Date()).toISOString()} session reset for new conversation: oldSessionKey=${oldSessionKey.slice(0, 8)}\u2026 newSessionKey=${newSessionKey.slice(0, 8)}\u2026 previousConversationId=${previousConversationId?.slice(0, 8) ?? "none"}\u2026 newConversationId=deferred`);
|
|
8806
8885
|
return c.json({ session_key: newSessionKey, conversationId: null });
|
|
8807
8886
|
});
|
|
8808
|
-
|
|
8887
|
+
app17.delete("/:id", requireAdminSession, async (c) => {
|
|
8809
8888
|
const conversationId = c.req.param("id");
|
|
8810
8889
|
const sessionKey = c.var.sessionKey;
|
|
8811
8890
|
const accountId = getAccountIdForSession(sessionKey);
|
|
@@ -8820,7 +8899,7 @@ app18.delete("/:id", requireAdminSession, async (c) => {
|
|
|
8820
8899
|
return c.json({ error: "Failed to delete session" }, 500);
|
|
8821
8900
|
}
|
|
8822
8901
|
});
|
|
8823
|
-
|
|
8902
|
+
app17.get("/:id/messages", requireAdminSession, async (c) => {
|
|
8824
8903
|
const conversationId = c.req.param("id");
|
|
8825
8904
|
const sessionKey = c.var.sessionKey;
|
|
8826
8905
|
const accountId = getAccountIdForSession(sessionKey);
|
|
@@ -8835,7 +8914,7 @@ app18.get("/:id/messages", requireAdminSession, async (c) => {
|
|
|
8835
8914
|
return c.json({ error: "Failed to fetch messages" }, 500);
|
|
8836
8915
|
}
|
|
8837
8916
|
});
|
|
8838
|
-
|
|
8917
|
+
app17.post("/:id/resume", requireAdminSession, async (c) => {
|
|
8839
8918
|
const conversationId = c.req.param("id");
|
|
8840
8919
|
const sessionKey = c.var.sessionKey;
|
|
8841
8920
|
const accountId = getAccountIdForSession(sessionKey);
|
|
@@ -8863,7 +8942,7 @@ app18.post("/:id/resume", requireAdminSession, async (c) => {
|
|
|
8863
8942
|
console.log(`[session-resume] ${(/* @__PURE__ */ new Date()).toISOString()} conversationId=${conversationId.slice(0, 8)}\u2026 age=${age} loaded=${messages.length} messages (${estimatedTokens} estimated tokens) previousConversationId=${previousConversationId?.slice(0, 8) ?? "none"}\u2026 sessionKey=${sessionKey.slice(0, 8)}\u2026`);
|
|
8864
8943
|
return c.json({ conversationId, messages });
|
|
8865
8944
|
});
|
|
8866
|
-
|
|
8945
|
+
app17.post("/:id/label", requireAdminSession, async (c) => {
|
|
8867
8946
|
const conversationId = c.req.param("id");
|
|
8868
8947
|
const sessionKey = c.var.sessionKey;
|
|
8869
8948
|
const accountId = getAccountIdForSession(sessionKey);
|
|
@@ -8890,7 +8969,7 @@ app18.post("/:id/label", requireAdminSession, async (c) => {
|
|
|
8890
8969
|
return c.json({ label: null });
|
|
8891
8970
|
}
|
|
8892
8971
|
});
|
|
8893
|
-
|
|
8972
|
+
app17.put("/:id/label", requireAdminSession, async (c) => {
|
|
8894
8973
|
const conversationId = c.req.param("id");
|
|
8895
8974
|
const sessionKey = c.var.sessionKey;
|
|
8896
8975
|
let body;
|
|
@@ -8916,11 +8995,11 @@ app18.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
8916
8995
|
return c.json({ error: "Failed to rename session" }, 500);
|
|
8917
8996
|
}
|
|
8918
8997
|
});
|
|
8919
|
-
var sessions_default =
|
|
8998
|
+
var sessions_default = app17;
|
|
8920
8999
|
|
|
8921
9000
|
// server/routes/admin/browser.ts
|
|
8922
|
-
var
|
|
8923
|
-
|
|
9001
|
+
var app18 = new Hono();
|
|
9002
|
+
app18.post("/launch", async (c) => {
|
|
8924
9003
|
try {
|
|
8925
9004
|
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
8926
9005
|
if (transport === "vnc") {
|
|
@@ -8942,7 +9021,7 @@ app19.post("/launch", async (c) => {
|
|
|
8942
9021
|
);
|
|
8943
9022
|
}
|
|
8944
9023
|
});
|
|
8945
|
-
var browser_default =
|
|
9024
|
+
var browser_default = app18;
|
|
8946
9025
|
|
|
8947
9026
|
// app/lib/cdp-client.ts
|
|
8948
9027
|
var CDP_HOST = "127.0.0.1";
|
|
@@ -8985,8 +9064,8 @@ async function cdpNavigateNewTab(url, opts = {}) {
|
|
|
8985
9064
|
}
|
|
8986
9065
|
|
|
8987
9066
|
// server/routes/admin/device-browser.ts
|
|
8988
|
-
var
|
|
8989
|
-
|
|
9067
|
+
var app19 = new Hono();
|
|
9068
|
+
app19.post("/navigate", async (c) => {
|
|
8990
9069
|
const TAG17 = "[device-url:click]";
|
|
8991
9070
|
let body;
|
|
8992
9071
|
try {
|
|
@@ -9073,7 +9152,7 @@ app20.post("/navigate", async (c) => {
|
|
|
9073
9152
|
targetId: outcome.targetId
|
|
9074
9153
|
});
|
|
9075
9154
|
});
|
|
9076
|
-
var device_browser_default =
|
|
9155
|
+
var device_browser_default = app19;
|
|
9077
9156
|
|
|
9078
9157
|
// server/routes/admin/events.ts
|
|
9079
9158
|
var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
@@ -9082,8 +9161,8 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
9082
9161
|
"device-url:vnc-surface-shown",
|
|
9083
9162
|
"device-url:malformed"
|
|
9084
9163
|
]);
|
|
9085
|
-
var
|
|
9086
|
-
|
|
9164
|
+
var app20 = new Hono();
|
|
9165
|
+
app20.post("/", async (c) => {
|
|
9087
9166
|
const TAG17 = "[admin:events]";
|
|
9088
9167
|
let body;
|
|
9089
9168
|
try {
|
|
@@ -9114,12 +9193,12 @@ app21.post("/", async (c) => {
|
|
|
9114
9193
|
console.error(`[${event}] ${formatted}`);
|
|
9115
9194
|
return c.json({ ok: true });
|
|
9116
9195
|
});
|
|
9117
|
-
var events_default =
|
|
9196
|
+
var events_default = app20;
|
|
9118
9197
|
|
|
9119
9198
|
// server/routes/admin/cloudflare.ts
|
|
9120
9199
|
import { homedir } from "os";
|
|
9121
|
-
import { resolve as
|
|
9122
|
-
import { readFileSync as
|
|
9200
|
+
import { resolve as resolve17 } from "path";
|
|
9201
|
+
import { readFileSync as readFileSync15 } from "fs";
|
|
9123
9202
|
|
|
9124
9203
|
// app/lib/dns-label.ts
|
|
9125
9204
|
var VALID_LABEL = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
@@ -9135,14 +9214,14 @@ function isValidDomain(value) {
|
|
|
9135
9214
|
}
|
|
9136
9215
|
|
|
9137
9216
|
// app/lib/alias-domains.ts
|
|
9138
|
-
import { existsSync as existsSync18, mkdirSync as mkdirSync8, readFileSync as
|
|
9217
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync8 } from "fs";
|
|
9139
9218
|
import { dirname as dirname7 } from "path";
|
|
9140
|
-
import { resolve as
|
|
9141
|
-
var ALIAS_DOMAINS_PATH =
|
|
9219
|
+
import { resolve as resolve16 } from "path";
|
|
9220
|
+
var ALIAS_DOMAINS_PATH = resolve16(MAXY_DIR, "alias-domains.json");
|
|
9142
9221
|
function readExisting() {
|
|
9143
9222
|
if (!existsSync18(ALIAS_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
|
|
9144
9223
|
try {
|
|
9145
|
-
const parsed = JSON.parse(
|
|
9224
|
+
const parsed = JSON.parse(readFileSync14(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
9146
9225
|
if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
|
|
9147
9226
|
return new Set(parsed.filter((h) => typeof h === "string"));
|
|
9148
9227
|
} catch {
|
|
@@ -9154,17 +9233,17 @@ function addAliasDomain(hostname2) {
|
|
|
9154
9233
|
if (existing.has(hostname2)) return;
|
|
9155
9234
|
existing.add(hostname2);
|
|
9156
9235
|
mkdirSync8(dirname7(ALIAS_DOMAINS_PATH), { recursive: true });
|
|
9157
|
-
|
|
9236
|
+
writeFileSync8(ALIAS_DOMAINS_PATH, JSON.stringify([...existing], null, 2) + "\n", "utf-8");
|
|
9158
9237
|
}
|
|
9159
9238
|
|
|
9160
9239
|
// server/routes/admin/cloudflare.ts
|
|
9161
9240
|
var SETUP_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
9162
9241
|
var DOMAINS_TIMEOUT_MS = 40 * 1e3;
|
|
9163
9242
|
function loadBrandInfo() {
|
|
9164
|
-
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ??
|
|
9165
|
-
const brandPath =
|
|
9243
|
+
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
|
|
9244
|
+
const brandPath = resolve17(platformRoot2, "config", "brand.json");
|
|
9166
9245
|
try {
|
|
9167
|
-
const parsed = JSON.parse(
|
|
9246
|
+
const parsed = JSON.parse(readFileSync15(brandPath, "utf-8"));
|
|
9168
9247
|
const hostname2 = typeof parsed.hostname === "string" && parsed.hostname ? parsed.hostname : "maxy";
|
|
9169
9248
|
const configDir2 = typeof parsed.configDir === "string" && parsed.configDir ? parsed.configDir : ".maxy";
|
|
9170
9249
|
return { hostname: hostname2, configDir: configDir2 };
|
|
@@ -9207,7 +9286,7 @@ function validateBody(body) {
|
|
|
9207
9286
|
}
|
|
9208
9287
|
return null;
|
|
9209
9288
|
}
|
|
9210
|
-
var
|
|
9289
|
+
var app21 = new Hono();
|
|
9211
9290
|
function fieldFromReason(reason) {
|
|
9212
9291
|
switch (reason) {
|
|
9213
9292
|
case "not-signed-in":
|
|
@@ -9224,7 +9303,7 @@ function fieldFromReason(reason) {
|
|
|
9224
9303
|
return "script";
|
|
9225
9304
|
}
|
|
9226
9305
|
}
|
|
9227
|
-
|
|
9306
|
+
app21.get("/domains", requireAdminSession, async (c) => {
|
|
9228
9307
|
const started = Date.now();
|
|
9229
9308
|
const sessionKey = c.var.sessionKey;
|
|
9230
9309
|
let correlationId;
|
|
@@ -9267,7 +9346,7 @@ app22.get("/domains", requireAdminSession, async (c) => {
|
|
|
9267
9346
|
streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
|
|
9268
9347
|
log(`phase=stream-log-resolved path=${streamLogPath}`);
|
|
9269
9348
|
const brand = loadBrandInfo();
|
|
9270
|
-
const scriptPath =
|
|
9349
|
+
const scriptPath = resolve17(homedir(), "list-cf-domains.sh");
|
|
9271
9350
|
const result = await runFormSpawn({
|
|
9272
9351
|
scriptPath,
|
|
9273
9352
|
args: [brand.hostname],
|
|
@@ -9317,7 +9396,7 @@ ${result.stderr}` : ""}`;
|
|
|
9317
9396
|
);
|
|
9318
9397
|
return c.json(success, 200);
|
|
9319
9398
|
});
|
|
9320
|
-
|
|
9399
|
+
app21.post("/setup", requireAdminSession, async (c) => {
|
|
9321
9400
|
const started = Date.now();
|
|
9322
9401
|
const sessionKey = c.var.sessionKey;
|
|
9323
9402
|
let correlationId;
|
|
@@ -9452,23 +9531,23 @@ actionId: ${actionId}`,
|
|
|
9452
9531
|
};
|
|
9453
9532
|
return ok(success);
|
|
9454
9533
|
});
|
|
9455
|
-
var cloudflare_default =
|
|
9534
|
+
var cloudflare_default = app21;
|
|
9456
9535
|
|
|
9457
9536
|
// server/routes/admin/files.ts
|
|
9458
9537
|
import { createReadStream as createReadStream3 } from "fs";
|
|
9459
9538
|
import { readdir as readdir2, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
|
|
9460
9539
|
import { realpathSync as realpathSync4 } from "fs";
|
|
9461
|
-
import { basename as basename6, dirname as dirname8, join as join9, resolve as
|
|
9540
|
+
import { basename as basename6, dirname as dirname8, join as join9, resolve as resolve19, sep as sep2 } from "path";
|
|
9462
9541
|
import { Readable as Readable2 } from "stream";
|
|
9463
9542
|
|
|
9464
9543
|
// app/lib/data-path.ts
|
|
9465
9544
|
import { realpathSync as realpathSync3 } from "fs";
|
|
9466
|
-
import { resolve as
|
|
9467
|
-
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ??
|
|
9468
|
-
var DATA_ROOT =
|
|
9545
|
+
import { resolve as resolve18, normalize, sep, relative } from "path";
|
|
9546
|
+
var PLATFORM_ROOT5 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "../platform");
|
|
9547
|
+
var DATA_ROOT = resolve18(PLATFORM_ROOT5, "..", "data");
|
|
9469
9548
|
function resolveDataPath(raw) {
|
|
9470
9549
|
const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
|
|
9471
|
-
const absolute =
|
|
9550
|
+
const absolute = resolve18(DATA_ROOT, cleaned);
|
|
9472
9551
|
let dataRootReal;
|
|
9473
9552
|
try {
|
|
9474
9553
|
dataRootReal = realpathSync3(DATA_ROOT);
|
|
@@ -9827,7 +9906,7 @@ async function readMeta(absDir, baseName) {
|
|
|
9827
9906
|
}
|
|
9828
9907
|
async function readAccountNames() {
|
|
9829
9908
|
const map = /* @__PURE__ */ new Map();
|
|
9830
|
-
const accountsDir =
|
|
9909
|
+
const accountsDir = resolve19(DATA_ROOT, "accounts");
|
|
9831
9910
|
let names;
|
|
9832
9911
|
try {
|
|
9833
9912
|
names = await readdir2(accountsDir);
|
|
@@ -9836,7 +9915,7 @@ async function readAccountNames() {
|
|
|
9836
9915
|
}
|
|
9837
9916
|
for (const name of names) {
|
|
9838
9917
|
if (!UUID_RE3.test(name)) continue;
|
|
9839
|
-
const configPath2 =
|
|
9918
|
+
const configPath2 = resolve19(accountsDir, name, "account.json");
|
|
9840
9919
|
try {
|
|
9841
9920
|
const raw = await readFile4(configPath2, "utf8");
|
|
9842
9921
|
const parsed = JSON.parse(raw);
|
|
@@ -9885,8 +9964,8 @@ function buildDisplayPath(relPath, accountNames) {
|
|
|
9885
9964
|
return dn ? { name: seg, displayName: dn } : { name: seg };
|
|
9886
9965
|
});
|
|
9887
9966
|
}
|
|
9888
|
-
var
|
|
9889
|
-
|
|
9967
|
+
var app22 = new Hono();
|
|
9968
|
+
app22.get("/", requireAdminSession, async (c) => {
|
|
9890
9969
|
const sessionKey = c.var.sessionKey;
|
|
9891
9970
|
if (!getAccountIdForSession(sessionKey)) {
|
|
9892
9971
|
console.error(`[data] auth-rejected endpoint="/api/admin/files" reason="no account for session"`);
|
|
@@ -9947,7 +10026,7 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
9947
10026
|
return c.json({ error: message }, 500);
|
|
9948
10027
|
}
|
|
9949
10028
|
});
|
|
9950
|
-
|
|
10029
|
+
app22.get("/download", requireAdminSession, async (c) => {
|
|
9951
10030
|
const sessionKey = c.var.sessionKey;
|
|
9952
10031
|
if (!getAccountIdForSession(sessionKey)) {
|
|
9953
10032
|
console.error(`[data] auth-rejected endpoint="/api/admin/files/download" reason="no account for session"`);
|
|
@@ -9995,7 +10074,7 @@ app23.get("/download", requireAdminSession, async (c) => {
|
|
|
9995
10074
|
return c.json({ error: message }, 500);
|
|
9996
10075
|
}
|
|
9997
10076
|
});
|
|
9998
|
-
|
|
10077
|
+
app22.post("/upload", requireAdminSession, async (c) => {
|
|
9999
10078
|
const sessionKey = c.var.sessionKey;
|
|
10000
10079
|
const accountId = getAccountIdForSession(sessionKey);
|
|
10001
10080
|
if (!accountId) {
|
|
@@ -10027,8 +10106,8 @@ app23.post("/upload", requireAdminSession, async (c) => {
|
|
|
10027
10106
|
}
|
|
10028
10107
|
const safeName = basename6(file.name).replace(/[\0/\\]/g, "_");
|
|
10029
10108
|
const finalName = `${Date.now()}-${safeName}`;
|
|
10030
|
-
const destDir =
|
|
10031
|
-
const destPath =
|
|
10109
|
+
const destDir = resolve19(DATA_ROOT, "uploads", accountId);
|
|
10110
|
+
const destPath = resolve19(destDir, finalName);
|
|
10032
10111
|
try {
|
|
10033
10112
|
await mkdir3(destDir, { recursive: true });
|
|
10034
10113
|
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
@@ -10053,7 +10132,7 @@ app23.post("/upload", requireAdminSession, async (c) => {
|
|
|
10053
10132
|
mimeType: file.type
|
|
10054
10133
|
});
|
|
10055
10134
|
});
|
|
10056
|
-
|
|
10135
|
+
app22.delete("/", requireAdminSession, async (c) => {
|
|
10057
10136
|
const sessionKey = c.var.sessionKey;
|
|
10058
10137
|
const accountId = getAccountIdForSession(sessionKey);
|
|
10059
10138
|
if (!accountId) {
|
|
@@ -10120,7 +10199,7 @@ app23.delete("/", requireAdminSession, async (c) => {
|
|
|
10120
10199
|
return c.json({ error: message }, 500);
|
|
10121
10200
|
}
|
|
10122
10201
|
});
|
|
10123
|
-
var files_default =
|
|
10202
|
+
var files_default = app22;
|
|
10124
10203
|
|
|
10125
10204
|
// ../lib/graph-search/src/index.ts
|
|
10126
10205
|
var import_dist = __toESM(require_dist());
|
|
@@ -10437,8 +10516,8 @@ function plainProperties(properties) {
|
|
|
10437
10516
|
// server/routes/admin/graph-search.ts
|
|
10438
10517
|
var DEFAULT_LIMIT = 20;
|
|
10439
10518
|
var MAX_LIMIT = 2e3;
|
|
10440
|
-
var
|
|
10441
|
-
|
|
10519
|
+
var app23 = new Hono();
|
|
10520
|
+
app23.get("/", requireAdminSession, async (c) => {
|
|
10442
10521
|
const sessionKey = c.var.sessionKey;
|
|
10443
10522
|
const q = (c.req.query("q") ?? "").trim();
|
|
10444
10523
|
const rawLimit = c.req.query("limit");
|
|
@@ -10488,7 +10567,7 @@ app24.get("/", requireAdminSession, async (c) => {
|
|
|
10488
10567
|
await session.close();
|
|
10489
10568
|
}
|
|
10490
10569
|
});
|
|
10491
|
-
var graph_search_default =
|
|
10570
|
+
var graph_search_default = app23;
|
|
10492
10571
|
|
|
10493
10572
|
// server/routes/admin/graph-subgraph.ts
|
|
10494
10573
|
import neo4j2 from "neo4j-driver";
|
|
@@ -10643,8 +10722,8 @@ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
|
|
|
10643
10722
|
"otpCode",
|
|
10644
10723
|
"sessionKey"
|
|
10645
10724
|
]);
|
|
10646
|
-
var
|
|
10647
|
-
|
|
10725
|
+
var app24 = new Hono();
|
|
10726
|
+
app24.get("/", requireAdminSession, async (c) => {
|
|
10648
10727
|
const sessionKey = c.var.sessionKey;
|
|
10649
10728
|
const accountId = getAccountIdForSession(sessionKey);
|
|
10650
10729
|
if (!accountId) {
|
|
@@ -11071,12 +11150,12 @@ function pruneNode(node, warnedClasses, conversationWarnings) {
|
|
|
11071
11150
|
}
|
|
11072
11151
|
return trashed ? { id: node.id, labels, properties, trashed: true } : { id: node.id, labels, properties };
|
|
11073
11152
|
}
|
|
11074
|
-
var graph_subgraph_default =
|
|
11153
|
+
var graph_subgraph_default = app24;
|
|
11075
11154
|
|
|
11076
11155
|
// server/routes/admin/graph-delete.ts
|
|
11077
11156
|
var ALLOWED_BY = ["graph-page", "graph-drag-trash"];
|
|
11078
|
-
var
|
|
11079
|
-
|
|
11157
|
+
var app25 = new Hono();
|
|
11158
|
+
app25.post("/", requireAdminSession, async (c) => {
|
|
11080
11159
|
const sessionKey = c.var.sessionKey;
|
|
11081
11160
|
const accountId = getAccountIdForSession(sessionKey);
|
|
11082
11161
|
if (!accountId) {
|
|
@@ -11147,11 +11226,11 @@ app26.post("/", requireAdminSession, async (c) => {
|
|
|
11147
11226
|
}
|
|
11148
11227
|
}
|
|
11149
11228
|
});
|
|
11150
|
-
var graph_delete_default =
|
|
11229
|
+
var graph_delete_default = app25;
|
|
11151
11230
|
|
|
11152
11231
|
// server/routes/admin/graph-restore.ts
|
|
11153
|
-
var
|
|
11154
|
-
|
|
11232
|
+
var app26 = new Hono();
|
|
11233
|
+
app26.post("/", requireAdminSession, async (c) => {
|
|
11155
11234
|
const sessionKey = c.var.sessionKey;
|
|
11156
11235
|
const accountId = getAccountIdForSession(sessionKey);
|
|
11157
11236
|
if (!accountId) {
|
|
@@ -11215,11 +11294,11 @@ app27.post("/", requireAdminSession, async (c) => {
|
|
|
11215
11294
|
}
|
|
11216
11295
|
}
|
|
11217
11296
|
});
|
|
11218
|
-
var graph_restore_default =
|
|
11297
|
+
var graph_restore_default = app26;
|
|
11219
11298
|
|
|
11220
11299
|
// server/routes/admin/graph-labels-in-graph.ts
|
|
11221
|
-
var
|
|
11222
|
-
|
|
11300
|
+
var app27 = new Hono();
|
|
11301
|
+
app27.get("/", requireAdminSession, async (c) => {
|
|
11223
11302
|
const sessionKey = c.var.sessionKey;
|
|
11224
11303
|
const accountId = getAccountIdForSession(sessionKey);
|
|
11225
11304
|
if (!accountId) {
|
|
@@ -11285,11 +11364,11 @@ var LABELS_IN_GRAPH_CYPHER = `
|
|
|
11285
11364
|
sum(halfEdges) AS relDegree
|
|
11286
11365
|
RETURN label, nodeCount, relDegree
|
|
11287
11366
|
`;
|
|
11288
|
-
var graph_labels_in_graph_default =
|
|
11367
|
+
var graph_labels_in_graph_default = app27;
|
|
11289
11368
|
|
|
11290
11369
|
// server/routes/admin/graph-default-view.ts
|
|
11291
|
-
var
|
|
11292
|
-
|
|
11370
|
+
var app28 = new Hono();
|
|
11371
|
+
app28.get("/", requireAdminSession, async (c) => {
|
|
11293
11372
|
const sessionKey = c.var.sessionKey;
|
|
11294
11373
|
const accountId = getAccountIdForSession(sessionKey);
|
|
11295
11374
|
const userId = getUserIdForSession(sessionKey);
|
|
@@ -11327,7 +11406,7 @@ app29.get("/", requireAdminSession, async (c) => {
|
|
|
11327
11406
|
}
|
|
11328
11407
|
}
|
|
11329
11408
|
});
|
|
11330
|
-
|
|
11409
|
+
app28.put("/", requireAdminSession, async (c) => {
|
|
11331
11410
|
const sessionKey = c.var.sessionKey;
|
|
11332
11411
|
const accountId = getAccountIdForSession(sessionKey);
|
|
11333
11412
|
const userId = getUserIdForSession(sessionKey);
|
|
@@ -11416,11 +11495,11 @@ var WRITE_CYPHER = `
|
|
|
11416
11495
|
p.updatedAt = $updatedAt
|
|
11417
11496
|
RETURN p.labels AS labels
|
|
11418
11497
|
`;
|
|
11419
|
-
var graph_default_view_default =
|
|
11498
|
+
var graph_default_view_default = app28;
|
|
11420
11499
|
|
|
11421
11500
|
// server/routes/admin/file-attach.ts
|
|
11422
|
-
var
|
|
11423
|
-
|
|
11501
|
+
var app29 = new Hono();
|
|
11502
|
+
app29.post("/", async (c) => {
|
|
11424
11503
|
try {
|
|
11425
11504
|
const body = await c.req.json();
|
|
11426
11505
|
const { filePath, accountId } = body;
|
|
@@ -11443,11 +11522,11 @@ app30.post("/", async (c) => {
|
|
|
11443
11522
|
return c.json({ error: message }, 500);
|
|
11444
11523
|
}
|
|
11445
11524
|
});
|
|
11446
|
-
var file_attach_default =
|
|
11525
|
+
var file_attach_default = app29;
|
|
11447
11526
|
|
|
11448
11527
|
// server/routes/admin/adherence.ts
|
|
11449
|
-
var
|
|
11450
|
-
|
|
11528
|
+
var app30 = new Hono();
|
|
11529
|
+
app30.get("/", requireAdminSession, async (c) => {
|
|
11451
11530
|
const agent = c.req.query("agent") ?? "admin";
|
|
11452
11531
|
const includeBlock = c.req.query("block") === "1";
|
|
11453
11532
|
const account = resolveAccount();
|
|
@@ -11468,33 +11547,32 @@ app31.get("/", requireAdminSession, async (c) => {
|
|
|
11468
11547
|
return c.json({ error: "Failed to read adherence ledger", agent }, 500);
|
|
11469
11548
|
}
|
|
11470
11549
|
});
|
|
11471
|
-
var adherence_default =
|
|
11550
|
+
var adherence_default = app30;
|
|
11472
11551
|
|
|
11473
11552
|
// server/routes/admin/index.ts
|
|
11474
|
-
var
|
|
11475
|
-
|
|
11476
|
-
|
|
11477
|
-
|
|
11478
|
-
|
|
11479
|
-
|
|
11480
|
-
|
|
11481
|
-
|
|
11482
|
-
|
|
11483
|
-
|
|
11484
|
-
|
|
11485
|
-
|
|
11486
|
-
|
|
11487
|
-
|
|
11488
|
-
|
|
11489
|
-
|
|
11490
|
-
|
|
11491
|
-
|
|
11492
|
-
|
|
11493
|
-
|
|
11494
|
-
|
|
11495
|
-
|
|
11496
|
-
|
|
11497
|
-
var admin_default = app32;
|
|
11553
|
+
var app31 = new Hono();
|
|
11554
|
+
app31.route("/session", session_default2);
|
|
11555
|
+
app31.route("/chat", chat_default2);
|
|
11556
|
+
app31.route("/compact", compact_default);
|
|
11557
|
+
app31.route("/logs", logs_default);
|
|
11558
|
+
app31.route("/claude-info", claude_info_default);
|
|
11559
|
+
app31.route("/attachment", attachment_default);
|
|
11560
|
+
app31.route("/agents", agents_default);
|
|
11561
|
+
app31.route("/sessions", sessions_default);
|
|
11562
|
+
app31.route("/browser", browser_default);
|
|
11563
|
+
app31.route("/device-browser", device_browser_default);
|
|
11564
|
+
app31.route("/events", events_default);
|
|
11565
|
+
app31.route("/cloudflare", cloudflare_default);
|
|
11566
|
+
app31.route("/files", files_default);
|
|
11567
|
+
app31.route("/graph-search", graph_search_default);
|
|
11568
|
+
app31.route("/graph-subgraph", graph_subgraph_default);
|
|
11569
|
+
app31.route("/graph-delete", graph_delete_default);
|
|
11570
|
+
app31.route("/graph-restore", graph_restore_default);
|
|
11571
|
+
app31.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
11572
|
+
app31.route("/graph-default-view", graph_default_view_default);
|
|
11573
|
+
app31.route("/file-attach", file_attach_default);
|
|
11574
|
+
app31.route("/adherence", adherence_default);
|
|
11575
|
+
var admin_default = app31;
|
|
11498
11576
|
|
|
11499
11577
|
// app/lib/graph-health.ts
|
|
11500
11578
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -11561,7 +11639,7 @@ if (BRAND_JSON_PATH && !existsSync19(BRAND_JSON_PATH)) {
|
|
|
11561
11639
|
}
|
|
11562
11640
|
if (BRAND_JSON_PATH && existsSync19(BRAND_JSON_PATH)) {
|
|
11563
11641
|
try {
|
|
11564
|
-
const parsed = JSON.parse(
|
|
11642
|
+
const parsed = JSON.parse(readFileSync16(BRAND_JSON_PATH, "utf-8"));
|
|
11565
11643
|
BRAND = { ...BRAND, ...parsed };
|
|
11566
11644
|
} catch (err) {
|
|
11567
11645
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -11584,7 +11662,7 @@ var ALIAS_DOMAINS_PATH2 = join10(homedir2(), BRAND.configDir, "alias-domains.jso
|
|
|
11584
11662
|
function loadAliasDomains() {
|
|
11585
11663
|
try {
|
|
11586
11664
|
if (!existsSync19(ALIAS_DOMAINS_PATH2)) return null;
|
|
11587
|
-
const parsed = JSON.parse(
|
|
11665
|
+
const parsed = JSON.parse(readFileSync16(ALIAS_DOMAINS_PATH2, "utf-8"));
|
|
11588
11666
|
if (!Array.isArray(parsed)) {
|
|
11589
11667
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
11590
11668
|
return null;
|
|
@@ -11608,9 +11686,9 @@ watchFile(ALIAS_DOMAINS_PATH2, { interval: 2e3 }, () => {
|
|
|
11608
11686
|
function isPublicHost(host) {
|
|
11609
11687
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
11610
11688
|
}
|
|
11611
|
-
var
|
|
11612
|
-
|
|
11613
|
-
|
|
11689
|
+
var app32 = new Hono();
|
|
11690
|
+
app32.use("*", clientIpMiddleware);
|
|
11691
|
+
app32.use("*", async (c, next) => {
|
|
11614
11692
|
await next();
|
|
11615
11693
|
c.header("X-Content-Type-Options", "nosniff");
|
|
11616
11694
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -11633,7 +11711,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
11633
11711
|
"/g/"
|
|
11634
11712
|
];
|
|
11635
11713
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
11636
|
-
|
|
11714
|
+
app32.use("*", async (c, next) => {
|
|
11637
11715
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
11638
11716
|
if (!isPublicHost(host)) {
|
|
11639
11717
|
await next();
|
|
@@ -11673,7 +11751,7 @@ function resolveRemoteAuthOpts() {
|
|
|
11673
11751
|
return brandLoginOpts;
|
|
11674
11752
|
}
|
|
11675
11753
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
11676
|
-
|
|
11754
|
+
app32.post("/__remote-auth/login", async (c) => {
|
|
11677
11755
|
const client = clientFrom(c);
|
|
11678
11756
|
const clientIp = client.ip || "unknown";
|
|
11679
11757
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -11717,7 +11795,7 @@ app33.post("/__remote-auth/login", async (c) => {
|
|
|
11717
11795
|
}
|
|
11718
11796
|
});
|
|
11719
11797
|
});
|
|
11720
|
-
|
|
11798
|
+
app32.get("/__remote-auth/logout", (c) => {
|
|
11721
11799
|
return new Response(null, {
|
|
11722
11800
|
status: 302,
|
|
11723
11801
|
headers: {
|
|
@@ -11727,7 +11805,7 @@ app33.get("/__remote-auth/logout", (c) => {
|
|
|
11727
11805
|
}
|
|
11728
11806
|
});
|
|
11729
11807
|
});
|
|
11730
|
-
|
|
11808
|
+
app32.post("/__remote-auth/change-password", async (c) => {
|
|
11731
11809
|
const client = clientFrom(c);
|
|
11732
11810
|
const clientIp = client.ip || "unknown";
|
|
11733
11811
|
const rateLimited = checkRateLimit(client);
|
|
@@ -11777,13 +11855,13 @@ app33.post("/__remote-auth/change-password", async (c) => {
|
|
|
11777
11855
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
11778
11856
|
}
|
|
11779
11857
|
});
|
|
11780
|
-
|
|
11858
|
+
app32.get("/__remote-auth/setup", (c) => {
|
|
11781
11859
|
if (isRemoteAuthConfigured()) {
|
|
11782
11860
|
return c.redirect("/");
|
|
11783
11861
|
}
|
|
11784
11862
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
11785
11863
|
});
|
|
11786
|
-
|
|
11864
|
+
app32.post("/__remote-auth/set-initial-password", async (c) => {
|
|
11787
11865
|
if (isRemoteAuthConfigured()) {
|
|
11788
11866
|
return c.redirect("/");
|
|
11789
11867
|
}
|
|
@@ -11819,10 +11897,10 @@ app33.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
11819
11897
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
11820
11898
|
}
|
|
11821
11899
|
});
|
|
11822
|
-
|
|
11900
|
+
app32.get("/api/remote-auth/status", (c) => {
|
|
11823
11901
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
11824
11902
|
});
|
|
11825
|
-
|
|
11903
|
+
app32.post("/api/remote-auth/set-password", async (c) => {
|
|
11826
11904
|
let body;
|
|
11827
11905
|
try {
|
|
11828
11906
|
body = await c.req.json();
|
|
@@ -11852,9 +11930,9 @@ app33.post("/api/remote-auth/set-password", async (c) => {
|
|
|
11852
11930
|
return c.json({ error: "Failed to save password" }, 500);
|
|
11853
11931
|
}
|
|
11854
11932
|
});
|
|
11855
|
-
|
|
11933
|
+
app32.route("/api/_client-error", client_error_default);
|
|
11856
11934
|
console.log("[client-error-route] mounted");
|
|
11857
|
-
|
|
11935
|
+
app32.use("*", async (c, next) => {
|
|
11858
11936
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
11859
11937
|
const path2 = c.req.path;
|
|
11860
11938
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -11887,15 +11965,15 @@ app33.use("*", async (c, next) => {
|
|
|
11887
11965
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
11888
11966
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
11889
11967
|
});
|
|
11890
|
-
|
|
11891
|
-
|
|
11892
|
-
|
|
11893
|
-
|
|
11894
|
-
|
|
11895
|
-
|
|
11896
|
-
|
|
11897
|
-
|
|
11898
|
-
|
|
11968
|
+
app32.route("/api/health", health_default);
|
|
11969
|
+
app32.route("/api/session", session_default);
|
|
11970
|
+
app32.route("/api/chat", chat_default);
|
|
11971
|
+
app32.route("/api/group", group_default);
|
|
11972
|
+
app32.route("/api/access", access_default);
|
|
11973
|
+
app32.route("/api/telegram", telegram_default);
|
|
11974
|
+
app32.route("/api/whatsapp", whatsapp_default);
|
|
11975
|
+
app32.route("/api/onboarding", onboarding_default);
|
|
11976
|
+
app32.route("/api/admin", admin_default);
|
|
11899
11977
|
var SAFE_SLUG_RE = /^[a-z][a-z0-9-]{2,49}$/;
|
|
11900
11978
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
11901
11979
|
var IMAGE_MIME = {
|
|
@@ -11907,7 +11985,7 @@ var IMAGE_MIME = {
|
|
|
11907
11985
|
".svg": "image/svg+xml",
|
|
11908
11986
|
".ico": "image/x-icon"
|
|
11909
11987
|
};
|
|
11910
|
-
|
|
11988
|
+
app32.get("/agent-assets/:slug/:filename", (c) => {
|
|
11911
11989
|
const slug = c.req.param("slug");
|
|
11912
11990
|
const filename = c.req.param("filename");
|
|
11913
11991
|
if (!SAFE_SLUG_RE.test(slug)) {
|
|
@@ -11923,8 +12001,8 @@ app33.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
11923
12001
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
11924
12002
|
return c.text("Not found", 404);
|
|
11925
12003
|
}
|
|
11926
|
-
const filePath =
|
|
11927
|
-
const expectedDir =
|
|
12004
|
+
const filePath = resolve20(account.accountDir, "agents", slug, "assets", filename);
|
|
12005
|
+
const expectedDir = resolve20(account.accountDir, "agents", slug, "assets");
|
|
11928
12006
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
11929
12007
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
11930
12008
|
return c.text("Forbidden", 403);
|
|
@@ -11936,13 +12014,13 @@ app33.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
11936
12014
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
11937
12015
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
11938
12016
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
11939
|
-
const body =
|
|
12017
|
+
const body = readFileSync16(filePath);
|
|
11940
12018
|
return c.body(body, 200, {
|
|
11941
12019
|
"Content-Type": contentType,
|
|
11942
12020
|
"Cache-Control": "public, max-age=3600"
|
|
11943
12021
|
});
|
|
11944
12022
|
});
|
|
11945
|
-
|
|
12023
|
+
app32.get("/generated/:filename", (c) => {
|
|
11946
12024
|
const filename = c.req.param("filename");
|
|
11947
12025
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
11948
12026
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -11953,8 +12031,8 @@ app33.get("/generated/:filename", (c) => {
|
|
|
11953
12031
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
11954
12032
|
return c.text("Not found", 404);
|
|
11955
12033
|
}
|
|
11956
|
-
const filePath =
|
|
11957
|
-
const expectedDir =
|
|
12034
|
+
const filePath = resolve20(account.accountDir, "generated", filename);
|
|
12035
|
+
const expectedDir = resolve20(account.accountDir, "generated");
|
|
11958
12036
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
11959
12037
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
11960
12038
|
return c.text("Forbidden", 403);
|
|
@@ -11966,7 +12044,7 @@ app33.get("/generated/:filename", (c) => {
|
|
|
11966
12044
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
11967
12045
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
11968
12046
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
11969
|
-
const body =
|
|
12047
|
+
const body = readFileSync16(filePath);
|
|
11970
12048
|
return c.body(body, 200, {
|
|
11971
12049
|
"Content-Type": contentType,
|
|
11972
12050
|
"Cache-Control": "public, max-age=86400"
|
|
@@ -11977,7 +12055,7 @@ var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
|
11977
12055
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
11978
12056
|
if (BRAND_JSON_PATH && existsSync19(BRAND_JSON_PATH)) {
|
|
11979
12057
|
try {
|
|
11980
|
-
const fullBrand = JSON.parse(
|
|
12058
|
+
const fullBrand = JSON.parse(readFileSync16(BRAND_JSON_PATH, "utf-8"));
|
|
11981
12059
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
11982
12060
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
11983
12061
|
} catch {
|
|
@@ -11996,7 +12074,7 @@ function readInstalledVersion() {
|
|
|
11996
12074
|
if (!PLATFORM_ROOT6) return "unknown";
|
|
11997
12075
|
const versionFile = join10(PLATFORM_ROOT6, "config", `.${BRAND.hostname}-version`);
|
|
11998
12076
|
if (!existsSync19(versionFile)) return "unknown";
|
|
11999
|
-
const content =
|
|
12077
|
+
const content = readFileSync16(versionFile, "utf-8").trim();
|
|
12000
12078
|
return content || "unknown";
|
|
12001
12079
|
} catch {
|
|
12002
12080
|
return "unknown";
|
|
@@ -12037,7 +12115,7 @@ var clientErrorReporterScript = `<script>
|
|
|
12037
12115
|
function cachedHtml(file) {
|
|
12038
12116
|
let html = htmlCache.get(file);
|
|
12039
12117
|
if (!html) {
|
|
12040
|
-
html =
|
|
12118
|
+
html = readFileSync16(resolve20(process.cwd(), "public", file), "utf-8");
|
|
12041
12119
|
html = html.replace("<title>Maxy</title>", `<title>${escapeHtml(BRAND.productName)}</title>`);
|
|
12042
12120
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
12043
12121
|
const headInjection = file === "index.html" ? `${brandScript}
|
|
@@ -12056,12 +12134,12 @@ function loadBrandingCache(agentSlug) {
|
|
|
12056
12134
|
try {
|
|
12057
12135
|
const accountJsonPath = join10(configDir2, "account.json");
|
|
12058
12136
|
if (!existsSync19(accountJsonPath)) return null;
|
|
12059
|
-
const account = JSON.parse(
|
|
12137
|
+
const account = JSON.parse(readFileSync16(accountJsonPath, "utf-8"));
|
|
12060
12138
|
const accountId = account.accountId;
|
|
12061
12139
|
if (!accountId) return null;
|
|
12062
12140
|
const cachePath = join10(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
12063
12141
|
if (!existsSync19(cachePath)) return null;
|
|
12064
|
-
return JSON.parse(
|
|
12142
|
+
return JSON.parse(readFileSync16(cachePath, "utf-8"));
|
|
12065
12143
|
} catch {
|
|
12066
12144
|
return null;
|
|
12067
12145
|
}
|
|
@@ -12071,7 +12149,7 @@ function resolveDefaultSlug() {
|
|
|
12071
12149
|
const configDir2 = join10(homedir2(), BRAND.configDir);
|
|
12072
12150
|
const accountJsonPath = join10(configDir2, "account.json");
|
|
12073
12151
|
if (!existsSync19(accountJsonPath)) return null;
|
|
12074
|
-
const account = JSON.parse(
|
|
12152
|
+
const account = JSON.parse(readFileSync16(accountJsonPath, "utf-8"));
|
|
12075
12153
|
return account.defaultAgent || null;
|
|
12076
12154
|
} catch {
|
|
12077
12155
|
return null;
|
|
@@ -12107,7 +12185,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
12107
12185
|
function escapeHtml(s) {
|
|
12108
12186
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
12109
12187
|
}
|
|
12110
|
-
|
|
12188
|
+
app32.get("/", (c) => {
|
|
12111
12189
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12112
12190
|
if (isPublicHost(host)) {
|
|
12113
12191
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -12115,12 +12193,12 @@ app33.get("/", (c) => {
|
|
|
12115
12193
|
}
|
|
12116
12194
|
return c.html(cachedHtml("index.html"));
|
|
12117
12195
|
});
|
|
12118
|
-
|
|
12196
|
+
app32.get("/public", (c) => {
|
|
12119
12197
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12120
12198
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
12121
12199
|
return c.html(cachedHtml("public.html"));
|
|
12122
12200
|
});
|
|
12123
|
-
|
|
12201
|
+
app32.get("/chat", (c) => {
|
|
12124
12202
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12125
12203
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
12126
12204
|
return c.html(cachedHtml("public.html"));
|
|
@@ -12139,12 +12217,12 @@ async function logViewerFetch(c, next) {
|
|
|
12139
12217
|
duration_ms: Date.now() - start
|
|
12140
12218
|
});
|
|
12141
12219
|
}
|
|
12142
|
-
|
|
12143
|
-
|
|
12144
|
-
|
|
12220
|
+
app32.use("/vnc-viewer.html", logViewerFetch);
|
|
12221
|
+
app32.use("/vnc-popout.html", logViewerFetch);
|
|
12222
|
+
app32.get("/vnc-popout.html", (c) => {
|
|
12145
12223
|
let html = htmlCache.get("vnc-popout.html");
|
|
12146
12224
|
if (!html) {
|
|
12147
|
-
html =
|
|
12225
|
+
html = readFileSync16(resolve20(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
12148
12226
|
const name = escapeHtml(BRAND.productName);
|
|
12149
12227
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
12150
12228
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -12154,7 +12232,7 @@ app33.get("/vnc-popout.html", (c) => {
|
|
|
12154
12232
|
}
|
|
12155
12233
|
return c.html(html);
|
|
12156
12234
|
});
|
|
12157
|
-
|
|
12235
|
+
app32.post("/api/vnc/client-event", async (c) => {
|
|
12158
12236
|
let body;
|
|
12159
12237
|
try {
|
|
12160
12238
|
body = await c.req.json();
|
|
@@ -12175,20 +12253,20 @@ app33.post("/api/vnc/client-event", async (c) => {
|
|
|
12175
12253
|
});
|
|
12176
12254
|
return c.json({ ok: true });
|
|
12177
12255
|
});
|
|
12178
|
-
|
|
12256
|
+
app32.get("/g/:slug", (c) => {
|
|
12179
12257
|
return c.html(brandedPublicHtml());
|
|
12180
12258
|
});
|
|
12181
|
-
|
|
12259
|
+
app32.get("/graph", (c) => {
|
|
12182
12260
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12183
12261
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
12184
12262
|
return c.html(cachedHtml("graph.html"));
|
|
12185
12263
|
});
|
|
12186
|
-
|
|
12264
|
+
app32.get("/data", (c) => {
|
|
12187
12265
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
12188
12266
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
12189
12267
|
return c.html(cachedHtml("data.html"));
|
|
12190
12268
|
});
|
|
12191
|
-
|
|
12269
|
+
app32.get("/:slug", async (c, next) => {
|
|
12192
12270
|
const slug = c.req.param("slug");
|
|
12193
12271
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
12194
12272
|
const branding = loadBrandingCache(slug);
|
|
@@ -12197,10 +12275,10 @@ app33.get("/:slug", async (c, next) => {
|
|
|
12197
12275
|
}
|
|
12198
12276
|
await next();
|
|
12199
12277
|
});
|
|
12200
|
-
|
|
12278
|
+
app32.use("/*", serveStatic({ root: "./public" }));
|
|
12201
12279
|
var port = parseInt(process.env.MAXY_UI_INTERNAL_PORT ?? process.env.PORT ?? "19199", 10);
|
|
12202
12280
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
12203
|
-
var httpServer = serve({ fetch:
|
|
12281
|
+
var httpServer = serve({ fetch: app32.fetch, port, hostname });
|
|
12204
12282
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
12205
12283
|
var SUBAPP_MANIFEST = [
|
|
12206
12284
|
{ prefix: "/api/health", file: "server/routes/health.ts", subapp: health_default },
|
|
@@ -12220,7 +12298,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
12220
12298
|
}
|
|
12221
12299
|
try {
|
|
12222
12300
|
const registered = [];
|
|
12223
|
-
for (const r of
|
|
12301
|
+
for (const r of app32.routes ?? []) {
|
|
12224
12302
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
12225
12303
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
12226
12304
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -12235,7 +12313,7 @@ try {
|
|
|
12235
12313
|
try {
|
|
12236
12314
|
let userId = "";
|
|
12237
12315
|
if (existsSync19(USERS_FILE)) {
|
|
12238
|
-
const users = JSON.parse(
|
|
12316
|
+
const users = JSON.parse(readFileSync16(USERS_FILE, "utf-8").trim() || "[]");
|
|
12239
12317
|
userId = users[0]?.userId ?? "";
|
|
12240
12318
|
}
|
|
12241
12319
|
await backfillNullUserIdConversations(userId);
|
|
@@ -12262,7 +12340,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
12262
12340
|
}
|
|
12263
12341
|
init({
|
|
12264
12342
|
configDir: configDirForWhatsApp,
|
|
12265
|
-
platformRoot:
|
|
12343
|
+
platformRoot: resolve20(process.env.MAXY_PLATFORM_ROOT ?? join10(__dirname, "..")),
|
|
12266
12344
|
accountConfig: bootAccountConfig,
|
|
12267
12345
|
onMessage: async (msg) => {
|
|
12268
12346
|
try {
|