@rubytech/create-maxy-code 0.1.310 → 0.1.312
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/lib/graph-style/dist/index.d.ts +5 -2
- package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-style/dist/index.js +65 -2
- package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-style/src/__tests__/parity.test.ts +218 -0
- package/payload/platform/lib/graph-style/src/index.ts +53 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +21 -3
- package/payload/platform/plugins/docs/references/admin-ui.md +20 -2
- package/payload/platform/scripts/check-no-esm-require.mjs +4 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +29 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +16 -2
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +10 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +22 -2
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts +49 -0
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js +148 -0
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/scope-record.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/scope-record.js +35 -53
- package/payload/platform/services/claude-session-manager/dist/scope-record.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/sidecar-store.d.ts +45 -0
- package/payload/platform/services/claude-session-manager/dist/sidecar-store.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/sidecar-store.js +118 -0
- package/payload/platform/services/claude-session-manager/dist/sidecar-store.js.map +1 -0
- package/payload/server/public/assets/{AccessGate-BOqUU-za.js → AccessGate-Dh5A79FU.js} +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-WvRuaNIg.js → AdminLoginScreens-B8s2TbT7.js} +1 -1
- package/payload/server/public/assets/AdminShell-Cu1zlb6L.js +1 -0
- package/payload/server/public/assets/{Checkbox-DjM6aYP_.js → Checkbox-B_sOAyv1.js} +1 -1
- package/payload/server/public/assets/OperatorConversations-hm0Gpu_Q.js +1 -0
- package/payload/server/public/assets/{admin-XbVTsU2q.js → admin-gZEndvJT.js} +1 -1
- package/payload/server/public/assets/{audio-attachment-mime-CVxjPN8V.js → audio-attachment-mime-B0b89VnH.js} +1 -1
- package/payload/server/public/assets/brand-BcNavK6q.css +1 -0
- package/payload/server/public/assets/{browser-Ct5Kwlmk.js → browser-BUlB5_MD.js} +1 -1
- package/payload/server/public/assets/chat-BnceaVl7.js +1 -0
- package/payload/server/public/assets/data-3Nl3P5wt.js +1 -0
- package/payload/server/public/assets/{graph-DWT1rhy9.js → graph-DMCKpW6P.js} +2 -2
- package/payload/server/public/assets/graph-labels-AZLGoVy8.js +1 -0
- package/payload/server/public/assets/operator-BF4F7k23.js +1 -0
- package/payload/server/public/assets/page-DQUEst1o.js +1 -0
- package/payload/server/public/assets/{public-owWW-MIA.js → public-G_-UI9nB.js} +1 -1
- package/payload/server/public/assets/{public-next-ClQwtyeC.js → public-next-C8_nExQB.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-BZsJuUm-.js → useSelectionMode-Bf6Rt-sl.js} +1 -1
- package/payload/server/public/browser.html +6 -6
- package/payload/server/public/chat.html +8 -8
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +8 -8
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/operator.html +10 -10
- package/payload/server/public/public-next.html +9 -9
- package/payload/server/public/public.html +7 -7
- package/payload/server/server.js +1007 -458
- package/payload/server/public/assets/AdminShell-DHv6_SZ4.js +0 -1
- package/payload/server/public/assets/OperatorConversations-CDY0jUMb.js +0 -1
- package/payload/server/public/assets/brand-N-Hi3IPA.css +0 -1
- package/payload/server/public/assets/chat-CEde1CLX.js +0 -1
- package/payload/server/public/assets/data-TZOmA1Qg.js +0 -1
- package/payload/server/public/assets/graph-labels-OBadNo54.js +0 -1
- package/payload/server/public/assets/operator-BpzQ9Ezb.js +0 -1
- package/payload/server/public/assets/page-Dts8u8MD.js +0 -1
- /package/payload/server/public/assets/{brand-zL3tAdql.js → brand-BQ_u9UdS.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -562,6 +562,30 @@ var require_dist2 = __commonJS({
|
|
|
562
562
|
if (v.length > 0) {
|
|
563
563
|
return v.length > 24 ? v.slice(0, 24) + "\u2026" : v;
|
|
564
564
|
}
|
|
565
|
+
} else if (primaryLabel === "Job") {
|
|
566
|
+
const client = typeof props.client === "string" ? props.client : "";
|
|
567
|
+
const jobId = typeof props.jobId === "string" ? props.jobId : "";
|
|
568
|
+
const composed = [client, jobId.length > 0 ? `#${jobId}` : ""].filter((s) => s.length > 0).join(" ");
|
|
569
|
+
if (composed.length > 0) {
|
|
570
|
+
return composed.length > 24 ? composed.slice(0, 24) + "\u2026" : composed;
|
|
571
|
+
}
|
|
572
|
+
} else if (primaryLabel === "QuoteDocument") {
|
|
573
|
+
const ref = typeof props.ref === "string" ? props.ref : "";
|
|
574
|
+
if (ref.length > 0) {
|
|
575
|
+
return ref.length > 24 ? ref.slice(0, 24) + "\u2026" : ref;
|
|
576
|
+
}
|
|
577
|
+
} else if (primaryLabel === "InboundInvoice") {
|
|
578
|
+
const supplier = typeof props.supplier === "string" ? props.supplier : "";
|
|
579
|
+
const conf = typeof props.confirmationNumber === "string" ? props.confirmationNumber : "";
|
|
580
|
+
const composed = [supplier, conf.length > 0 ? `#${conf}` : ""].filter((s) => s.length > 0).join(" ");
|
|
581
|
+
if (composed.length > 0) {
|
|
582
|
+
return composed.length > 24 ? composed.slice(0, 24) + "\u2026" : composed;
|
|
583
|
+
}
|
|
584
|
+
} else if (primaryLabel === "WhatsAppGroup") {
|
|
585
|
+
const clientName = typeof props.clientName === "string" ? props.clientName : "";
|
|
586
|
+
if (clientName.length > 0) {
|
|
587
|
+
return clientName.length > 24 ? clientName.slice(0, 24) + "\u2026" : clientName;
|
|
588
|
+
}
|
|
565
589
|
} else if (primaryLabel === "Message") {
|
|
566
590
|
const role = typeof props.role === "string" ? props.role : "";
|
|
567
591
|
const roleShort = role === "user" ? "user" : role === "assistant" ? "asst" : role === "system" ? "sys" : role === "tool" ? "tool" : null;
|
|
@@ -615,6 +639,26 @@ var require_dist2 = __commonJS({
|
|
|
615
639
|
const v = dn.length > 0 ? dn : slug;
|
|
616
640
|
if (v.length > 0)
|
|
617
641
|
return v;
|
|
642
|
+
} else if (primaryLabel === "Job") {
|
|
643
|
+
const client = typeof props.client === "string" ? props.client : "";
|
|
644
|
+
const jobId = typeof props.jobId === "string" ? props.jobId : "";
|
|
645
|
+
const composed = [client, jobId.length > 0 ? `#${jobId}` : ""].filter((s) => s.length > 0).join(" ");
|
|
646
|
+
if (composed.length > 0)
|
|
647
|
+
return composed;
|
|
648
|
+
} else if (primaryLabel === "QuoteDocument") {
|
|
649
|
+
const ref = typeof props.ref === "string" ? props.ref : "";
|
|
650
|
+
if (ref.length > 0)
|
|
651
|
+
return ref;
|
|
652
|
+
} else if (primaryLabel === "InboundInvoice") {
|
|
653
|
+
const supplier = typeof props.supplier === "string" ? props.supplier : "";
|
|
654
|
+
const conf = typeof props.confirmationNumber === "string" ? props.confirmationNumber : "";
|
|
655
|
+
const composed = [supplier, conf.length > 0 ? `#${conf}` : ""].filter((s) => s.length > 0).join(" ");
|
|
656
|
+
if (composed.length > 0)
|
|
657
|
+
return composed;
|
|
658
|
+
} else if (primaryLabel === "WhatsAppGroup") {
|
|
659
|
+
const clientName = typeof props.clientName === "string" ? props.clientName : "";
|
|
660
|
+
if (clientName.length > 0)
|
|
661
|
+
return clientName;
|
|
618
662
|
}
|
|
619
663
|
for (const k of ["name", "title", "summary", "givenName", "subject", "text"]) {
|
|
620
664
|
const v = props[k];
|
|
@@ -1227,8 +1271,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1227
1271
|
};
|
|
1228
1272
|
|
|
1229
1273
|
// server/index.ts
|
|
1230
|
-
import { readFileSync as
|
|
1231
|
-
import { resolve as resolve31, join as
|
|
1274
|
+
import { readFileSync as readFileSync28, existsSync as existsSync30, watchFile } from "fs";
|
|
1275
|
+
import { resolve as resolve31, join as join26, basename as basename9 } from "path";
|
|
1232
1276
|
import { homedir as homedir3 } from "os";
|
|
1233
1277
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1234
1278
|
|
|
@@ -4871,6 +4915,10 @@ function crossesForeignAccountPartition(relPath, accountId) {
|
|
|
4871
4915
|
if (!ACCOUNT_UUID_RE.test(owner)) return false;
|
|
4872
4916
|
return owner !== accountId;
|
|
4873
4917
|
}
|
|
4918
|
+
function isWithinOwnAccountPartition(relPath, accountId) {
|
|
4919
|
+
const segs = relPath.split("/").filter(Boolean);
|
|
4920
|
+
return segs.length >= 2 && segs[0] === "accounts" && segs[1] === accountId;
|
|
4921
|
+
}
|
|
4874
4922
|
function resolveUnderRoot(raw, rootAbs, rootLabel) {
|
|
4875
4923
|
const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
|
|
4876
4924
|
const absolute = resolve5(rootAbs, cleaned);
|
|
@@ -4937,6 +4985,7 @@ var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
|
4937
4985
|
]);
|
|
4938
4986
|
var MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024;
|
|
4939
4987
|
var MAX_FILES_PER_MESSAGE = 5;
|
|
4988
|
+
var MAX_DATA_UPLOAD_BYTES = 2 * 1024 * 1024 * 1024;
|
|
4940
4989
|
var MAX_ZIP_UNCOMPRESSED_BYTES = 100 * 1024 * 1024;
|
|
4941
4990
|
function assertSupportedMime(mimeType) {
|
|
4942
4991
|
if (!SUPPORTED_MIME_TYPES.has(mimeType)) {
|
|
@@ -5176,8 +5225,8 @@ function webchatTurnTimeoutMs() {
|
|
|
5176
5225
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
5177
5226
|
}
|
|
5178
5227
|
function createChatRoutes(deps) {
|
|
5179
|
-
const
|
|
5180
|
-
|
|
5228
|
+
const app52 = new Hono();
|
|
5229
|
+
app52.post("/", async (c) => {
|
|
5181
5230
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
5182
5231
|
const contentType = c.req.header("content-type") ?? "";
|
|
5183
5232
|
const account = resolveAccount();
|
|
@@ -5400,7 +5449,7 @@ ${result.result.text}` : result.result.text;
|
|
|
5400
5449
|
}
|
|
5401
5450
|
});
|
|
5402
5451
|
});
|
|
5403
|
-
return
|
|
5452
|
+
return app52;
|
|
5404
5453
|
}
|
|
5405
5454
|
|
|
5406
5455
|
// server/routes/whatsapp.ts
|
|
@@ -6615,10 +6664,8 @@ function selectReaderChannelSessions(rows) {
|
|
|
6615
6664
|
// server/routes/admin/sidebar-sessions.ts
|
|
6616
6665
|
var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
|
|
6617
6666
|
var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
|
|
6618
|
-
var PUBLIC_ROLE = "public";
|
|
6619
6667
|
var ADMIN_ROLE = "admin";
|
|
6620
6668
|
var WEBCHAT_CHANNEL = "webchat";
|
|
6621
|
-
var WHATSAPP_CHANNEL = "whatsapp";
|
|
6622
6669
|
var app3 = new Hono();
|
|
6623
6670
|
function claudeConfigDir() {
|
|
6624
6671
|
return process.env.CLAUDE_CONFIG_DIR ?? null;
|
|
@@ -6836,7 +6883,6 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
6836
6883
|
const seenIds = /* @__PURE__ */ new Set();
|
|
6837
6884
|
let liveCount = 0;
|
|
6838
6885
|
let subagentCount = 0;
|
|
6839
|
-
let nonResumableCount = 0;
|
|
6840
6886
|
let archivedCount = 0;
|
|
6841
6887
|
let excludedChannelCount = 0;
|
|
6842
6888
|
const titleSourceCounts = { user: 0, ai: 0, "first-message": 0, prefix: 0 };
|
|
@@ -6870,7 +6916,6 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
6870
6916
|
excludedChannelCount += 1;
|
|
6871
6917
|
continue;
|
|
6872
6918
|
}
|
|
6873
|
-
const resumable = !(role === PUBLIC_ROLE && (sidecarChannel === WEBCHAT_CHANNEL || sidecarChannel === WHATSAPP_CHANNEL));
|
|
6874
6919
|
if (personId) personIdBySession.set(sessionId, personId);
|
|
6875
6920
|
if (adminUserId && role === ADMIN_ROLE && sidecarChannel === WEBCHAT_CHANNEL) {
|
|
6876
6921
|
adminUserIdBySession.set(sessionId, adminUserId);
|
|
@@ -6885,14 +6930,12 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
6885
6930
|
pid,
|
|
6886
6931
|
projectDir,
|
|
6887
6932
|
bridgeIds,
|
|
6888
|
-
resumable,
|
|
6889
6933
|
archived,
|
|
6890
6934
|
channel: resolved.channel,
|
|
6891
6935
|
personName: null
|
|
6892
6936
|
});
|
|
6893
6937
|
if (live) liveCount += 1;
|
|
6894
6938
|
if (isSubagent) subagentCount += 1;
|
|
6895
|
-
if (!resumable) nonResumableCount += 1;
|
|
6896
6939
|
if (archived) archivedCount += 1;
|
|
6897
6940
|
}
|
|
6898
6941
|
let personNameCount = 0;
|
|
@@ -6923,7 +6966,7 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
6923
6966
|
}
|
|
6924
6967
|
rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
|
|
6925
6968
|
console.log(
|
|
6926
|
-
`[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount}
|
|
6969
|
+
`[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} excludedChannel=${excludedChannelCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
|
|
6927
6970
|
);
|
|
6928
6971
|
return c.json({ sessions: rows, accountId });
|
|
6929
6972
|
});
|
|
@@ -7067,6 +7110,20 @@ function unwrapChannel(text) {
|
|
|
7067
7110
|
}
|
|
7068
7111
|
return source ? { text: inner, source } : { text: inner };
|
|
7069
7112
|
}
|
|
7113
|
+
var COMPOSED_ADMIN_FRAME = /^## Context\n([\s\S]*)\n\n## Instruction\n[\s\S]*$/;
|
|
7114
|
+
function rawFromComposedAdminFrame(text) {
|
|
7115
|
+
return text.match(COMPOSED_ADMIN_FRAME)?.[1];
|
|
7116
|
+
}
|
|
7117
|
+
function operatorInboundTurn(u, ts) {
|
|
7118
|
+
const rawBody = rawFromComposedAdminFrame(u.text);
|
|
7119
|
+
return {
|
|
7120
|
+
kind: "operator-inbound",
|
|
7121
|
+
text: u.text,
|
|
7122
|
+
ts,
|
|
7123
|
+
...u.source ? { source: u.source } : {},
|
|
7124
|
+
...rawBody !== void 0 ? { rawBody } : {}
|
|
7125
|
+
};
|
|
7126
|
+
}
|
|
7070
7127
|
function asString(content) {
|
|
7071
7128
|
return typeof content === "string" ? content : null;
|
|
7072
7129
|
}
|
|
@@ -7129,6 +7186,14 @@ function lastTurnTs(turns) {
|
|
|
7129
7186
|
function isModelGated(turns) {
|
|
7130
7187
|
return turns.some((t) => t.kind === "agent-error" && t.code === "model_unavailable");
|
|
7131
7188
|
}
|
|
7189
|
+
function renderOrSuppressChannelInbound(u, ts, out, queuedPendingSuppress) {
|
|
7190
|
+
const armed = queuedPendingSuppress.get(u.text) ?? 0;
|
|
7191
|
+
if (armed > 0) {
|
|
7192
|
+
queuedPendingSuppress.set(u.text, armed - 1);
|
|
7193
|
+
} else {
|
|
7194
|
+
out.push(operatorInboundTurn(u, ts));
|
|
7195
|
+
}
|
|
7196
|
+
}
|
|
7132
7197
|
function parseTranscript(lines) {
|
|
7133
7198
|
const out = [];
|
|
7134
7199
|
const queuedPendingSuppress = /* @__PURE__ */ new Map();
|
|
@@ -7160,7 +7225,7 @@ function parseTranscript(lines) {
|
|
|
7160
7225
|
const content = asString(row.content);
|
|
7161
7226
|
if (content !== null && CHANNEL_WRAPPER2.test(content)) {
|
|
7162
7227
|
const u = unwrapChannel(content);
|
|
7163
|
-
out.push(
|
|
7228
|
+
out.push(operatorInboundTurn(u, ts));
|
|
7164
7229
|
queuedPendingSuppress.set(u.text, (queuedPendingSuppress.get(u.text) ?? 0) + 1);
|
|
7165
7230
|
}
|
|
7166
7231
|
continue;
|
|
@@ -7169,13 +7234,7 @@ function parseTranscript(lines) {
|
|
|
7169
7234
|
const att = row.attachment;
|
|
7170
7235
|
const isChannelQueued = att?.type === "queued_command" && att.isMeta === true && typeof att.origin === "object" && att.origin !== null && att.origin.kind === "channel" && typeof att.prompt === "string";
|
|
7171
7236
|
if (isChannelQueued) {
|
|
7172
|
-
|
|
7173
|
-
const armed = queuedPendingSuppress.get(u.text) ?? 0;
|
|
7174
|
-
if (armed > 0) {
|
|
7175
|
-
queuedPendingSuppress.set(u.text, armed - 1);
|
|
7176
|
-
} else {
|
|
7177
|
-
out.push({ kind: "operator-inbound", text: u.text, ts, ...u.source ? { source: u.source } : {} });
|
|
7178
|
-
}
|
|
7237
|
+
renderOrSuppressChannelInbound(unwrapChannel(att.prompt), ts, out, queuedPendingSuppress);
|
|
7179
7238
|
}
|
|
7180
7239
|
continue;
|
|
7181
7240
|
}
|
|
@@ -7189,8 +7248,7 @@ function parseTranscript(lines) {
|
|
|
7189
7248
|
if (CLI_MARKER_PREFIXES2.some((p) => text.startsWith(p))) continue;
|
|
7190
7249
|
const isChannel = row.isMeta === true && typeof row.origin === "object" && row.origin !== null && row.origin.kind === "channel";
|
|
7191
7250
|
if (isChannel) {
|
|
7192
|
-
|
|
7193
|
-
out.push({ kind: "operator-inbound", text: u.text, ts, ...u.source ? { source: u.source } : {} });
|
|
7251
|
+
renderOrSuppressChannelInbound(unwrapChannel(text), ts, out, queuedPendingSuppress);
|
|
7194
7252
|
} else {
|
|
7195
7253
|
out.push({ kind: "operator-typed", text, ts });
|
|
7196
7254
|
}
|
|
@@ -7652,8 +7710,8 @@ var public_reader_default = app5;
|
|
|
7652
7710
|
|
|
7653
7711
|
// server/routes/webchat.ts
|
|
7654
7712
|
import { basename as basename4, dirname as dirname3 } from "path";
|
|
7655
|
-
import { join as
|
|
7656
|
-
import { existsSync as
|
|
7713
|
+
import { join as join14 } from "path";
|
|
7714
|
+
import { existsSync as existsSync9, readdirSync as readdirSync8, readFileSync as readFileSync14, renameSync as renameSync3, statSync as statSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
7657
7715
|
|
|
7658
7716
|
// server/canonical-webchat-override.ts
|
|
7659
7717
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync5, renameSync } from "fs";
|
|
@@ -7690,16 +7748,141 @@ function adminSessionIdFor(accountId, senderId, personId) {
|
|
|
7690
7748
|
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
|
|
7691
7749
|
}
|
|
7692
7750
|
|
|
7751
|
+
// ../services/claude-session-manager/src/sidecar-store.ts
|
|
7752
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readdirSync as readdirSync7, readFileSync as readFileSync13, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
|
|
7753
|
+
import { join as join13 } from "path";
|
|
7754
|
+
function escapeRegExp(s) {
|
|
7755
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7756
|
+
}
|
|
7757
|
+
function createSidecarStore(config) {
|
|
7758
|
+
const { suffix, validate: validate2 } = config;
|
|
7759
|
+
const suffixRe = new RegExp(`${escapeRegExp(suffix)}$`);
|
|
7760
|
+
function pathFor(sessionsDir, id) {
|
|
7761
|
+
return join13(sessionsDir, `${id}${suffix}`);
|
|
7762
|
+
}
|
|
7763
|
+
function write(sessionsDir, id, record) {
|
|
7764
|
+
mkdirSync2(sessionsDir, { recursive: true });
|
|
7765
|
+
const path2 = pathFor(sessionsDir, id);
|
|
7766
|
+
const tmp = `${path2}.tmp.${process.pid}`;
|
|
7767
|
+
try {
|
|
7768
|
+
writeFileSync6(tmp, JSON.stringify(record), "utf8");
|
|
7769
|
+
renameSync2(tmp, path2);
|
|
7770
|
+
return { ok: true };
|
|
7771
|
+
} catch (error) {
|
|
7772
|
+
try {
|
|
7773
|
+
if (existsSync8(tmp)) unlinkSync(tmp);
|
|
7774
|
+
} catch {
|
|
7775
|
+
}
|
|
7776
|
+
return { ok: false, error };
|
|
7777
|
+
}
|
|
7778
|
+
}
|
|
7779
|
+
function readFileAt(path2) {
|
|
7780
|
+
let raw;
|
|
7781
|
+
try {
|
|
7782
|
+
raw = readFileSync13(path2, "utf8");
|
|
7783
|
+
} catch {
|
|
7784
|
+
return null;
|
|
7785
|
+
}
|
|
7786
|
+
try {
|
|
7787
|
+
return validate2(JSON.parse(raw));
|
|
7788
|
+
} catch {
|
|
7789
|
+
return null;
|
|
7790
|
+
}
|
|
7791
|
+
}
|
|
7792
|
+
function read(sessionsDir, id) {
|
|
7793
|
+
return readFileAt(pathFor(sessionsDir, id));
|
|
7794
|
+
}
|
|
7795
|
+
function readAll(sessionsDir, onSkip) {
|
|
7796
|
+
let names;
|
|
7797
|
+
try {
|
|
7798
|
+
names = readdirSync7(sessionsDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name);
|
|
7799
|
+
} catch {
|
|
7800
|
+
return [];
|
|
7801
|
+
}
|
|
7802
|
+
const out = [];
|
|
7803
|
+
for (const name of names) {
|
|
7804
|
+
if (!suffixRe.test(name)) continue;
|
|
7805
|
+
const path2 = join13(sessionsDir, name);
|
|
7806
|
+
let raw;
|
|
7807
|
+
try {
|
|
7808
|
+
raw = readFileSync13(path2, "utf8");
|
|
7809
|
+
} catch {
|
|
7810
|
+
onSkip?.(name, "unreadable");
|
|
7811
|
+
continue;
|
|
7812
|
+
}
|
|
7813
|
+
let parsed;
|
|
7814
|
+
try {
|
|
7815
|
+
parsed = JSON.parse(raw);
|
|
7816
|
+
} catch {
|
|
7817
|
+
onSkip?.(name, "unreadable");
|
|
7818
|
+
continue;
|
|
7819
|
+
}
|
|
7820
|
+
const record = validate2(parsed);
|
|
7821
|
+
if (record) out.push(record);
|
|
7822
|
+
else onSkip?.(name, "invalid");
|
|
7823
|
+
}
|
|
7824
|
+
return out;
|
|
7825
|
+
}
|
|
7826
|
+
function clear(sessionsDir, id) {
|
|
7827
|
+
const path2 = pathFor(sessionsDir, id);
|
|
7828
|
+
try {
|
|
7829
|
+
if (existsSync8(path2)) {
|
|
7830
|
+
unlinkSync(path2);
|
|
7831
|
+
return { ok: true, removed: true };
|
|
7832
|
+
}
|
|
7833
|
+
return { ok: true, removed: false };
|
|
7834
|
+
} catch (error) {
|
|
7835
|
+
return { ok: false, error };
|
|
7836
|
+
}
|
|
7837
|
+
}
|
|
7838
|
+
return { pathFor, write, read, readAll, clear };
|
|
7839
|
+
}
|
|
7840
|
+
|
|
7841
|
+
// ../services/claude-session-manager/src/reseat-ledger.ts
|
|
7842
|
+
var RESEAT_CHAIN_MAX_DEPTH = 16;
|
|
7843
|
+
var store = createSidecarStore({
|
|
7844
|
+
suffix: ".reseated.json",
|
|
7845
|
+
validate: (raw) => {
|
|
7846
|
+
if (!raw || typeof raw !== "object") return null;
|
|
7847
|
+
const r = raw;
|
|
7848
|
+
if (typeof r.sourceSessionId === "string" && typeof r.forkSessionId === "string" && typeof r.at === "number") {
|
|
7849
|
+
return { sourceSessionId: r.sourceSessionId, forkSessionId: r.forkSessionId, at: r.at };
|
|
7850
|
+
}
|
|
7851
|
+
return null;
|
|
7852
|
+
}
|
|
7853
|
+
});
|
|
7854
|
+
function readAllReseatMarkers(sessionsDir, logger) {
|
|
7855
|
+
return store.readAll(sessionsDir, (name) => logger(`[reseat-ledger] skip-unreadable file=${name}`));
|
|
7856
|
+
}
|
|
7857
|
+
function resolveBridgeSource(sessionsDir, forkSessionId, jsonlExists, maxDepth = RESEAT_CHAIN_MAX_DEPTH) {
|
|
7858
|
+
const sourceOf = /* @__PURE__ */ new Map();
|
|
7859
|
+
for (const m of readAllReseatMarkers(sessionsDir, () => {
|
|
7860
|
+
})) {
|
|
7861
|
+
sourceOf.set(m.forkSessionId, m.sourceSessionId);
|
|
7862
|
+
}
|
|
7863
|
+
const visited = /* @__PURE__ */ new Set([forkSessionId]);
|
|
7864
|
+
let current = forkSessionId;
|
|
7865
|
+
for (let depth = 0; depth < maxDepth; depth++) {
|
|
7866
|
+
const source = sourceOf.get(current);
|
|
7867
|
+
if (source === void 0) return null;
|
|
7868
|
+
if (visited.has(source)) return null;
|
|
7869
|
+
visited.add(source);
|
|
7870
|
+
if (jsonlExists(source)) return source;
|
|
7871
|
+
current = source;
|
|
7872
|
+
}
|
|
7873
|
+
return null;
|
|
7874
|
+
}
|
|
7875
|
+
|
|
7693
7876
|
// server/routes/webchat.ts
|
|
7694
7877
|
var WEBCHAT_ADMIN_KEY = "webchat-admin";
|
|
7695
7878
|
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
7696
7879
|
function locateSession(sessionId) {
|
|
7697
7880
|
const cfg = claudeConfigDir();
|
|
7698
7881
|
if (!cfg) return { projectDir: null, channel: null };
|
|
7699
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
7882
|
+
for (const { path: path2 } of enumerateJsonls(join14(cfg, "projects"))) {
|
|
7700
7883
|
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
7701
7884
|
const dir = dirname3(path2);
|
|
7702
|
-
const meta = readSidecarMeta(
|
|
7885
|
+
const meta = readSidecarMeta(join14(dir, `${sessionId}.meta.json`));
|
|
7703
7886
|
return { projectDir: dir, channel: meta.channel };
|
|
7704
7887
|
}
|
|
7705
7888
|
}
|
|
@@ -7708,16 +7891,16 @@ function locateSession(sessionId) {
|
|
|
7708
7891
|
function locateSidecar(sessionId) {
|
|
7709
7892
|
const cfg = claudeConfigDir();
|
|
7710
7893
|
if (!cfg) return null;
|
|
7711
|
-
const projectsRoot =
|
|
7894
|
+
const projectsRoot = join14(cfg, "projects");
|
|
7712
7895
|
let slugs;
|
|
7713
7896
|
try {
|
|
7714
|
-
slugs =
|
|
7897
|
+
slugs = readdirSync8(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
7715
7898
|
} catch {
|
|
7716
7899
|
return null;
|
|
7717
7900
|
}
|
|
7718
7901
|
for (const slug of slugs) {
|
|
7719
|
-
const metaPath =
|
|
7720
|
-
if (
|
|
7902
|
+
const metaPath = join14(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
7903
|
+
if (existsSync9(metaPath)) {
|
|
7721
7904
|
return { channel: readSidecarMeta(metaPath).channel };
|
|
7722
7905
|
}
|
|
7723
7906
|
}
|
|
@@ -7726,6 +7909,14 @@ function locateSidecar(sessionId) {
|
|
|
7726
7909
|
function sessionSidecarExists(sessionId) {
|
|
7727
7910
|
return locateSidecar(sessionId) !== null;
|
|
7728
7911
|
}
|
|
7912
|
+
function jsonlSizeBytes(projectDir, sessionId) {
|
|
7913
|
+
if (projectDir === null) return null;
|
|
7914
|
+
try {
|
|
7915
|
+
return statSync6(join14(projectDir, `${sessionId}.jsonl`)).size;
|
|
7916
|
+
} catch {
|
|
7917
|
+
return null;
|
|
7918
|
+
}
|
|
7919
|
+
}
|
|
7729
7920
|
function conflictingBinding(channel) {
|
|
7730
7921
|
return channel !== null && channel !== "webchat" ? channel : null;
|
|
7731
7922
|
}
|
|
@@ -7786,14 +7977,38 @@ function readLevers(preResolved) {
|
|
|
7786
7977
|
leverMode: typeof mode === "string" && PERMISSION_MODE_VALUES.has(mode) ? mode : null
|
|
7787
7978
|
};
|
|
7788
7979
|
}
|
|
7789
|
-
function
|
|
7980
|
+
function latestAdminWebchatSessionId() {
|
|
7981
|
+
const cfg = claudeConfigDir();
|
|
7982
|
+
if (!cfg) return null;
|
|
7983
|
+
let best = null;
|
|
7984
|
+
for (const { path: path2, isSubagent, archived } of enumerateJsonls(join14(cfg, "projects"))) {
|
|
7985
|
+
if (isSubagent || archived) continue;
|
|
7986
|
+
const id = basename4(path2).slice(0, -".jsonl".length);
|
|
7987
|
+
const meta = readSidecarMeta(join14(dirname3(path2), `${id}.meta.json`));
|
|
7988
|
+
if (meta.role !== "admin" || meta.channel !== "webchat") continue;
|
|
7989
|
+
let mtimeMs;
|
|
7990
|
+
try {
|
|
7991
|
+
mtimeMs = statSync6(path2).mtimeMs;
|
|
7992
|
+
} catch {
|
|
7993
|
+
continue;
|
|
7994
|
+
}
|
|
7995
|
+
if (best === null || mtimeMs > best.mtimeMs) best = { id, mtimeMs };
|
|
7996
|
+
}
|
|
7997
|
+
return best === null ? null : best.id;
|
|
7998
|
+
}
|
|
7999
|
+
function overrideKnownNonArchived(id) {
|
|
8000
|
+
const { projectDir } = locateSession(id);
|
|
8001
|
+
if (projectDir === null) return sessionSidecarExists(id);
|
|
8002
|
+
return basename4(projectDir) !== "archive";
|
|
8003
|
+
}
|
|
8004
|
+
function resolveCanonical(accountId, accountDir) {
|
|
8005
|
+
const latest = latestAdminWebchatSessionId();
|
|
8006
|
+
if (latest !== null) return { sessionId: latest, source: "latest" };
|
|
7790
8007
|
if (accountDir) {
|
|
7791
8008
|
const override = readCanonicalOverrideId(accountDir);
|
|
7792
|
-
if (override && (
|
|
7793
|
-
return override;
|
|
7794
|
-
}
|
|
8009
|
+
if (override && overrideKnownNonArchived(override)) return { sessionId: override, source: "override" };
|
|
7795
8010
|
}
|
|
7796
|
-
return adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY);
|
|
8011
|
+
return { sessionId: adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY), source: "canonical-empty" };
|
|
7797
8012
|
}
|
|
7798
8013
|
var REAPPLY_TIMEOUT_MS = 1500;
|
|
7799
8014
|
async function reapplyLeversViaManager() {
|
|
@@ -7813,9 +8028,11 @@ async function reapplyLeversViaManager() {
|
|
|
7813
8028
|
return false;
|
|
7814
8029
|
}
|
|
7815
8030
|
}
|
|
8031
|
+
var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
|
|
8032
|
+
var sendSeq = 0;
|
|
7816
8033
|
function createWebchatRoutes(deps) {
|
|
7817
|
-
const
|
|
7818
|
-
|
|
8034
|
+
const app52 = new Hono();
|
|
8035
|
+
app52.post("/send", requireAdminSession, async (c) => {
|
|
7819
8036
|
let accountId;
|
|
7820
8037
|
try {
|
|
7821
8038
|
accountId = resolvePlatformAccountId();
|
|
@@ -7864,6 +8081,10 @@ function createWebchatRoutes(deps) {
|
|
|
7864
8081
|
}
|
|
7865
8082
|
let deliveryKey = WEBCHAT_ADMIN_KEY;
|
|
7866
8083
|
let deliverySessionId;
|
|
8084
|
+
if (target === void 0) {
|
|
8085
|
+
const latest = latestAdminWebchatSessionId();
|
|
8086
|
+
if (latest !== null) target = latest;
|
|
8087
|
+
}
|
|
7867
8088
|
if (target !== void 0) {
|
|
7868
8089
|
let { projectDir, channel } = locateSession(target);
|
|
7869
8090
|
if (projectDir === null) {
|
|
@@ -7944,9 +8165,33 @@ ${note}` : note;
|
|
|
7944
8165
|
} else {
|
|
7945
8166
|
await deps.handleInbound({ role: "admin", accountId, key: deliveryKey, text });
|
|
7946
8167
|
}
|
|
8168
|
+
const sendId = ++sendSeq;
|
|
8169
|
+
let turnSessionId = deliverySessionId;
|
|
8170
|
+
if (turnSessionId === void 0) {
|
|
8171
|
+
let canonAccount;
|
|
8172
|
+
try {
|
|
8173
|
+
canonAccount = resolveAccount();
|
|
8174
|
+
} catch {
|
|
8175
|
+
canonAccount = null;
|
|
8176
|
+
}
|
|
8177
|
+
turnSessionId = resolveCanonical(accountId, canonAccount?.accountDir ?? null).sessionId;
|
|
8178
|
+
}
|
|
8179
|
+
const keyDisplay2 = deliveryKey.startsWith("session:") ? deliveryKey.slice(0, "session:".length + 8) : WEBCHAT_ADMIN_KEY;
|
|
8180
|
+
const baseline = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
|
|
8181
|
+
console.error(`[webchat:inbound] op=send-accepted key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"}`);
|
|
8182
|
+
const turnTimer = setTimeout(() => {
|
|
8183
|
+
const now = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
|
|
8184
|
+
const grew = now !== null && (baseline === null || now > baseline);
|
|
8185
|
+
if (grew) {
|
|
8186
|
+
console.error(`[webchat:inbound] op=send-turned key=${keyDisplay2} sendId=${sendId} bytes=${now}`);
|
|
8187
|
+
} else {
|
|
8188
|
+
console.error(`[webchat:inbound] op=send-no-turn key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"}`);
|
|
8189
|
+
}
|
|
8190
|
+
}, WEBCHAT_SEND_TURN_WINDOW_MS);
|
|
8191
|
+
if (turnTimer.unref) turnTimer.unref();
|
|
7947
8192
|
return c.json({ ok: true });
|
|
7948
8193
|
});
|
|
7949
|
-
|
|
8194
|
+
app52.post("/settings", requireAdminSession, async (c) => {
|
|
7950
8195
|
const body = await c.req.json().catch(() => null);
|
|
7951
8196
|
const op = body?.op;
|
|
7952
8197
|
const value = body?.value;
|
|
@@ -7968,15 +8213,15 @@ ${note}` : note;
|
|
|
7968
8213
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-unresolved`);
|
|
7969
8214
|
return c.json({ error: "account unresolved" }, 503);
|
|
7970
8215
|
}
|
|
7971
|
-
const accountJsonPath =
|
|
8216
|
+
const accountJsonPath = join14(account.accountDir, "account.json");
|
|
7972
8217
|
try {
|
|
7973
|
-
const parsed = JSON.parse(
|
|
8218
|
+
const parsed = JSON.parse(readFileSync14(accountJsonPath, "utf8"));
|
|
7974
8219
|
if (op === "model") parsed.adminModel = value;
|
|
7975
8220
|
else if (op === "effort") parsed.effort = value;
|
|
7976
8221
|
else parsed.adminPermissionMode = value;
|
|
7977
8222
|
const tmp = `${accountJsonPath}.${process.pid}.tmp`;
|
|
7978
|
-
|
|
7979
|
-
|
|
8223
|
+
writeFileSync7(tmp, JSON.stringify(parsed, null, 2), "utf8");
|
|
8224
|
+
renameSync3(tmp, accountJsonPath);
|
|
7980
8225
|
} catch (err) {
|
|
7981
8226
|
const detail = err instanceof Error ? err.message : String(err);
|
|
7982
8227
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=write-failed detail=${detail}`);
|
|
@@ -7986,7 +8231,7 @@ ${note}` : note;
|
|
|
7986
8231
|
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
7987
8232
|
return c.json({ ok: true, settingsApplied });
|
|
7988
8233
|
});
|
|
7989
|
-
|
|
8234
|
+
app52.get("/session", requireAdminSession, async (c) => {
|
|
7990
8235
|
let accountId;
|
|
7991
8236
|
try {
|
|
7992
8237
|
accountId = resolvePlatformAccountId();
|
|
@@ -8001,9 +8246,26 @@ ${note}` : note;
|
|
|
8001
8246
|
return c.json({ error: "invalid session id" }, 400);
|
|
8002
8247
|
}
|
|
8003
8248
|
const { projectDir: projectDir2, channel } = locateSession(target);
|
|
8004
|
-
|
|
8249
|
+
let resolvedProjectDir = projectDir2;
|
|
8250
|
+
let transcriptSessionId = target;
|
|
8251
|
+
if (projectDir2 === null) {
|
|
8252
|
+
const cfg2 = claudeConfigDir();
|
|
8253
|
+
if (cfg2) {
|
|
8254
|
+
const source2 = resolveBridgeSource(
|
|
8255
|
+
join14(cfg2, "sessions"),
|
|
8256
|
+
target,
|
|
8257
|
+
(id) => locateSession(id).projectDir !== null
|
|
8258
|
+
);
|
|
8259
|
+
if (source2) {
|
|
8260
|
+
resolvedProjectDir = locateSession(source2).projectDir;
|
|
8261
|
+
transcriptSessionId = source2;
|
|
8262
|
+
console.log(`[chat-reseat] op=bridge fork=${target.slice(0, 8)} source=${source2.slice(0, 8)}`);
|
|
8263
|
+
}
|
|
8264
|
+
}
|
|
8265
|
+
}
|
|
8266
|
+
const known = resolvedProjectDir !== null || sessionSidecarExists(target);
|
|
8005
8267
|
const indicators2 = await fetchComposerIndicators(target);
|
|
8006
|
-
return c.json({ sessionId: target, projectDir:
|
|
8268
|
+
return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), ...indicators2, ...readLevers() });
|
|
8007
8269
|
}
|
|
8008
8270
|
let account;
|
|
8009
8271
|
try {
|
|
@@ -8011,11 +8273,15 @@ ${note}` : note;
|
|
|
8011
8273
|
} catch {
|
|
8012
8274
|
account = null;
|
|
8013
8275
|
}
|
|
8014
|
-
const sessionId =
|
|
8276
|
+
const { sessionId, source } = resolveCanonical(accountId, account?.accountDir ?? null);
|
|
8277
|
+
if (source === "latest" && account?.accountDir) {
|
|
8278
|
+
writeCanonicalOverrideId(account.accountDir, sessionId);
|
|
8279
|
+
}
|
|
8280
|
+
console.log(`[webchat:inbound] op=session-resolve key=${sessionId.slice(0, 8)} source=${source}`);
|
|
8015
8281
|
const cfg = claudeConfigDir();
|
|
8016
8282
|
let projectDir = null;
|
|
8017
8283
|
if (cfg) {
|
|
8018
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
8284
|
+
for (const { path: path2 } of enumerateJsonls(join14(cfg, "projects"))) {
|
|
8019
8285
|
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
8020
8286
|
projectDir = dirname3(path2);
|
|
8021
8287
|
break;
|
|
@@ -8023,17 +8289,17 @@ ${note}` : note;
|
|
|
8023
8289
|
}
|
|
8024
8290
|
}
|
|
8025
8291
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
8026
|
-
return c.json({ sessionId, projectDir, ...indicators, ...readLevers(account) });
|
|
8292
|
+
return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), ...indicators, ...readLevers(account) });
|
|
8027
8293
|
});
|
|
8028
|
-
return
|
|
8294
|
+
return app52;
|
|
8029
8295
|
}
|
|
8030
8296
|
|
|
8031
8297
|
// server/routes/webchat-greeting.ts
|
|
8032
8298
|
import { resolve as resolve13 } from "path";
|
|
8033
8299
|
|
|
8034
8300
|
// app/lib/claude-agent/specialist-roster.ts
|
|
8035
|
-
import { existsSync as
|
|
8036
|
-
import { join as
|
|
8301
|
+
import { existsSync as existsSync10, readFileSync as readFileSync15, readdirSync as readdirSync9 } from "fs";
|
|
8302
|
+
import { join as join15 } from "path";
|
|
8037
8303
|
function field(fm, name) {
|
|
8038
8304
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
8039
8305
|
if (!m) return null;
|
|
@@ -8044,15 +8310,15 @@ function field(fm, name) {
|
|
|
8044
8310
|
return value || null;
|
|
8045
8311
|
}
|
|
8046
8312
|
function readSpecialistRoster(specialistsDir) {
|
|
8047
|
-
if (!
|
|
8048
|
-
const entries =
|
|
8313
|
+
if (!existsSync10(specialistsDir)) return { specialists: [], skipped: [] };
|
|
8314
|
+
const entries = readdirSync9(specialistsDir);
|
|
8049
8315
|
const specialists = [];
|
|
8050
8316
|
const skipped = [];
|
|
8051
8317
|
for (const file of entries.sort()) {
|
|
8052
8318
|
if (!file.endsWith(".md")) continue;
|
|
8053
8319
|
let raw;
|
|
8054
8320
|
try {
|
|
8055
|
-
raw =
|
|
8321
|
+
raw = readFileSync15(join15(specialistsDir, file), "utf-8");
|
|
8056
8322
|
} catch (err) {
|
|
8057
8323
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
8058
8324
|
continue;
|
|
@@ -8169,8 +8435,8 @@ var webchat_greeting_default = app6;
|
|
|
8169
8435
|
|
|
8170
8436
|
// server/routes/telegram.ts
|
|
8171
8437
|
import { homedir } from "os";
|
|
8172
|
-
import { resolve as resolve15, join as
|
|
8173
|
-
import { existsSync as
|
|
8438
|
+
import { resolve as resolve15, join as join16 } from "path";
|
|
8439
|
+
import { existsSync as existsSync11, readFileSync as readFileSync16 } from "fs";
|
|
8174
8440
|
|
|
8175
8441
|
// app/lib/channel-pty-bridge/bridge.ts
|
|
8176
8442
|
import { resolve as resolve14 } from "path";
|
|
@@ -9058,10 +9324,10 @@ var TAG23 = "[telegram-inbound]";
|
|
|
9058
9324
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
9059
9325
|
function configDirName() {
|
|
9060
9326
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve15(process.cwd(), "..");
|
|
9061
|
-
const brandPath =
|
|
9062
|
-
if (
|
|
9327
|
+
const brandPath = join16(platformRoot2, "config", "brand.json");
|
|
9328
|
+
if (existsSync11(brandPath)) {
|
|
9063
9329
|
try {
|
|
9064
|
-
return JSON.parse(
|
|
9330
|
+
return JSON.parse(readFileSync16(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
9065
9331
|
} catch {
|
|
9066
9332
|
}
|
|
9067
9333
|
}
|
|
@@ -9093,11 +9359,11 @@ app7.post("/", async (c) => {
|
|
|
9093
9359
|
return c.json({ ok: false }, 400);
|
|
9094
9360
|
}
|
|
9095
9361
|
const sp = secretPath(botType);
|
|
9096
|
-
if (!
|
|
9362
|
+
if (!existsSync11(sp)) {
|
|
9097
9363
|
console.error(`${TAG23} op=reject reason=no-secret-file botType=${botType}`);
|
|
9098
9364
|
return c.json({ ok: false }, 401);
|
|
9099
9365
|
}
|
|
9100
|
-
const expected =
|
|
9366
|
+
const expected = readFileSync16(sp, "utf-8").trim();
|
|
9101
9367
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
9102
9368
|
if (got !== expected) {
|
|
9103
9369
|
console.error(`${TAG23} op=reject reason=bad-secret botType=${botType}`);
|
|
@@ -9160,12 +9426,12 @@ var telegram_default = app7;
|
|
|
9160
9426
|
|
|
9161
9427
|
// server/routes/onboarding.ts
|
|
9162
9428
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
|
|
9163
|
-
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as
|
|
9429
|
+
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeFileSync9, writeSync, existsSync as existsSync13, readFileSync as readFileSync18, unlinkSync as unlinkSync2 } from "fs";
|
|
9164
9430
|
import { createHash as createHash3, randomUUID as randomUUID8 } from "crypto";
|
|
9165
9431
|
|
|
9166
9432
|
// ../lib/admins-write/src/index.ts
|
|
9167
|
-
import { existsSync as
|
|
9168
|
-
import { dirname as dirname4, join as
|
|
9433
|
+
import { existsSync as existsSync12, readFileSync as readFileSync17, writeFileSync as writeFileSync8, renameSync as renameSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync10, statSync as statSync7 } from "fs";
|
|
9434
|
+
import { dirname as dirname4, join as join17 } from "path";
|
|
9169
9435
|
function logLine(input, result) {
|
|
9170
9436
|
const userIdShort = input.userId.slice(0, 8);
|
|
9171
9437
|
console.error(
|
|
@@ -9173,17 +9439,17 @@ function logLine(input, result) {
|
|
|
9173
9439
|
);
|
|
9174
9440
|
}
|
|
9175
9441
|
function writeFileAtomic(filePath, contents, mode) {
|
|
9176
|
-
|
|
9442
|
+
mkdirSync3(dirname4(filePath), { recursive: true });
|
|
9177
9443
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
9178
|
-
|
|
9179
|
-
|
|
9444
|
+
writeFileSync8(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
9445
|
+
renameSync4(tempPath, filePath);
|
|
9180
9446
|
}
|
|
9181
9447
|
function writeAdminEntry(input) {
|
|
9182
9448
|
const result = { usersJsonResult: "noop", accountJsonResult: "noop" };
|
|
9183
9449
|
try {
|
|
9184
9450
|
let users = [];
|
|
9185
|
-
if (
|
|
9186
|
-
const raw =
|
|
9451
|
+
if (existsSync12(input.usersFile)) {
|
|
9452
|
+
const raw = readFileSync17(input.usersFile, "utf-8").trim();
|
|
9187
9453
|
if (raw) {
|
|
9188
9454
|
const parsed = JSON.parse(raw);
|
|
9189
9455
|
if (!Array.isArray(parsed)) {
|
|
@@ -9207,11 +9473,11 @@ function writeAdminEntry(input) {
|
|
|
9207
9473
|
return result;
|
|
9208
9474
|
}
|
|
9209
9475
|
try {
|
|
9210
|
-
const accountJsonPath =
|
|
9211
|
-
if (!
|
|
9476
|
+
const accountJsonPath = join17(input.accountDir, "account.json");
|
|
9477
|
+
if (!existsSync12(accountJsonPath)) {
|
|
9212
9478
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
9213
9479
|
}
|
|
9214
|
-
const config = JSON.parse(
|
|
9480
|
+
const config = JSON.parse(readFileSync17(accountJsonPath, "utf-8"));
|
|
9215
9481
|
const admins = config.admins ?? [];
|
|
9216
9482
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
9217
9483
|
result.accountJsonResult = "noop";
|
|
@@ -9235,9 +9501,9 @@ function checkAdminAuthInvariant(input) {
|
|
|
9235
9501
|
usersWithoutAccount: []
|
|
9236
9502
|
};
|
|
9237
9503
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
9238
|
-
if (
|
|
9504
|
+
if (existsSync12(input.usersFile)) {
|
|
9239
9505
|
try {
|
|
9240
|
-
const raw =
|
|
9506
|
+
const raw = readFileSync17(input.usersFile, "utf-8").trim();
|
|
9241
9507
|
if (raw) {
|
|
9242
9508
|
const users = JSON.parse(raw);
|
|
9243
9509
|
for (const u of users) {
|
|
@@ -9250,10 +9516,10 @@ function checkAdminAuthInvariant(input) {
|
|
|
9250
9516
|
}
|
|
9251
9517
|
}
|
|
9252
9518
|
const accountUserIds = /* @__PURE__ */ new Set();
|
|
9253
|
-
if (
|
|
9519
|
+
if (existsSync12(input.accountsDir)) {
|
|
9254
9520
|
let entries;
|
|
9255
9521
|
try {
|
|
9256
|
-
entries =
|
|
9522
|
+
entries = readdirSync10(input.accountsDir);
|
|
9257
9523
|
} catch (err) {
|
|
9258
9524
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9259
9525
|
console.error(`[${input.tag}] accounts-dir unreadable accountsDir=${input.accountsDir} error=${msg}`);
|
|
@@ -9262,17 +9528,17 @@ function checkAdminAuthInvariant(input) {
|
|
|
9262
9528
|
}
|
|
9263
9529
|
for (const entry of entries) {
|
|
9264
9530
|
if (entry.startsWith(".")) continue;
|
|
9265
|
-
const accountDir =
|
|
9531
|
+
const accountDir = join17(input.accountsDir, entry);
|
|
9266
9532
|
try {
|
|
9267
|
-
if (!
|
|
9533
|
+
if (!statSync7(accountDir).isDirectory()) continue;
|
|
9268
9534
|
} catch {
|
|
9269
9535
|
continue;
|
|
9270
9536
|
}
|
|
9271
|
-
const accountJsonPath =
|
|
9272
|
-
if (!
|
|
9537
|
+
const accountJsonPath = join17(accountDir, "account.json");
|
|
9538
|
+
if (!existsSync12(accountJsonPath)) continue;
|
|
9273
9539
|
let admins = [];
|
|
9274
9540
|
try {
|
|
9275
|
-
const config = JSON.parse(
|
|
9541
|
+
const config = JSON.parse(readFileSync17(accountJsonPath, "utf-8"));
|
|
9276
9542
|
admins = config.admins ?? [];
|
|
9277
9543
|
} catch (err) {
|
|
9278
9544
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -9312,8 +9578,8 @@ function hashPin2(pin) {
|
|
|
9312
9578
|
return createHash3("sha256").update(pin).digest("hex");
|
|
9313
9579
|
}
|
|
9314
9580
|
function readUsersFile2() {
|
|
9315
|
-
if (!
|
|
9316
|
-
const raw =
|
|
9581
|
+
if (!existsSync13(USERS_FILE)) return null;
|
|
9582
|
+
const raw = readFileSync18(USERS_FILE, "utf-8").trim();
|
|
9317
9583
|
if (!raw) return [];
|
|
9318
9584
|
return JSON.parse(raw);
|
|
9319
9585
|
}
|
|
@@ -9366,7 +9632,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
9366
9632
|
} catch (err) {
|
|
9367
9633
|
logoutError = err instanceof Error ? err.message : String(err);
|
|
9368
9634
|
}
|
|
9369
|
-
const credentialsPresent =
|
|
9635
|
+
const credentialsPresent = existsSync13(CLAUDE_CREDENTIALS_FILE);
|
|
9370
9636
|
const ranMs = Date.now() - start;
|
|
9371
9637
|
console.log(`[onboarding] op=claude-logout credentialsPresent=${credentialsPresent} ranMs=${ranMs} logoutError=${logoutError ? JSON.stringify(logoutError.slice(0, 120)) : "none"}`);
|
|
9372
9638
|
return c.json({ logged_out: !credentialsPresent });
|
|
@@ -9384,7 +9650,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
9384
9650
|
return c.json({ launched: cdpReady });
|
|
9385
9651
|
}
|
|
9386
9652
|
ensureLogDir();
|
|
9387
|
-
|
|
9653
|
+
writeFileSync9(logPath("claude-auth"), "");
|
|
9388
9654
|
const claudeAuthLogFd = openSync3(logPath("claude-auth"), "a");
|
|
9389
9655
|
const onClaudeOutput = (chunk) => writeSync(claudeAuthLogFd, chunk);
|
|
9390
9656
|
if (process.platform === "darwin") {
|
|
@@ -9473,9 +9739,9 @@ app8.post("/set-pin", async (c) => {
|
|
|
9473
9739
|
console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
|
|
9474
9740
|
if (process.platform === "linux") {
|
|
9475
9741
|
let installOwner = null;
|
|
9476
|
-
if (
|
|
9742
|
+
if (existsSync13(INSTALL_OWNER_FILE)) {
|
|
9477
9743
|
try {
|
|
9478
|
-
const raw =
|
|
9744
|
+
const raw = readFileSync18(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
9479
9745
|
if (raw.length > 0) installOwner = raw;
|
|
9480
9746
|
} catch (err) {
|
|
9481
9747
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -9545,10 +9811,10 @@ app8.delete("/set-pin", async (c) => {
|
|
|
9545
9811
|
}
|
|
9546
9812
|
const remaining = users.filter((u) => u.userId !== matchedUser.userId);
|
|
9547
9813
|
if (remaining.length === 0) {
|
|
9548
|
-
|
|
9814
|
+
unlinkSync2(USERS_FILE);
|
|
9549
9815
|
console.log(`[set-pin] cleared users.json (last entry removed): userId=${matchedUser.userId.slice(0, 8)}\u2026`);
|
|
9550
9816
|
} else {
|
|
9551
|
-
|
|
9817
|
+
writeFileSync9(USERS_FILE, JSON.stringify(remaining), { mode: 384 });
|
|
9552
9818
|
console.log(`[set-pin] removed entry from users.json: userId=${matchedUser.userId.slice(0, 8)}\u2026 remaining=${remaining.length}`);
|
|
9553
9819
|
}
|
|
9554
9820
|
return c.json({ ok: true });
|
|
@@ -9556,9 +9822,9 @@ app8.delete("/set-pin", async (c) => {
|
|
|
9556
9822
|
var onboarding_default = app8;
|
|
9557
9823
|
|
|
9558
9824
|
// server/routes/client-error.ts
|
|
9559
|
-
import { appendFileSync, existsSync as
|
|
9560
|
-
import { join as
|
|
9561
|
-
var CLIENT_ERRORS_LOG =
|
|
9825
|
+
import { appendFileSync, existsSync as existsSync14, renameSync as renameSync5, statSync as statSync8 } from "fs";
|
|
9826
|
+
import { join as join18 } from "path";
|
|
9827
|
+
var CLIENT_ERRORS_LOG = join18(LOG_DIR, "client-errors.log");
|
|
9562
9828
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
9563
9829
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
9564
9830
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -9601,10 +9867,10 @@ function stackHead(stack) {
|
|
|
9601
9867
|
}
|
|
9602
9868
|
function rotateIfNeeded() {
|
|
9603
9869
|
try {
|
|
9604
|
-
if (!
|
|
9605
|
-
const stats =
|
|
9870
|
+
if (!existsSync14(CLIENT_ERRORS_LOG)) return;
|
|
9871
|
+
const stats = statSync8(CLIENT_ERRORS_LOG);
|
|
9606
9872
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
9607
|
-
|
|
9873
|
+
renameSync5(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
9608
9874
|
} catch (err) {
|
|
9609
9875
|
console.error(`[client-error] log rotation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
9610
9876
|
}
|
|
@@ -9883,18 +10149,18 @@ app10.post("/", async (c) => {
|
|
|
9883
10149
|
var session_default = app10;
|
|
9884
10150
|
|
|
9885
10151
|
// server/routes/admin/logs.ts
|
|
9886
|
-
import { existsSync as
|
|
10152
|
+
import { existsSync as existsSync16, readdirSync as readdirSync11, readFileSync as readFileSync19, statSync as statSync9 } from "fs";
|
|
9887
10153
|
import { resolve as resolve16, basename as basename5 } from "path";
|
|
9888
10154
|
|
|
9889
10155
|
// app/lib/logs-read-resolve.ts
|
|
9890
|
-
import { existsSync as
|
|
9891
|
-
import { join as
|
|
10156
|
+
import { existsSync as existsSync15 } from "fs";
|
|
10157
|
+
import { join as join19 } from "path";
|
|
9892
10158
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
9893
10159
|
const tried = [filename];
|
|
9894
10160
|
const hits = [];
|
|
9895
10161
|
for (const dir of logDirs) {
|
|
9896
|
-
const fullPath =
|
|
9897
|
-
if (
|
|
10162
|
+
const fullPath = join19(dir, filename);
|
|
10163
|
+
if (existsSync15(fullPath)) {
|
|
9898
10164
|
hits.push({ path: fullPath, dir });
|
|
9899
10165
|
}
|
|
9900
10166
|
}
|
|
@@ -9922,8 +10188,8 @@ app11.get("/", async (c) => {
|
|
|
9922
10188
|
const filePath = resolve16(dir, safe);
|
|
9923
10189
|
searched.push(filePath);
|
|
9924
10190
|
try {
|
|
9925
|
-
const buffer =
|
|
9926
|
-
const onDiskBytes =
|
|
10191
|
+
const buffer = readFileSync19(filePath);
|
|
10192
|
+
const onDiskBytes = statSync9(filePath).size;
|
|
9927
10193
|
const headers = {
|
|
9928
10194
|
"Content-Type": "text/plain; charset=utf-8",
|
|
9929
10195
|
"Content-Length": String(buffer.byteLength)
|
|
@@ -9987,8 +10253,8 @@ app11.get("/", async (c) => {
|
|
|
9987
10253
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
9988
10254
|
try {
|
|
9989
10255
|
const filename = basename5(hit.path);
|
|
9990
|
-
const buffer =
|
|
9991
|
-
const onDiskBytes =
|
|
10256
|
+
const buffer = readFileSync19(hit.path);
|
|
10257
|
+
const onDiskBytes = statSync9(hit.path).size;
|
|
9992
10258
|
const headers = {
|
|
9993
10259
|
"Content-Type": "text/plain; charset=utf-8",
|
|
9994
10260
|
"Content-Length": String(buffer.byteLength)
|
|
@@ -10022,19 +10288,19 @@ app11.get("/", async (c) => {
|
|
|
10022
10288
|
const seen = /* @__PURE__ */ new Set();
|
|
10023
10289
|
const logs = {};
|
|
10024
10290
|
for (const dir of logDirs) {
|
|
10025
|
-
if (!
|
|
10291
|
+
if (!existsSync16(dir)) continue;
|
|
10026
10292
|
let files;
|
|
10027
10293
|
try {
|
|
10028
|
-
files =
|
|
10294
|
+
files = readdirSync11(dir).filter((f) => f.endsWith(".log"));
|
|
10029
10295
|
} catch (err) {
|
|
10030
10296
|
const reason = err instanceof Error ? err.message : String(err);
|
|
10031
10297
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
10032
10298
|
continue;
|
|
10033
10299
|
}
|
|
10034
|
-
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime:
|
|
10300
|
+
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync9(resolve16(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
10035
10301
|
seen.add(name);
|
|
10036
10302
|
try {
|
|
10037
|
-
const content =
|
|
10303
|
+
const content = readFileSync19(resolve16(dir, name));
|
|
10038
10304
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
10039
10305
|
logs[name] = tail.trim() || "(empty)";
|
|
10040
10306
|
} catch (err) {
|
|
@@ -10073,7 +10339,7 @@ var claude_info_default = app12;
|
|
|
10073
10339
|
|
|
10074
10340
|
// server/routes/admin/attachment.ts
|
|
10075
10341
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
10076
|
-
import { existsSync as
|
|
10342
|
+
import { existsSync as existsSync17 } from "fs";
|
|
10077
10343
|
import { resolve as resolve17 } from "path";
|
|
10078
10344
|
var app13 = new Hono();
|
|
10079
10345
|
app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
@@ -10087,11 +10353,11 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
10087
10353
|
return new Response("Not found", { status: 404 });
|
|
10088
10354
|
}
|
|
10089
10355
|
const dir = resolve17(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
|
|
10090
|
-
if (!
|
|
10356
|
+
if (!existsSync17(dir)) {
|
|
10091
10357
|
return new Response("Not found", { status: 404 });
|
|
10092
10358
|
}
|
|
10093
10359
|
const metaPath = resolve17(dir, `${attachmentId}.meta.json`);
|
|
10094
|
-
if (!
|
|
10360
|
+
if (!existsSync17(metaPath)) {
|
|
10095
10361
|
return new Response("Not found", { status: 404 });
|
|
10096
10362
|
}
|
|
10097
10363
|
let meta;
|
|
@@ -10119,23 +10385,23 @@ var attachment_default = app13;
|
|
|
10119
10385
|
|
|
10120
10386
|
// server/routes/admin/agents.ts
|
|
10121
10387
|
import { resolve as resolve18 } from "path";
|
|
10122
|
-
import { readdirSync as
|
|
10388
|
+
import { readdirSync as readdirSync12, readFileSync as readFileSync20, existsSync as existsSync18, rmSync } from "fs";
|
|
10123
10389
|
var app14 = new Hono();
|
|
10124
10390
|
app14.get("/", (c) => {
|
|
10125
10391
|
const account = resolveAccount();
|
|
10126
10392
|
if (!account) return c.json({ agents: [] });
|
|
10127
10393
|
const agentsDir = resolve18(account.accountDir, "agents");
|
|
10128
|
-
if (!
|
|
10394
|
+
if (!existsSync18(agentsDir)) return c.json({ agents: [] });
|
|
10129
10395
|
const agents = [];
|
|
10130
10396
|
try {
|
|
10131
|
-
const entries =
|
|
10397
|
+
const entries = readdirSync12(agentsDir, { withFileTypes: true });
|
|
10132
10398
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
10133
10399
|
if (!entry.isDirectory()) continue;
|
|
10134
10400
|
if (entry.name === "admin") continue;
|
|
10135
10401
|
const configPath2 = resolve18(agentsDir, entry.name, "config.json");
|
|
10136
|
-
if (!
|
|
10402
|
+
if (!existsSync18(configPath2)) continue;
|
|
10137
10403
|
try {
|
|
10138
|
-
const config = JSON.parse(
|
|
10404
|
+
const config = JSON.parse(readFileSync20(configPath2, "utf-8"));
|
|
10139
10405
|
agents.push({
|
|
10140
10406
|
slug: entry.name,
|
|
10141
10407
|
displayName: config.displayName ?? entry.name,
|
|
@@ -10162,7 +10428,7 @@ app14.delete("/:slug", async (c) => {
|
|
|
10162
10428
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
10163
10429
|
}
|
|
10164
10430
|
const agentDir = resolve18(account.accountDir, "agents", slug);
|
|
10165
|
-
if (!
|
|
10431
|
+
if (!existsSync18(agentDir)) {
|
|
10166
10432
|
return c.json({ error: "Agent not found" }, 404);
|
|
10167
10433
|
}
|
|
10168
10434
|
try {
|
|
@@ -10192,7 +10458,7 @@ app14.post("/:slug/project", async (c) => {
|
|
|
10192
10458
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
10193
10459
|
}
|
|
10194
10460
|
const agentDir = resolve18(account.accountDir, "agents", slug);
|
|
10195
|
-
if (!
|
|
10461
|
+
if (!existsSync18(agentDir)) {
|
|
10196
10462
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
10197
10463
|
}
|
|
10198
10464
|
try {
|
|
@@ -10208,7 +10474,7 @@ var agents_default = app14;
|
|
|
10208
10474
|
// server/routes/admin/sessions.ts
|
|
10209
10475
|
import crypto2 from "crypto";
|
|
10210
10476
|
import { resolve as resolvePath } from "path";
|
|
10211
|
-
import { existsSync as
|
|
10477
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync4, createWriteStream } from "fs";
|
|
10212
10478
|
|
|
10213
10479
|
// ../lib/admin-conversation-purge/src/index.ts
|
|
10214
10480
|
async function purgeAdminConversationJsonls(args) {
|
|
@@ -10355,7 +10621,7 @@ var pickComponentBytes = (..._args) => null;
|
|
|
10355
10621
|
function openResumeStreamLog(accountId, sessionId) {
|
|
10356
10622
|
const dir = resolvePath(ACCOUNTS_DIR, accountId, "resume-logs");
|
|
10357
10623
|
try {
|
|
10358
|
-
|
|
10624
|
+
mkdirSync4(dir, { recursive: true });
|
|
10359
10625
|
} catch {
|
|
10360
10626
|
}
|
|
10361
10627
|
return createWriteStream(resolvePath(dir, `${sessionId}.log`), { flags: "a" });
|
|
@@ -10368,7 +10634,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
|
|
|
10368
10634
|
let reason = null;
|
|
10369
10635
|
if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
|
|
10370
10636
|
else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
|
|
10371
|
-
else if (!
|
|
10637
|
+
else if (!existsSync19(a.storagePath)) reason = "missing-file";
|
|
10372
10638
|
if (reason) {
|
|
10373
10639
|
invalid++;
|
|
10374
10640
|
try {
|
|
@@ -10894,8 +11160,8 @@ app15.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
10894
11160
|
var sessions_default = app15;
|
|
10895
11161
|
|
|
10896
11162
|
// app/lib/claude-agent/spawn-context.ts
|
|
10897
|
-
import { existsSync as
|
|
10898
|
-
import { dirname as dirname5, resolve as resolve19, join as
|
|
11163
|
+
import { existsSync as existsSync20, readFileSync as readFileSync21, readdirSync as readdirSync13, statSync as statSync10 } from "fs";
|
|
11164
|
+
import { dirname as dirname5, resolve as resolve19, join as join20 } from "path";
|
|
10899
11165
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
10900
11166
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
10901
11167
|
try {
|
|
@@ -10936,14 +11202,14 @@ function frontmatterField(manifest, field2) {
|
|
|
10936
11202
|
function extractPluginToolDescriptions(pluginDir) {
|
|
10937
11203
|
const out = /* @__PURE__ */ new Map();
|
|
10938
11204
|
const candidates = [
|
|
10939
|
-
|
|
10940
|
-
|
|
11205
|
+
join20(pluginDir, "mcp/dist/index.js"),
|
|
11206
|
+
join20(pluginDir, "mcp/src/index.ts")
|
|
10941
11207
|
];
|
|
10942
11208
|
let raw = null;
|
|
10943
11209
|
for (const path2 of candidates) {
|
|
10944
|
-
if (!
|
|
11210
|
+
if (!existsSync20(path2)) continue;
|
|
10945
11211
|
try {
|
|
10946
|
-
raw =
|
|
11212
|
+
raw = readFileSync21(path2, "utf-8");
|
|
10947
11213
|
break;
|
|
10948
11214
|
} catch {
|
|
10949
11215
|
}
|
|
@@ -10993,25 +11259,25 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
10993
11259
|
function listPluginDirs() {
|
|
10994
11260
|
const out = /* @__PURE__ */ new Map();
|
|
10995
11261
|
const platformPlugins = resolve19(PLATFORM_ROOT, "plugins");
|
|
10996
|
-
if (
|
|
10997
|
-
for (const name of
|
|
10998
|
-
const dir =
|
|
11262
|
+
if (existsSync20(platformPlugins)) {
|
|
11263
|
+
for (const name of readdirSync13(platformPlugins)) {
|
|
11264
|
+
const dir = join20(platformPlugins, name);
|
|
10999
11265
|
try {
|
|
11000
|
-
if (
|
|
11266
|
+
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
11001
11267
|
} catch {
|
|
11002
11268
|
}
|
|
11003
11269
|
}
|
|
11004
11270
|
}
|
|
11005
11271
|
const premiumRoot = resolve19(dirname5(PLATFORM_ROOT), "premium-plugins");
|
|
11006
|
-
if (
|
|
11007
|
-
for (const bundle of
|
|
11008
|
-
const bundlePlugins =
|
|
11009
|
-
if (!
|
|
11272
|
+
if (existsSync20(premiumRoot)) {
|
|
11273
|
+
for (const bundle of readdirSync13(premiumRoot)) {
|
|
11274
|
+
const bundlePlugins = join20(premiumRoot, bundle, "plugins");
|
|
11275
|
+
if (!existsSync20(bundlePlugins)) continue;
|
|
11010
11276
|
try {
|
|
11011
|
-
for (const name of
|
|
11012
|
-
const dir =
|
|
11277
|
+
for (const name of readdirSync13(bundlePlugins)) {
|
|
11278
|
+
const dir = join20(bundlePlugins, name);
|
|
11013
11279
|
try {
|
|
11014
|
-
if (
|
|
11280
|
+
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
11015
11281
|
} catch {
|
|
11016
11282
|
}
|
|
11017
11283
|
}
|
|
@@ -11023,9 +11289,9 @@ function listPluginDirs() {
|
|
|
11023
11289
|
}
|
|
11024
11290
|
function readEnabledPlugins(accountId) {
|
|
11025
11291
|
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
11026
|
-
if (!
|
|
11292
|
+
if (!existsSync20(accountFile)) return /* @__PURE__ */ new Set();
|
|
11027
11293
|
try {
|
|
11028
|
-
const parsed = JSON.parse(
|
|
11294
|
+
const parsed = JSON.parse(readFileSync21(accountFile, "utf-8"));
|
|
11029
11295
|
return new Set(
|
|
11030
11296
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
11031
11297
|
);
|
|
@@ -11034,10 +11300,10 @@ function readEnabledPlugins(accountId) {
|
|
|
11034
11300
|
}
|
|
11035
11301
|
}
|
|
11036
11302
|
function readFrontmatter(path2) {
|
|
11037
|
-
if (!
|
|
11303
|
+
if (!existsSync20(path2)) return null;
|
|
11038
11304
|
let raw;
|
|
11039
11305
|
try {
|
|
11040
|
-
raw =
|
|
11306
|
+
raw = readFileSync21(path2, "utf-8");
|
|
11041
11307
|
} catch {
|
|
11042
11308
|
return null;
|
|
11043
11309
|
}
|
|
@@ -11052,7 +11318,7 @@ function computeActivePlugins(accountId) {
|
|
|
11052
11318
|
for (const name of Array.from(enabled).sort()) {
|
|
11053
11319
|
const dir = pluginDirs.get(name);
|
|
11054
11320
|
if (!dir) continue;
|
|
11055
|
-
const fm = readFrontmatter(
|
|
11321
|
+
const fm = readFrontmatter(join20(dir, "PLUGIN.md"));
|
|
11056
11322
|
if (!fm) continue;
|
|
11057
11323
|
const description = frontmatterField(`---
|
|
11058
11324
|
${fm}
|
|
@@ -11069,7 +11335,7 @@ ${fm}
|
|
|
11069
11335
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
11070
11336
|
);
|
|
11071
11337
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
11072
|
-
const hasSource =
|
|
11338
|
+
const hasSource = existsSync20(join20(dir, "mcp/dist/index.js")) || existsSync20(join20(dir, "mcp/src/index.ts"));
|
|
11073
11339
|
if (hasSource) {
|
|
11074
11340
|
console.warn(
|
|
11075
11341
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -11079,7 +11345,7 @@ ${fm}
|
|
|
11079
11345
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
11080
11346
|
const skills = [];
|
|
11081
11347
|
for (const relPath of skillPaths) {
|
|
11082
|
-
const skillPath =
|
|
11348
|
+
const skillPath = join20(dir, relPath);
|
|
11083
11349
|
const skillFm = readFrontmatter(skillPath);
|
|
11084
11350
|
if (!skillFm) continue;
|
|
11085
11351
|
const skillName = frontmatterField(`---
|
|
@@ -11096,10 +11362,10 @@ ${skillFm}
|
|
|
11096
11362
|
}
|
|
11097
11363
|
function computeSpecialistDomains(accountId) {
|
|
11098
11364
|
const specialistsDir = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
11099
|
-
if (!
|
|
11365
|
+
if (!existsSync20(specialistsDir)) return [];
|
|
11100
11366
|
let entries;
|
|
11101
11367
|
try {
|
|
11102
|
-
entries =
|
|
11368
|
+
entries = readdirSync13(specialistsDir);
|
|
11103
11369
|
} catch {
|
|
11104
11370
|
return [];
|
|
11105
11371
|
}
|
|
@@ -11123,7 +11389,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
11123
11389
|
const out = [];
|
|
11124
11390
|
for (const file of entries.sort()) {
|
|
11125
11391
|
if (!file.endsWith(".md")) continue;
|
|
11126
|
-
const fm = readFrontmatter(
|
|
11392
|
+
const fm = readFrontmatter(join20(specialistsDir, file));
|
|
11127
11393
|
if (!fm) continue;
|
|
11128
11394
|
const wrapped = `---
|
|
11129
11395
|
${fm}
|
|
@@ -11142,10 +11408,10 @@ ${fm}
|
|
|
11142
11408
|
}
|
|
11143
11409
|
function computeDormantPlugins(accountId) {
|
|
11144
11410
|
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
11145
|
-
if (!
|
|
11411
|
+
if (!existsSync20(accountFile)) return [];
|
|
11146
11412
|
let enabled;
|
|
11147
11413
|
try {
|
|
11148
|
-
const raw =
|
|
11414
|
+
const raw = readFileSync21(accountFile, "utf-8");
|
|
11149
11415
|
const parsed = JSON.parse(raw);
|
|
11150
11416
|
enabled = new Set(
|
|
11151
11417
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -11157,10 +11423,10 @@ function computeDormantPlugins(accountId) {
|
|
|
11157
11423
|
return [];
|
|
11158
11424
|
}
|
|
11159
11425
|
const pluginsDir = resolve19(PLATFORM_ROOT, "plugins");
|
|
11160
|
-
if (!
|
|
11426
|
+
if (!existsSync20(pluginsDir)) return [];
|
|
11161
11427
|
let entries;
|
|
11162
11428
|
try {
|
|
11163
|
-
entries =
|
|
11429
|
+
entries = readdirSync13(pluginsDir);
|
|
11164
11430
|
} catch {
|
|
11165
11431
|
return [];
|
|
11166
11432
|
}
|
|
@@ -11168,10 +11434,10 @@ function computeDormantPlugins(accountId) {
|
|
|
11168
11434
|
for (const name of entries) {
|
|
11169
11435
|
if (enabled.has(name)) continue;
|
|
11170
11436
|
const manifestPath = resolve19(pluginsDir, name, "PLUGIN.md");
|
|
11171
|
-
if (!
|
|
11437
|
+
if (!existsSync20(manifestPath)) continue;
|
|
11172
11438
|
let manifest;
|
|
11173
11439
|
try {
|
|
11174
|
-
manifest =
|
|
11440
|
+
manifest = readFileSync21(manifestPath, "utf-8");
|
|
11175
11441
|
} catch {
|
|
11176
11442
|
continue;
|
|
11177
11443
|
}
|
|
@@ -11185,13 +11451,13 @@ function computeDormantPlugins(accountId) {
|
|
|
11185
11451
|
}
|
|
11186
11452
|
|
|
11187
11453
|
// server/routes/admin/claude-sessions.ts
|
|
11188
|
-
import { existsSync as
|
|
11454
|
+
import { existsSync as existsSync21, readFileSync as readFileSync22 } from "fs";
|
|
11189
11455
|
import { resolve as resolve20 } from "path";
|
|
11190
11456
|
function readTunnelState(brandConfigDir) {
|
|
11191
11457
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
11192
|
-
if (!
|
|
11458
|
+
if (!existsSync21(statePath)) return null;
|
|
11193
11459
|
try {
|
|
11194
|
-
const parsed = JSON.parse(
|
|
11460
|
+
const parsed = JSON.parse(readFileSync22(statePath, "utf-8"));
|
|
11195
11461
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
11196
11462
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
11197
11463
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -11205,7 +11471,7 @@ function resolveTunnelUrl() {
|
|
|
11205
11471
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
11206
11472
|
let brand;
|
|
11207
11473
|
try {
|
|
11208
|
-
brand = JSON.parse(
|
|
11474
|
+
brand = JSON.parse(readFileSync22(resolve20(platformRoot2, "config", "brand.json"), "utf-8"));
|
|
11209
11475
|
} catch {
|
|
11210
11476
|
return null;
|
|
11211
11477
|
}
|
|
@@ -11447,10 +11713,11 @@ app18.post("/", async (c) => {
|
|
|
11447
11713
|
var events_default = app18;
|
|
11448
11714
|
|
|
11449
11715
|
// server/routes/admin/files.ts
|
|
11450
|
-
import { createReadStream as createReadStream2 } from "fs";
|
|
11451
|
-
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3,
|
|
11716
|
+
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync22 } from "fs";
|
|
11717
|
+
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename } from "fs/promises";
|
|
11452
11718
|
import { realpathSync as realpathSync4 } from "fs";
|
|
11453
|
-
import {
|
|
11719
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
11720
|
+
import { basename as basename7, dirname as dirname6, join as join22, resolve as resolve22, sep as sep6 } from "path";
|
|
11454
11721
|
import { Readable as Readable2 } from "stream";
|
|
11455
11722
|
|
|
11456
11723
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -11768,7 +12035,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
11768
12035
|
|
|
11769
12036
|
// app/lib/file-index.ts
|
|
11770
12037
|
import * as fsp from "fs/promises";
|
|
11771
|
-
import { resolve as resolve21, relative as relative2, join as
|
|
12038
|
+
import { resolve as resolve21, relative as relative2, join as join21, basename as basename6, extname as extname2, sep as sep5 } from "path";
|
|
11772
12039
|
import { tmpdir as tmpdir2 } from "os";
|
|
11773
12040
|
import { execFile as execFile2 } from "child_process";
|
|
11774
12041
|
import { promisify as promisify2 } from "util";
|
|
@@ -11850,7 +12117,7 @@ async function extractPdf(absolute) {
|
|
|
11850
12117
|
return stdout.trim();
|
|
11851
12118
|
}
|
|
11852
12119
|
async function ocrPdf(absolute) {
|
|
11853
|
-
const outPdf =
|
|
12120
|
+
const outPdf = join21(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
11854
12121
|
try {
|
|
11855
12122
|
await execFileAsync2(
|
|
11856
12123
|
"ocrmypdf",
|
|
@@ -11912,7 +12179,7 @@ async function readDisplayName(absolute) {
|
|
|
11912
12179
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
11913
12180
|
if (base === `${stem}.meta.json`) return null;
|
|
11914
12181
|
try {
|
|
11915
|
-
const raw = await fsp.readFile(
|
|
12182
|
+
const raw = await fsp.readFile(join21(dir, `${stem}.meta.json`), "utf-8");
|
|
11916
12183
|
const meta = JSON.parse(raw);
|
|
11917
12184
|
const dn = meta.displayName ?? meta.filename;
|
|
11918
12185
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -11932,7 +12199,8 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
11932
12199
|
let clean = true;
|
|
11933
12200
|
for (const entry of entries) {
|
|
11934
12201
|
if (entry.isSymbolicLink()) continue;
|
|
11935
|
-
|
|
12202
|
+
if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
|
|
12203
|
+
const abs = join21(root, entry.name);
|
|
11936
12204
|
if (entry.isDirectory()) {
|
|
11937
12205
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
11938
12206
|
if (!sub.clean) clean = false;
|
|
@@ -12201,10 +12469,11 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
12201
12469
|
}
|
|
12202
12470
|
|
|
12203
12471
|
// server/routes/admin/files.ts
|
|
12472
|
+
var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
12204
12473
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12205
12474
|
async function readMeta(absDir, baseName) {
|
|
12206
12475
|
try {
|
|
12207
|
-
const raw = await readFile4(
|
|
12476
|
+
const raw = await readFile4(join22(absDir, `${baseName}.meta.json`), "utf8");
|
|
12208
12477
|
const parsed = JSON.parse(raw);
|
|
12209
12478
|
if (typeof parsed?.filename === "string") {
|
|
12210
12479
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -12242,7 +12511,7 @@ async function readAccountNames() {
|
|
|
12242
12511
|
}
|
|
12243
12512
|
async function enrich(absolute, entry, accountNames) {
|
|
12244
12513
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
12245
|
-
const meta = await readMeta(
|
|
12514
|
+
const meta = await readMeta(join22(absolute, entry.name), entry.name);
|
|
12246
12515
|
if (meta?.filename) {
|
|
12247
12516
|
entry.displayName = meta.filename;
|
|
12248
12517
|
entry.mimeType = meta.mimeType;
|
|
@@ -12311,6 +12580,44 @@ function isProtectedFromDeletion(relPath) {
|
|
|
12311
12580
|
}
|
|
12312
12581
|
return { protected: false };
|
|
12313
12582
|
}
|
|
12583
|
+
function isProtectedFromRename(relPath) {
|
|
12584
|
+
if (isProtectedFromDeletion(relPath).protected) return true;
|
|
12585
|
+
const segments = relPath.split("/").filter(Boolean);
|
|
12586
|
+
const base = segments[segments.length - 1] ?? "";
|
|
12587
|
+
if (segments.length === 2 && segments[0] === "accounts") return true;
|
|
12588
|
+
if (segments.length === 3 && segments[0] === "accounts" && segments[2] === "uploads") {
|
|
12589
|
+
return true;
|
|
12590
|
+
}
|
|
12591
|
+
if (segments.length === 4 && segments[0] === "accounts" && segments[2] === "uploads" && UUID_RE3.test(segments[3])) {
|
|
12592
|
+
return true;
|
|
12593
|
+
}
|
|
12594
|
+
if (parseAttachmentPath(relPath) !== null) return true;
|
|
12595
|
+
if (UUID_RE3.test(base.replace(/\.meta\.json$/, "")) && base.endsWith(".meta.json")) {
|
|
12596
|
+
return true;
|
|
12597
|
+
}
|
|
12598
|
+
return false;
|
|
12599
|
+
}
|
|
12600
|
+
function isValidEntryName(name) {
|
|
12601
|
+
if (typeof name !== "string" || name.length === 0) return false;
|
|
12602
|
+
if (name === "." || name === "..") return false;
|
|
12603
|
+
return !/[\\/\0]/.test(name);
|
|
12604
|
+
}
|
|
12605
|
+
function resolveOwnAccountWrite(rawPath, accountId, endpoint) {
|
|
12606
|
+
const res = resolveDataPath(rawPath);
|
|
12607
|
+
if (!res.ok) {
|
|
12608
|
+
if (res.status === 403) console.error(`[data] path-traversal-blocked requested="${rawPath}" resolved="${res.resolved ?? "n/a"}"`);
|
|
12609
|
+
return { ok: false, status: res.status, error: res.error };
|
|
12610
|
+
}
|
|
12611
|
+
if (crossesForeignAccountPartition(res.relative, accountId)) {
|
|
12612
|
+
console.error(`[data] account-scope-blocked endpoint="${endpoint}" path="${res.relative}" account=${accountId.slice(0, 8)}\u2026`);
|
|
12613
|
+
return { ok: false, status: 404, error: "Not found" };
|
|
12614
|
+
}
|
|
12615
|
+
if (!isWithinOwnAccountPartition(res.relative, accountId)) {
|
|
12616
|
+
console.error(`[data] write-scope-blocked endpoint="${endpoint}" path="${res.relative}" account=${accountId.slice(0, 8)}\u2026`);
|
|
12617
|
+
return { ok: false, status: 403, error: "Path is outside your account folder" };
|
|
12618
|
+
}
|
|
12619
|
+
return { ok: true, absolute: res.absolute, relative: res.relative };
|
|
12620
|
+
}
|
|
12314
12621
|
async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
|
|
12315
12622
|
if (!attachmentId) return false;
|
|
12316
12623
|
const session = getSession();
|
|
@@ -12368,7 +12675,7 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
12368
12675
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
12369
12676
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
12370
12677
|
try {
|
|
12371
|
-
const entryPath =
|
|
12678
|
+
const entryPath = join22(absolute, name);
|
|
12372
12679
|
const s = await stat4(entryPath);
|
|
12373
12680
|
entries.push({
|
|
12374
12681
|
name,
|
|
@@ -12462,67 +12769,177 @@ app19.get("/download", requireAdminSession, async (c) => {
|
|
|
12462
12769
|
return c.json({ error: message }, 500);
|
|
12463
12770
|
}
|
|
12464
12771
|
});
|
|
12772
|
+
function dataUploadCeiling() {
|
|
12773
|
+
const override = Number(process.env.MAXY_DATA_UPLOAD_MAX_BYTES);
|
|
12774
|
+
return Number.isFinite(override) && override > 0 ? override : MAX_DATA_UPLOAD_BYTES;
|
|
12775
|
+
}
|
|
12465
12776
|
app19.post("/upload", requireAdminSession, async (c) => {
|
|
12466
12777
|
const cacheKey = c.var.cacheKey;
|
|
12467
12778
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12468
12779
|
if (!accountId) {
|
|
12469
|
-
console.error(`[data] auth-
|
|
12780
|
+
console.error(`[data-upload] op=auth-reject reason="no account for session"`);
|
|
12470
12781
|
return c.json({ error: "Account not found for session" }, 401);
|
|
12471
12782
|
}
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
|
|
12479
|
-
const
|
|
12480
|
-
|
|
12481
|
-
|
|
12482
|
-
|
|
12483
|
-
|
|
12484
|
-
console.error(`[data] file-upload rejected reason="size" filename="${file.name}" size=${file.size}`);
|
|
12783
|
+
const rawName = c.req.query("filename") ?? "";
|
|
12784
|
+
const safeName = basename7(rawName).replace(/[\0/\\]/g, "_");
|
|
12785
|
+
if (!safeName) return c.json({ error: "filename query param required" }, 400);
|
|
12786
|
+
const uid = `${Date.now()}-${randomUUID10().slice(0, 8)}`;
|
|
12787
|
+
const declaredBytes = c.req.header("content-length") ?? "unknown";
|
|
12788
|
+
const rawRelpath = c.req.query("relpath") ?? "";
|
|
12789
|
+
const relpath = rawRelpath !== "" ? rawRelpath : null;
|
|
12790
|
+
const token = c.req.query("token") ?? "";
|
|
12791
|
+
const finalName = relpath ? basename7(relpath).replace(/[\0/\\]/g, "_") : `${Date.now()}-${safeName}`;
|
|
12792
|
+
const mimeType = (c.req.header("content-type") ?? "").split(";")[0].trim();
|
|
12793
|
+
if (!SUPPORTED_MIME_TYPES.has(mimeType)) {
|
|
12794
|
+
console.error(`[data-upload] op=reject-mime uid=${uid} mime="${mimeType}" token=${token} rel="${relpath ?? ""}"`);
|
|
12485
12795
|
return c.json({
|
|
12486
|
-
error: `
|
|
12796
|
+
error: `Unsupported file type: "${mimeType}". Supported: ${[...SUPPORTED_MIME_TYPES].join(", ")}.`
|
|
12487
12797
|
}, 422);
|
|
12488
12798
|
}
|
|
12489
|
-
|
|
12490
|
-
|
|
12491
|
-
|
|
12492
|
-
|
|
12493
|
-
|
|
12799
|
+
const rawDir = c.req.query("path") ?? "";
|
|
12800
|
+
const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
12801
|
+
if (!base.ok) return c.json({ error: base.error }, base.status);
|
|
12802
|
+
const relDir = relpath ? dirname6(relpath) : ".";
|
|
12803
|
+
const destRel = relDir === "." ? base.relative : join22(base.relative, relDir);
|
|
12804
|
+
if (crossesForeignAccountPartition(destRel, accountId)) {
|
|
12805
|
+
console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
12806
|
+
return c.json({ error: "Not found" }, 404);
|
|
12807
|
+
}
|
|
12808
|
+
if (!isWithinOwnAccountPartition(destRel, accountId)) {
|
|
12809
|
+
console.error(`[data] write-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
12810
|
+
return c.json({ error: "Path is outside your account folder" }, 403);
|
|
12494
12811
|
}
|
|
12495
|
-
const
|
|
12496
|
-
const finalName = `${Date.now()}-${safeName}`;
|
|
12497
|
-
const destDir = resolve22(DATA_ROOT, "accounts", accountId, "uploads");
|
|
12812
|
+
const destDir = relDir === "." ? base.absolute : resolve22(base.absolute, relDir);
|
|
12498
12813
|
const destPath = resolve22(destDir, finalName);
|
|
12499
|
-
|
|
12500
|
-
await mkdir3(destDir, { recursive: true });
|
|
12501
|
-
|
|
12502
|
-
|
|
12503
|
-
|
|
12504
|
-
|
|
12505
|
-
|
|
12814
|
+
if (relpath) {
|
|
12815
|
+
const firstCreated = await mkdir3(destDir, { recursive: true });
|
|
12816
|
+
if (firstCreated) console.error(`[data-upload] op=mkdir uid=${uid} token=${token} dir="${destRel}"`);
|
|
12817
|
+
} else {
|
|
12818
|
+
const info = await stat4(destDir).catch(() => null);
|
|
12819
|
+
if (!info || !info.isDirectory()) return c.json({ error: "Upload destination is not a directory" }, 400);
|
|
12820
|
+
}
|
|
12821
|
+
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
12822
|
+
const destDirReal = realpathSync4(destDir);
|
|
12823
|
+
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep6)) {
|
|
12824
|
+
console.error(`[data-upload] op=path-traversal-blocked uid=${uid} requested="${destRel}" resolved="${destDirReal}"`);
|
|
12825
|
+
return c.json({ error: "Upload destination escapes DATA_ROOT" }, 403);
|
|
12826
|
+
}
|
|
12827
|
+
const body = c.req.raw.body;
|
|
12828
|
+
if (!body) return c.json({ error: "Empty request body" }, 400);
|
|
12829
|
+
console.error(`[data-upload] op=request uid=${uid} account=${accountId} dir="${destRel}" token=${token} rel="${relpath ?? ""}" declaredBytes=${declaredBytes}`);
|
|
12830
|
+
const ceiling = dataUploadCeiling();
|
|
12831
|
+
const tmpDir = resolve22(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
|
|
12832
|
+
await mkdir3(tmpDir, { recursive: true });
|
|
12833
|
+
const tmpPath = resolve22(tmpDir, `${uid}.part`);
|
|
12834
|
+
const out = createWriteStream2(tmpPath);
|
|
12835
|
+
const t0 = Date.now();
|
|
12836
|
+
let received = 0;
|
|
12837
|
+
let lastLogged = 0;
|
|
12838
|
+
const LOG_EVERY = 64 * 1024 * 1024;
|
|
12839
|
+
let writeError = null;
|
|
12840
|
+
out.on("error", (e) => {
|
|
12841
|
+
writeError = e;
|
|
12842
|
+
});
|
|
12843
|
+
const cleanup = async () => {
|
|
12844
|
+
await new Promise((res) => {
|
|
12845
|
+
if (out.closed) return res();
|
|
12846
|
+
out.once("close", () => res());
|
|
12847
|
+
out.destroy();
|
|
12848
|
+
});
|
|
12849
|
+
await unlink2(tmpPath).catch(() => {
|
|
12850
|
+
});
|
|
12851
|
+
const tempRemoved = !existsSync22(tmpPath);
|
|
12852
|
+
console.error(`[data-upload] op=cleanup uid=${uid} tempRemoved=${tempRemoved}`);
|
|
12853
|
+
};
|
|
12854
|
+
const reader = body.getReader();
|
|
12855
|
+
try {
|
|
12856
|
+
for (; ; ) {
|
|
12857
|
+
if (writeError) throw writeError;
|
|
12858
|
+
const { done, value } = await reader.read();
|
|
12859
|
+
if (done) break;
|
|
12860
|
+
if (!value) continue;
|
|
12861
|
+
received += value.byteLength;
|
|
12862
|
+
if (received > ceiling) {
|
|
12863
|
+
console.error(`[data-upload] op=reject-size uid=${uid} received=${received} ceiling=${ceiling}`);
|
|
12864
|
+
await reader.cancel().catch(() => {
|
|
12865
|
+
});
|
|
12866
|
+
await cleanup();
|
|
12867
|
+
return c.json({
|
|
12868
|
+
error: `File exceeds the ${Math.floor(ceiling / 1024 / 1024)} MB limit.`
|
|
12869
|
+
}, 413);
|
|
12870
|
+
}
|
|
12871
|
+
if (!out.write(value)) {
|
|
12872
|
+
await new Promise((res, rej) => {
|
|
12873
|
+
const onDrain = () => {
|
|
12874
|
+
out.off("error", onErr);
|
|
12875
|
+
res();
|
|
12876
|
+
};
|
|
12877
|
+
const onErr = (e) => {
|
|
12878
|
+
out.off("drain", onDrain);
|
|
12879
|
+
rej(e);
|
|
12880
|
+
};
|
|
12881
|
+
out.once("drain", onDrain);
|
|
12882
|
+
out.once("error", onErr);
|
|
12883
|
+
});
|
|
12884
|
+
}
|
|
12885
|
+
if (received - lastLogged >= LOG_EVERY) {
|
|
12886
|
+
lastLogged = received;
|
|
12887
|
+
console.error(`[data-upload] op=streaming uid=${uid} received=${received}`);
|
|
12888
|
+
}
|
|
12506
12889
|
}
|
|
12507
|
-
|
|
12508
|
-
|
|
12890
|
+
await new Promise((res, rej) => {
|
|
12891
|
+
if (writeError) return rej(writeError);
|
|
12892
|
+
out.once("error", rej);
|
|
12893
|
+
out.end(() => res());
|
|
12894
|
+
});
|
|
12895
|
+
await rename(tmpPath, destPath);
|
|
12509
12896
|
} catch (err) {
|
|
12510
12897
|
const message = err instanceof Error ? err.message : String(err);
|
|
12511
|
-
console.error(`[data
|
|
12898
|
+
console.error(`[data-upload] op=error uid=${uid} err="${message}" token=${token} rel="${relpath ?? ""}"`);
|
|
12899
|
+
await cleanup();
|
|
12512
12900
|
return c.json({ error: message }, 500);
|
|
12513
12901
|
}
|
|
12514
|
-
const relativeDest =
|
|
12515
|
-
console.error(`[data
|
|
12902
|
+
const relativeDest = `${destRel}/${finalName}`;
|
|
12903
|
+
console.error(`[data-upload] op=committed uid=${uid} path="${relativeDest}" bytes=${received} token=${token} rel="${relpath ?? ""}" ms=${Date.now() - t0}`);
|
|
12516
12904
|
void indexFile(accountId, relativeDest).catch((err) => {
|
|
12517
|
-
console.error(`[data
|
|
12905
|
+
console.error(`[data-upload] op=index-failed uid=${uid} dest="${relativeDest}" err="${err instanceof Error ? err.message : String(err)}"`);
|
|
12518
12906
|
});
|
|
12519
12907
|
return c.json({
|
|
12520
12908
|
path: relativeDest,
|
|
12521
12909
|
filename: finalName,
|
|
12522
|
-
sizeBytes:
|
|
12523
|
-
mimeType
|
|
12910
|
+
sizeBytes: received,
|
|
12911
|
+
mimeType
|
|
12524
12912
|
});
|
|
12525
12913
|
});
|
|
12914
|
+
async function sweepStaleUploadTemps() {
|
|
12915
|
+
const accountsRoot = resolve22(DATA_ROOT, "accounts");
|
|
12916
|
+
let accounts;
|
|
12917
|
+
try {
|
|
12918
|
+
accounts = await readdir3(accountsRoot, { withFileTypes: true });
|
|
12919
|
+
} catch {
|
|
12920
|
+
return 0;
|
|
12921
|
+
}
|
|
12922
|
+
let removed = 0;
|
|
12923
|
+
for (const acc of accounts) {
|
|
12924
|
+
if (!acc.isDirectory()) continue;
|
|
12925
|
+
const tmpDir = resolve22(accountsRoot, acc.name, UPLOAD_TMP_DIR);
|
|
12926
|
+
let entries;
|
|
12927
|
+
try {
|
|
12928
|
+
entries = await readdir3(tmpDir);
|
|
12929
|
+
} catch {
|
|
12930
|
+
continue;
|
|
12931
|
+
}
|
|
12932
|
+
for (const name of entries) {
|
|
12933
|
+
try {
|
|
12934
|
+
await unlink2(resolve22(tmpDir, name));
|
|
12935
|
+
removed++;
|
|
12936
|
+
} catch {
|
|
12937
|
+
}
|
|
12938
|
+
}
|
|
12939
|
+
}
|
|
12940
|
+
if (removed > 0) console.error(`[data-upload] op=sweep removed=${removed}`);
|
|
12941
|
+
return removed;
|
|
12942
|
+
}
|
|
12526
12943
|
app19.delete("/", requireAdminSession, async (c) => {
|
|
12527
12944
|
const cacheKey = c.var.cacheKey;
|
|
12528
12945
|
const accountId = getAccountIdForSession(cacheKey);
|
|
@@ -12560,7 +12977,7 @@ app19.delete("/", requireAdminSession, async (c) => {
|
|
|
12560
12977
|
}
|
|
12561
12978
|
const dot = base.lastIndexOf(".");
|
|
12562
12979
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
12563
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
12980
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join22(dirname6(absolute), `${stem}.meta.json`) : null;
|
|
12564
12981
|
await unlink2(absolute);
|
|
12565
12982
|
if (sidecarPath) {
|
|
12566
12983
|
try {
|
|
@@ -12599,6 +13016,91 @@ app19.delete("/", requireAdminSession, async (c) => {
|
|
|
12599
13016
|
return c.json({ error: message }, 500);
|
|
12600
13017
|
}
|
|
12601
13018
|
});
|
|
13019
|
+
app19.post("/folder", requireAdminSession, async (c) => {
|
|
13020
|
+
const cacheKey = c.var.cacheKey;
|
|
13021
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
13022
|
+
if (!accountId) {
|
|
13023
|
+
console.error(`[data] auth-rejected endpoint="POST /api/admin/files/folder" reason="no account for session"`);
|
|
13024
|
+
return c.json({ error: "Account not found for session" }, 401);
|
|
13025
|
+
}
|
|
13026
|
+
let body;
|
|
13027
|
+
try {
|
|
13028
|
+
body = await c.req.json();
|
|
13029
|
+
} catch {
|
|
13030
|
+
return c.json({ error: "Invalid JSON body" }, 400);
|
|
13031
|
+
}
|
|
13032
|
+
const rawPath = typeof body.path === "string" ? body.path : "";
|
|
13033
|
+
const name = typeof body.name === "string" ? body.name : "";
|
|
13034
|
+
if (!isValidEntryName(name)) return c.json({ error: "Invalid folder name" }, 400);
|
|
13035
|
+
const parent = resolveOwnAccountWrite(rawPath, accountId, "POST /api/admin/files/folder");
|
|
13036
|
+
if (!parent.ok) return c.json({ error: parent.error }, parent.status);
|
|
13037
|
+
const newAbs = resolve22(parent.absolute, name);
|
|
13038
|
+
const newRel = `${parent.relative}/${name}`;
|
|
13039
|
+
try {
|
|
13040
|
+
const info = await stat4(parent.absolute);
|
|
13041
|
+
if (!info.isDirectory()) return c.json({ error: "Parent is not a directory" }, 400);
|
|
13042
|
+
await mkdir3(newAbs, { recursive: false });
|
|
13043
|
+
} catch (err) {
|
|
13044
|
+
const code = err.code;
|
|
13045
|
+
if (code === "EEXIST") return c.json({ error: "A file or folder with that name already exists" }, 409);
|
|
13046
|
+
if (code === "ENOENT") return c.json({ error: "Not found" }, 404);
|
|
13047
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13048
|
+
console.error(`[data] folder-create error path="${newRel}" err="${message}"`);
|
|
13049
|
+
return c.json({ error: message }, 500);
|
|
13050
|
+
}
|
|
13051
|
+
console.error(`[data] folder-create path="${newRel}"`);
|
|
13052
|
+
return c.json({ path: newRel });
|
|
13053
|
+
});
|
|
13054
|
+
app19.post("/rename", requireAdminSession, async (c) => {
|
|
13055
|
+
const cacheKey = c.var.cacheKey;
|
|
13056
|
+
const accountId = getAccountIdForSession(cacheKey);
|
|
13057
|
+
if (!accountId) {
|
|
13058
|
+
console.error(`[data] auth-rejected endpoint="POST /api/admin/files/rename" reason="no account for session"`);
|
|
13059
|
+
return c.json({ error: "Account not found for session" }, 401);
|
|
13060
|
+
}
|
|
13061
|
+
let body;
|
|
13062
|
+
try {
|
|
13063
|
+
body = await c.req.json();
|
|
13064
|
+
} catch {
|
|
13065
|
+
return c.json({ error: "Invalid JSON body" }, 400);
|
|
13066
|
+
}
|
|
13067
|
+
const rawPath = typeof body.path === "string" ? body.path : "";
|
|
13068
|
+
const newName = typeof body.newName === "string" ? body.newName : "";
|
|
13069
|
+
if (!isValidEntryName(newName)) return c.json({ error: "Invalid name" }, 400);
|
|
13070
|
+
const src = resolveOwnAccountWrite(rawPath, accountId, "POST /api/admin/files/rename");
|
|
13071
|
+
if (!src.ok) return c.json({ error: src.error }, src.status);
|
|
13072
|
+
if (isProtectedFromRename(src.relative)) {
|
|
13073
|
+
console.error(`[data] file-rename blocked path="${src.relative}" reason="protected"`);
|
|
13074
|
+
return c.json({ error: "Protected entry \u2014 refusing to rename" }, 403);
|
|
13075
|
+
}
|
|
13076
|
+
const destAbs = resolve22(dirname6(src.absolute), newName);
|
|
13077
|
+
const newRel = `${dirname6(src.relative)}/${newName}`.replace(/^\.\//, "");
|
|
13078
|
+
if (isProtectedFromRename(newRel)) {
|
|
13079
|
+
console.error(`[data] file-rename blocked path="${newRel}" reason="protected-target"`);
|
|
13080
|
+
return c.json({ error: "That name is reserved" }, 403);
|
|
13081
|
+
}
|
|
13082
|
+
try {
|
|
13083
|
+
let collision = true;
|
|
13084
|
+
try {
|
|
13085
|
+
await stat4(destAbs);
|
|
13086
|
+
} catch (e) {
|
|
13087
|
+
if (e.code === "ENOENT") collision = false;
|
|
13088
|
+
}
|
|
13089
|
+
if (collision) return c.json({ error: "A file or folder with that name already exists" }, 409);
|
|
13090
|
+
await rename(src.absolute, destAbs);
|
|
13091
|
+
} catch (err) {
|
|
13092
|
+
const code = err.code;
|
|
13093
|
+
if (code === "ENOENT") return c.json({ error: "Not found" }, 404);
|
|
13094
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
13095
|
+
console.error(`[data] file-rename error from="${src.relative}" to="${newRel}" err="${message}"`);
|
|
13096
|
+
return c.json({ error: message }, 500);
|
|
13097
|
+
}
|
|
13098
|
+
console.error(`[data] file-rename from="${src.relative}" to="${newRel}"`);
|
|
13099
|
+
void reconcileFileIndex(accountId).catch((err) => {
|
|
13100
|
+
console.error(`[data] file-rename reconcile-failed account=${accountId.slice(0, 8)}\u2026 err="${err instanceof Error ? err.message : String(err)}"`);
|
|
13101
|
+
});
|
|
13102
|
+
return c.json({ path: newRel });
|
|
13103
|
+
});
|
|
12602
13104
|
var files_default = app19;
|
|
12603
13105
|
|
|
12604
13106
|
// ../lib/graph-search/src/index.ts
|
|
@@ -14610,7 +15112,7 @@ var graph_default_view_default = app25;
|
|
|
14610
15112
|
// server/routes/admin/sidebar-artefacts.ts
|
|
14611
15113
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
14612
15114
|
import { resolve as resolve23, relative as relative3, isAbsolute, sep as sep7, basename as basename8 } from "path";
|
|
14613
|
-
import { existsSync as
|
|
15115
|
+
import { existsSync as existsSync23 } from "fs";
|
|
14614
15116
|
var LIMIT = 50;
|
|
14615
15117
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
14616
15118
|
function toDataRootRelPath(absPath) {
|
|
@@ -14717,7 +15219,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
14717
15219
|
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
14718
15220
|
const names = /* @__PURE__ */ new Set();
|
|
14719
15221
|
for (const dir of [overrideDir, bundledDir]) {
|
|
14720
|
-
if (!
|
|
15222
|
+
if (!existsSync23(dir)) continue;
|
|
14721
15223
|
try {
|
|
14722
15224
|
const entries = await readdir4(dir);
|
|
14723
15225
|
for (const entry of entries) {
|
|
@@ -14732,7 +15234,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
14732
15234
|
}
|
|
14733
15235
|
async function readAgentTemplateRow(inp) {
|
|
14734
15236
|
let chosenPath = null;
|
|
14735
|
-
if (
|
|
15237
|
+
if (existsSync23(inp.overridePath)) {
|
|
14736
15238
|
try {
|
|
14737
15239
|
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
14738
15240
|
chosenPath = inp.overridePath;
|
|
@@ -14743,7 +15245,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
14743
15245
|
);
|
|
14744
15246
|
return null;
|
|
14745
15247
|
}
|
|
14746
|
-
} else if (
|
|
15248
|
+
} else if (existsSync23(inp.bundledPath)) {
|
|
14747
15249
|
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
14748
15250
|
console.error(
|
|
14749
15251
|
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
@@ -14907,9 +15409,52 @@ app29.post("/", requireAdminSession, async (c) => {
|
|
|
14907
15409
|
});
|
|
14908
15410
|
var session_archive_default = app29;
|
|
14909
15411
|
|
|
15412
|
+
// server/routes/admin/session-rename.ts
|
|
15413
|
+
var app30 = new Hono();
|
|
15414
|
+
app30.post("/", requireAdminSession, async (c) => {
|
|
15415
|
+
let body;
|
|
15416
|
+
try {
|
|
15417
|
+
body = await c.req.json();
|
|
15418
|
+
} catch {
|
|
15419
|
+
return c.json({ error: "invalid JSON body" }, 400);
|
|
15420
|
+
}
|
|
15421
|
+
const sessionId = typeof body.sessionId === "string" ? body.sessionId : "";
|
|
15422
|
+
if (!SESSION_ID_RE2.test(sessionId)) {
|
|
15423
|
+
return c.json({ error: "sessionId must be a v4 UUID" }, 400);
|
|
15424
|
+
}
|
|
15425
|
+
let res;
|
|
15426
|
+
try {
|
|
15427
|
+
res = await fetch(`${managerBase("session-rename:wrapper")}/${sessionId}/rename`, {
|
|
15428
|
+
method: "POST",
|
|
15429
|
+
headers: { "Content-Type": "application/json" },
|
|
15430
|
+
body: JSON.stringify({ title: body.title })
|
|
15431
|
+
});
|
|
15432
|
+
} catch (err) {
|
|
15433
|
+
console.error(`[session-rename] sessionId=${sessionId.slice(0, 8)} manager-unreachable err=${err instanceof Error ? err.message : String(err)}`);
|
|
15434
|
+
return c.json({ error: "manager-unreachable" }, 502);
|
|
15435
|
+
}
|
|
15436
|
+
if (res.status === 200) {
|
|
15437
|
+
const ok = await res.json().catch(() => ({}));
|
|
15438
|
+
console.log(`[session-rename] sessionId=${sessionId.slice(0, 8)} renamed`);
|
|
15439
|
+
return c.json({ ok: true, sessionId: ok.sessionId ?? sessionId, titleSource: ok.titleSource ?? "user" });
|
|
15440
|
+
}
|
|
15441
|
+
if (res.status === 400) {
|
|
15442
|
+
const b = await res.json().catch(() => ({}));
|
|
15443
|
+
console.error(`[session-rename] sessionId=${sessionId.slice(0, 8)} invalid-title reason=${b.reason ?? "unknown"}`);
|
|
15444
|
+
return c.json({ error: "invalid-title", reason: b.reason ?? "invalid" }, 400);
|
|
15445
|
+
}
|
|
15446
|
+
if (res.status === 404) {
|
|
15447
|
+
console.error(`[session-rename] sessionId=${sessionId.slice(0, 8)} session-not-found`);
|
|
15448
|
+
return c.json({ error: "session-not-found" }, 404);
|
|
15449
|
+
}
|
|
15450
|
+
console.error(`[session-rename] sessionId=${sessionId.slice(0, 8)} manager-status=${res.status}`);
|
|
15451
|
+
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
15452
|
+
});
|
|
15453
|
+
var session_rename_default = app30;
|
|
15454
|
+
|
|
14910
15455
|
// server/routes/admin/session-rc-spawn.ts
|
|
14911
|
-
import { randomUUID as
|
|
14912
|
-
function resolveSpawnPlan(host, operatorDomains, body, mintId =
|
|
15456
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
15457
|
+
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID11, adminUserId, authenticatedName) {
|
|
14913
15458
|
const operator = isOperatorHost(host, operatorDomains);
|
|
14914
15459
|
const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
|
|
14915
15460
|
const name = typeof body.name === "string" && body.name.length > 0 ? body.name : void 0;
|
|
@@ -14938,10 +15483,12 @@ function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, ad
|
|
|
14938
15483
|
}
|
|
14939
15484
|
function shapeWebchatResponse(sessionId, manager) {
|
|
14940
15485
|
const outcome = typeof manager?.outcome === "string" ? manager.outcome : "bound";
|
|
14941
|
-
|
|
15486
|
+
const redirected = manager?.redirected === true && typeof manager?.sessionId === "string";
|
|
15487
|
+
const landed = redirected ? manager.sessionId : sessionId;
|
|
15488
|
+
return { sessionId: landed, outcome, target: `/chat?session=${landed}` };
|
|
14942
15489
|
}
|
|
14943
|
-
var
|
|
14944
|
-
|
|
15490
|
+
var app31 = new Hono();
|
|
15491
|
+
app31.post("/", requireAdminSession, async (c) => {
|
|
14945
15492
|
let body;
|
|
14946
15493
|
try {
|
|
14947
15494
|
body = await c.req.json();
|
|
@@ -14953,8 +15500,8 @@ app30.post("/", requireAdminSession, async (c) => {
|
|
|
14953
15500
|
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
14954
15501
|
const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
|
|
14955
15502
|
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
14956
|
-
const plan = resolveSpawnPlan(host, getOperatorDomains(), body,
|
|
14957
|
-
const spawnReqId =
|
|
15503
|
+
const plan = resolveSpawnPlan(host, getOperatorDomains(), body, randomUUID11, adminUserId, authenticatedName);
|
|
15504
|
+
const spawnReqId = randomUUID11();
|
|
14958
15505
|
console.log(
|
|
14959
15506
|
`[chat-spawn] op=request spawnReqId=${spawnReqId} origin=${plan.origin} kind=${plan.kind} sessionId=${plan.kind === "new" ? "new" : plan.sessionId}`
|
|
14960
15507
|
);
|
|
@@ -14996,10 +15543,10 @@ app30.post("/", requireAdminSession, async (c) => {
|
|
|
14996
15543
|
}
|
|
14997
15544
|
return c.json(parsed ?? {});
|
|
14998
15545
|
});
|
|
14999
|
-
var session_rc_spawn_default =
|
|
15546
|
+
var session_rc_spawn_default = app31;
|
|
15000
15547
|
|
|
15001
15548
|
// server/routes/admin/session-reseat.ts
|
|
15002
|
-
import { randomUUID as
|
|
15549
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
15003
15550
|
|
|
15004
15551
|
// ../lib/models/src/index.ts
|
|
15005
15552
|
var OPUS_MODEL = "claude-opus-4-8[1m]";
|
|
@@ -15021,7 +15568,7 @@ function isSelectableModel(id) {
|
|
|
15021
15568
|
}
|
|
15022
15569
|
|
|
15023
15570
|
// server/routes/admin/session-reseat.ts
|
|
15024
|
-
function resolveReseatPlan(body, mintId =
|
|
15571
|
+
function resolveReseatPlan(body, mintId = randomUUID12, adminUserId, authenticatedName) {
|
|
15025
15572
|
const sessionId = mintId();
|
|
15026
15573
|
const key = `session:${sessionId}`;
|
|
15027
15574
|
const payload = {
|
|
@@ -15038,9 +15585,9 @@ function resolveReseatPlan(body, mintId = randomUUID11, adminUserId, authenticat
|
|
|
15038
15585
|
if (authenticatedName) payload.authenticatedName = authenticatedName;
|
|
15039
15586
|
return { sessionId, payload };
|
|
15040
15587
|
}
|
|
15041
|
-
var
|
|
15588
|
+
var app32 = new Hono();
|
|
15042
15589
|
var reseatsInFlight = /* @__PURE__ */ new Set();
|
|
15043
|
-
|
|
15590
|
+
app32.post("/", requireAdminSession, async (c) => {
|
|
15044
15591
|
let body;
|
|
15045
15592
|
try {
|
|
15046
15593
|
body = await c.req.json();
|
|
@@ -15060,8 +15607,8 @@ app31.post("/", requireAdminSession, async (c) => {
|
|
|
15060
15607
|
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
15061
15608
|
const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
|
|
15062
15609
|
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
15063
|
-
const plan = resolveReseatPlan({ fromSessionId, model },
|
|
15064
|
-
const reseatReqId =
|
|
15610
|
+
const plan = resolveReseatPlan({ fromSessionId, model }, randomUUID12, adminUserId, authenticatedName);
|
|
15611
|
+
const reseatReqId = randomUUID12();
|
|
15065
15612
|
console.log(`[chat-reseat] op=request reseatReqId=${reseatReqId} from=${fromSessionId} to-model=${model} new=${plan.sessionId}`);
|
|
15066
15613
|
let res;
|
|
15067
15614
|
try {
|
|
@@ -15111,7 +15658,7 @@ app31.post("/", requireAdminSession, async (c) => {
|
|
|
15111
15658
|
reseatsInFlight.delete(fromSessionId);
|
|
15112
15659
|
}
|
|
15113
15660
|
});
|
|
15114
|
-
var session_reseat_default =
|
|
15661
|
+
var session_reseat_default = app32;
|
|
15115
15662
|
|
|
15116
15663
|
// server/routes/admin/system-stats.ts
|
|
15117
15664
|
import { readFile as readFile5 } from "fs/promises";
|
|
@@ -15208,8 +15755,8 @@ async function sample() {
|
|
|
15208
15755
|
if (process.platform === "linux") return sampleLinux();
|
|
15209
15756
|
return sampleOsFallback();
|
|
15210
15757
|
}
|
|
15211
|
-
var
|
|
15212
|
-
|
|
15758
|
+
var app33 = new Hono();
|
|
15759
|
+
app33.get("/", async (c) => {
|
|
15213
15760
|
const started = Date.now();
|
|
15214
15761
|
if (!inflight) {
|
|
15215
15762
|
inflight = sample().finally(() => {
|
|
@@ -15232,17 +15779,17 @@ app32.get("/", async (c) => {
|
|
|
15232
15779
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
15233
15780
|
}
|
|
15234
15781
|
});
|
|
15235
|
-
var system_stats_default =
|
|
15782
|
+
var system_stats_default = app33;
|
|
15236
15783
|
|
|
15237
15784
|
// server/routes/admin/health.ts
|
|
15238
|
-
import { existsSync as
|
|
15239
|
-
import { resolve as resolve24, join as
|
|
15785
|
+
import { existsSync as existsSync24, readFileSync as readFileSync23 } from "fs";
|
|
15786
|
+
import { resolve as resolve24, join as join23 } from "path";
|
|
15240
15787
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
|
|
15241
15788
|
var brandHostname = "maxy";
|
|
15242
|
-
var brandJsonPath =
|
|
15243
|
-
if (
|
|
15789
|
+
var brandJsonPath = join23(PLATFORM_ROOT6, "config", "brand.json");
|
|
15790
|
+
if (existsSync24(brandJsonPath)) {
|
|
15244
15791
|
try {
|
|
15245
|
-
const brand = JSON.parse(
|
|
15792
|
+
const brand = JSON.parse(readFileSync23(brandJsonPath, "utf-8"));
|
|
15246
15793
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
15247
15794
|
} catch {
|
|
15248
15795
|
}
|
|
@@ -15251,8 +15798,8 @@ var VERSION_FILE = resolve24(PLATFORM_ROOT6, `config/.${brandHostname}-version`)
|
|
|
15251
15798
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
15252
15799
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
15253
15800
|
function readVersion() {
|
|
15254
|
-
if (!
|
|
15255
|
-
return
|
|
15801
|
+
if (!existsSync24(VERSION_FILE)) return "unknown";
|
|
15802
|
+
return readFileSync23(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
15256
15803
|
}
|
|
15257
15804
|
async function probeConversationDb() {
|
|
15258
15805
|
let session;
|
|
@@ -15277,8 +15824,8 @@ async function probeConversationDb() {
|
|
|
15277
15824
|
});
|
|
15278
15825
|
}
|
|
15279
15826
|
}
|
|
15280
|
-
var
|
|
15281
|
-
|
|
15827
|
+
var app34 = new Hono();
|
|
15828
|
+
app34.get("/", async (c) => {
|
|
15282
15829
|
const version = readVersion();
|
|
15283
15830
|
const probe = await probeConversationDb();
|
|
15284
15831
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -15300,10 +15847,10 @@ app33.get("/", async (c) => {
|
|
|
15300
15847
|
uptimeMs
|
|
15301
15848
|
});
|
|
15302
15849
|
});
|
|
15303
|
-
var health_default2 =
|
|
15850
|
+
var health_default2 = app34;
|
|
15304
15851
|
|
|
15305
15852
|
// server/routes/admin/linkedin-ingest.ts
|
|
15306
|
-
import { randomUUID as
|
|
15853
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
15307
15854
|
var TAG26 = "[linkedin-ingest-route]";
|
|
15308
15855
|
var UUID2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
15309
15856
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
@@ -15402,8 +15949,8 @@ function buildInitialMessage(env) {
|
|
|
15402
15949
|
}
|
|
15403
15950
|
return header;
|
|
15404
15951
|
}
|
|
15405
|
-
var
|
|
15406
|
-
|
|
15952
|
+
var app35 = new Hono();
|
|
15953
|
+
app35.post("/", requireAdminSession, async (c) => {
|
|
15407
15954
|
let body;
|
|
15408
15955
|
try {
|
|
15409
15956
|
body = await c.req.json();
|
|
@@ -15429,7 +15976,7 @@ app34.post("/", requireAdminSession, async (c) => {
|
|
|
15429
15976
|
);
|
|
15430
15977
|
const initialMessage = buildInitialMessage(envelope);
|
|
15431
15978
|
const spawnStart = Date.now();
|
|
15432
|
-
const sessionId =
|
|
15979
|
+
const sessionId = randomUUID13();
|
|
15433
15980
|
console.log(TAG26 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
15434
15981
|
const spawned = await managerRcSpawn({
|
|
15435
15982
|
sessionId,
|
|
@@ -15448,7 +15995,7 @@ app34.post("/", requireAdminSession, async (c) => {
|
|
|
15448
15995
|
);
|
|
15449
15996
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
15450
15997
|
});
|
|
15451
|
-
var linkedin_ingest_default =
|
|
15998
|
+
var linkedin_ingest_default = app35;
|
|
15452
15999
|
|
|
15453
16000
|
// server/routes/admin/post-turn-context.ts
|
|
15454
16001
|
import neo4j3 from "neo4j-driver";
|
|
@@ -15490,8 +16037,8 @@ function pruneProperties(raw) {
|
|
|
15490
16037
|
}
|
|
15491
16038
|
return out;
|
|
15492
16039
|
}
|
|
15493
|
-
var
|
|
15494
|
-
|
|
16040
|
+
var app36 = new Hono();
|
|
16041
|
+
app36.get("/", async (c) => {
|
|
15495
16042
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15496
16043
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
15497
16044
|
console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -15551,7 +16098,7 @@ app35.get("/", async (c) => {
|
|
|
15551
16098
|
await session.close();
|
|
15552
16099
|
}
|
|
15553
16100
|
});
|
|
15554
|
-
var post_turn_context_default =
|
|
16101
|
+
var post_turn_context_default = app36;
|
|
15555
16102
|
|
|
15556
16103
|
// server/routes/admin/public-session-context.ts
|
|
15557
16104
|
import neo4j4 from "neo4j-driver";
|
|
@@ -15593,8 +16140,8 @@ function pruneProperties2(raw) {
|
|
|
15593
16140
|
}
|
|
15594
16141
|
return out;
|
|
15595
16142
|
}
|
|
15596
|
-
var
|
|
15597
|
-
|
|
16143
|
+
var app37 = new Hono();
|
|
16144
|
+
app37.get("/", async (c) => {
|
|
15598
16145
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15599
16146
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
15600
16147
|
console.error(`${TAG28} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -15653,15 +16200,15 @@ app36.get("/", async (c) => {
|
|
|
15653
16200
|
await session.close();
|
|
15654
16201
|
}
|
|
15655
16202
|
});
|
|
15656
|
-
var public_session_context_default =
|
|
16203
|
+
var public_session_context_default = app37;
|
|
15657
16204
|
|
|
15658
16205
|
// server/routes/admin/public-session-exit.ts
|
|
15659
16206
|
var TAG29 = "[public-session-exit-route]";
|
|
15660
16207
|
function isLoopbackAddr4(addr) {
|
|
15661
16208
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15662
16209
|
}
|
|
15663
|
-
var
|
|
15664
|
-
|
|
16210
|
+
var app38 = new Hono();
|
|
16211
|
+
app38.post("/", async (c) => {
|
|
15665
16212
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15666
16213
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
15667
16214
|
console.error(`${TAG29} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -15688,15 +16235,15 @@ app37.post("/", async (c) => {
|
|
|
15688
16235
|
handlePublicSessionExit(sessionId);
|
|
15689
16236
|
return c.json({ ok: true });
|
|
15690
16237
|
});
|
|
15691
|
-
var public_session_exit_default =
|
|
16238
|
+
var public_session_exit_default = app38;
|
|
15692
16239
|
|
|
15693
16240
|
// server/routes/admin/access-session-evict.ts
|
|
15694
16241
|
var TAG30 = "[access-session-evict]";
|
|
15695
16242
|
function isLoopbackAddr5(addr) {
|
|
15696
16243
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15697
16244
|
}
|
|
15698
|
-
var
|
|
15699
|
-
|
|
16245
|
+
var app39 = new Hono();
|
|
16246
|
+
app39.post("/", async (c) => {
|
|
15700
16247
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15701
16248
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
15702
16249
|
console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -15724,7 +16271,7 @@ app38.post("/", async (c) => {
|
|
|
15724
16271
|
console.log(`${TAG30} grantId=${grantId} dropped=${dropped}`);
|
|
15725
16272
|
return c.json({ ok: true, dropped });
|
|
15726
16273
|
});
|
|
15727
|
-
var access_session_evict_default =
|
|
16274
|
+
var access_session_evict_default = app39;
|
|
15728
16275
|
|
|
15729
16276
|
// server/routes/admin/enrol-person.ts
|
|
15730
16277
|
var TAG31 = "[enrol]";
|
|
@@ -15732,8 +16279,8 @@ function isLoopbackAddr6(addr) {
|
|
|
15732
16279
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15733
16280
|
}
|
|
15734
16281
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
15735
|
-
var
|
|
15736
|
-
|
|
16282
|
+
var app40 = new Hono();
|
|
16283
|
+
app40.post("/", async (c) => {
|
|
15737
16284
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15738
16285
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
15739
16286
|
console.error(`${TAG31} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -15796,11 +16343,11 @@ app39.post("/", async (c) => {
|
|
|
15796
16343
|
);
|
|
15797
16344
|
return c.json({ personId, grant }, 200);
|
|
15798
16345
|
});
|
|
15799
|
-
var enrol_person_default =
|
|
16346
|
+
var enrol_person_default = app40;
|
|
15800
16347
|
|
|
15801
16348
|
// server/routes/admin/browser.ts
|
|
15802
|
-
var
|
|
15803
|
-
|
|
16349
|
+
var app41 = new Hono();
|
|
16350
|
+
app41.post("/launch", requireAdminSession, async (c) => {
|
|
15804
16351
|
try {
|
|
15805
16352
|
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
15806
16353
|
console.error(`[admin/browser/launch] op=request transport=${transport}`);
|
|
@@ -15828,50 +16375,51 @@ app40.post("/launch", requireAdminSession, async (c) => {
|
|
|
15828
16375
|
);
|
|
15829
16376
|
}
|
|
15830
16377
|
});
|
|
15831
|
-
var browser_default =
|
|
16378
|
+
var browser_default = app41;
|
|
15832
16379
|
|
|
15833
16380
|
// server/routes/admin/index.ts
|
|
15834
|
-
var
|
|
15835
|
-
|
|
15836
|
-
|
|
15837
|
-
|
|
15838
|
-
|
|
15839
|
-
|
|
15840
|
-
|
|
15841
|
-
|
|
15842
|
-
|
|
15843
|
-
|
|
15844
|
-
|
|
15845
|
-
|
|
15846
|
-
|
|
15847
|
-
|
|
15848
|
-
|
|
15849
|
-
|
|
15850
|
-
|
|
15851
|
-
|
|
15852
|
-
|
|
15853
|
-
|
|
15854
|
-
|
|
15855
|
-
|
|
15856
|
-
|
|
15857
|
-
|
|
15858
|
-
|
|
15859
|
-
|
|
15860
|
-
|
|
15861
|
-
|
|
15862
|
-
|
|
15863
|
-
|
|
15864
|
-
|
|
15865
|
-
|
|
15866
|
-
|
|
15867
|
-
|
|
16381
|
+
var app42 = new Hono();
|
|
16382
|
+
app42.route("/session", session_default);
|
|
16383
|
+
app42.route("/logs", logs_default);
|
|
16384
|
+
app42.route("/claude-info", claude_info_default);
|
|
16385
|
+
app42.route("/attachment", attachment_default);
|
|
16386
|
+
app42.route("/agents", agents_default);
|
|
16387
|
+
app42.route("/sessions", sessions_default);
|
|
16388
|
+
app42.route("/claude-sessions", claude_sessions_default);
|
|
16389
|
+
app42.route("/log-ingest", log_ingest_default);
|
|
16390
|
+
app42.route("/events", events_default);
|
|
16391
|
+
app42.route("/files", files_default);
|
|
16392
|
+
app42.route("/graph-search", graph_search_default);
|
|
16393
|
+
app42.route("/graph-subgraph", graph_subgraph_default);
|
|
16394
|
+
app42.route("/graph-delete", graph_delete_default);
|
|
16395
|
+
app42.route("/graph-restore", graph_restore_default);
|
|
16396
|
+
app42.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
16397
|
+
app42.route("/graph-default-view", graph_default_view_default);
|
|
16398
|
+
app42.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
16399
|
+
app42.route("/sidebar-sessions", sidebar_sessions_default);
|
|
16400
|
+
app42.route("/session-delete", session_delete_default);
|
|
16401
|
+
app42.route("/session-stop", session_stop_default);
|
|
16402
|
+
app42.route("/session-archive", session_archive_default);
|
|
16403
|
+
app42.route("/session-rename", session_rename_default);
|
|
16404
|
+
app42.route("/browser", browser_default);
|
|
16405
|
+
app42.route("/session-rc-spawn", session_rc_spawn_default);
|
|
16406
|
+
app42.route("/session-reseat", session_reseat_default);
|
|
16407
|
+
app42.route("/system-stats", system_stats_default);
|
|
16408
|
+
app42.route("/health-brand", health_default2);
|
|
16409
|
+
app42.route("/linkedin-ingest", linkedin_ingest_default);
|
|
16410
|
+
app42.route("/post-turn-context", post_turn_context_default);
|
|
16411
|
+
app42.route("/public-session-context", public_session_context_default);
|
|
16412
|
+
app42.route("/public-session-exit", public_session_exit_default);
|
|
16413
|
+
app42.route("/access-session-evict", access_session_evict_default);
|
|
16414
|
+
app42.route("/enrol-person", enrol_person_default);
|
|
16415
|
+
var admin_default = app42;
|
|
15868
16416
|
|
|
15869
16417
|
// server/routes/access/verify-token.ts
|
|
15870
16418
|
var TAG32 = "[access-verify]";
|
|
15871
16419
|
var MINT_TAG = "[access-session-mint]";
|
|
15872
16420
|
var COOKIE_NAME = "__access_session";
|
|
15873
|
-
var
|
|
15874
|
-
|
|
16421
|
+
var app43 = new Hono();
|
|
16422
|
+
app43.post("/", async (c) => {
|
|
15875
16423
|
const ip = c.var.clientIp || "unknown";
|
|
15876
16424
|
let body;
|
|
15877
16425
|
try {
|
|
@@ -15953,7 +16501,7 @@ app42.post("/", async (c) => {
|
|
|
15953
16501
|
displayName: grant.displayName
|
|
15954
16502
|
});
|
|
15955
16503
|
});
|
|
15956
|
-
var verify_token_default =
|
|
16504
|
+
var verify_token_default = app43;
|
|
15957
16505
|
|
|
15958
16506
|
// app/lib/access-email.ts
|
|
15959
16507
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -16016,9 +16564,9 @@ async function sendMagicLinkEmail(payload) {
|
|
|
16016
16564
|
|
|
16017
16565
|
// server/routes/access/request-magic-link.ts
|
|
16018
16566
|
var TAG33 = "[access-request-link]";
|
|
16019
|
-
var
|
|
16567
|
+
var app44 = new Hono();
|
|
16020
16568
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
16021
|
-
|
|
16569
|
+
app44.post("/", async (c) => {
|
|
16022
16570
|
let body;
|
|
16023
16571
|
try {
|
|
16024
16572
|
body = await c.req.json();
|
|
@@ -16092,16 +16640,16 @@ app43.post("/", async (c) => {
|
|
|
16092
16640
|
);
|
|
16093
16641
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
16094
16642
|
});
|
|
16095
|
-
var request_magic_link_default =
|
|
16643
|
+
var request_magic_link_default = app44;
|
|
16096
16644
|
|
|
16097
16645
|
// server/routes/access/index.ts
|
|
16098
|
-
var
|
|
16099
|
-
|
|
16100
|
-
|
|
16101
|
-
var access_default =
|
|
16646
|
+
var app45 = new Hono();
|
|
16647
|
+
app45.route("/verify-token", verify_token_default);
|
|
16648
|
+
app45.route("/request-magic-link", request_magic_link_default);
|
|
16649
|
+
var access_default = app45;
|
|
16102
16650
|
|
|
16103
16651
|
// server/routes/sites.ts
|
|
16104
|
-
import { existsSync as
|
|
16652
|
+
import { existsSync as existsSync25, readFileSync as readFileSync24, realpathSync as realpathSync5, statSync as statSync11 } from "fs";
|
|
16105
16653
|
import { resolve as resolve26 } from "path";
|
|
16106
16654
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
16107
16655
|
var MIME = {
|
|
@@ -16133,8 +16681,8 @@ function getExt(p) {
|
|
|
16133
16681
|
if (idx < p.lastIndexOf("/")) return "";
|
|
16134
16682
|
return p.slice(idx).toLowerCase();
|
|
16135
16683
|
}
|
|
16136
|
-
var
|
|
16137
|
-
|
|
16684
|
+
var app46 = new Hono();
|
|
16685
|
+
app46.get("/:rel{.*}", (c) => {
|
|
16138
16686
|
const reqPath = c.req.path;
|
|
16139
16687
|
const rawRel = c.req.param("rel") ?? "";
|
|
16140
16688
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -16167,7 +16715,7 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16167
16715
|
}
|
|
16168
16716
|
let stat7;
|
|
16169
16717
|
try {
|
|
16170
|
-
stat7 =
|
|
16718
|
+
stat7 = existsSync25(filePath) ? statSync11(filePath) : null;
|
|
16171
16719
|
} catch {
|
|
16172
16720
|
stat7 = null;
|
|
16173
16721
|
}
|
|
@@ -16186,7 +16734,7 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16186
16734
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
16187
16735
|
return c.text("Forbidden", 403);
|
|
16188
16736
|
}
|
|
16189
|
-
if (!
|
|
16737
|
+
if (!existsSync25(filePath)) {
|
|
16190
16738
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
16191
16739
|
return c.text("Not found", 404);
|
|
16192
16740
|
}
|
|
@@ -16205,7 +16753,7 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16205
16753
|
}
|
|
16206
16754
|
let body;
|
|
16207
16755
|
try {
|
|
16208
|
-
body =
|
|
16756
|
+
body = readFileSync24(realPath);
|
|
16209
16757
|
} catch (err) {
|
|
16210
16758
|
const code = err?.code;
|
|
16211
16759
|
if (code === "EISDIR") {
|
|
@@ -16237,11 +16785,11 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16237
16785
|
"X-Content-Type-Options": "nosniff"
|
|
16238
16786
|
});
|
|
16239
16787
|
});
|
|
16240
|
-
var sites_default =
|
|
16788
|
+
var sites_default = app46;
|
|
16241
16789
|
|
|
16242
16790
|
// app/lib/visitor-token.ts
|
|
16243
16791
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
16244
|
-
import { mkdirSync as
|
|
16792
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync25, writeFileSync as writeFileSync10 } from "fs";
|
|
16245
16793
|
import { dirname as dirname7 } from "path";
|
|
16246
16794
|
var TOKEN_PREFIX = "v1.";
|
|
16247
16795
|
var SECRET_BYTES = 32;
|
|
@@ -16250,7 +16798,7 @@ var cachedSecret = null;
|
|
|
16250
16798
|
function getSecret() {
|
|
16251
16799
|
if (cachedSecret) return cachedSecret;
|
|
16252
16800
|
try {
|
|
16253
|
-
const hex2 =
|
|
16801
|
+
const hex2 = readFileSync25(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
16254
16802
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
16255
16803
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
16256
16804
|
return cachedSecret;
|
|
@@ -16259,12 +16807,12 @@ function getSecret() {
|
|
|
16259
16807
|
}
|
|
16260
16808
|
const fresh = randomBytes(SECRET_BYTES).toString("hex");
|
|
16261
16809
|
try {
|
|
16262
|
-
|
|
16263
|
-
|
|
16810
|
+
mkdirSync5(dirname7(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
16811
|
+
writeFileSync10(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
16264
16812
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
16265
16813
|
} catch {
|
|
16266
16814
|
}
|
|
16267
|
-
const hex =
|
|
16815
|
+
const hex = readFileSync25(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
16268
16816
|
cachedSecret = Buffer.from(hex, "hex");
|
|
16269
16817
|
return cachedSecret;
|
|
16270
16818
|
}
|
|
@@ -16317,8 +16865,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
16317
16865
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
16318
16866
|
|
|
16319
16867
|
// app/lib/brand-config.ts
|
|
16320
|
-
import { existsSync as
|
|
16321
|
-
import { join as
|
|
16868
|
+
import { existsSync as existsSync26, readFileSync as readFileSync26 } from "fs";
|
|
16869
|
+
import { join as join24 } from "path";
|
|
16322
16870
|
var cached2 = null;
|
|
16323
16871
|
var cachedAttempted = false;
|
|
16324
16872
|
function readBrandConfig() {
|
|
@@ -16326,10 +16874,10 @@ function readBrandConfig() {
|
|
|
16326
16874
|
cachedAttempted = true;
|
|
16327
16875
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
|
|
16328
16876
|
if (!platformRoot2) return null;
|
|
16329
|
-
const brandPath =
|
|
16330
|
-
if (!
|
|
16877
|
+
const brandPath = join24(platformRoot2, "config", "brand.json");
|
|
16878
|
+
if (!existsSync26(brandPath)) return null;
|
|
16331
16879
|
try {
|
|
16332
|
-
cached2 = JSON.parse(
|
|
16880
|
+
cached2 = JSON.parse(readFileSync26(brandPath, "utf-8"));
|
|
16333
16881
|
return cached2;
|
|
16334
16882
|
} catch {
|
|
16335
16883
|
return null;
|
|
@@ -16337,7 +16885,7 @@ function readBrandConfig() {
|
|
|
16337
16885
|
}
|
|
16338
16886
|
|
|
16339
16887
|
// server/routes/visitor-consent.ts
|
|
16340
|
-
var
|
|
16888
|
+
var app47 = new Hono();
|
|
16341
16889
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
16342
16890
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
16343
16891
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -16382,17 +16930,17 @@ function siteSlugFromReferer(referer) {
|
|
|
16382
16930
|
return "";
|
|
16383
16931
|
}
|
|
16384
16932
|
}
|
|
16385
|
-
|
|
16933
|
+
app47.options("/consent", (c) => {
|
|
16386
16934
|
const origin = getOrigin(c);
|
|
16387
16935
|
setCorsHeaders(c, origin);
|
|
16388
16936
|
return c.body(null, 204);
|
|
16389
16937
|
});
|
|
16390
|
-
|
|
16938
|
+
app47.options("/brand-config", (c) => {
|
|
16391
16939
|
const origin = getOrigin(c);
|
|
16392
16940
|
setCorsHeaders(c, origin);
|
|
16393
16941
|
return c.body(null, 204);
|
|
16394
16942
|
});
|
|
16395
|
-
|
|
16943
|
+
app47.post("/consent", async (c) => {
|
|
16396
16944
|
const origin = getOrigin(c);
|
|
16397
16945
|
setCorsHeaders(c, origin);
|
|
16398
16946
|
let raw;
|
|
@@ -16432,7 +16980,7 @@ app46.post("/consent", async (c) => {
|
|
|
16432
16980
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
16433
16981
|
return c.body(null, 204);
|
|
16434
16982
|
});
|
|
16435
|
-
|
|
16983
|
+
app47.get("/brand-config", (c) => {
|
|
16436
16984
|
const origin = getOrigin(c);
|
|
16437
16985
|
setCorsHeaders(c, origin);
|
|
16438
16986
|
const brand = readBrandConfig();
|
|
@@ -16442,7 +16990,7 @@ app46.get("/brand-config", (c) => {
|
|
|
16442
16990
|
c.header("Cache-Control", "public, max-age=300");
|
|
16443
16991
|
return c.json({ consent: { copy, palette } });
|
|
16444
16992
|
});
|
|
16445
|
-
var visitor_consent_default =
|
|
16993
|
+
var visitor_consent_default = app47;
|
|
16446
16994
|
|
|
16447
16995
|
// server/routes/listings.ts
|
|
16448
16996
|
function getCookie(headerValue, name) {
|
|
@@ -16469,8 +17017,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
16469
17017
|
}
|
|
16470
17018
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
16471
17019
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
16472
|
-
var
|
|
16473
|
-
|
|
17020
|
+
var app48 = new Hono();
|
|
17021
|
+
app48.get("/:slug/click", async (c) => {
|
|
16474
17022
|
const slug = c.req.param("slug") ?? "";
|
|
16475
17023
|
const rawSession = c.req.query("session") ?? "";
|
|
16476
17024
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -16534,10 +17082,10 @@ app47.get("/:slug/click", async (c) => {
|
|
|
16534
17082
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
16535
17083
|
return c.redirect(redirectUrl, 302);
|
|
16536
17084
|
});
|
|
16537
|
-
var listings_default =
|
|
17085
|
+
var listings_default = app48;
|
|
16538
17086
|
|
|
16539
17087
|
// server/routes/visitor-event.ts
|
|
16540
|
-
var
|
|
17088
|
+
var app49 = new Hono();
|
|
16541
17089
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
16542
17090
|
var buckets = /* @__PURE__ */ new Map();
|
|
16543
17091
|
var RATE_LIMIT = 60;
|
|
@@ -16604,12 +17152,12 @@ function originAllowed(origin, allowlist) {
|
|
|
16604
17152
|
return false;
|
|
16605
17153
|
}
|
|
16606
17154
|
}
|
|
16607
|
-
|
|
17155
|
+
app49.options("/event", (c) => {
|
|
16608
17156
|
const origin = getOrigin2(c);
|
|
16609
17157
|
setCorsHeaders2(c, origin);
|
|
16610
17158
|
return c.body(null, 204);
|
|
16611
17159
|
});
|
|
16612
|
-
|
|
17160
|
+
app49.post("/event", async (c) => {
|
|
16613
17161
|
const origin = getOrigin2(c);
|
|
16614
17162
|
setCorsHeaders2(c, origin);
|
|
16615
17163
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -16814,17 +17362,17 @@ async function writeEvent(opts) {
|
|
|
16814
17362
|
);
|
|
16815
17363
|
}
|
|
16816
17364
|
}
|
|
16817
|
-
var visitor_event_default =
|
|
17365
|
+
var visitor_event_default = app49;
|
|
16818
17366
|
|
|
16819
17367
|
// server/routes/session.ts
|
|
16820
17368
|
import { resolve as resolve27 } from "path";
|
|
16821
|
-
import { existsSync as
|
|
17369
|
+
import { existsSync as existsSync27, writeFileSync as writeFileSync11, mkdirSync as mkdirSync6 } from "fs";
|
|
16822
17370
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16823
17371
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
16824
17372
|
try {
|
|
16825
17373
|
const cacheDir = resolve27(MAXY_DIR, "branding-cache", accountId);
|
|
16826
|
-
|
|
16827
|
-
|
|
17374
|
+
mkdirSync6(cacheDir, { recursive: true });
|
|
17375
|
+
writeFileSync11(resolve27(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
16828
17376
|
} catch (err) {
|
|
16829
17377
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
16830
17378
|
}
|
|
@@ -16860,8 +17408,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
16860
17408
|
headers
|
|
16861
17409
|
});
|
|
16862
17410
|
}
|
|
16863
|
-
var
|
|
16864
|
-
|
|
17411
|
+
var app50 = new Hono();
|
|
17412
|
+
app50.post("/", async (c) => {
|
|
16865
17413
|
let body;
|
|
16866
17414
|
try {
|
|
16867
17415
|
body = await c.req.json();
|
|
@@ -16913,7 +17461,7 @@ app49.post("/", async (c) => {
|
|
|
16913
17461
|
let agentConfig = null;
|
|
16914
17462
|
if (account) {
|
|
16915
17463
|
const agentDir = resolve27(account.accountDir, "agents", agentSlug);
|
|
16916
|
-
if (!
|
|
17464
|
+
if (!existsSync27(agentDir) || !existsSync27(resolve27(agentDir, "config.json"))) {
|
|
16917
17465
|
return c.json({ error: "Agent not found" }, 404);
|
|
16918
17466
|
}
|
|
16919
17467
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -17072,7 +17620,7 @@ app49.post("/", async (c) => {
|
|
|
17072
17620
|
newVisitorId
|
|
17073
17621
|
);
|
|
17074
17622
|
});
|
|
17075
|
-
var session_default2 =
|
|
17623
|
+
var session_default2 = app50;
|
|
17076
17624
|
|
|
17077
17625
|
// app/lib/graph-health.ts
|
|
17078
17626
|
var import_dist4 = __toESM(require_dist3(), 1);
|
|
@@ -17295,7 +17843,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
17295
17843
|
}
|
|
17296
17844
|
|
|
17297
17845
|
// app/lib/migrate-uploads.ts
|
|
17298
|
-
import { mkdir as mkdir5, readdir as readdir5, rename, rm as rm3 } from "fs/promises";
|
|
17846
|
+
import { mkdir as mkdir5, readdir as readdir5, rename as rename2, rm as rm3 } from "fs/promises";
|
|
17299
17847
|
import { dirname as dirname8, relative as relative4, resolve as resolve29 } from "path";
|
|
17300
17848
|
var ACCOUNT_UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
17301
17849
|
async function walkFiles(dir) {
|
|
@@ -17329,7 +17877,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
17329
17877
|
const suffix = relative4(srcDir, oldAbs);
|
|
17330
17878
|
const newAbs = resolve29(destDir, suffix);
|
|
17331
17879
|
await mkdir5(dirname8(newAbs), { recursive: true });
|
|
17332
|
-
await
|
|
17880
|
+
await rename2(oldAbs, newAbs);
|
|
17333
17881
|
moved++;
|
|
17334
17882
|
const oldRel = relative4(dataRoot, oldAbs);
|
|
17335
17883
|
const newRel = relative4(dataRoot, newAbs);
|
|
@@ -17418,9 +17966,9 @@ async function migrateUploads(opts = {}) {
|
|
|
17418
17966
|
}
|
|
17419
17967
|
|
|
17420
17968
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
17421
|
-
import { readdir as readdir6, readFile as readFile6, rename as
|
|
17422
|
-
import { existsSync as
|
|
17423
|
-
import { join as
|
|
17969
|
+
import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as writeFile4, unlink as unlink3 } from "fs/promises";
|
|
17970
|
+
import { existsSync as existsSync28 } from "fs";
|
|
17971
|
+
import { join as join25 } from "path";
|
|
17424
17972
|
var ADMIN_ROLE2 = "admin";
|
|
17425
17973
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
17426
17974
|
var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
@@ -17445,11 +17993,11 @@ async function readRaw(path2) {
|
|
|
17445
17993
|
async function writeRaw(path2, obj) {
|
|
17446
17994
|
const tmp = `${path2}.tmp.${process.pid}.${Date.now()}`;
|
|
17447
17995
|
try {
|
|
17448
|
-
await
|
|
17449
|
-
await
|
|
17996
|
+
await writeFile4(tmp, JSON.stringify(obj, null, 2), "utf8");
|
|
17997
|
+
await rename3(tmp, path2);
|
|
17450
17998
|
} catch (err) {
|
|
17451
17999
|
try {
|
|
17452
|
-
if (
|
|
18000
|
+
if (existsSync28(tmp)) await unlink3(tmp);
|
|
17453
18001
|
} catch {
|
|
17454
18002
|
}
|
|
17455
18003
|
throw err;
|
|
@@ -17465,7 +18013,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17465
18013
|
}
|
|
17466
18014
|
for (const slug of slugs) {
|
|
17467
18015
|
if (!slug.isDirectory()) continue;
|
|
17468
|
-
const slugDir =
|
|
18016
|
+
const slugDir = join25(projectsRoot, slug.name);
|
|
17469
18017
|
let entries;
|
|
17470
18018
|
try {
|
|
17471
18019
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -17474,9 +18022,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17474
18022
|
}
|
|
17475
18023
|
for (const entry of entries) {
|
|
17476
18024
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
17477
|
-
out.push(
|
|
18025
|
+
out.push(join25(slugDir, entry.name));
|
|
17478
18026
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
17479
|
-
const subDir =
|
|
18027
|
+
const subDir = join25(slugDir, entry.name);
|
|
17480
18028
|
let subs;
|
|
17481
18029
|
try {
|
|
17482
18030
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -17484,7 +18032,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17484
18032
|
continue;
|
|
17485
18033
|
}
|
|
17486
18034
|
for (const s of subs) {
|
|
17487
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
18035
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join25(subDir, s.name));
|
|
17488
18036
|
}
|
|
17489
18037
|
}
|
|
17490
18038
|
}
|
|
@@ -17496,7 +18044,7 @@ function shortId(path2) {
|
|
|
17496
18044
|
return base.slice(0, 8);
|
|
17497
18045
|
}
|
|
17498
18046
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
17499
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
18047
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join25(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
17500
18048
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
17501
18049
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
17502
18050
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -17838,8 +18386,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
17838
18386
|
|
|
17839
18387
|
// app/lib/whatsapp/gateway/routes.ts
|
|
17840
18388
|
function createWaChannelRoutes(deps) {
|
|
17841
|
-
const
|
|
17842
|
-
|
|
18389
|
+
const app52 = new Hono();
|
|
18390
|
+
app52.get("/wa-channel/inbound", (c) => {
|
|
17843
18391
|
const senderId = c.req.query("senderId");
|
|
17844
18392
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
17845
18393
|
return streamSSE(c, async (stream2) => {
|
|
@@ -17857,7 +18405,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17857
18405
|
}
|
|
17858
18406
|
});
|
|
17859
18407
|
});
|
|
17860
|
-
|
|
18408
|
+
app52.post("/wa-channel/reply", async (c) => {
|
|
17861
18409
|
const body = await c.req.json().catch(() => null);
|
|
17862
18410
|
const senderId = body?.senderId;
|
|
17863
18411
|
const text = body?.text;
|
|
@@ -17878,7 +18426,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17878
18426
|
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
17879
18427
|
return c.json({ ok: true });
|
|
17880
18428
|
});
|
|
17881
|
-
|
|
18429
|
+
app52.post("/wa-channel/reply-document", async (c) => {
|
|
17882
18430
|
const body = await c.req.json().catch(() => null);
|
|
17883
18431
|
const senderId = body?.senderId;
|
|
17884
18432
|
const files = body?.files;
|
|
@@ -17917,7 +18465,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17917
18465
|
}
|
|
17918
18466
|
return c.json({ ok: true, results });
|
|
17919
18467
|
});
|
|
17920
|
-
|
|
18468
|
+
app52.post("/wa-channel/ready", async (c) => {
|
|
17921
18469
|
const body = await c.req.json().catch(() => null);
|
|
17922
18470
|
const senderId = body?.senderId;
|
|
17923
18471
|
if (typeof senderId !== "string") {
|
|
@@ -17926,7 +18474,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17926
18474
|
deps.onReady?.(senderId);
|
|
17927
18475
|
return c.json({ ok: true });
|
|
17928
18476
|
});
|
|
17929
|
-
|
|
18477
|
+
app52.post("/wa-channel/received", async (c) => {
|
|
17930
18478
|
const body = await c.req.json().catch(() => null);
|
|
17931
18479
|
const senderId = body?.senderId;
|
|
17932
18480
|
const waMessageId = body?.waMessageId;
|
|
@@ -17936,7 +18484,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17936
18484
|
deps.onReceived?.(senderId, waMessageId);
|
|
17937
18485
|
return c.json({ ok: true });
|
|
17938
18486
|
});
|
|
17939
|
-
|
|
18487
|
+
app52.post("/wa-channel/turn-end", async (c) => {
|
|
17940
18488
|
const body = await c.req.json().catch(() => null);
|
|
17941
18489
|
const senderId = body?.senderId;
|
|
17942
18490
|
const sessionId = body?.sessionId;
|
|
@@ -17967,7 +18515,7 @@ function createWaChannelRoutes(deps) {
|
|
|
17967
18515
|
console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=fallback bytes=${bytes}`);
|
|
17968
18516
|
return c.json({ ok: true, delivered: "fallback" });
|
|
17969
18517
|
});
|
|
17970
|
-
return
|
|
18518
|
+
return app52;
|
|
17971
18519
|
}
|
|
17972
18520
|
|
|
17973
18521
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -18220,8 +18768,8 @@ var InboundHub2 = class {
|
|
|
18220
18768
|
|
|
18221
18769
|
// app/lib/webchat/gateway/routes.ts
|
|
18222
18770
|
function createWebchatChannelRoutes(deps) {
|
|
18223
|
-
const
|
|
18224
|
-
|
|
18771
|
+
const app52 = new Hono();
|
|
18772
|
+
app52.get("/webchat-channel/inbound", (c) => {
|
|
18225
18773
|
const key = c.req.query("key");
|
|
18226
18774
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
18227
18775
|
return streamSSE(c, async (stream2) => {
|
|
@@ -18239,7 +18787,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18239
18787
|
}
|
|
18240
18788
|
});
|
|
18241
18789
|
});
|
|
18242
|
-
|
|
18790
|
+
app52.post("/webchat-channel/reply", async (c) => {
|
|
18243
18791
|
const body = await c.req.json().catch(() => null);
|
|
18244
18792
|
const key = body?.key;
|
|
18245
18793
|
const text = body?.text;
|
|
@@ -18249,7 +18797,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18249
18797
|
deps.onReply?.(key, text);
|
|
18250
18798
|
return c.json({ ok: true });
|
|
18251
18799
|
});
|
|
18252
|
-
|
|
18800
|
+
app52.post("/webchat-channel/ready", async (c) => {
|
|
18253
18801
|
const body = await c.req.json().catch(() => null);
|
|
18254
18802
|
const key = body?.key;
|
|
18255
18803
|
if (typeof key !== "string") {
|
|
@@ -18258,7 +18806,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18258
18806
|
deps.onReady?.(key);
|
|
18259
18807
|
return c.json({ ok: true });
|
|
18260
18808
|
});
|
|
18261
|
-
|
|
18809
|
+
app52.post("/webchat-channel/received", async (c) => {
|
|
18262
18810
|
const body = await c.req.json().catch(() => null);
|
|
18263
18811
|
const key = body?.key;
|
|
18264
18812
|
const messageId = body?.messageId;
|
|
@@ -18268,7 +18816,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18268
18816
|
deps.onReceived?.(key, messageId);
|
|
18269
18817
|
return c.json({ ok: true });
|
|
18270
18818
|
});
|
|
18271
|
-
return
|
|
18819
|
+
return app52;
|
|
18272
18820
|
}
|
|
18273
18821
|
|
|
18274
18822
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -18581,7 +19129,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
18581
19129
|
|
|
18582
19130
|
// ../lib/entitlement/src/index.ts
|
|
18583
19131
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
18584
|
-
import { existsSync as
|
|
19132
|
+
import { existsSync as existsSync29, readFileSync as readFileSync27, statSync as statSync12 } from "fs";
|
|
18585
19133
|
import { resolve as resolve30 } from "path";
|
|
18586
19134
|
|
|
18587
19135
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -18630,10 +19178,10 @@ function resolveEntitlement(brand, account) {
|
|
|
18630
19178
|
return logResolved(implicitTrust(account), null);
|
|
18631
19179
|
}
|
|
18632
19180
|
const entitlementPath = resolve30(brand.configDir, "entitlement.json");
|
|
18633
|
-
if (!
|
|
19181
|
+
if (!existsSync29(entitlementPath)) {
|
|
18634
19182
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
18635
19183
|
}
|
|
18636
|
-
const stat7 =
|
|
19184
|
+
const stat7 = statSync12(entitlementPath);
|
|
18637
19185
|
const key = memoKey(stat7.mtimeMs, account);
|
|
18638
19186
|
if (memo && memo.key === key) {
|
|
18639
19187
|
return memo.result;
|
|
@@ -18645,7 +19193,7 @@ function resolveEntitlement(brand, account) {
|
|
|
18645
19193
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
18646
19194
|
let pubkeyPem;
|
|
18647
19195
|
try {
|
|
18648
|
-
pubkeyPem =
|
|
19196
|
+
pubkeyPem = readFileSync27(pubkeyPath(brand), "utf-8");
|
|
18649
19197
|
} catch (err) {
|
|
18650
19198
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
18651
19199
|
reason: "pubkey-missing"
|
|
@@ -18659,7 +19207,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
18659
19207
|
}
|
|
18660
19208
|
let envelope;
|
|
18661
19209
|
try {
|
|
18662
|
-
envelope = JSON.parse(
|
|
19210
|
+
envelope = JSON.parse(readFileSync27(entitlementPath, "utf-8"));
|
|
18663
19211
|
} catch {
|
|
18664
19212
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
18665
19213
|
}
|
|
@@ -18820,14 +19368,14 @@ function clientFrom(c) {
|
|
|
18820
19368
|
);
|
|
18821
19369
|
}
|
|
18822
19370
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
18823
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
19371
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join26(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
18824
19372
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
18825
|
-
if (BRAND_JSON_PATH && !
|
|
19373
|
+
if (BRAND_JSON_PATH && !existsSync30(BRAND_JSON_PATH)) {
|
|
18826
19374
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
18827
19375
|
}
|
|
18828
|
-
if (BRAND_JSON_PATH &&
|
|
19376
|
+
if (BRAND_JSON_PATH && existsSync30(BRAND_JSON_PATH)) {
|
|
18829
19377
|
try {
|
|
18830
|
-
const parsed = JSON.parse(
|
|
19378
|
+
const parsed = JSON.parse(readFileSync28(BRAND_JSON_PATH, "utf-8"));
|
|
18831
19379
|
BRAND = { ...BRAND, ...parsed };
|
|
18832
19380
|
} catch (err) {
|
|
18833
19381
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -18846,11 +19394,11 @@ var brandLoginOpts = {
|
|
|
18846
19394
|
bodyFont: BRAND.defaultFonts?.body,
|
|
18847
19395
|
logoContainsName: !!BRAND.logoContainsName
|
|
18848
19396
|
};
|
|
18849
|
-
var ALIAS_DOMAINS_PATH =
|
|
19397
|
+
var ALIAS_DOMAINS_PATH = join26(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
18850
19398
|
function loadAliasDomains() {
|
|
18851
19399
|
try {
|
|
18852
|
-
if (!
|
|
18853
|
-
const parsed = JSON.parse(
|
|
19400
|
+
if (!existsSync30(ALIAS_DOMAINS_PATH)) return null;
|
|
19401
|
+
const parsed = JSON.parse(readFileSync28(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
18854
19402
|
if (!Array.isArray(parsed)) {
|
|
18855
19403
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
18856
19404
|
return null;
|
|
@@ -18874,11 +19422,11 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
18874
19422
|
function isPublicHost(host) {
|
|
18875
19423
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
18876
19424
|
}
|
|
18877
|
-
var
|
|
19425
|
+
var app51 = new Hono();
|
|
18878
19426
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
18879
19427
|
var waGateway = new WaGateway({
|
|
18880
19428
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
18881
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ??
|
|
19429
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join26(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
18882
19430
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
18883
19431
|
// account + path validation here and funnel through the shared send core.
|
|
18884
19432
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -18894,7 +19442,7 @@ var waGateway = new WaGateway({
|
|
|
18894
19442
|
caption,
|
|
18895
19443
|
accountId,
|
|
18896
19444
|
maxyAccountId,
|
|
18897
|
-
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ??
|
|
19445
|
+
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ?? join26(__dirname, ".."))
|
|
18898
19446
|
});
|
|
18899
19447
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
18900
19448
|
},
|
|
@@ -18924,7 +19472,7 @@ var waGateway = new WaGateway({
|
|
|
18924
19472
|
nativeFileFollowers.set(senderId, ac);
|
|
18925
19473
|
}
|
|
18926
19474
|
});
|
|
18927
|
-
|
|
19475
|
+
app51.route("/", waGateway.routes());
|
|
18928
19476
|
waGateway.startSweeper();
|
|
18929
19477
|
var webchatGateway = new WebchatGateway({
|
|
18930
19478
|
gatewayUrl: webchatGatewayUrl(),
|
|
@@ -18964,15 +19512,15 @@ var webchatGateway = new WebchatGateway({
|
|
|
18964
19512
|
deleteSession: (sessionId) => managerDelete(sessionId),
|
|
18965
19513
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
18966
19514
|
});
|
|
18967
|
-
|
|
19515
|
+
app51.route("/", webchatGateway.routes());
|
|
18968
19516
|
webchatGateway.startSweeper();
|
|
18969
19517
|
webchatGateway.startPublicReaper();
|
|
18970
19518
|
var chatRoutes = createChatRoutes({
|
|
18971
19519
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
18972
19520
|
awaitReply: (key, timeoutMs) => webchatGateway.awaitReply(key, timeoutMs)
|
|
18973
19521
|
});
|
|
18974
|
-
|
|
18975
|
-
|
|
19522
|
+
app51.use("*", clientIpMiddleware);
|
|
19523
|
+
app51.use("*", async (c, next) => {
|
|
18976
19524
|
await next();
|
|
18977
19525
|
c.header("X-Content-Type-Options", "nosniff");
|
|
18978
19526
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -18982,7 +19530,7 @@ app50.use("*", async (c, next) => {
|
|
|
18982
19530
|
);
|
|
18983
19531
|
});
|
|
18984
19532
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
18985
|
-
|
|
19533
|
+
app51.use("*", async (c, next) => {
|
|
18986
19534
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
18987
19535
|
await next();
|
|
18988
19536
|
return;
|
|
@@ -19000,7 +19548,7 @@ app50.use("*", async (c, next) => {
|
|
|
19000
19548
|
});
|
|
19001
19549
|
}
|
|
19002
19550
|
});
|
|
19003
|
-
|
|
19551
|
+
app51.use("*", async (c, next) => {
|
|
19004
19552
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19005
19553
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
19006
19554
|
await next();
|
|
@@ -19031,7 +19579,7 @@ function resolveRemoteAuthOpts() {
|
|
|
19031
19579
|
return brandLoginOpts;
|
|
19032
19580
|
}
|
|
19033
19581
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
19034
|
-
|
|
19582
|
+
app51.post("/__remote-auth/login", async (c) => {
|
|
19035
19583
|
const client = clientFrom(c);
|
|
19036
19584
|
const clientIp = client.ip || "unknown";
|
|
19037
19585
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -19076,7 +19624,7 @@ app50.post("/__remote-auth/login", async (c) => {
|
|
|
19076
19624
|
}
|
|
19077
19625
|
});
|
|
19078
19626
|
});
|
|
19079
|
-
|
|
19627
|
+
app51.get("/__remote-auth/logout", (c) => {
|
|
19080
19628
|
const client = clientFrom(c);
|
|
19081
19629
|
const clientIp = client.ip || "unknown";
|
|
19082
19630
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -19089,7 +19637,7 @@ app50.get("/__remote-auth/logout", (c) => {
|
|
|
19089
19637
|
}
|
|
19090
19638
|
});
|
|
19091
19639
|
});
|
|
19092
|
-
|
|
19640
|
+
app51.post("/__remote-auth/change-password", async (c) => {
|
|
19093
19641
|
const client = clientFrom(c);
|
|
19094
19642
|
const clientIp = client.ip || "unknown";
|
|
19095
19643
|
const rateLimited = checkRateLimit(client);
|
|
@@ -19148,13 +19696,13 @@ app50.post("/__remote-auth/change-password", async (c) => {
|
|
|
19148
19696
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
19149
19697
|
}
|
|
19150
19698
|
});
|
|
19151
|
-
|
|
19699
|
+
app51.get("/__remote-auth/setup", (c) => {
|
|
19152
19700
|
if (isRemoteAuthConfigured()) {
|
|
19153
19701
|
return c.redirect("/");
|
|
19154
19702
|
}
|
|
19155
19703
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
19156
19704
|
});
|
|
19157
|
-
|
|
19705
|
+
app51.post("/__remote-auth/set-initial-password", async (c) => {
|
|
19158
19706
|
if (isRemoteAuthConfigured()) {
|
|
19159
19707
|
return c.redirect("/");
|
|
19160
19708
|
}
|
|
@@ -19192,10 +19740,10 @@ app50.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
19192
19740
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
19193
19741
|
}
|
|
19194
19742
|
});
|
|
19195
|
-
|
|
19743
|
+
app51.get("/api/remote-auth/status", (c) => {
|
|
19196
19744
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
19197
19745
|
});
|
|
19198
|
-
|
|
19746
|
+
app51.post("/api/remote-auth/set-password", async (c) => {
|
|
19199
19747
|
let body;
|
|
19200
19748
|
try {
|
|
19201
19749
|
body = await c.req.json();
|
|
@@ -19234,10 +19782,10 @@ app50.post("/api/remote-auth/set-password", async (c) => {
|
|
|
19234
19782
|
return c.json({ error: "Failed to save password" }, 500);
|
|
19235
19783
|
}
|
|
19236
19784
|
});
|
|
19237
|
-
|
|
19785
|
+
app51.route("/api/_client-error", client_error_default);
|
|
19238
19786
|
console.log("[client-error-route] mounted");
|
|
19239
19787
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
19240
|
-
|
|
19788
|
+
app51.use("*", async (c, next) => {
|
|
19241
19789
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19242
19790
|
const path2 = c.req.path;
|
|
19243
19791
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") || PWA_PUBLIC_PATHS.has(path2)) {
|
|
@@ -19277,18 +19825,18 @@ app50.use("*", async (c, next) => {
|
|
|
19277
19825
|
}
|
|
19278
19826
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
19279
19827
|
});
|
|
19280
|
-
|
|
19281
|
-
|
|
19282
|
-
|
|
19283
|
-
|
|
19284
|
-
|
|
19285
|
-
|
|
19286
|
-
|
|
19287
|
-
|
|
19288
|
-
|
|
19289
|
-
|
|
19290
|
-
|
|
19291
|
-
|
|
19828
|
+
app51.route("/api/health", health_default);
|
|
19829
|
+
app51.route("/api/chat", chatRoutes);
|
|
19830
|
+
app51.route("/api/whatsapp", whatsapp_default);
|
|
19831
|
+
app51.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
19832
|
+
app51.route("/api/public-reader", public_reader_default);
|
|
19833
|
+
app51.route("/api/webchat", createWebchatRoutes({ handleInbound: (input) => webchatGateway.handleInbound(input) }));
|
|
19834
|
+
app51.route("/api/webchat/greeting", webchat_greeting_default);
|
|
19835
|
+
app51.route("/api/telegram", telegram_default);
|
|
19836
|
+
app51.route("/api/onboarding", onboarding_default);
|
|
19837
|
+
app51.route("/api/admin", admin_default);
|
|
19838
|
+
app51.route("/api/access", access_default);
|
|
19839
|
+
app51.route("/api/session", session_default2);
|
|
19292
19840
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
19293
19841
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
19294
19842
|
var IMAGE_MIME = {
|
|
@@ -19300,7 +19848,7 @@ var IMAGE_MIME = {
|
|
|
19300
19848
|
".svg": "image/svg+xml",
|
|
19301
19849
|
".ico": "image/x-icon"
|
|
19302
19850
|
};
|
|
19303
|
-
|
|
19851
|
+
app51.get("/agent-assets/:slug/:filename", (c) => {
|
|
19304
19852
|
const slug = c.req.param("slug");
|
|
19305
19853
|
const filename = c.req.param("filename");
|
|
19306
19854
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -19322,20 +19870,20 @@ app50.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
19322
19870
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
19323
19871
|
return c.text("Forbidden", 403);
|
|
19324
19872
|
}
|
|
19325
|
-
if (!
|
|
19873
|
+
if (!existsSync30(filePath)) {
|
|
19326
19874
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
19327
19875
|
return c.text("Not found", 404);
|
|
19328
19876
|
}
|
|
19329
19877
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
19330
19878
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
19331
19879
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
19332
|
-
const body =
|
|
19880
|
+
const body = readFileSync28(filePath);
|
|
19333
19881
|
return c.body(body, 200, {
|
|
19334
19882
|
"Content-Type": contentType,
|
|
19335
19883
|
"Cache-Control": "public, max-age=3600"
|
|
19336
19884
|
});
|
|
19337
19885
|
});
|
|
19338
|
-
|
|
19886
|
+
app51.get("/generated/:filename", (c) => {
|
|
19339
19887
|
const filename = c.req.param("filename");
|
|
19340
19888
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
19341
19889
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -19352,29 +19900,29 @@ app50.get("/generated/:filename", (c) => {
|
|
|
19352
19900
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
19353
19901
|
return c.text("Forbidden", 403);
|
|
19354
19902
|
}
|
|
19355
|
-
if (!
|
|
19903
|
+
if (!existsSync30(filePath)) {
|
|
19356
19904
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
19357
19905
|
return c.text("Not found", 404);
|
|
19358
19906
|
}
|
|
19359
19907
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
19360
19908
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
19361
19909
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
19362
|
-
const body =
|
|
19910
|
+
const body = readFileSync28(filePath);
|
|
19363
19911
|
return c.body(body, 200, {
|
|
19364
19912
|
"Content-Type": contentType,
|
|
19365
19913
|
"Cache-Control": "public, max-age=86400"
|
|
19366
19914
|
});
|
|
19367
19915
|
});
|
|
19368
|
-
|
|
19369
|
-
|
|
19370
|
-
|
|
19371
|
-
|
|
19916
|
+
app51.route("/sites", sites_default);
|
|
19917
|
+
app51.route("/listings", listings_default);
|
|
19918
|
+
app51.route("/v", visitor_event_default);
|
|
19919
|
+
app51.route("/v", visitor_consent_default);
|
|
19372
19920
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
19373
19921
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
19374
19922
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
19375
|
-
if (BRAND_JSON_PATH &&
|
|
19923
|
+
if (BRAND_JSON_PATH && existsSync30(BRAND_JSON_PATH)) {
|
|
19376
19924
|
try {
|
|
19377
|
-
const fullBrand = JSON.parse(
|
|
19925
|
+
const fullBrand = JSON.parse(readFileSync28(BRAND_JSON_PATH, "utf-8"));
|
|
19378
19926
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
19379
19927
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
19380
19928
|
} catch {
|
|
@@ -19391,10 +19939,10 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
19391
19939
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
19392
19940
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
19393
19941
|
var brandIconFsPath = resolve31(process.cwd(), "public", brandIconPath.replace(/^\//, ""));
|
|
19394
|
-
var brandIconExists =
|
|
19942
|
+
var brandIconExists = existsSync30(brandIconFsPath);
|
|
19395
19943
|
var SW_SOURCE = (() => {
|
|
19396
19944
|
try {
|
|
19397
|
-
return
|
|
19945
|
+
return readFileSync28(resolve31(process.cwd(), "public", "sw.js"), "utf-8");
|
|
19398
19946
|
} catch {
|
|
19399
19947
|
return null;
|
|
19400
19948
|
}
|
|
@@ -19402,9 +19950,9 @@ var SW_SOURCE = (() => {
|
|
|
19402
19950
|
function readInstalledVersion() {
|
|
19403
19951
|
try {
|
|
19404
19952
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
19405
|
-
const versionFile =
|
|
19406
|
-
if (!
|
|
19407
|
-
const content =
|
|
19953
|
+
const versionFile = join26(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
19954
|
+
if (!existsSync30(versionFile)) return "unknown";
|
|
19955
|
+
const content = readFileSync28(versionFile, "utf-8").trim();
|
|
19408
19956
|
return content || "unknown";
|
|
19409
19957
|
} catch {
|
|
19410
19958
|
return "unknown";
|
|
@@ -19445,7 +19993,7 @@ var clientErrorReporterScript = `<script>
|
|
|
19445
19993
|
function cachedHtml(file) {
|
|
19446
19994
|
let html = htmlCache.get(file);
|
|
19447
19995
|
if (!html) {
|
|
19448
|
-
html =
|
|
19996
|
+
html = readFileSync28(resolve31(process.cwd(), "public", file), "utf-8");
|
|
19449
19997
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
19450
19998
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
19451
19999
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -19463,13 +20011,13 @@ ${clientErrorReporterScript}
|
|
|
19463
20011
|
}
|
|
19464
20012
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
19465
20013
|
function loadBrandingCache(agentSlug) {
|
|
19466
|
-
const configDir2 =
|
|
20014
|
+
const configDir2 = join26(homedir3(), BRAND.configDir);
|
|
19467
20015
|
try {
|
|
19468
20016
|
const accountId = getDefaultAccountId();
|
|
19469
20017
|
if (!accountId) return null;
|
|
19470
|
-
const cachePath =
|
|
19471
|
-
if (!
|
|
19472
|
-
return JSON.parse(
|
|
20018
|
+
const cachePath = join26(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
20019
|
+
if (!existsSync30(cachePath)) return null;
|
|
20020
|
+
return JSON.parse(readFileSync28(cachePath, "utf-8"));
|
|
19473
20021
|
} catch {
|
|
19474
20022
|
return null;
|
|
19475
20023
|
}
|
|
@@ -19515,7 +20063,7 @@ function escapeHtml(s) {
|
|
|
19515
20063
|
function agentUnavailableHtml() {
|
|
19516
20064
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(BRAND.productName)}</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;padding:0 1.5rem;color:#222"><h1 style="font-size:1.25rem">Agent unavailable</h1><p>This agent isn't available right now. If you reached this page from a saved link, the agent may have been turned off.</p></body></html>`;
|
|
19517
20065
|
}
|
|
19518
|
-
|
|
20066
|
+
app51.get("/", (c) => {
|
|
19519
20067
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19520
20068
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
19521
20069
|
if (klass === "operator") {
|
|
@@ -19538,13 +20086,13 @@ app50.get("/", (c) => {
|
|
|
19538
20086
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
19539
20087
|
return c.html(cachedHtml("index.html"));
|
|
19540
20088
|
});
|
|
19541
|
-
|
|
20089
|
+
app51.get("/public", (c) => {
|
|
19542
20090
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19543
20091
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19544
20092
|
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
19545
20093
|
return c.html(cachedHtml("public.html"));
|
|
19546
20094
|
});
|
|
19547
|
-
|
|
20095
|
+
app51.get("/public-chat", (c) => {
|
|
19548
20096
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19549
20097
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19550
20098
|
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
@@ -19564,12 +20112,12 @@ async function logViewerFetch(c, next) {
|
|
|
19564
20112
|
duration_ms: Date.now() - start
|
|
19565
20113
|
});
|
|
19566
20114
|
}
|
|
19567
|
-
|
|
19568
|
-
|
|
19569
|
-
|
|
20115
|
+
app51.use("/vnc-viewer.html", logViewerFetch);
|
|
20116
|
+
app51.use("/vnc-popout.html", logViewerFetch);
|
|
20117
|
+
app51.get("/vnc-popout.html", (c) => {
|
|
19570
20118
|
let html = htmlCache.get("vnc-popout.html");
|
|
19571
20119
|
if (!html) {
|
|
19572
|
-
html =
|
|
20120
|
+
html = readFileSync28(resolve31(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
19573
20121
|
const name = escapeHtml(BRAND.productName);
|
|
19574
20122
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
19575
20123
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -19579,7 +20127,7 @@ app50.get("/vnc-popout.html", (c) => {
|
|
|
19579
20127
|
}
|
|
19580
20128
|
return c.html(html);
|
|
19581
20129
|
});
|
|
19582
|
-
|
|
20130
|
+
app51.post("/api/vnc/client-event", async (c) => {
|
|
19583
20131
|
let body;
|
|
19584
20132
|
try {
|
|
19585
20133
|
body = await c.req.json();
|
|
@@ -19600,11 +20148,11 @@ app50.post("/api/vnc/client-event", async (c) => {
|
|
|
19600
20148
|
});
|
|
19601
20149
|
return c.json({ ok: true });
|
|
19602
20150
|
});
|
|
19603
|
-
|
|
20151
|
+
app51.get("/g/:slug", (c) => {
|
|
19604
20152
|
return c.html(brandedPublicHtml());
|
|
19605
20153
|
});
|
|
19606
20154
|
for (const pwa of PWA_SURFACES) {
|
|
19607
|
-
|
|
20155
|
+
app51.get(pwa.manifestPath, (c) => {
|
|
19608
20156
|
const manifest = buildManifest(pwa, {
|
|
19609
20157
|
productName: BRAND.productName,
|
|
19610
20158
|
iconPath: brandIconPath,
|
|
@@ -19618,7 +20166,7 @@ for (const pwa of PWA_SURFACES) {
|
|
|
19618
20166
|
return c.body(JSON.stringify(manifest));
|
|
19619
20167
|
});
|
|
19620
20168
|
}
|
|
19621
|
-
|
|
20169
|
+
app51.get("/sw.js", (c) => {
|
|
19622
20170
|
if (SW_SOURCE == null) {
|
|
19623
20171
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
19624
20172
|
return c.text("Service worker unavailable", 500);
|
|
@@ -19627,27 +20175,27 @@ app50.get("/sw.js", (c) => {
|
|
|
19627
20175
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
19628
20176
|
return c.body(SW_SOURCE);
|
|
19629
20177
|
});
|
|
19630
|
-
|
|
20178
|
+
app51.get("/graph", (c) => {
|
|
19631
20179
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19632
20180
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
19633
20181
|
return c.html(cachedHtml("graph.html"));
|
|
19634
20182
|
});
|
|
19635
|
-
|
|
20183
|
+
app51.get("/chat", (c) => {
|
|
19636
20184
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19637
20185
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19638
20186
|
return c.html(cachedHtml("chat.html"));
|
|
19639
20187
|
});
|
|
19640
|
-
|
|
20188
|
+
app51.get("/data", (c) => {
|
|
19641
20189
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19642
20190
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19643
20191
|
return c.html(cachedHtml("data.html"));
|
|
19644
20192
|
});
|
|
19645
|
-
|
|
20193
|
+
app51.get("/browser", (c) => {
|
|
19646
20194
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19647
20195
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
19648
20196
|
return c.html(cachedHtml("browser.html"));
|
|
19649
20197
|
});
|
|
19650
|
-
|
|
20198
|
+
app51.get("/:slug", async (c, next) => {
|
|
19651
20199
|
const slug = c.req.param("slug");
|
|
19652
20200
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
19653
20201
|
const account = resolveAccount();
|
|
@@ -19663,13 +20211,13 @@ app50.get("/:slug", async (c, next) => {
|
|
|
19663
20211
|
await next();
|
|
19664
20212
|
});
|
|
19665
20213
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
19666
|
-
|
|
20214
|
+
app51.get("/favicon.ico", (c) => {
|
|
19667
20215
|
c.header("Cache-Control", "public, max-age=300");
|
|
19668
20216
|
return c.redirect(brandFaviconPath, 302);
|
|
19669
20217
|
});
|
|
19670
20218
|
}
|
|
19671
|
-
|
|
19672
|
-
|
|
20219
|
+
app51.use("/*", serveStatic({ root: "./public" }));
|
|
20220
|
+
app51.all("*", (c) => {
|
|
19673
20221
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19674
20222
|
const path2 = c.req.path;
|
|
19675
20223
|
if (isPublicHost(host)) {
|
|
@@ -19683,7 +20231,7 @@ app50.all("*", (c) => {
|
|
|
19683
20231
|
});
|
|
19684
20232
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
19685
20233
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
19686
|
-
var httpServer = serve({ fetch:
|
|
20234
|
+
var httpServer = serve({ fetch: app51.fetch, port, hostname });
|
|
19687
20235
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
19688
20236
|
{
|
|
19689
20237
|
const census = pwaCensus({
|
|
@@ -19737,7 +20285,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
19737
20285
|
}
|
|
19738
20286
|
try {
|
|
19739
20287
|
const registered = [];
|
|
19740
|
-
for (const r of
|
|
20288
|
+
for (const r of app51.routes ?? []) {
|
|
19741
20289
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
19742
20290
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
19743
20291
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -19777,11 +20325,11 @@ try {
|
|
|
19777
20325
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
19778
20326
|
async function runAdminUserReconcileTick() {
|
|
19779
20327
|
try {
|
|
19780
|
-
if (!
|
|
20328
|
+
if (!existsSync30(USERS_FILE)) {
|
|
19781
20329
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
19782
20330
|
return;
|
|
19783
20331
|
}
|
|
19784
|
-
const usersRaw =
|
|
20332
|
+
const usersRaw = readFileSync28(USERS_FILE, "utf-8").trim();
|
|
19785
20333
|
if (!usersRaw) {
|
|
19786
20334
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
19787
20335
|
return;
|
|
@@ -19813,6 +20361,7 @@ void migrateUploads().catch((err) => console.error(`[uploads-migrate] failed err
|
|
|
19813
20361
|
console.error(`[file-watcher] start-failed err="${err instanceof Error ? err.message : String(err)}"`);
|
|
19814
20362
|
});
|
|
19815
20363
|
});
|
|
20364
|
+
void sweepStaleUploadTemps().catch((err) => console.error(`[data-upload] op=sweep-failed err="${err instanceof Error ? err.message : String(err)}"`));
|
|
19816
20365
|
void migrateAdminWebchatSidecars().catch((err) => console.error(`[sidecar-backfill] failed err="${err instanceof Error ? err.message : String(err)}"`));
|
|
19817
20366
|
try {
|
|
19818
20367
|
const accounts = enumerateValidAccountIds(getAccountsDirFromEnv());
|
|
@@ -19894,7 +20443,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
19894
20443
|
}
|
|
19895
20444
|
init({
|
|
19896
20445
|
configDir: configDirForWhatsApp,
|
|
19897
|
-
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ??
|
|
20446
|
+
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ?? join26(__dirname, "..")),
|
|
19898
20447
|
accountConfig: bootAccountConfig,
|
|
19899
20448
|
onMessage: async (msg) => {
|
|
19900
20449
|
if (msg.isOwnerMirror) {
|