@rubytech/create-maxy 1.0.884 → 1.0.886
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/neo4j/schema.cypher +7 -0
- package/payload/platform/plugins/admin/PLUGIN.md +1 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +21 -50
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
- package/payload/platform/scripts/__tests__/logs-read-prefix.sh +85 -240
- package/payload/platform/scripts/check-no-conversation-id-leaks.mjs +165 -0
- package/payload/platform/scripts/conversation-id-allowlist.txt +151 -0
- package/payload/platform/scripts/log-adherence-check.sh +100 -0
- package/payload/platform/scripts/logs-read.sh +71 -141
- package/payload/platform/scripts/logs-read.test.sh +47 -104
- package/payload/platform/scripts/seed-neo4j.sh +46 -0
- package/payload/premium-plugins/real-agency/BUNDLE.md +1 -1
- package/payload/server/chunk-IFMZ5I3E.js +1460 -0
- package/payload/server/chunk-MOAY7KG2.js +11667 -0
- package/payload/server/chunk-NPKQWE3S.js +1431 -0
- package/payload/server/chunk-ZVO5ASQA.js +11660 -0
- package/payload/server/client-pool-M6NS5G2U.js +34 -0
- package/payload/server/client-pool-QUMX7OUT.js +34 -0
- package/payload/server/maxy-edge.js +2 -2
- package/payload/server/server.js +181 -137
package/payload/server/server.js
CHANGED
|
@@ -42,7 +42,8 @@ import {
|
|
|
42
42
|
load,
|
|
43
43
|
logPath,
|
|
44
44
|
pickComponentBytes,
|
|
45
|
-
|
|
45
|
+
readBundleSubPlugins,
|
|
46
|
+
reconcileEnabledPlugins,
|
|
46
47
|
recordFailedAttempt,
|
|
47
48
|
render,
|
|
48
49
|
renderLoginPage,
|
|
@@ -51,7 +52,6 @@ import {
|
|
|
51
52
|
resolveAgentConfig,
|
|
52
53
|
resolveBrowserTransport,
|
|
53
54
|
resolveClientIp,
|
|
54
|
-
resolveConversationLogPaths,
|
|
55
55
|
resolveDefaultAgentSlug,
|
|
56
56
|
resolveEntitlement,
|
|
57
57
|
resolveUserAccounts,
|
|
@@ -76,7 +76,7 @@ import {
|
|
|
76
76
|
vncLog,
|
|
77
77
|
waitForExit,
|
|
78
78
|
writeChromiumWrapper
|
|
79
|
-
} from "./chunk-
|
|
79
|
+
} from "./chunk-MOAY7KG2.js";
|
|
80
80
|
import {
|
|
81
81
|
CDP_PORT,
|
|
82
82
|
COMMERCIAL_MODE,
|
|
@@ -90,6 +90,8 @@ import {
|
|
|
90
90
|
clearSessionHistory,
|
|
91
91
|
completeGrantSetup,
|
|
92
92
|
consumeWantsPriorConversation,
|
|
93
|
+
emitMissingOnResolve,
|
|
94
|
+
fingerprintSessionKey,
|
|
93
95
|
getAccountIdForSession,
|
|
94
96
|
getActiveClient,
|
|
95
97
|
getAgentNameForSession,
|
|
@@ -97,6 +99,7 @@ import {
|
|
|
97
99
|
getGrantForSession,
|
|
98
100
|
getGroupSlugForSession,
|
|
99
101
|
getRoleForSession,
|
|
102
|
+
getSessionKeyByConversationId,
|
|
100
103
|
getSessionMessages,
|
|
101
104
|
getUserIdForSession,
|
|
102
105
|
getUserNameForSession,
|
|
@@ -104,7 +107,6 @@ import {
|
|
|
104
107
|
interruptClient,
|
|
105
108
|
listAdminSessionsInProgress,
|
|
106
109
|
mintAdminSessionToken,
|
|
107
|
-
preConversationLogStream,
|
|
108
110
|
registerGrantSession,
|
|
109
111
|
registerResumedSession,
|
|
110
112
|
registerSession,
|
|
@@ -115,7 +117,7 @@ import {
|
|
|
115
117
|
sigtermFlushStreamLogs,
|
|
116
118
|
unregisterSession,
|
|
117
119
|
validateSession
|
|
118
|
-
} from "./chunk-
|
|
120
|
+
} from "./chunk-IFMZ5I3E.js";
|
|
119
121
|
import {
|
|
120
122
|
CLOUDFLARE_TASK_DIAGNOSTICS,
|
|
121
123
|
appendCloudflareSteps,
|
|
@@ -662,8 +664,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
662
664
|
};
|
|
663
665
|
|
|
664
666
|
// server/index.ts
|
|
665
|
-
import { readFileSync as readFileSync18, existsSync as
|
|
666
|
-
import { resolve as resolve21, join as
|
|
667
|
+
import { readFileSync as readFileSync18, existsSync as existsSync24, watchFile } from "fs";
|
|
668
|
+
import { resolve as resolve21, join as join12, basename as basename4 } from "path";
|
|
667
669
|
import { homedir as homedir3 } from "os";
|
|
668
670
|
|
|
669
671
|
// app/lib/agent-slug-pattern.ts
|
|
@@ -4425,9 +4427,8 @@ app3.post("/", async (c) => {
|
|
|
4425
4427
|
if (!account) {
|
|
4426
4428
|
return c.json({ error: "No account configured" }, 500);
|
|
4427
4429
|
}
|
|
4428
|
-
const
|
|
4429
|
-
const
|
|
4430
|
-
const sk = publicSseConvId?.slice(0, 8) ?? session_key.slice(0, 8);
|
|
4430
|
+
const sseLog = agentLogStream("sse-events", account.accountDir, session_key);
|
|
4431
|
+
const sk = session_key.slice(0, 8);
|
|
4431
4432
|
const agentName = getAgentNameForSession(session_key);
|
|
4432
4433
|
if (!agentName) {
|
|
4433
4434
|
console.log(`[chat] no agent for session=${sk} \u2014 session expired or server restarted`);
|
|
@@ -7017,7 +7018,8 @@ async function resolveUserIdentity(accountId, userId) {
|
|
|
7017
7018
|
async function createAdminSession(accountId, thinkingView, userId, userName, role, avatar) {
|
|
7018
7019
|
const account = resolveAccount();
|
|
7019
7020
|
const effectiveThinkingView = thinkingView ?? account?.config.thinkingView ?? "default";
|
|
7020
|
-
const
|
|
7021
|
+
const signedSessionToken = userId ? mintAdminSessionToken({ accountId, userId }) : crypto.randomUUID();
|
|
7022
|
+
const cacheKey = fingerprintSessionKey(signedSessionToken);
|
|
7021
7023
|
registerSession(cacheKey, "admin", accountId, void 0, userId, userName, role);
|
|
7022
7024
|
if (userId) setWantsPriorConversation(cacheKey);
|
|
7023
7025
|
let onboardingComplete = true;
|
|
@@ -7053,7 +7055,7 @@ async function createAdminSession(accountId, thinkingView, userId, userName, rol
|
|
|
7053
7055
|
console.log(`[session] ${(/* @__PURE__ */ new Date()).toISOString()} admin session created: userId=${userId ?? "\u2013"} userName=${userName ?? "\u2013"} accountId=${accountId} conversationId=${initialConversationId ?? "unbound"} cacheKey=${cacheKey.slice(0, 8)}`);
|
|
7054
7056
|
console.log(`[admin-session] role=${role ?? "null"} cacheKey=${cacheKey.slice(0, 8)} phase=create eager-ensured=${initialConversationId ? "true" : "false"}`);
|
|
7055
7057
|
return {
|
|
7056
|
-
session_key:
|
|
7058
|
+
session_key: signedSessionToken,
|
|
7057
7059
|
agent_id: "admin",
|
|
7058
7060
|
userId,
|
|
7059
7061
|
userName,
|
|
@@ -7067,8 +7069,12 @@ async function createAdminSession(accountId, thinkingView, userId, userName, rol
|
|
|
7067
7069
|
}
|
|
7068
7070
|
var app10 = new Hono();
|
|
7069
7071
|
app10.get("/", async (c) => {
|
|
7070
|
-
const
|
|
7071
|
-
if (!
|
|
7072
|
+
const signedSessionToken = c.req.query("session_key");
|
|
7073
|
+
if (!signedSessionToken) {
|
|
7074
|
+
return c.json({ error: "Invalid or expired admin session" }, 401);
|
|
7075
|
+
}
|
|
7076
|
+
const cacheKey = fingerprintSessionKey(signedSessionToken);
|
|
7077
|
+
if (!validateSession(cacheKey, "admin", signedSessionToken).ok) {
|
|
7072
7078
|
return c.json({ error: "Invalid or expired admin session" }, 401);
|
|
7073
7079
|
}
|
|
7074
7080
|
const accountId = getAccountIdForSession(cacheKey);
|
|
@@ -7104,7 +7110,7 @@ app10.get("/", async (c) => {
|
|
|
7104
7110
|
}
|
|
7105
7111
|
}
|
|
7106
7112
|
return c.json({
|
|
7107
|
-
session_key:
|
|
7113
|
+
session_key: signedSessionToken,
|
|
7108
7114
|
agent_id: "admin",
|
|
7109
7115
|
userId: restoredUserId,
|
|
7110
7116
|
userName: restoredUserName,
|
|
@@ -7474,7 +7480,7 @@ var app11 = new Hono();
|
|
|
7474
7480
|
app11.post("/cancel", requireAdminSession, async (c) => {
|
|
7475
7481
|
const session_key = c.var.cacheKey;
|
|
7476
7482
|
try {
|
|
7477
|
-
const { interruptClient: interruptClient2 } = await import("./client-pool-
|
|
7483
|
+
const { interruptClient: interruptClient2 } = await import("./client-pool-M6NS5G2U.js");
|
|
7478
7484
|
await interruptClient2(session_key);
|
|
7479
7485
|
return c.json({ ok: true });
|
|
7480
7486
|
} catch (err) {
|
|
@@ -7578,8 +7584,7 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7578
7584
|
try {
|
|
7579
7585
|
const parsed = JSON.parse(message);
|
|
7580
7586
|
if (parsed._lifecycle) {
|
|
7581
|
-
const
|
|
7582
|
-
const lifecycleLog = lifecycleConvId ? agentLogStream("component-lifecycle", account.accountDir, lifecycleConvId) : preConversationLogStream("component-lifecycle", account.accountDir);
|
|
7587
|
+
const lifecycleLog = agentLogStream("component-lifecycle", account.accountDir, session_key);
|
|
7583
7588
|
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
7584
7589
|
const detail = parsed.filePath ? ` filePath=${parsed.filePath}` : "";
|
|
7585
7590
|
lifecycleLog.write(`[${ts}] [component:${parsed.component ?? "unknown"}] ${parsed.event ?? "unknown"}${detail}
|
|
@@ -7603,8 +7608,7 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7603
7608
|
try {
|
|
7604
7609
|
const parsed = JSON.parse(message);
|
|
7605
7610
|
if (isComponentDone(parsed)) {
|
|
7606
|
-
const
|
|
7607
|
-
const componentLog = componentConvId ? agentLogStream("component-lifecycle", account.accountDir, componentConvId) : preConversationLogStream("component-lifecycle", account.accountDir);
|
|
7611
|
+
const componentLog = agentLogStream("component-lifecycle", account.accountDir, session_key);
|
|
7608
7612
|
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
7609
7613
|
message = transformComponentDone(parsed);
|
|
7610
7614
|
componentLog.write(`[${ts}] [component:${parsed.component}] componentDone \u2192 transformed
|
|
@@ -7668,11 +7672,11 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7668
7672
|
}
|
|
7669
7673
|
}
|
|
7670
7674
|
const encoder = new TextEncoder();
|
|
7671
|
-
const sseLogStream = agentLogStream("sse-events", account.accountDir,
|
|
7675
|
+
const sseLogStream = agentLogStream("sse-events", account.accountDir, session_key);
|
|
7672
7676
|
const sk = conversationId.slice(0, 8);
|
|
7673
|
-
const teeStreamLogPath = resolve8(account.accountDir, "logs", `claude-agent-stream-${
|
|
7677
|
+
const teeStreamLogPath = resolve8(account.accountDir, "logs", `claude-agent-stream-${session_key}.log`);
|
|
7674
7678
|
try {
|
|
7675
|
-
appendFileSync3(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [chat-route-version=
|
|
7679
|
+
appendFileSync3(teeStreamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [chat-route-version=task1006-sessionkey-on-disk] cacheKey=${session_key.slice(0, 12)}\u2026 conversationId=${conversationId}
|
|
7676
7680
|
`);
|
|
7677
7681
|
} catch {
|
|
7678
7682
|
}
|
|
@@ -7760,7 +7764,7 @@ app11.post("/", requireAdminSession, async (c) => {
|
|
|
7760
7764
|
const reqSignal = c.req.raw?.signal;
|
|
7761
7765
|
if (reqSignal) {
|
|
7762
7766
|
reqSignal.addEventListener("abort", () => {
|
|
7763
|
-
const abortStreamLog = agentLogStream("claude-agent-stream", account.accountDir,
|
|
7767
|
+
const abortStreamLog = agentLogStream("claude-agent-stream", account.accountDir, session_key);
|
|
7764
7768
|
const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
|
|
7765
7769
|
sseLog.write(`[${ts}] [${sk}] admin: ABORT [operator-cancel] interrupting pool client
|
|
7766
7770
|
`);
|
|
@@ -7976,8 +7980,25 @@ app13.post("/", requireAdminSession, async (c) => {
|
|
|
7976
7980
|
var compact_default = app13;
|
|
7977
7981
|
|
|
7978
7982
|
// server/routes/admin/logs.ts
|
|
7979
|
-
import { existsSync as
|
|
7983
|
+
import { existsSync as existsSync13, readdirSync as readdirSync5, readFileSync as readFileSync11, statSync as statSync6 } from "fs";
|
|
7980
7984
|
import { resolve as resolve9, basename as basename2 } from "path";
|
|
7985
|
+
|
|
7986
|
+
// app/lib/logs-read-resolve.ts
|
|
7987
|
+
import { existsSync as existsSync12 } from "fs";
|
|
7988
|
+
import { join as join9 } from "path";
|
|
7989
|
+
function resolveSessionLogPaths(filename, logDirs) {
|
|
7990
|
+
const tried = [filename];
|
|
7991
|
+
const hits = [];
|
|
7992
|
+
for (const dir of logDirs) {
|
|
7993
|
+
const fullPath = join9(dir, filename);
|
|
7994
|
+
if (existsSync12(fullPath)) {
|
|
7995
|
+
hits.push({ path: fullPath, dir });
|
|
7996
|
+
}
|
|
7997
|
+
}
|
|
7998
|
+
return { hits, tried };
|
|
7999
|
+
}
|
|
8000
|
+
|
|
8001
|
+
// server/routes/admin/logs.ts
|
|
7981
8002
|
var TAIL_BYTES = 8192;
|
|
7982
8003
|
var app14 = new Hono();
|
|
7983
8004
|
app14.get("/", async (c) => {
|
|
@@ -8040,31 +8061,29 @@ app14.get("/", async (c) => {
|
|
|
8040
8061
|
}
|
|
8041
8062
|
const cacheKey = cacheKeyParam ?? null;
|
|
8042
8063
|
const conversationId = conversationIdParam ?? null;
|
|
8043
|
-
const
|
|
8044
|
-
const
|
|
8045
|
-
const
|
|
8046
|
-
const
|
|
8047
|
-
|
|
8048
|
-
|
|
8049
|
-
|
|
8050
|
-
|
|
8051
|
-
|
|
8064
|
+
const sessionKeyFromConv = conversationId ? getSessionKeyByConversationId(conversationId) ?? null : null;
|
|
8065
|
+
const primaryId = cacheKey ?? sessionKeyFromConv ?? conversationId;
|
|
8066
|
+
const fallbackId = primaryId !== conversationId && conversationId ? conversationId : null;
|
|
8067
|
+
const tried = [];
|
|
8068
|
+
let hit = null;
|
|
8069
|
+
if (primaryId) {
|
|
8070
|
+
const filename = `${prefix}-${primaryId}.log`;
|
|
8071
|
+
tried.push(filename);
|
|
8072
|
+
const result = resolveSessionLogPaths(filename, logDirs);
|
|
8073
|
+
if (result.hits.length > 0) hit = result.hits[0];
|
|
8074
|
+
}
|
|
8075
|
+
if (!hit && fallbackId) {
|
|
8076
|
+
const filename = `${prefix}-${fallbackId}.log`;
|
|
8077
|
+
tried.push(filename);
|
|
8078
|
+
const result = resolveSessionLogPaths(filename, logDirs);
|
|
8079
|
+
if (result.hits.length > 0) hit = result.hits[0];
|
|
8080
|
+
}
|
|
8052
8081
|
const cacheKeySlice = cacheKey ? cacheKey.slice(0, 12) : "none";
|
|
8053
8082
|
const conversationIdSlice = conversationId ? conversationId.slice(0, 12) : "none";
|
|
8054
|
-
if (
|
|
8055
|
-
|
|
8056
|
-
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} conversationId=${conversationIdSlice} shape=${hit.shape} stalePreflushCount=${stalePreflushCount}`);
|
|
8083
|
+
if (hit) {
|
|
8084
|
+
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} conversationId=${conversationIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "conversationId-fallback"}`);
|
|
8057
8085
|
try {
|
|
8058
8086
|
const filename = basename2(hit.path);
|
|
8059
|
-
if (stalePreflushCount > 0 && !download) {
|
|
8060
|
-
const content = readFileSync11(hit.path, "utf-8");
|
|
8061
|
-
return c.json({
|
|
8062
|
-
log: content,
|
|
8063
|
-
filename,
|
|
8064
|
-
shape: hit.shape,
|
|
8065
|
-
warnings: stalePreflushPaths.map((path2) => ({ kind: "stale-preflush", path: path2 }))
|
|
8066
|
-
});
|
|
8067
|
-
}
|
|
8068
8087
|
const buffer = readFileSync11(hit.path);
|
|
8069
8088
|
const onDiskBytes = statSync6(hit.path).size;
|
|
8070
8089
|
const headers = {
|
|
@@ -8083,7 +8102,8 @@ app14.get("/", async (c) => {
|
|
|
8083
8102
|
);
|
|
8084
8103
|
}
|
|
8085
8104
|
}
|
|
8086
|
-
const reason =
|
|
8105
|
+
const reason = "no log file on disk for the given identifier(s)";
|
|
8106
|
+
if (primaryId) emitMissingOnResolve(primaryId, "admin-logs-route", reason);
|
|
8087
8107
|
console.warn(`[admin/logs] not-found tried=[${tried.join(",")}] cacheKey=${cacheKeySlice} conversationId=${conversationIdSlice} reason=${JSON.stringify(reason)}`);
|
|
8088
8108
|
return c.json(
|
|
8089
8109
|
{
|
|
@@ -8099,7 +8119,7 @@ app14.get("/", async (c) => {
|
|
|
8099
8119
|
const seen = /* @__PURE__ */ new Set();
|
|
8100
8120
|
const logs = {};
|
|
8101
8121
|
for (const dir of logDirs) {
|
|
8102
|
-
if (!
|
|
8122
|
+
if (!existsSync13(dir)) continue;
|
|
8103
8123
|
let files;
|
|
8104
8124
|
try {
|
|
8105
8125
|
files = readdirSync5(dir).filter((f) => f.endsWith(".log"));
|
|
@@ -8150,7 +8170,7 @@ var claude_info_default = app15;
|
|
|
8150
8170
|
|
|
8151
8171
|
// server/routes/admin/attachment.ts
|
|
8152
8172
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
8153
|
-
import { existsSync as
|
|
8173
|
+
import { existsSync as existsSync14 } from "fs";
|
|
8154
8174
|
import { resolve as resolve10 } from "path";
|
|
8155
8175
|
var app16 = new Hono();
|
|
8156
8176
|
app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
@@ -8164,11 +8184,11 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
8164
8184
|
return new Response("Not found", { status: 404 });
|
|
8165
8185
|
}
|
|
8166
8186
|
const dir = resolve10(ATTACHMENTS_ROOT, accountId, attachmentId);
|
|
8167
|
-
if (!
|
|
8187
|
+
if (!existsSync14(dir)) {
|
|
8168
8188
|
return new Response("Not found", { status: 404 });
|
|
8169
8189
|
}
|
|
8170
8190
|
const metaPath = resolve10(dir, `${attachmentId}.meta.json`);
|
|
8171
|
-
if (!
|
|
8191
|
+
if (!existsSync14(metaPath)) {
|
|
8172
8192
|
return new Response("Not found", { status: 404 });
|
|
8173
8193
|
}
|
|
8174
8194
|
let meta;
|
|
@@ -8196,13 +8216,13 @@ var attachment_default = app16;
|
|
|
8196
8216
|
|
|
8197
8217
|
// server/routes/admin/agents.ts
|
|
8198
8218
|
import { resolve as resolve11 } from "path";
|
|
8199
|
-
import { readdirSync as readdirSync6, readFileSync as readFileSync12, existsSync as
|
|
8219
|
+
import { readdirSync as readdirSync6, readFileSync as readFileSync12, existsSync as existsSync15, rmSync } from "fs";
|
|
8200
8220
|
var app17 = new Hono();
|
|
8201
8221
|
app17.get("/", (c) => {
|
|
8202
8222
|
const account = resolveAccount();
|
|
8203
8223
|
if (!account) return c.json({ agents: [] });
|
|
8204
8224
|
const agentsDir = resolve11(account.accountDir, "agents");
|
|
8205
|
-
if (!
|
|
8225
|
+
if (!existsSync15(agentsDir)) return c.json({ agents: [] });
|
|
8206
8226
|
const agents = [];
|
|
8207
8227
|
try {
|
|
8208
8228
|
const entries = readdirSync6(agentsDir, { withFileTypes: true });
|
|
@@ -8210,7 +8230,7 @@ app17.get("/", (c) => {
|
|
|
8210
8230
|
if (!entry.isDirectory()) continue;
|
|
8211
8231
|
if (entry.name === "admin") continue;
|
|
8212
8232
|
const configPath2 = resolve11(agentsDir, entry.name, "config.json");
|
|
8213
|
-
if (!
|
|
8233
|
+
if (!existsSync15(configPath2)) continue;
|
|
8214
8234
|
try {
|
|
8215
8235
|
const config = JSON.parse(readFileSync12(configPath2, "utf-8"));
|
|
8216
8236
|
agents.push({
|
|
@@ -8239,7 +8259,7 @@ app17.delete("/:slug", async (c) => {
|
|
|
8239
8259
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
8240
8260
|
}
|
|
8241
8261
|
const agentDir = resolve11(account.accountDir, "agents", slug);
|
|
8242
|
-
if (!
|
|
8262
|
+
if (!existsSync15(agentDir)) {
|
|
8243
8263
|
return c.json({ error: "Agent not found" }, 404);
|
|
8244
8264
|
}
|
|
8245
8265
|
try {
|
|
@@ -8269,7 +8289,7 @@ app17.post("/:slug/project", async (c) => {
|
|
|
8269
8289
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
8270
8290
|
}
|
|
8271
8291
|
const agentDir = resolve11(account.accountDir, "agents", slug);
|
|
8272
|
-
if (!
|
|
8292
|
+
if (!existsSync15(agentDir)) {
|
|
8273
8293
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
8274
8294
|
}
|
|
8275
8295
|
try {
|
|
@@ -8285,7 +8305,7 @@ var agents_default = app17;
|
|
|
8285
8305
|
// server/routes/admin/sessions.ts
|
|
8286
8306
|
import crypto2 from "crypto";
|
|
8287
8307
|
import { resolve as resolvePath } from "path";
|
|
8288
|
-
import { appendFileSync as appendFileSync4, existsSync as
|
|
8308
|
+
import { appendFileSync as appendFileSync4, existsSync as existsSync17 } from "fs";
|
|
8289
8309
|
|
|
8290
8310
|
// app/lib/synthetic-marker.ts
|
|
8291
8311
|
var CLOUDFLARE_MARKER_PREFIX = "Cloudflare setup completed (actionId: ";
|
|
@@ -8297,9 +8317,9 @@ function isSyntheticUserMarker(content) {
|
|
|
8297
8317
|
}
|
|
8298
8318
|
|
|
8299
8319
|
// app/lib/claude-agent/jsonl-replay.ts
|
|
8300
|
-
import { existsSync as
|
|
8320
|
+
import { existsSync as existsSync16, readFileSync as readFileSync13 } from "fs";
|
|
8301
8321
|
function replayJsonl(jsonlPath) {
|
|
8302
|
-
if (!
|
|
8322
|
+
if (!existsSync16(jsonlPath)) {
|
|
8303
8323
|
return { messages: [], jsonlMissing: true, malformedLines: 0 };
|
|
8304
8324
|
}
|
|
8305
8325
|
let raw;
|
|
@@ -8464,7 +8484,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, conversationId
|
|
|
8464
8484
|
let reason = null;
|
|
8465
8485
|
if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
|
|
8466
8486
|
else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
|
|
8467
|
-
else if (!
|
|
8487
|
+
else if (!existsSync17(a.storagePath)) reason = "missing-file";
|
|
8468
8488
|
if (reason) {
|
|
8469
8489
|
invalid++;
|
|
8470
8490
|
try {
|
|
@@ -8619,13 +8639,14 @@ app18.post("/new", requireAdminSession, async (c) => {
|
|
|
8619
8639
|
if (!accountId || !userId) {
|
|
8620
8640
|
return c.json({ error: "Session missing account or user context" }, 400);
|
|
8621
8641
|
}
|
|
8622
|
-
const
|
|
8642
|
+
const newSignedSessionToken = crypto2.randomUUID();
|
|
8643
|
+
const newCacheKey = fingerprintSessionKey(newSignedSessionToken);
|
|
8623
8644
|
const userName = getUserNameForSession(oldCacheKey);
|
|
8624
8645
|
registerSession(newCacheKey, "admin", accountId, void 0, userId, userName);
|
|
8625
8646
|
const previousConversationId = clearSessionHistory(oldCacheKey);
|
|
8626
8647
|
unregisterSession(oldCacheKey);
|
|
8627
8648
|
console.log(`[session] ${(/* @__PURE__ */ new Date()).toISOString()} session reset for new conversation: oldCacheKey=${oldCacheKey.slice(0, 8)}\u2026 newCacheKey=${newCacheKey.slice(0, 8)}\u2026 previousConversationId=${previousConversationId?.slice(0, 8) ?? "none"}\u2026 newConversationId=deferred`);
|
|
8628
|
-
return c.json({ session_key:
|
|
8649
|
+
return c.json({ session_key: newSignedSessionToken, conversationId: null });
|
|
8629
8650
|
});
|
|
8630
8651
|
app18.post("/switch", requireAdminSession, async (c) => {
|
|
8631
8652
|
const cacheKey = c.var.cacheKey;
|
|
@@ -8635,11 +8656,12 @@ app18.post("/switch", requireAdminSession, async (c) => {
|
|
|
8635
8656
|
return c.json({ error: "Session missing account or user context" }, 400);
|
|
8636
8657
|
}
|
|
8637
8658
|
const body = await c.req.json().catch(() => ({}));
|
|
8638
|
-
const
|
|
8639
|
-
if (!
|
|
8659
|
+
const targetSignedSessionToken = typeof body.target_session_key === "string" ? body.target_session_key : "";
|
|
8660
|
+
if (!targetSignedSessionToken) {
|
|
8640
8661
|
return c.json({ error: "target_session_key required" }, 400);
|
|
8641
8662
|
}
|
|
8642
|
-
const
|
|
8663
|
+
const targetCacheKey = fingerprintSessionKey(targetSignedSessionToken);
|
|
8664
|
+
const targetCheck = validateSession(targetCacheKey, "admin", targetSignedSessionToken);
|
|
8643
8665
|
if (!targetCheck.ok) {
|
|
8644
8666
|
console.error(`[session-switch] reject reason=${targetCheck.reason} from=${cacheKey.slice(0, 8)} target=${targetCacheKey.slice(0, 8)}`);
|
|
8645
8667
|
return c.json({ error: "Target session not registered or wrong agent type", code: targetCheck.reason }, 404);
|
|
@@ -8652,7 +8674,7 @@ app18.post("/switch", requireAdminSession, async (c) => {
|
|
|
8652
8674
|
}
|
|
8653
8675
|
const targetConversationId = getConversationIdForSession(targetCacheKey) ?? null;
|
|
8654
8676
|
console.log(`[session-switch] from=${cacheKey.slice(0, 8)} to=${targetCacheKey.slice(0, 8)} targetConvId=${targetConversationId?.slice(0, 8) ?? "none"} accountId=${accountId.slice(0, 8)}`);
|
|
8655
|
-
return c.json({ session_key:
|
|
8677
|
+
return c.json({ session_key: targetSignedSessionToken, conversationId: targetConversationId });
|
|
8656
8678
|
});
|
|
8657
8679
|
app18.delete("/:id", requireAdminSession, async (c) => {
|
|
8658
8680
|
const conversationId = c.req.param("id");
|
|
@@ -8671,13 +8693,14 @@ app18.delete("/:id", requireAdminSession, async (c) => {
|
|
|
8671
8693
|
});
|
|
8672
8694
|
app18.post("/:id/resume", async (c) => {
|
|
8673
8695
|
const conversationId = c.req.param("id");
|
|
8674
|
-
const
|
|
8675
|
-
if (!
|
|
8696
|
+
const signedSessionToken = c.req.query("session_key") ?? "";
|
|
8697
|
+
if (!signedSessionToken) {
|
|
8676
8698
|
console.error(`[session] middleware-reject status=400 code=session-missing reason="session_key required" path=${c.req.path}`);
|
|
8677
8699
|
return c.json({ error: "session_key required", code: "session-missing" }, 400);
|
|
8678
8700
|
}
|
|
8701
|
+
const cacheKey = fingerprintSessionKey(signedSessionToken);
|
|
8679
8702
|
let bridged = false;
|
|
8680
|
-
let result = validateSession(cacheKey, "admin");
|
|
8703
|
+
let result = validateSession(cacheKey, "admin", signedSessionToken);
|
|
8681
8704
|
if (!result.ok) {
|
|
8682
8705
|
if (result.reason === "session-not-registered") {
|
|
8683
8706
|
const bridge = await tryCookieBridgeForConversation(c, cacheKey, conversationId);
|
|
@@ -8690,7 +8713,7 @@ app18.post("/:id/resume", async (c) => {
|
|
|
8690
8713
|
return c.json({ error: "Invalid or expired admin session", code: "session-not-registered" }, 401);
|
|
8691
8714
|
}
|
|
8692
8715
|
bridged = true;
|
|
8693
|
-
result = validateSession(cacheKey, "admin");
|
|
8716
|
+
result = validateSession(cacheKey, "admin", signedSessionToken);
|
|
8694
8717
|
if (!result.ok) {
|
|
8695
8718
|
const tail = cacheKey.slice(0, 8);
|
|
8696
8719
|
console.error(`[session] middleware-reject status=401 code=session-not-registered reason="post-bridge re-validate failed" path=${c.req.path} cacheKey=${tail}\u2026`);
|
|
@@ -9255,12 +9278,12 @@ function isValidDomain(value) {
|
|
|
9255
9278
|
}
|
|
9256
9279
|
|
|
9257
9280
|
// app/lib/alias-domains.ts
|
|
9258
|
-
import { existsSync as
|
|
9281
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync6, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
|
|
9259
9282
|
import { dirname as dirname5 } from "path";
|
|
9260
9283
|
import { resolve as resolve12 } from "path";
|
|
9261
9284
|
var ALIAS_DOMAINS_PATH = resolve12(MAXY_DIR, "alias-domains.json");
|
|
9262
9285
|
function readExisting() {
|
|
9263
|
-
if (!
|
|
9286
|
+
if (!existsSync18(ALIAS_DOMAINS_PATH)) return /* @__PURE__ */ new Set();
|
|
9264
9287
|
try {
|
|
9265
9288
|
const parsed = JSON.parse(readFileSync14(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
9266
9289
|
if (!Array.isArray(parsed)) return /* @__PURE__ */ new Set();
|
|
@@ -9534,8 +9557,8 @@ app23.get("/tunnels", requireAdminSession, async (c) => {
|
|
|
9534
9557
|
if (!correlationId) return err("session", "No active conversation for session \u2014 refresh chat.");
|
|
9535
9558
|
streamLogPath = streamLogPathFor(accountId, correlationId).streamLogPath;
|
|
9536
9559
|
const certPath = resolve13(homedir2(), brand.configDir, "cloudflared", "cert.pem");
|
|
9537
|
-
const { existsSync:
|
|
9538
|
-
if (!
|
|
9560
|
+
const { existsSync: existsSync25 } = await import("fs");
|
|
9561
|
+
if (!existsSync25(certPath)) {
|
|
9539
9562
|
return err("cert", `Cloudflare origin certificate is not on disk yet (${certPath}). Complete the Cloudflare login first by submitting the form once \u2014 the OAuth flow writes cert.pem.`);
|
|
9540
9563
|
}
|
|
9541
9564
|
const result = await runFormSpawn({
|
|
@@ -9859,7 +9882,7 @@ var cloudflare_default = app23;
|
|
|
9859
9882
|
import { createReadStream as createReadStream3 } from "fs";
|
|
9860
9883
|
import { readdir as readdir2, readFile as readFile3, stat as stat3, mkdir as mkdir2, writeFile as writeFile3, unlink as unlink2 } from "fs/promises";
|
|
9861
9884
|
import { realpathSync as realpathSync3 } from "fs";
|
|
9862
|
-
import { basename as basename3, dirname as dirname6, join as
|
|
9885
|
+
import { basename as basename3, dirname as dirname6, join as join10, resolve as resolve15, sep as sep2 } from "path";
|
|
9863
9886
|
import { Readable as Readable2 } from "stream";
|
|
9864
9887
|
|
|
9865
9888
|
// app/lib/data-path.ts
|
|
@@ -10217,7 +10240,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
10217
10240
|
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
10218
10241
|
async function readMeta(absDir, baseName) {
|
|
10219
10242
|
try {
|
|
10220
|
-
const raw = await readFile3(
|
|
10243
|
+
const raw = await readFile3(join10(absDir, `${baseName}.meta.json`), "utf8");
|
|
10221
10244
|
const parsed = JSON.parse(raw);
|
|
10222
10245
|
if (typeof parsed?.filename === "string") {
|
|
10223
10246
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -10255,7 +10278,7 @@ async function readAccountNames() {
|
|
|
10255
10278
|
}
|
|
10256
10279
|
async function enrich(absolute, entry, accountNames) {
|
|
10257
10280
|
if (entry.kind === "directory" && UUID_RE5.test(entry.name)) {
|
|
10258
|
-
const meta = await readMeta(
|
|
10281
|
+
const meta = await readMeta(join10(absolute, entry.name), entry.name);
|
|
10259
10282
|
if (meta?.filename) {
|
|
10260
10283
|
entry.displayName = meta.filename;
|
|
10261
10284
|
entry.mimeType = meta.mimeType;
|
|
@@ -10314,7 +10337,7 @@ app24.get("/", requireAdminSession, async (c) => {
|
|
|
10314
10337
|
continue;
|
|
10315
10338
|
}
|
|
10316
10339
|
try {
|
|
10317
|
-
const entryPath =
|
|
10340
|
+
const entryPath = join10(absolute, name);
|
|
10318
10341
|
const s = await stat3(entryPath);
|
|
10319
10342
|
entries.push({
|
|
10320
10343
|
name,
|
|
@@ -10487,7 +10510,7 @@ app24.delete("/", requireAdminSession, async (c) => {
|
|
|
10487
10510
|
}
|
|
10488
10511
|
const dot = base.lastIndexOf(".");
|
|
10489
10512
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
10490
|
-
const sidecarPath = UUID_RE5.test(stem) && base !== `${stem}.meta.json` ?
|
|
10513
|
+
const sidecarPath = UUID_RE5.test(stem) && base !== `${stem}.meta.json` ? join10(dirname6(absolute), `${stem}.meta.json`) : null;
|
|
10491
10514
|
await unlink2(absolute);
|
|
10492
10515
|
if (sidecarPath) {
|
|
10493
10516
|
try {
|
|
@@ -12178,7 +12201,7 @@ var adherence_default = app32;
|
|
|
12178
12201
|
import neo4j3 from "neo4j-driver";
|
|
12179
12202
|
import { readFile as readFile4, readdir as readdir3, stat as stat4 } from "fs/promises";
|
|
12180
12203
|
import { resolve as resolve16, relative as relative2, isAbsolute } from "path";
|
|
12181
|
-
import { existsSync as
|
|
12204
|
+
import { existsSync as existsSync19 } from "fs";
|
|
12182
12205
|
var LIMIT = 50;
|
|
12183
12206
|
var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
|
|
12184
12207
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
@@ -12326,7 +12349,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
12326
12349
|
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
12327
12350
|
const names = /* @__PURE__ */ new Set();
|
|
12328
12351
|
for (const dir of [overrideDir, bundledDir]) {
|
|
12329
|
-
if (!
|
|
12352
|
+
if (!existsSync19(dir)) continue;
|
|
12330
12353
|
try {
|
|
12331
12354
|
const entries = await readdir3(dir);
|
|
12332
12355
|
for (const entry of entries) {
|
|
@@ -12341,7 +12364,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
12341
12364
|
}
|
|
12342
12365
|
async function readAgentTemplateRow(inp) {
|
|
12343
12366
|
let chosenPath = null;
|
|
12344
|
-
if (
|
|
12367
|
+
if (existsSync19(inp.overridePath)) {
|
|
12345
12368
|
try {
|
|
12346
12369
|
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
12347
12370
|
chosenPath = inp.overridePath;
|
|
@@ -12352,7 +12375,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
12352
12375
|
);
|
|
12353
12376
|
return null;
|
|
12354
12377
|
}
|
|
12355
|
-
} else if (
|
|
12378
|
+
} else if (existsSync19(inp.bundledPath)) {
|
|
12356
12379
|
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
12357
12380
|
console.error(
|
|
12358
12381
|
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
@@ -12394,7 +12417,7 @@ var sidebar_artefacts_default = app33;
|
|
|
12394
12417
|
// server/routes/admin/sidebar-artefact-save.ts
|
|
12395
12418
|
import { mkdir as mkdir3, readdir as readdir4, stat as stat5, writeFile as writeFile4 } from "fs/promises";
|
|
12396
12419
|
import { resolve as resolve17 } from "path";
|
|
12397
|
-
import { existsSync as
|
|
12420
|
+
import { existsSync as existsSync20 } from "fs";
|
|
12398
12421
|
var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
|
|
12399
12422
|
var UUID_RE6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
12400
12423
|
var app34 = new Hono();
|
|
@@ -12462,7 +12485,7 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
12462
12485
|
}
|
|
12463
12486
|
if (UUID_RE6.test(id)) {
|
|
12464
12487
|
const dir = resolve17(ATTACHMENTS_ROOT, accountId, id);
|
|
12465
|
-
if (!
|
|
12488
|
+
if (!existsSync20(dir)) {
|
|
12466
12489
|
const attShort = id.slice(0, 8);
|
|
12467
12490
|
if (isHealPending(accountId, id)) {
|
|
12468
12491
|
console.error(`[admin/sidebar-artefact-save] heal-race attachmentId=${attShort} outcome=503-retry source=heal-pending`);
|
|
@@ -12514,7 +12537,7 @@ var sidebar_artefact_save_default = app34;
|
|
|
12514
12537
|
|
|
12515
12538
|
// server/routes/admin/sidebar-artefact-content.ts
|
|
12516
12539
|
import { readFile as readFile5, readdir as readdir5 } from "fs/promises";
|
|
12517
|
-
import { existsSync as
|
|
12540
|
+
import { existsSync as existsSync21 } from "fs";
|
|
12518
12541
|
import { resolve as resolve18 } from "path";
|
|
12519
12542
|
var UUID_RE7 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
12520
12543
|
var app35 = new Hono();
|
|
@@ -12528,7 +12551,7 @@ app35.get("/", requireAdminSession, async (c) => {
|
|
|
12528
12551
|
return new Response("Not found", { status: 404 });
|
|
12529
12552
|
}
|
|
12530
12553
|
const dir = resolve18(ATTACHMENTS_ROOT, accountId, id);
|
|
12531
|
-
if (!
|
|
12554
|
+
if (!existsSync21(dir)) {
|
|
12532
12555
|
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
12533
12556
|
return new Response("Not found", { status: 404 });
|
|
12534
12557
|
}
|
|
@@ -12562,12 +12585,12 @@ app35.get("/", requireAdminSession, async (c) => {
|
|
|
12562
12585
|
var sidebar_artefact_content_default = app35;
|
|
12563
12586
|
|
|
12564
12587
|
// server/routes/admin/health.ts
|
|
12565
|
-
import { existsSync as
|
|
12566
|
-
import { resolve as resolve19, join as
|
|
12588
|
+
import { existsSync as existsSync22, readFileSync as readFileSync16 } from "fs";
|
|
12589
|
+
import { resolve as resolve19, join as join11 } from "path";
|
|
12567
12590
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
|
|
12568
12591
|
var brandHostname = "maxy";
|
|
12569
|
-
var brandJsonPath =
|
|
12570
|
-
if (
|
|
12592
|
+
var brandJsonPath = join11(PLATFORM_ROOT6, "config", "brand.json");
|
|
12593
|
+
if (existsSync22(brandJsonPath)) {
|
|
12571
12594
|
try {
|
|
12572
12595
|
const brand = JSON.parse(readFileSync16(brandJsonPath, "utf-8"));
|
|
12573
12596
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
@@ -12578,7 +12601,7 @@ var VERSION_FILE = resolve19(PLATFORM_ROOT6, `config/.${brandHostname}-version`)
|
|
|
12578
12601
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
12579
12602
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
12580
12603
|
function readVersion() {
|
|
12581
|
-
if (!
|
|
12604
|
+
if (!existsSync22(VERSION_FILE)) return "unknown";
|
|
12582
12605
|
return readFileSync16(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
12583
12606
|
}
|
|
12584
12607
|
async function probeConversationDb() {
|
|
@@ -12661,7 +12684,7 @@ app37.route("/health-brand", health_default2);
|
|
|
12661
12684
|
var admin_default = app37;
|
|
12662
12685
|
|
|
12663
12686
|
// server/routes/sites.ts
|
|
12664
|
-
import { existsSync as
|
|
12687
|
+
import { existsSync as existsSync23, readFileSync as readFileSync17, realpathSync as realpathSync4, statSync as statSync7 } from "fs";
|
|
12665
12688
|
import { resolve as resolve20 } from "path";
|
|
12666
12689
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
12667
12690
|
var MIME = {
|
|
@@ -12727,7 +12750,7 @@ app38.get("/:rel{.*}", (c) => {
|
|
|
12727
12750
|
}
|
|
12728
12751
|
let stat6;
|
|
12729
12752
|
try {
|
|
12730
|
-
stat6 =
|
|
12753
|
+
stat6 = existsSync23(filePath) ? statSync7(filePath) : null;
|
|
12731
12754
|
} catch {
|
|
12732
12755
|
stat6 = null;
|
|
12733
12756
|
}
|
|
@@ -12746,7 +12769,7 @@ app38.get("/:rel{.*}", (c) => {
|
|
|
12746
12769
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
12747
12770
|
return c.text("Forbidden", 403);
|
|
12748
12771
|
}
|
|
12749
|
-
if (!
|
|
12772
|
+
if (!existsSync23(filePath)) {
|
|
12750
12773
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
12751
12774
|
return c.text("Not found", 404);
|
|
12752
12775
|
}
|
|
@@ -12867,10 +12890,42 @@ async function verifyUserProfileConstraint() {
|
|
|
12867
12890
|
await session.close();
|
|
12868
12891
|
}
|
|
12869
12892
|
}
|
|
12893
|
+
async function verifySessionKeyAdherence() {
|
|
12894
|
+
const session = getSession();
|
|
12895
|
+
try {
|
|
12896
|
+
const convResult = await session.run(
|
|
12897
|
+
`MATCH (c:Conversation) WHERE c.sessionKey IS NULL RETURN count(c) AS n`
|
|
12898
|
+
);
|
|
12899
|
+
const convNull = convResult.records[0]?.get("n")?.toNumber?.() ?? 0;
|
|
12900
|
+
console.error(
|
|
12901
|
+
`[migration-1007] adherence-check label=Conversation rows-with-null-sessionkey=${convNull}`
|
|
12902
|
+
);
|
|
12903
|
+
const msgResult = await session.run(
|
|
12904
|
+
`MATCH (m:Message) WHERE m.sessionKey IS NULL RETURN count(m) AS n`
|
|
12905
|
+
);
|
|
12906
|
+
const msgNull = msgResult.records[0]?.get("n")?.toNumber?.() ?? 0;
|
|
12907
|
+
console.error(
|
|
12908
|
+
`[migration-1007] adherence-check label=Message rows-with-null-sessionkey=${msgNull}`
|
|
12909
|
+
);
|
|
12910
|
+
if (convNull > 0 || msgNull > 0) {
|
|
12911
|
+
console.error(
|
|
12912
|
+
`[migration-1007] adherence-check P0=true reason=null-sessionkey-on-boot \u2014 re-run seed-neo4j.sh`
|
|
12913
|
+
);
|
|
12914
|
+
}
|
|
12915
|
+
} catch (err) {
|
|
12916
|
+
console.error(
|
|
12917
|
+
`[migration-1007] adherence-check verify failed: ${err instanceof Error ? err.message : String(err)}`
|
|
12918
|
+
);
|
|
12919
|
+
} finally {
|
|
12920
|
+
await session.close();
|
|
12921
|
+
}
|
|
12922
|
+
}
|
|
12870
12923
|
function startGraphHealthTimer() {
|
|
12871
12924
|
if (timer) return;
|
|
12872
12925
|
verifyUserProfileConstraint().catch(() => {
|
|
12873
12926
|
});
|
|
12927
|
+
verifySessionKeyAdherence().catch(() => {
|
|
12928
|
+
});
|
|
12874
12929
|
runGraphHealthTick().catch(() => {
|
|
12875
12930
|
});
|
|
12876
12931
|
timer = setInterval(() => {
|
|
@@ -12881,7 +12936,7 @@ function startGraphHealthTimer() {
|
|
|
12881
12936
|
}
|
|
12882
12937
|
|
|
12883
12938
|
// server/index.ts
|
|
12884
|
-
import { existsSync as existsSyncBoot
|
|
12939
|
+
import { existsSync as existsSyncBoot } from "fs";
|
|
12885
12940
|
import { resolve as resolveBoot } from "path";
|
|
12886
12941
|
function requestIsTlsTerminated(c) {
|
|
12887
12942
|
const remote = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
@@ -12897,12 +12952,12 @@ function clientFrom(c) {
|
|
|
12897
12952
|
);
|
|
12898
12953
|
}
|
|
12899
12954
|
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
12900
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT7 ?
|
|
12955
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join12(PLATFORM_ROOT7, "config", "brand.json") : "";
|
|
12901
12956
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
|
|
12902
|
-
if (BRAND_JSON_PATH && !
|
|
12957
|
+
if (BRAND_JSON_PATH && !existsSync24(BRAND_JSON_PATH)) {
|
|
12903
12958
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
12904
12959
|
}
|
|
12905
|
-
if (BRAND_JSON_PATH &&
|
|
12960
|
+
if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
|
|
12906
12961
|
try {
|
|
12907
12962
|
const parsed = JSON.parse(readFileSync18(BRAND_JSON_PATH, "utf-8"));
|
|
12908
12963
|
BRAND = { ...BRAND, ...parsed };
|
|
@@ -12923,10 +12978,10 @@ var brandLoginOpts = {
|
|
|
12923
12978
|
bodyFont: BRAND.defaultFonts?.body,
|
|
12924
12979
|
logoContainsName: !!BRAND.logoContainsName
|
|
12925
12980
|
};
|
|
12926
|
-
var ALIAS_DOMAINS_PATH2 =
|
|
12981
|
+
var ALIAS_DOMAINS_PATH2 = join12(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
12927
12982
|
function loadAliasDomains() {
|
|
12928
12983
|
try {
|
|
12929
|
-
if (!
|
|
12984
|
+
if (!existsSync24(ALIAS_DOMAINS_PATH2)) return null;
|
|
12930
12985
|
const parsed = JSON.parse(readFileSync18(ALIAS_DOMAINS_PATH2, "utf-8"));
|
|
12931
12986
|
if (!Array.isArray(parsed)) {
|
|
12932
12987
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
@@ -13199,7 +13254,8 @@ app39.post("/api/remote-auth/set-password", async (c) => {
|
|
|
13199
13254
|
} catch {
|
|
13200
13255
|
return c.json({ error: "Invalid request" }, 400);
|
|
13201
13256
|
}
|
|
13202
|
-
|
|
13257
|
+
const cacheKey = body.session_key ? fingerprintSessionKey(body.session_key) : "";
|
|
13258
|
+
if (!cacheKey || !validateSession(cacheKey, "admin", body.session_key).ok) {
|
|
13203
13259
|
return c.json({ error: "Unauthorized" }, 401);
|
|
13204
13260
|
}
|
|
13205
13261
|
if (!body.password) {
|
|
@@ -13306,7 +13362,7 @@ app39.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
13306
13362
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
13307
13363
|
return c.text("Forbidden", 403);
|
|
13308
13364
|
}
|
|
13309
|
-
if (!
|
|
13365
|
+
if (!existsSync24(filePath)) {
|
|
13310
13366
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
13311
13367
|
return c.text("Not found", 404);
|
|
13312
13368
|
}
|
|
@@ -13336,7 +13392,7 @@ app39.get("/generated/:filename", (c) => {
|
|
|
13336
13392
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
13337
13393
|
return c.text("Forbidden", 403);
|
|
13338
13394
|
}
|
|
13339
|
-
if (!
|
|
13395
|
+
if (!existsSync24(filePath)) {
|
|
13340
13396
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
13341
13397
|
return c.text("Not found", 404);
|
|
13342
13398
|
}
|
|
@@ -13353,7 +13409,7 @@ app39.route("/sites", sites_default);
|
|
|
13353
13409
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
13354
13410
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
13355
13411
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
13356
|
-
if (BRAND_JSON_PATH &&
|
|
13412
|
+
if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
|
|
13357
13413
|
try {
|
|
13358
13414
|
const fullBrand = JSON.parse(readFileSync18(BRAND_JSON_PATH, "utf-8"));
|
|
13359
13415
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
@@ -13372,8 +13428,8 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
13372
13428
|
function readInstalledVersion() {
|
|
13373
13429
|
try {
|
|
13374
13430
|
if (!PLATFORM_ROOT7) return "unknown";
|
|
13375
|
-
const versionFile =
|
|
13376
|
-
if (!
|
|
13431
|
+
const versionFile = join12(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
|
|
13432
|
+
if (!existsSync24(versionFile)) return "unknown";
|
|
13377
13433
|
const content = readFileSync18(versionFile, "utf-8").trim();
|
|
13378
13434
|
return content || "unknown";
|
|
13379
13435
|
} catch {
|
|
@@ -13431,15 +13487,15 @@ ${clientErrorReporterScript}
|
|
|
13431
13487
|
}
|
|
13432
13488
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
13433
13489
|
function loadBrandingCache(agentSlug) {
|
|
13434
|
-
const configDir2 =
|
|
13490
|
+
const configDir2 = join12(homedir3(), BRAND.configDir);
|
|
13435
13491
|
try {
|
|
13436
|
-
const accountJsonPath =
|
|
13437
|
-
if (!
|
|
13492
|
+
const accountJsonPath = join12(configDir2, "account.json");
|
|
13493
|
+
if (!existsSync24(accountJsonPath)) return null;
|
|
13438
13494
|
const account = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
|
|
13439
13495
|
const accountId = account.accountId;
|
|
13440
13496
|
if (!accountId) return null;
|
|
13441
|
-
const cachePath =
|
|
13442
|
-
if (!
|
|
13497
|
+
const cachePath = join12(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
13498
|
+
if (!existsSync24(cachePath)) return null;
|
|
13443
13499
|
return JSON.parse(readFileSync18(cachePath, "utf-8"));
|
|
13444
13500
|
} catch {
|
|
13445
13501
|
return null;
|
|
@@ -13447,9 +13503,9 @@ function loadBrandingCache(agentSlug) {
|
|
|
13447
13503
|
}
|
|
13448
13504
|
function resolveDefaultSlug() {
|
|
13449
13505
|
try {
|
|
13450
|
-
const configDir2 =
|
|
13451
|
-
const accountJsonPath =
|
|
13452
|
-
if (!
|
|
13506
|
+
const configDir2 = join12(homedir3(), BRAND.configDir);
|
|
13507
|
+
const accountJsonPath = join12(configDir2, "account.json");
|
|
13508
|
+
if (!existsSync24(accountJsonPath)) return null;
|
|
13453
13509
|
const account = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
|
|
13454
13510
|
return account.defaultAgent || null;
|
|
13455
13511
|
} catch {
|
|
@@ -13629,7 +13685,7 @@ try {
|
|
|
13629
13685
|
(async () => {
|
|
13630
13686
|
try {
|
|
13631
13687
|
let userId = "";
|
|
13632
|
-
if (
|
|
13688
|
+
if (existsSync24(USERS_FILE)) {
|
|
13633
13689
|
const users = JSON.parse(readFileSync18(USERS_FILE, "utf-8").trim() || "[]");
|
|
13634
13690
|
userId = users[0]?.userId ?? "";
|
|
13635
13691
|
}
|
|
@@ -13647,7 +13703,7 @@ try {
|
|
|
13647
13703
|
})();
|
|
13648
13704
|
(async () => {
|
|
13649
13705
|
try {
|
|
13650
|
-
if (!
|
|
13706
|
+
if (!existsSync24(USERS_FILE)) return;
|
|
13651
13707
|
const usersRaw = readFileSync18(USERS_FILE, "utf-8").trim();
|
|
13652
13708
|
if (!usersRaw) return;
|
|
13653
13709
|
const users = JSON.parse(usersRaw);
|
|
@@ -13700,6 +13756,11 @@ autoDeliverPremiumPlugins(
|
|
|
13700
13756
|
bootAccount?.accountDir,
|
|
13701
13757
|
bootAccount?.config
|
|
13702
13758
|
);
|
|
13759
|
+
reconcileEnabledPlugins(
|
|
13760
|
+
bootAccount?.accountDir,
|
|
13761
|
+
bootAccount?.config,
|
|
13762
|
+
bootEntitlement?.purchasedPlugins ?? void 0
|
|
13763
|
+
);
|
|
13703
13764
|
(async () => {
|
|
13704
13765
|
if (!bootAccount) return;
|
|
13705
13766
|
try {
|
|
@@ -13749,25 +13810,8 @@ if (bootEntitlement?.purchasedPlugins?.length) {
|
|
|
13749
13810
|
const enabledSet = new Set(bootEnabled);
|
|
13750
13811
|
for (const purchased of bootEntitlement.purchasedPlugins) {
|
|
13751
13812
|
const bundlePath = resolveBoot(PLATFORM_ROOT, "..", "premium-plugins", purchased, "BUNDLE.md");
|
|
13752
|
-
|
|
13753
|
-
|
|
13754
|
-
const raw = readFileSyncBoot(bundlePath, "utf-8");
|
|
13755
|
-
const fm = raw.match(/^---\n([\s\S]*?)\n---/);
|
|
13756
|
-
if (!fm) continue;
|
|
13757
|
-
let inPlugins = false;
|
|
13758
|
-
for (const line of fm[1].split("\n")) {
|
|
13759
|
-
if (/^plugins:/.test(line)) {
|
|
13760
|
-
inPlugins = true;
|
|
13761
|
-
continue;
|
|
13762
|
-
}
|
|
13763
|
-
if (inPlugins) {
|
|
13764
|
-
const m = line.match(/^\s+- (.+)/);
|
|
13765
|
-
if (!m) break;
|
|
13766
|
-
const sub = m[1].trim();
|
|
13767
|
-
if (!enabledSet.has(sub)) bootEnabledNotDelivered.push(sub);
|
|
13768
|
-
}
|
|
13769
|
-
}
|
|
13770
|
-
} catch {
|
|
13813
|
+
for (const sub of readBundleSubPlugins(bundlePath)) {
|
|
13814
|
+
if (!enabledSet.has(sub)) bootEnabledNotDelivered.push(sub);
|
|
13771
13815
|
}
|
|
13772
13816
|
}
|
|
13773
13817
|
}
|
|
@@ -13780,7 +13824,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
13780
13824
|
}
|
|
13781
13825
|
init({
|
|
13782
13826
|
configDir: configDirForWhatsApp,
|
|
13783
|
-
platformRoot: resolve21(process.env.MAXY_PLATFORM_ROOT ??
|
|
13827
|
+
platformRoot: resolve21(process.env.MAXY_PLATFORM_ROOT ?? join12(__dirname, "..")),
|
|
13784
13828
|
accountConfig: bootAccountConfig,
|
|
13785
13829
|
onMessage: async (msg) => {
|
|
13786
13830
|
try {
|