@rubytech/create-maxy-code 0.1.311 → 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 +20 -2
- package/payload/platform/plugins/docs/references/admin-ui.md +19 -1
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts +10 -0
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js +62 -53
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js.map +1 -1
- 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-ChFLk-rp.js → AccessGate-Dh5A79FU.js} +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-DU6zgbk5.js → AdminLoginScreens-B8s2TbT7.js} +1 -1
- package/payload/server/public/assets/AdminShell-Cu1zlb6L.js +1 -0
- package/payload/server/public/assets/{Checkbox-CQGLKMXu.js → Checkbox-B_sOAyv1.js} +1 -1
- package/payload/server/public/assets/OperatorConversations-hm0Gpu_Q.js +1 -0
- package/payload/server/public/assets/{admin-COHPIWdb.js → admin-gZEndvJT.js} +1 -1
- package/payload/server/public/assets/{audio-attachment-mime-DL06xo72.js → audio-attachment-mime-B0b89VnH.js} +1 -1
- package/payload/server/public/assets/{brand-CN7uSSKl.css → brand-BcNavK6q.css} +1 -1
- package/payload/server/public/assets/{browser-L7N4tAOl.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-Cro3-mgY.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-CX148JKi.js → public-G_-UI9nB.js} +1 -1
- package/payload/server/public/assets/{public-next-BCItsUbZ.js → public-next-C8_nExQB.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-BHAAhkDg.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 +832 -444
- package/payload/server/public/assets/AdminShell-BJCYb1v5.js +0 -1
- package/payload/server/public/assets/OperatorConversations-CHEQTz20.js +0 -1
- package/payload/server/public/assets/chat-B_jYIH9a.js +0 -1
- package/payload/server/public/assets/data-BmSTKHR1.js +0 -1
- package/payload/server/public/assets/graph-labels-WQQn6JIJ.js +0 -1
- package/payload/server/public/assets/operator-B4I25isQ.js +0 -1
- package/payload/server/public/assets/page-B-6ZQ4JG.js +0 -1
- /package/payload/server/public/assets/{brand-MKGM8WZp.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
|
|
|
@@ -4941,6 +4985,7 @@ var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
|
4941
4985
|
]);
|
|
4942
4986
|
var MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024;
|
|
4943
4987
|
var MAX_FILES_PER_MESSAGE = 5;
|
|
4988
|
+
var MAX_DATA_UPLOAD_BYTES = 2 * 1024 * 1024 * 1024;
|
|
4944
4989
|
var MAX_ZIP_UNCOMPRESSED_BYTES = 100 * 1024 * 1024;
|
|
4945
4990
|
function assertSupportedMime(mimeType) {
|
|
4946
4991
|
if (!SUPPORTED_MIME_TYPES.has(mimeType)) {
|
|
@@ -5180,8 +5225,8 @@ function webchatTurnTimeoutMs() {
|
|
|
5180
5225
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
5181
5226
|
}
|
|
5182
5227
|
function createChatRoutes(deps) {
|
|
5183
|
-
const
|
|
5184
|
-
|
|
5228
|
+
const app52 = new Hono();
|
|
5229
|
+
app52.post("/", async (c) => {
|
|
5185
5230
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
5186
5231
|
const contentType = c.req.header("content-type") ?? "";
|
|
5187
5232
|
const account = resolveAccount();
|
|
@@ -5404,7 +5449,7 @@ ${result.result.text}` : result.result.text;
|
|
|
5404
5449
|
}
|
|
5405
5450
|
});
|
|
5406
5451
|
});
|
|
5407
|
-
return
|
|
5452
|
+
return app52;
|
|
5408
5453
|
}
|
|
5409
5454
|
|
|
5410
5455
|
// server/routes/whatsapp.ts
|
|
@@ -7065,6 +7110,20 @@ function unwrapChannel(text) {
|
|
|
7065
7110
|
}
|
|
7066
7111
|
return source ? { text: inner, source } : { text: inner };
|
|
7067
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
|
+
}
|
|
7068
7127
|
function asString(content) {
|
|
7069
7128
|
return typeof content === "string" ? content : null;
|
|
7070
7129
|
}
|
|
@@ -7127,6 +7186,14 @@ function lastTurnTs(turns) {
|
|
|
7127
7186
|
function isModelGated(turns) {
|
|
7128
7187
|
return turns.some((t) => t.kind === "agent-error" && t.code === "model_unavailable");
|
|
7129
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
|
+
}
|
|
7130
7197
|
function parseTranscript(lines) {
|
|
7131
7198
|
const out = [];
|
|
7132
7199
|
const queuedPendingSuppress = /* @__PURE__ */ new Map();
|
|
@@ -7158,7 +7225,7 @@ function parseTranscript(lines) {
|
|
|
7158
7225
|
const content = asString(row.content);
|
|
7159
7226
|
if (content !== null && CHANNEL_WRAPPER2.test(content)) {
|
|
7160
7227
|
const u = unwrapChannel(content);
|
|
7161
|
-
out.push(
|
|
7228
|
+
out.push(operatorInboundTurn(u, ts));
|
|
7162
7229
|
queuedPendingSuppress.set(u.text, (queuedPendingSuppress.get(u.text) ?? 0) + 1);
|
|
7163
7230
|
}
|
|
7164
7231
|
continue;
|
|
@@ -7167,13 +7234,7 @@ function parseTranscript(lines) {
|
|
|
7167
7234
|
const att = row.attachment;
|
|
7168
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";
|
|
7169
7236
|
if (isChannelQueued) {
|
|
7170
|
-
|
|
7171
|
-
const armed = queuedPendingSuppress.get(u.text) ?? 0;
|
|
7172
|
-
if (armed > 0) {
|
|
7173
|
-
queuedPendingSuppress.set(u.text, armed - 1);
|
|
7174
|
-
} else {
|
|
7175
|
-
out.push({ kind: "operator-inbound", text: u.text, ts, ...u.source ? { source: u.source } : {} });
|
|
7176
|
-
}
|
|
7237
|
+
renderOrSuppressChannelInbound(unwrapChannel(att.prompt), ts, out, queuedPendingSuppress);
|
|
7177
7238
|
}
|
|
7178
7239
|
continue;
|
|
7179
7240
|
}
|
|
@@ -7187,8 +7248,7 @@ function parseTranscript(lines) {
|
|
|
7187
7248
|
if (CLI_MARKER_PREFIXES2.some((p) => text.startsWith(p))) continue;
|
|
7188
7249
|
const isChannel = row.isMeta === true && typeof row.origin === "object" && row.origin !== null && row.origin.kind === "channel";
|
|
7189
7250
|
if (isChannel) {
|
|
7190
|
-
|
|
7191
|
-
out.push({ kind: "operator-inbound", text: u.text, ts, ...u.source ? { source: u.source } : {} });
|
|
7251
|
+
renderOrSuppressChannelInbound(unwrapChannel(text), ts, out, queuedPendingSuppress);
|
|
7192
7252
|
} else {
|
|
7193
7253
|
out.push({ kind: "operator-typed", text, ts });
|
|
7194
7254
|
}
|
|
@@ -7650,8 +7710,8 @@ var public_reader_default = app5;
|
|
|
7650
7710
|
|
|
7651
7711
|
// server/routes/webchat.ts
|
|
7652
7712
|
import { basename as basename4, dirname as dirname3 } from "path";
|
|
7653
|
-
import { join as
|
|
7654
|
-
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";
|
|
7655
7715
|
|
|
7656
7716
|
// server/canonical-webchat-override.ts
|
|
7657
7717
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync5, renameSync } from "fs";
|
|
@@ -7688,16 +7748,141 @@ function adminSessionIdFor(accountId, senderId, personId) {
|
|
|
7688
7748
|
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
|
|
7689
7749
|
}
|
|
7690
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
|
+
|
|
7691
7876
|
// server/routes/webchat.ts
|
|
7692
7877
|
var WEBCHAT_ADMIN_KEY = "webchat-admin";
|
|
7693
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;
|
|
7694
7879
|
function locateSession(sessionId) {
|
|
7695
7880
|
const cfg = claudeConfigDir();
|
|
7696
7881
|
if (!cfg) return { projectDir: null, channel: null };
|
|
7697
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
7882
|
+
for (const { path: path2 } of enumerateJsonls(join14(cfg, "projects"))) {
|
|
7698
7883
|
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
7699
7884
|
const dir = dirname3(path2);
|
|
7700
|
-
const meta = readSidecarMeta(
|
|
7885
|
+
const meta = readSidecarMeta(join14(dir, `${sessionId}.meta.json`));
|
|
7701
7886
|
return { projectDir: dir, channel: meta.channel };
|
|
7702
7887
|
}
|
|
7703
7888
|
}
|
|
@@ -7706,16 +7891,16 @@ function locateSession(sessionId) {
|
|
|
7706
7891
|
function locateSidecar(sessionId) {
|
|
7707
7892
|
const cfg = claudeConfigDir();
|
|
7708
7893
|
if (!cfg) return null;
|
|
7709
|
-
const projectsRoot =
|
|
7894
|
+
const projectsRoot = join14(cfg, "projects");
|
|
7710
7895
|
let slugs;
|
|
7711
7896
|
try {
|
|
7712
|
-
slugs =
|
|
7897
|
+
slugs = readdirSync8(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
7713
7898
|
} catch {
|
|
7714
7899
|
return null;
|
|
7715
7900
|
}
|
|
7716
7901
|
for (const slug of slugs) {
|
|
7717
|
-
const metaPath =
|
|
7718
|
-
if (
|
|
7902
|
+
const metaPath = join14(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
7903
|
+
if (existsSync9(metaPath)) {
|
|
7719
7904
|
return { channel: readSidecarMeta(metaPath).channel };
|
|
7720
7905
|
}
|
|
7721
7906
|
}
|
|
@@ -7727,7 +7912,7 @@ function sessionSidecarExists(sessionId) {
|
|
|
7727
7912
|
function jsonlSizeBytes(projectDir, sessionId) {
|
|
7728
7913
|
if (projectDir === null) return null;
|
|
7729
7914
|
try {
|
|
7730
|
-
return statSync6(
|
|
7915
|
+
return statSync6(join14(projectDir, `${sessionId}.jsonl`)).size;
|
|
7731
7916
|
} catch {
|
|
7732
7917
|
return null;
|
|
7733
7918
|
}
|
|
@@ -7792,14 +7977,38 @@ function readLevers(preResolved) {
|
|
|
7792
7977
|
leverMode: typeof mode === "string" && PERMISSION_MODE_VALUES.has(mode) ? mode : null
|
|
7793
7978
|
};
|
|
7794
7979
|
}
|
|
7795
|
-
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" };
|
|
7796
8007
|
if (accountDir) {
|
|
7797
8008
|
const override = readCanonicalOverrideId(accountDir);
|
|
7798
|
-
if (override && (
|
|
7799
|
-
return override;
|
|
7800
|
-
}
|
|
8009
|
+
if (override && overrideKnownNonArchived(override)) return { sessionId: override, source: "override" };
|
|
7801
8010
|
}
|
|
7802
|
-
return adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY);
|
|
8011
|
+
return { sessionId: adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY), source: "canonical-empty" };
|
|
7803
8012
|
}
|
|
7804
8013
|
var REAPPLY_TIMEOUT_MS = 1500;
|
|
7805
8014
|
async function reapplyLeversViaManager() {
|
|
@@ -7822,8 +8031,8 @@ async function reapplyLeversViaManager() {
|
|
|
7822
8031
|
var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
|
|
7823
8032
|
var sendSeq = 0;
|
|
7824
8033
|
function createWebchatRoutes(deps) {
|
|
7825
|
-
const
|
|
7826
|
-
|
|
8034
|
+
const app52 = new Hono();
|
|
8035
|
+
app52.post("/send", requireAdminSession, async (c) => {
|
|
7827
8036
|
let accountId;
|
|
7828
8037
|
try {
|
|
7829
8038
|
accountId = resolvePlatformAccountId();
|
|
@@ -7872,6 +8081,10 @@ function createWebchatRoutes(deps) {
|
|
|
7872
8081
|
}
|
|
7873
8082
|
let deliveryKey = WEBCHAT_ADMIN_KEY;
|
|
7874
8083
|
let deliverySessionId;
|
|
8084
|
+
if (target === void 0) {
|
|
8085
|
+
const latest = latestAdminWebchatSessionId();
|
|
8086
|
+
if (latest !== null) target = latest;
|
|
8087
|
+
}
|
|
7875
8088
|
if (target !== void 0) {
|
|
7876
8089
|
let { projectDir, channel } = locateSession(target);
|
|
7877
8090
|
if (projectDir === null) {
|
|
@@ -7961,7 +8174,7 @@ ${note}` : note;
|
|
|
7961
8174
|
} catch {
|
|
7962
8175
|
canonAccount = null;
|
|
7963
8176
|
}
|
|
7964
|
-
turnSessionId =
|
|
8177
|
+
turnSessionId = resolveCanonical(accountId, canonAccount?.accountDir ?? null).sessionId;
|
|
7965
8178
|
}
|
|
7966
8179
|
const keyDisplay2 = deliveryKey.startsWith("session:") ? deliveryKey.slice(0, "session:".length + 8) : WEBCHAT_ADMIN_KEY;
|
|
7967
8180
|
const baseline = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
|
|
@@ -7978,7 +8191,7 @@ ${note}` : note;
|
|
|
7978
8191
|
if (turnTimer.unref) turnTimer.unref();
|
|
7979
8192
|
return c.json({ ok: true });
|
|
7980
8193
|
});
|
|
7981
|
-
|
|
8194
|
+
app52.post("/settings", requireAdminSession, async (c) => {
|
|
7982
8195
|
const body = await c.req.json().catch(() => null);
|
|
7983
8196
|
const op = body?.op;
|
|
7984
8197
|
const value = body?.value;
|
|
@@ -8000,15 +8213,15 @@ ${note}` : note;
|
|
|
8000
8213
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-unresolved`);
|
|
8001
8214
|
return c.json({ error: "account unresolved" }, 503);
|
|
8002
8215
|
}
|
|
8003
|
-
const accountJsonPath =
|
|
8216
|
+
const accountJsonPath = join14(account.accountDir, "account.json");
|
|
8004
8217
|
try {
|
|
8005
|
-
const parsed = JSON.parse(
|
|
8218
|
+
const parsed = JSON.parse(readFileSync14(accountJsonPath, "utf8"));
|
|
8006
8219
|
if (op === "model") parsed.adminModel = value;
|
|
8007
8220
|
else if (op === "effort") parsed.effort = value;
|
|
8008
8221
|
else parsed.adminPermissionMode = value;
|
|
8009
8222
|
const tmp = `${accountJsonPath}.${process.pid}.tmp`;
|
|
8010
|
-
|
|
8011
|
-
|
|
8223
|
+
writeFileSync7(tmp, JSON.stringify(parsed, null, 2), "utf8");
|
|
8224
|
+
renameSync3(tmp, accountJsonPath);
|
|
8012
8225
|
} catch (err) {
|
|
8013
8226
|
const detail = err instanceof Error ? err.message : String(err);
|
|
8014
8227
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=write-failed detail=${detail}`);
|
|
@@ -8018,7 +8231,7 @@ ${note}` : note;
|
|
|
8018
8231
|
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
8019
8232
|
return c.json({ ok: true, settingsApplied });
|
|
8020
8233
|
});
|
|
8021
|
-
|
|
8234
|
+
app52.get("/session", requireAdminSession, async (c) => {
|
|
8022
8235
|
let accountId;
|
|
8023
8236
|
try {
|
|
8024
8237
|
accountId = resolvePlatformAccountId();
|
|
@@ -8033,9 +8246,26 @@ ${note}` : note;
|
|
|
8033
8246
|
return c.json({ error: "invalid session id" }, 400);
|
|
8034
8247
|
}
|
|
8035
8248
|
const { projectDir: projectDir2, channel } = locateSession(target);
|
|
8036
|
-
|
|
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);
|
|
8037
8267
|
const indicators2 = await fetchComposerIndicators(target);
|
|
8038
|
-
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() });
|
|
8039
8269
|
}
|
|
8040
8270
|
let account;
|
|
8041
8271
|
try {
|
|
@@ -8043,11 +8273,15 @@ ${note}` : note;
|
|
|
8043
8273
|
} catch {
|
|
8044
8274
|
account = null;
|
|
8045
8275
|
}
|
|
8046
|
-
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}`);
|
|
8047
8281
|
const cfg = claudeConfigDir();
|
|
8048
8282
|
let projectDir = null;
|
|
8049
8283
|
if (cfg) {
|
|
8050
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
8284
|
+
for (const { path: path2 } of enumerateJsonls(join14(cfg, "projects"))) {
|
|
8051
8285
|
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
8052
8286
|
projectDir = dirname3(path2);
|
|
8053
8287
|
break;
|
|
@@ -8057,15 +8291,15 @@ ${note}` : note;
|
|
|
8057
8291
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
8058
8292
|
return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), ...indicators, ...readLevers(account) });
|
|
8059
8293
|
});
|
|
8060
|
-
return
|
|
8294
|
+
return app52;
|
|
8061
8295
|
}
|
|
8062
8296
|
|
|
8063
8297
|
// server/routes/webchat-greeting.ts
|
|
8064
8298
|
import { resolve as resolve13 } from "path";
|
|
8065
8299
|
|
|
8066
8300
|
// app/lib/claude-agent/specialist-roster.ts
|
|
8067
|
-
import { existsSync as
|
|
8068
|
-
import { join as
|
|
8301
|
+
import { existsSync as existsSync10, readFileSync as readFileSync15, readdirSync as readdirSync9 } from "fs";
|
|
8302
|
+
import { join as join15 } from "path";
|
|
8069
8303
|
function field(fm, name) {
|
|
8070
8304
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
8071
8305
|
if (!m) return null;
|
|
@@ -8076,15 +8310,15 @@ function field(fm, name) {
|
|
|
8076
8310
|
return value || null;
|
|
8077
8311
|
}
|
|
8078
8312
|
function readSpecialistRoster(specialistsDir) {
|
|
8079
|
-
if (!
|
|
8080
|
-
const entries =
|
|
8313
|
+
if (!existsSync10(specialistsDir)) return { specialists: [], skipped: [] };
|
|
8314
|
+
const entries = readdirSync9(specialistsDir);
|
|
8081
8315
|
const specialists = [];
|
|
8082
8316
|
const skipped = [];
|
|
8083
8317
|
for (const file of entries.sort()) {
|
|
8084
8318
|
if (!file.endsWith(".md")) continue;
|
|
8085
8319
|
let raw;
|
|
8086
8320
|
try {
|
|
8087
|
-
raw =
|
|
8321
|
+
raw = readFileSync15(join15(specialistsDir, file), "utf-8");
|
|
8088
8322
|
} catch (err) {
|
|
8089
8323
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
8090
8324
|
continue;
|
|
@@ -8201,8 +8435,8 @@ var webchat_greeting_default = app6;
|
|
|
8201
8435
|
|
|
8202
8436
|
// server/routes/telegram.ts
|
|
8203
8437
|
import { homedir } from "os";
|
|
8204
|
-
import { resolve as resolve15, join as
|
|
8205
|
-
import { existsSync as
|
|
8438
|
+
import { resolve as resolve15, join as join16 } from "path";
|
|
8439
|
+
import { existsSync as existsSync11, readFileSync as readFileSync16 } from "fs";
|
|
8206
8440
|
|
|
8207
8441
|
// app/lib/channel-pty-bridge/bridge.ts
|
|
8208
8442
|
import { resolve as resolve14 } from "path";
|
|
@@ -9090,10 +9324,10 @@ var TAG23 = "[telegram-inbound]";
|
|
|
9090
9324
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
9091
9325
|
function configDirName() {
|
|
9092
9326
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve15(process.cwd(), "..");
|
|
9093
|
-
const brandPath =
|
|
9094
|
-
if (
|
|
9327
|
+
const brandPath = join16(platformRoot2, "config", "brand.json");
|
|
9328
|
+
if (existsSync11(brandPath)) {
|
|
9095
9329
|
try {
|
|
9096
|
-
return JSON.parse(
|
|
9330
|
+
return JSON.parse(readFileSync16(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
9097
9331
|
} catch {
|
|
9098
9332
|
}
|
|
9099
9333
|
}
|
|
@@ -9125,11 +9359,11 @@ app7.post("/", async (c) => {
|
|
|
9125
9359
|
return c.json({ ok: false }, 400);
|
|
9126
9360
|
}
|
|
9127
9361
|
const sp = secretPath(botType);
|
|
9128
|
-
if (!
|
|
9362
|
+
if (!existsSync11(sp)) {
|
|
9129
9363
|
console.error(`${TAG23} op=reject reason=no-secret-file botType=${botType}`);
|
|
9130
9364
|
return c.json({ ok: false }, 401);
|
|
9131
9365
|
}
|
|
9132
|
-
const expected =
|
|
9366
|
+
const expected = readFileSync16(sp, "utf-8").trim();
|
|
9133
9367
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
9134
9368
|
if (got !== expected) {
|
|
9135
9369
|
console.error(`${TAG23} op=reject reason=bad-secret botType=${botType}`);
|
|
@@ -9192,12 +9426,12 @@ var telegram_default = app7;
|
|
|
9192
9426
|
|
|
9193
9427
|
// server/routes/onboarding.ts
|
|
9194
9428
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
|
|
9195
|
-
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";
|
|
9196
9430
|
import { createHash as createHash3, randomUUID as randomUUID8 } from "crypto";
|
|
9197
9431
|
|
|
9198
9432
|
// ../lib/admins-write/src/index.ts
|
|
9199
|
-
import { existsSync as
|
|
9200
|
-
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";
|
|
9201
9435
|
function logLine(input, result) {
|
|
9202
9436
|
const userIdShort = input.userId.slice(0, 8);
|
|
9203
9437
|
console.error(
|
|
@@ -9205,17 +9439,17 @@ function logLine(input, result) {
|
|
|
9205
9439
|
);
|
|
9206
9440
|
}
|
|
9207
9441
|
function writeFileAtomic(filePath, contents, mode) {
|
|
9208
|
-
|
|
9442
|
+
mkdirSync3(dirname4(filePath), { recursive: true });
|
|
9209
9443
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
9210
|
-
|
|
9211
|
-
|
|
9444
|
+
writeFileSync8(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
9445
|
+
renameSync4(tempPath, filePath);
|
|
9212
9446
|
}
|
|
9213
9447
|
function writeAdminEntry(input) {
|
|
9214
9448
|
const result = { usersJsonResult: "noop", accountJsonResult: "noop" };
|
|
9215
9449
|
try {
|
|
9216
9450
|
let users = [];
|
|
9217
|
-
if (
|
|
9218
|
-
const raw =
|
|
9451
|
+
if (existsSync12(input.usersFile)) {
|
|
9452
|
+
const raw = readFileSync17(input.usersFile, "utf-8").trim();
|
|
9219
9453
|
if (raw) {
|
|
9220
9454
|
const parsed = JSON.parse(raw);
|
|
9221
9455
|
if (!Array.isArray(parsed)) {
|
|
@@ -9239,11 +9473,11 @@ function writeAdminEntry(input) {
|
|
|
9239
9473
|
return result;
|
|
9240
9474
|
}
|
|
9241
9475
|
try {
|
|
9242
|
-
const accountJsonPath =
|
|
9243
|
-
if (!
|
|
9476
|
+
const accountJsonPath = join17(input.accountDir, "account.json");
|
|
9477
|
+
if (!existsSync12(accountJsonPath)) {
|
|
9244
9478
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
9245
9479
|
}
|
|
9246
|
-
const config = JSON.parse(
|
|
9480
|
+
const config = JSON.parse(readFileSync17(accountJsonPath, "utf-8"));
|
|
9247
9481
|
const admins = config.admins ?? [];
|
|
9248
9482
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
9249
9483
|
result.accountJsonResult = "noop";
|
|
@@ -9267,9 +9501,9 @@ function checkAdminAuthInvariant(input) {
|
|
|
9267
9501
|
usersWithoutAccount: []
|
|
9268
9502
|
};
|
|
9269
9503
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
9270
|
-
if (
|
|
9504
|
+
if (existsSync12(input.usersFile)) {
|
|
9271
9505
|
try {
|
|
9272
|
-
const raw =
|
|
9506
|
+
const raw = readFileSync17(input.usersFile, "utf-8").trim();
|
|
9273
9507
|
if (raw) {
|
|
9274
9508
|
const users = JSON.parse(raw);
|
|
9275
9509
|
for (const u of users) {
|
|
@@ -9282,10 +9516,10 @@ function checkAdminAuthInvariant(input) {
|
|
|
9282
9516
|
}
|
|
9283
9517
|
}
|
|
9284
9518
|
const accountUserIds = /* @__PURE__ */ new Set();
|
|
9285
|
-
if (
|
|
9519
|
+
if (existsSync12(input.accountsDir)) {
|
|
9286
9520
|
let entries;
|
|
9287
9521
|
try {
|
|
9288
|
-
entries =
|
|
9522
|
+
entries = readdirSync10(input.accountsDir);
|
|
9289
9523
|
} catch (err) {
|
|
9290
9524
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9291
9525
|
console.error(`[${input.tag}] accounts-dir unreadable accountsDir=${input.accountsDir} error=${msg}`);
|
|
@@ -9294,17 +9528,17 @@ function checkAdminAuthInvariant(input) {
|
|
|
9294
9528
|
}
|
|
9295
9529
|
for (const entry of entries) {
|
|
9296
9530
|
if (entry.startsWith(".")) continue;
|
|
9297
|
-
const accountDir =
|
|
9531
|
+
const accountDir = join17(input.accountsDir, entry);
|
|
9298
9532
|
try {
|
|
9299
9533
|
if (!statSync7(accountDir).isDirectory()) continue;
|
|
9300
9534
|
} catch {
|
|
9301
9535
|
continue;
|
|
9302
9536
|
}
|
|
9303
|
-
const accountJsonPath =
|
|
9304
|
-
if (!
|
|
9537
|
+
const accountJsonPath = join17(accountDir, "account.json");
|
|
9538
|
+
if (!existsSync12(accountJsonPath)) continue;
|
|
9305
9539
|
let admins = [];
|
|
9306
9540
|
try {
|
|
9307
|
-
const config = JSON.parse(
|
|
9541
|
+
const config = JSON.parse(readFileSync17(accountJsonPath, "utf-8"));
|
|
9308
9542
|
admins = config.admins ?? [];
|
|
9309
9543
|
} catch (err) {
|
|
9310
9544
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -9344,8 +9578,8 @@ function hashPin2(pin) {
|
|
|
9344
9578
|
return createHash3("sha256").update(pin).digest("hex");
|
|
9345
9579
|
}
|
|
9346
9580
|
function readUsersFile2() {
|
|
9347
|
-
if (!
|
|
9348
|
-
const raw =
|
|
9581
|
+
if (!existsSync13(USERS_FILE)) return null;
|
|
9582
|
+
const raw = readFileSync18(USERS_FILE, "utf-8").trim();
|
|
9349
9583
|
if (!raw) return [];
|
|
9350
9584
|
return JSON.parse(raw);
|
|
9351
9585
|
}
|
|
@@ -9398,7 +9632,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
9398
9632
|
} catch (err) {
|
|
9399
9633
|
logoutError = err instanceof Error ? err.message : String(err);
|
|
9400
9634
|
}
|
|
9401
|
-
const credentialsPresent =
|
|
9635
|
+
const credentialsPresent = existsSync13(CLAUDE_CREDENTIALS_FILE);
|
|
9402
9636
|
const ranMs = Date.now() - start;
|
|
9403
9637
|
console.log(`[onboarding] op=claude-logout credentialsPresent=${credentialsPresent} ranMs=${ranMs} logoutError=${logoutError ? JSON.stringify(logoutError.slice(0, 120)) : "none"}`);
|
|
9404
9638
|
return c.json({ logged_out: !credentialsPresent });
|
|
@@ -9416,7 +9650,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
9416
9650
|
return c.json({ launched: cdpReady });
|
|
9417
9651
|
}
|
|
9418
9652
|
ensureLogDir();
|
|
9419
|
-
|
|
9653
|
+
writeFileSync9(logPath("claude-auth"), "");
|
|
9420
9654
|
const claudeAuthLogFd = openSync3(logPath("claude-auth"), "a");
|
|
9421
9655
|
const onClaudeOutput = (chunk) => writeSync(claudeAuthLogFd, chunk);
|
|
9422
9656
|
if (process.platform === "darwin") {
|
|
@@ -9505,9 +9739,9 @@ app8.post("/set-pin", async (c) => {
|
|
|
9505
9739
|
console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
|
|
9506
9740
|
if (process.platform === "linux") {
|
|
9507
9741
|
let installOwner = null;
|
|
9508
|
-
if (
|
|
9742
|
+
if (existsSync13(INSTALL_OWNER_FILE)) {
|
|
9509
9743
|
try {
|
|
9510
|
-
const raw =
|
|
9744
|
+
const raw = readFileSync18(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
9511
9745
|
if (raw.length > 0) installOwner = raw;
|
|
9512
9746
|
} catch (err) {
|
|
9513
9747
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -9577,10 +9811,10 @@ app8.delete("/set-pin", async (c) => {
|
|
|
9577
9811
|
}
|
|
9578
9812
|
const remaining = users.filter((u) => u.userId !== matchedUser.userId);
|
|
9579
9813
|
if (remaining.length === 0) {
|
|
9580
|
-
|
|
9814
|
+
unlinkSync2(USERS_FILE);
|
|
9581
9815
|
console.log(`[set-pin] cleared users.json (last entry removed): userId=${matchedUser.userId.slice(0, 8)}\u2026`);
|
|
9582
9816
|
} else {
|
|
9583
|
-
|
|
9817
|
+
writeFileSync9(USERS_FILE, JSON.stringify(remaining), { mode: 384 });
|
|
9584
9818
|
console.log(`[set-pin] removed entry from users.json: userId=${matchedUser.userId.slice(0, 8)}\u2026 remaining=${remaining.length}`);
|
|
9585
9819
|
}
|
|
9586
9820
|
return c.json({ ok: true });
|
|
@@ -9588,9 +9822,9 @@ app8.delete("/set-pin", async (c) => {
|
|
|
9588
9822
|
var onboarding_default = app8;
|
|
9589
9823
|
|
|
9590
9824
|
// server/routes/client-error.ts
|
|
9591
|
-
import { appendFileSync, existsSync as
|
|
9592
|
-
import { join as
|
|
9593
|
-
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");
|
|
9594
9828
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
9595
9829
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
9596
9830
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -9633,10 +9867,10 @@ function stackHead(stack) {
|
|
|
9633
9867
|
}
|
|
9634
9868
|
function rotateIfNeeded() {
|
|
9635
9869
|
try {
|
|
9636
|
-
if (!
|
|
9870
|
+
if (!existsSync14(CLIENT_ERRORS_LOG)) return;
|
|
9637
9871
|
const stats = statSync8(CLIENT_ERRORS_LOG);
|
|
9638
9872
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
9639
|
-
|
|
9873
|
+
renameSync5(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
9640
9874
|
} catch (err) {
|
|
9641
9875
|
console.error(`[client-error] log rotation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
9642
9876
|
}
|
|
@@ -9915,18 +10149,18 @@ app10.post("/", async (c) => {
|
|
|
9915
10149
|
var session_default = app10;
|
|
9916
10150
|
|
|
9917
10151
|
// server/routes/admin/logs.ts
|
|
9918
|
-
import { existsSync as
|
|
10152
|
+
import { existsSync as existsSync16, readdirSync as readdirSync11, readFileSync as readFileSync19, statSync as statSync9 } from "fs";
|
|
9919
10153
|
import { resolve as resolve16, basename as basename5 } from "path";
|
|
9920
10154
|
|
|
9921
10155
|
// app/lib/logs-read-resolve.ts
|
|
9922
|
-
import { existsSync as
|
|
9923
|
-
import { join as
|
|
10156
|
+
import { existsSync as existsSync15 } from "fs";
|
|
10157
|
+
import { join as join19 } from "path";
|
|
9924
10158
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
9925
10159
|
const tried = [filename];
|
|
9926
10160
|
const hits = [];
|
|
9927
10161
|
for (const dir of logDirs) {
|
|
9928
|
-
const fullPath =
|
|
9929
|
-
if (
|
|
10162
|
+
const fullPath = join19(dir, filename);
|
|
10163
|
+
if (existsSync15(fullPath)) {
|
|
9930
10164
|
hits.push({ path: fullPath, dir });
|
|
9931
10165
|
}
|
|
9932
10166
|
}
|
|
@@ -9954,7 +10188,7 @@ app11.get("/", async (c) => {
|
|
|
9954
10188
|
const filePath = resolve16(dir, safe);
|
|
9955
10189
|
searched.push(filePath);
|
|
9956
10190
|
try {
|
|
9957
|
-
const buffer =
|
|
10191
|
+
const buffer = readFileSync19(filePath);
|
|
9958
10192
|
const onDiskBytes = statSync9(filePath).size;
|
|
9959
10193
|
const headers = {
|
|
9960
10194
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -10019,7 +10253,7 @@ app11.get("/", async (c) => {
|
|
|
10019
10253
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
10020
10254
|
try {
|
|
10021
10255
|
const filename = basename5(hit.path);
|
|
10022
|
-
const buffer =
|
|
10256
|
+
const buffer = readFileSync19(hit.path);
|
|
10023
10257
|
const onDiskBytes = statSync9(hit.path).size;
|
|
10024
10258
|
const headers = {
|
|
10025
10259
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -10054,10 +10288,10 @@ app11.get("/", async (c) => {
|
|
|
10054
10288
|
const seen = /* @__PURE__ */ new Set();
|
|
10055
10289
|
const logs = {};
|
|
10056
10290
|
for (const dir of logDirs) {
|
|
10057
|
-
if (!
|
|
10291
|
+
if (!existsSync16(dir)) continue;
|
|
10058
10292
|
let files;
|
|
10059
10293
|
try {
|
|
10060
|
-
files =
|
|
10294
|
+
files = readdirSync11(dir).filter((f) => f.endsWith(".log"));
|
|
10061
10295
|
} catch (err) {
|
|
10062
10296
|
const reason = err instanceof Error ? err.message : String(err);
|
|
10063
10297
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
@@ -10066,7 +10300,7 @@ app11.get("/", async (c) => {
|
|
|
10066
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 }) => {
|
|
10067
10301
|
seen.add(name);
|
|
10068
10302
|
try {
|
|
10069
|
-
const content =
|
|
10303
|
+
const content = readFileSync19(resolve16(dir, name));
|
|
10070
10304
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
10071
10305
|
logs[name] = tail.trim() || "(empty)";
|
|
10072
10306
|
} catch (err) {
|
|
@@ -10105,7 +10339,7 @@ var claude_info_default = app12;
|
|
|
10105
10339
|
|
|
10106
10340
|
// server/routes/admin/attachment.ts
|
|
10107
10341
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
10108
|
-
import { existsSync as
|
|
10342
|
+
import { existsSync as existsSync17 } from "fs";
|
|
10109
10343
|
import { resolve as resolve17 } from "path";
|
|
10110
10344
|
var app13 = new Hono();
|
|
10111
10345
|
app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
@@ -10119,11 +10353,11 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
10119
10353
|
return new Response("Not found", { status: 404 });
|
|
10120
10354
|
}
|
|
10121
10355
|
const dir = resolve17(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
|
|
10122
|
-
if (!
|
|
10356
|
+
if (!existsSync17(dir)) {
|
|
10123
10357
|
return new Response("Not found", { status: 404 });
|
|
10124
10358
|
}
|
|
10125
10359
|
const metaPath = resolve17(dir, `${attachmentId}.meta.json`);
|
|
10126
|
-
if (!
|
|
10360
|
+
if (!existsSync17(metaPath)) {
|
|
10127
10361
|
return new Response("Not found", { status: 404 });
|
|
10128
10362
|
}
|
|
10129
10363
|
let meta;
|
|
@@ -10151,23 +10385,23 @@ var attachment_default = app13;
|
|
|
10151
10385
|
|
|
10152
10386
|
// server/routes/admin/agents.ts
|
|
10153
10387
|
import { resolve as resolve18 } from "path";
|
|
10154
|
-
import { readdirSync as
|
|
10388
|
+
import { readdirSync as readdirSync12, readFileSync as readFileSync20, existsSync as existsSync18, rmSync } from "fs";
|
|
10155
10389
|
var app14 = new Hono();
|
|
10156
10390
|
app14.get("/", (c) => {
|
|
10157
10391
|
const account = resolveAccount();
|
|
10158
10392
|
if (!account) return c.json({ agents: [] });
|
|
10159
10393
|
const agentsDir = resolve18(account.accountDir, "agents");
|
|
10160
|
-
if (!
|
|
10394
|
+
if (!existsSync18(agentsDir)) return c.json({ agents: [] });
|
|
10161
10395
|
const agents = [];
|
|
10162
10396
|
try {
|
|
10163
|
-
const entries =
|
|
10397
|
+
const entries = readdirSync12(agentsDir, { withFileTypes: true });
|
|
10164
10398
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
10165
10399
|
if (!entry.isDirectory()) continue;
|
|
10166
10400
|
if (entry.name === "admin") continue;
|
|
10167
10401
|
const configPath2 = resolve18(agentsDir, entry.name, "config.json");
|
|
10168
|
-
if (!
|
|
10402
|
+
if (!existsSync18(configPath2)) continue;
|
|
10169
10403
|
try {
|
|
10170
|
-
const config = JSON.parse(
|
|
10404
|
+
const config = JSON.parse(readFileSync20(configPath2, "utf-8"));
|
|
10171
10405
|
agents.push({
|
|
10172
10406
|
slug: entry.name,
|
|
10173
10407
|
displayName: config.displayName ?? entry.name,
|
|
@@ -10194,7 +10428,7 @@ app14.delete("/:slug", async (c) => {
|
|
|
10194
10428
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
10195
10429
|
}
|
|
10196
10430
|
const agentDir = resolve18(account.accountDir, "agents", slug);
|
|
10197
|
-
if (!
|
|
10431
|
+
if (!existsSync18(agentDir)) {
|
|
10198
10432
|
return c.json({ error: "Agent not found" }, 404);
|
|
10199
10433
|
}
|
|
10200
10434
|
try {
|
|
@@ -10224,7 +10458,7 @@ app14.post("/:slug/project", async (c) => {
|
|
|
10224
10458
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
10225
10459
|
}
|
|
10226
10460
|
const agentDir = resolve18(account.accountDir, "agents", slug);
|
|
10227
|
-
if (!
|
|
10461
|
+
if (!existsSync18(agentDir)) {
|
|
10228
10462
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
10229
10463
|
}
|
|
10230
10464
|
try {
|
|
@@ -10240,7 +10474,7 @@ var agents_default = app14;
|
|
|
10240
10474
|
// server/routes/admin/sessions.ts
|
|
10241
10475
|
import crypto2 from "crypto";
|
|
10242
10476
|
import { resolve as resolvePath } from "path";
|
|
10243
|
-
import { existsSync as
|
|
10477
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync4, createWriteStream } from "fs";
|
|
10244
10478
|
|
|
10245
10479
|
// ../lib/admin-conversation-purge/src/index.ts
|
|
10246
10480
|
async function purgeAdminConversationJsonls(args) {
|
|
@@ -10387,7 +10621,7 @@ var pickComponentBytes = (..._args) => null;
|
|
|
10387
10621
|
function openResumeStreamLog(accountId, sessionId) {
|
|
10388
10622
|
const dir = resolvePath(ACCOUNTS_DIR, accountId, "resume-logs");
|
|
10389
10623
|
try {
|
|
10390
|
-
|
|
10624
|
+
mkdirSync4(dir, { recursive: true });
|
|
10391
10625
|
} catch {
|
|
10392
10626
|
}
|
|
10393
10627
|
return createWriteStream(resolvePath(dir, `${sessionId}.log`), { flags: "a" });
|
|
@@ -10400,7 +10634,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
|
|
|
10400
10634
|
let reason = null;
|
|
10401
10635
|
if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
|
|
10402
10636
|
else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
|
|
10403
|
-
else if (!
|
|
10637
|
+
else if (!existsSync19(a.storagePath)) reason = "missing-file";
|
|
10404
10638
|
if (reason) {
|
|
10405
10639
|
invalid++;
|
|
10406
10640
|
try {
|
|
@@ -10926,8 +11160,8 @@ app15.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
10926
11160
|
var sessions_default = app15;
|
|
10927
11161
|
|
|
10928
11162
|
// app/lib/claude-agent/spawn-context.ts
|
|
10929
|
-
import { existsSync as
|
|
10930
|
-
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";
|
|
10931
11165
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
10932
11166
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
10933
11167
|
try {
|
|
@@ -10968,14 +11202,14 @@ function frontmatterField(manifest, field2) {
|
|
|
10968
11202
|
function extractPluginToolDescriptions(pluginDir) {
|
|
10969
11203
|
const out = /* @__PURE__ */ new Map();
|
|
10970
11204
|
const candidates = [
|
|
10971
|
-
|
|
10972
|
-
|
|
11205
|
+
join20(pluginDir, "mcp/dist/index.js"),
|
|
11206
|
+
join20(pluginDir, "mcp/src/index.ts")
|
|
10973
11207
|
];
|
|
10974
11208
|
let raw = null;
|
|
10975
11209
|
for (const path2 of candidates) {
|
|
10976
|
-
if (!
|
|
11210
|
+
if (!existsSync20(path2)) continue;
|
|
10977
11211
|
try {
|
|
10978
|
-
raw =
|
|
11212
|
+
raw = readFileSync21(path2, "utf-8");
|
|
10979
11213
|
break;
|
|
10980
11214
|
} catch {
|
|
10981
11215
|
}
|
|
@@ -11025,9 +11259,9 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
11025
11259
|
function listPluginDirs() {
|
|
11026
11260
|
const out = /* @__PURE__ */ new Map();
|
|
11027
11261
|
const platformPlugins = resolve19(PLATFORM_ROOT, "plugins");
|
|
11028
|
-
if (
|
|
11029
|
-
for (const name of
|
|
11030
|
-
const dir =
|
|
11262
|
+
if (existsSync20(platformPlugins)) {
|
|
11263
|
+
for (const name of readdirSync13(platformPlugins)) {
|
|
11264
|
+
const dir = join20(platformPlugins, name);
|
|
11031
11265
|
try {
|
|
11032
11266
|
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
11033
11267
|
} catch {
|
|
@@ -11035,13 +11269,13 @@ function listPluginDirs() {
|
|
|
11035
11269
|
}
|
|
11036
11270
|
}
|
|
11037
11271
|
const premiumRoot = resolve19(dirname5(PLATFORM_ROOT), "premium-plugins");
|
|
11038
|
-
if (
|
|
11039
|
-
for (const bundle of
|
|
11040
|
-
const bundlePlugins =
|
|
11041
|
-
if (!
|
|
11272
|
+
if (existsSync20(premiumRoot)) {
|
|
11273
|
+
for (const bundle of readdirSync13(premiumRoot)) {
|
|
11274
|
+
const bundlePlugins = join20(premiumRoot, bundle, "plugins");
|
|
11275
|
+
if (!existsSync20(bundlePlugins)) continue;
|
|
11042
11276
|
try {
|
|
11043
|
-
for (const name of
|
|
11044
|
-
const dir =
|
|
11277
|
+
for (const name of readdirSync13(bundlePlugins)) {
|
|
11278
|
+
const dir = join20(bundlePlugins, name);
|
|
11045
11279
|
try {
|
|
11046
11280
|
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
11047
11281
|
} catch {
|
|
@@ -11055,9 +11289,9 @@ function listPluginDirs() {
|
|
|
11055
11289
|
}
|
|
11056
11290
|
function readEnabledPlugins(accountId) {
|
|
11057
11291
|
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
11058
|
-
if (!
|
|
11292
|
+
if (!existsSync20(accountFile)) return /* @__PURE__ */ new Set();
|
|
11059
11293
|
try {
|
|
11060
|
-
const parsed = JSON.parse(
|
|
11294
|
+
const parsed = JSON.parse(readFileSync21(accountFile, "utf-8"));
|
|
11061
11295
|
return new Set(
|
|
11062
11296
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
11063
11297
|
);
|
|
@@ -11066,10 +11300,10 @@ function readEnabledPlugins(accountId) {
|
|
|
11066
11300
|
}
|
|
11067
11301
|
}
|
|
11068
11302
|
function readFrontmatter(path2) {
|
|
11069
|
-
if (!
|
|
11303
|
+
if (!existsSync20(path2)) return null;
|
|
11070
11304
|
let raw;
|
|
11071
11305
|
try {
|
|
11072
|
-
raw =
|
|
11306
|
+
raw = readFileSync21(path2, "utf-8");
|
|
11073
11307
|
} catch {
|
|
11074
11308
|
return null;
|
|
11075
11309
|
}
|
|
@@ -11084,7 +11318,7 @@ function computeActivePlugins(accountId) {
|
|
|
11084
11318
|
for (const name of Array.from(enabled).sort()) {
|
|
11085
11319
|
const dir = pluginDirs.get(name);
|
|
11086
11320
|
if (!dir) continue;
|
|
11087
|
-
const fm = readFrontmatter(
|
|
11321
|
+
const fm = readFrontmatter(join20(dir, "PLUGIN.md"));
|
|
11088
11322
|
if (!fm) continue;
|
|
11089
11323
|
const description = frontmatterField(`---
|
|
11090
11324
|
${fm}
|
|
@@ -11101,7 +11335,7 @@ ${fm}
|
|
|
11101
11335
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
11102
11336
|
);
|
|
11103
11337
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
11104
|
-
const hasSource =
|
|
11338
|
+
const hasSource = existsSync20(join20(dir, "mcp/dist/index.js")) || existsSync20(join20(dir, "mcp/src/index.ts"));
|
|
11105
11339
|
if (hasSource) {
|
|
11106
11340
|
console.warn(
|
|
11107
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`
|
|
@@ -11111,7 +11345,7 @@ ${fm}
|
|
|
11111
11345
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
11112
11346
|
const skills = [];
|
|
11113
11347
|
for (const relPath of skillPaths) {
|
|
11114
|
-
const skillPath =
|
|
11348
|
+
const skillPath = join20(dir, relPath);
|
|
11115
11349
|
const skillFm = readFrontmatter(skillPath);
|
|
11116
11350
|
if (!skillFm) continue;
|
|
11117
11351
|
const skillName = frontmatterField(`---
|
|
@@ -11128,10 +11362,10 @@ ${skillFm}
|
|
|
11128
11362
|
}
|
|
11129
11363
|
function computeSpecialistDomains(accountId) {
|
|
11130
11364
|
const specialistsDir = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
11131
|
-
if (!
|
|
11365
|
+
if (!existsSync20(specialistsDir)) return [];
|
|
11132
11366
|
let entries;
|
|
11133
11367
|
try {
|
|
11134
|
-
entries =
|
|
11368
|
+
entries = readdirSync13(specialistsDir);
|
|
11135
11369
|
} catch {
|
|
11136
11370
|
return [];
|
|
11137
11371
|
}
|
|
@@ -11155,7 +11389,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
11155
11389
|
const out = [];
|
|
11156
11390
|
for (const file of entries.sort()) {
|
|
11157
11391
|
if (!file.endsWith(".md")) continue;
|
|
11158
|
-
const fm = readFrontmatter(
|
|
11392
|
+
const fm = readFrontmatter(join20(specialistsDir, file));
|
|
11159
11393
|
if (!fm) continue;
|
|
11160
11394
|
const wrapped = `---
|
|
11161
11395
|
${fm}
|
|
@@ -11174,10 +11408,10 @@ ${fm}
|
|
|
11174
11408
|
}
|
|
11175
11409
|
function computeDormantPlugins(accountId) {
|
|
11176
11410
|
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
11177
|
-
if (!
|
|
11411
|
+
if (!existsSync20(accountFile)) return [];
|
|
11178
11412
|
let enabled;
|
|
11179
11413
|
try {
|
|
11180
|
-
const raw =
|
|
11414
|
+
const raw = readFileSync21(accountFile, "utf-8");
|
|
11181
11415
|
const parsed = JSON.parse(raw);
|
|
11182
11416
|
enabled = new Set(
|
|
11183
11417
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -11189,10 +11423,10 @@ function computeDormantPlugins(accountId) {
|
|
|
11189
11423
|
return [];
|
|
11190
11424
|
}
|
|
11191
11425
|
const pluginsDir = resolve19(PLATFORM_ROOT, "plugins");
|
|
11192
|
-
if (!
|
|
11426
|
+
if (!existsSync20(pluginsDir)) return [];
|
|
11193
11427
|
let entries;
|
|
11194
11428
|
try {
|
|
11195
|
-
entries =
|
|
11429
|
+
entries = readdirSync13(pluginsDir);
|
|
11196
11430
|
} catch {
|
|
11197
11431
|
return [];
|
|
11198
11432
|
}
|
|
@@ -11200,10 +11434,10 @@ function computeDormantPlugins(accountId) {
|
|
|
11200
11434
|
for (const name of entries) {
|
|
11201
11435
|
if (enabled.has(name)) continue;
|
|
11202
11436
|
const manifestPath = resolve19(pluginsDir, name, "PLUGIN.md");
|
|
11203
|
-
if (!
|
|
11437
|
+
if (!existsSync20(manifestPath)) continue;
|
|
11204
11438
|
let manifest;
|
|
11205
11439
|
try {
|
|
11206
|
-
manifest =
|
|
11440
|
+
manifest = readFileSync21(manifestPath, "utf-8");
|
|
11207
11441
|
} catch {
|
|
11208
11442
|
continue;
|
|
11209
11443
|
}
|
|
@@ -11217,13 +11451,13 @@ function computeDormantPlugins(accountId) {
|
|
|
11217
11451
|
}
|
|
11218
11452
|
|
|
11219
11453
|
// server/routes/admin/claude-sessions.ts
|
|
11220
|
-
import { existsSync as
|
|
11454
|
+
import { existsSync as existsSync21, readFileSync as readFileSync22 } from "fs";
|
|
11221
11455
|
import { resolve as resolve20 } from "path";
|
|
11222
11456
|
function readTunnelState(brandConfigDir) {
|
|
11223
11457
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
11224
|
-
if (!
|
|
11458
|
+
if (!existsSync21(statePath)) return null;
|
|
11225
11459
|
try {
|
|
11226
|
-
const parsed = JSON.parse(
|
|
11460
|
+
const parsed = JSON.parse(readFileSync22(statePath, "utf-8"));
|
|
11227
11461
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
11228
11462
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
11229
11463
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -11237,7 +11471,7 @@ function resolveTunnelUrl() {
|
|
|
11237
11471
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
11238
11472
|
let brand;
|
|
11239
11473
|
try {
|
|
11240
|
-
brand = JSON.parse(
|
|
11474
|
+
brand = JSON.parse(readFileSync22(resolve20(platformRoot2, "config", "brand.json"), "utf-8"));
|
|
11241
11475
|
} catch {
|
|
11242
11476
|
return null;
|
|
11243
11477
|
}
|
|
@@ -11479,10 +11713,11 @@ app18.post("/", async (c) => {
|
|
|
11479
11713
|
var events_default = app18;
|
|
11480
11714
|
|
|
11481
11715
|
// server/routes/admin/files.ts
|
|
11482
|
-
import { createReadStream as createReadStream2 } from "fs";
|
|
11483
|
-
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";
|
|
11484
11718
|
import { realpathSync as realpathSync4 } from "fs";
|
|
11485
|
-
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";
|
|
11486
11721
|
import { Readable as Readable2 } from "stream";
|
|
11487
11722
|
|
|
11488
11723
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -11800,7 +12035,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
11800
12035
|
|
|
11801
12036
|
// app/lib/file-index.ts
|
|
11802
12037
|
import * as fsp from "fs/promises";
|
|
11803
|
-
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";
|
|
11804
12039
|
import { tmpdir as tmpdir2 } from "os";
|
|
11805
12040
|
import { execFile as execFile2 } from "child_process";
|
|
11806
12041
|
import { promisify as promisify2 } from "util";
|
|
@@ -11882,7 +12117,7 @@ async function extractPdf(absolute) {
|
|
|
11882
12117
|
return stdout.trim();
|
|
11883
12118
|
}
|
|
11884
12119
|
async function ocrPdf(absolute) {
|
|
11885
|
-
const outPdf =
|
|
12120
|
+
const outPdf = join21(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
11886
12121
|
try {
|
|
11887
12122
|
await execFileAsync2(
|
|
11888
12123
|
"ocrmypdf",
|
|
@@ -11944,7 +12179,7 @@ async function readDisplayName(absolute) {
|
|
|
11944
12179
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
11945
12180
|
if (base === `${stem}.meta.json`) return null;
|
|
11946
12181
|
try {
|
|
11947
|
-
const raw = await fsp.readFile(
|
|
12182
|
+
const raw = await fsp.readFile(join21(dir, `${stem}.meta.json`), "utf-8");
|
|
11948
12183
|
const meta = JSON.parse(raw);
|
|
11949
12184
|
const dn = meta.displayName ?? meta.filename;
|
|
11950
12185
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -11964,7 +12199,8 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
11964
12199
|
let clean = true;
|
|
11965
12200
|
for (const entry of entries) {
|
|
11966
12201
|
if (entry.isSymbolicLink()) continue;
|
|
11967
|
-
|
|
12202
|
+
if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
|
|
12203
|
+
const abs = join21(root, entry.name);
|
|
11968
12204
|
if (entry.isDirectory()) {
|
|
11969
12205
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
11970
12206
|
if (!sub.clean) clean = false;
|
|
@@ -12233,10 +12469,11 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
12233
12469
|
}
|
|
12234
12470
|
|
|
12235
12471
|
// server/routes/admin/files.ts
|
|
12472
|
+
var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
12236
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;
|
|
12237
12474
|
async function readMeta(absDir, baseName) {
|
|
12238
12475
|
try {
|
|
12239
|
-
const raw = await readFile4(
|
|
12476
|
+
const raw = await readFile4(join22(absDir, `${baseName}.meta.json`), "utf8");
|
|
12240
12477
|
const parsed = JSON.parse(raw);
|
|
12241
12478
|
if (typeof parsed?.filename === "string") {
|
|
12242
12479
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -12274,7 +12511,7 @@ async function readAccountNames() {
|
|
|
12274
12511
|
}
|
|
12275
12512
|
async function enrich(absolute, entry, accountNames) {
|
|
12276
12513
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
12277
|
-
const meta = await readMeta(
|
|
12514
|
+
const meta = await readMeta(join22(absolute, entry.name), entry.name);
|
|
12278
12515
|
if (meta?.filename) {
|
|
12279
12516
|
entry.displayName = meta.filename;
|
|
12280
12517
|
entry.mimeType = meta.mimeType;
|
|
@@ -12438,7 +12675,7 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
12438
12675
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
12439
12676
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
12440
12677
|
try {
|
|
12441
|
-
const entryPath =
|
|
12678
|
+
const entryPath = join22(absolute, name);
|
|
12442
12679
|
const s = await stat4(entryPath);
|
|
12443
12680
|
entries.push({
|
|
12444
12681
|
name,
|
|
@@ -12532,71 +12769,177 @@ app19.get("/download", requireAdminSession, async (c) => {
|
|
|
12532
12769
|
return c.json({ error: message }, 500);
|
|
12533
12770
|
}
|
|
12534
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
|
+
}
|
|
12535
12776
|
app19.post("/upload", requireAdminSession, async (c) => {
|
|
12536
12777
|
const cacheKey = c.var.cacheKey;
|
|
12537
12778
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12538
12779
|
if (!accountId) {
|
|
12539
|
-
console.error(`[data] auth-
|
|
12780
|
+
console.error(`[data-upload] op=auth-reject reason="no account for session"`);
|
|
12540
12781
|
return c.json({ error: "Account not found for session" }, 401);
|
|
12541
12782
|
}
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
|
|
12546
|
-
|
|
12547
|
-
|
|
12548
|
-
|
|
12549
|
-
const
|
|
12550
|
-
|
|
12551
|
-
|
|
12552
|
-
|
|
12553
|
-
|
|
12554
|
-
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 ?? ""}"`);
|
|
12555
12795
|
return c.json({
|
|
12556
|
-
error: `
|
|
12796
|
+
error: `Unsupported file type: "${mimeType}". Supported: ${[...SUPPORTED_MIME_TYPES].join(", ")}.`
|
|
12557
12797
|
}, 422);
|
|
12558
12798
|
}
|
|
12559
|
-
|
|
12560
|
-
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
|
|
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);
|
|
12564
12811
|
}
|
|
12565
|
-
const
|
|
12566
|
-
const finalName = `${Date.now()}-${safeName}`;
|
|
12567
|
-
const rawDir = formData.get("path");
|
|
12568
|
-
const dest = resolveOwnAccountWrite(typeof rawDir === "string" ? rawDir : "", accountId, "POST /api/admin/files/upload");
|
|
12569
|
-
if (!dest.ok) return c.json({ error: dest.error }, dest.status);
|
|
12570
|
-
const destDir = dest.absolute;
|
|
12812
|
+
const destDir = relDir === "." ? base.absolute : resolve22(base.absolute, relDir);
|
|
12571
12813
|
const destPath = resolve22(destDir, finalName);
|
|
12572
|
-
|
|
12573
|
-
const
|
|
12574
|
-
if (
|
|
12575
|
-
|
|
12576
|
-
const
|
|
12577
|
-
if (
|
|
12578
|
-
|
|
12579
|
-
|
|
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
|
+
}
|
|
12580
12889
|
}
|
|
12581
|
-
|
|
12582
|
-
|
|
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);
|
|
12583
12896
|
} catch (err) {
|
|
12584
12897
|
const message = err instanceof Error ? err.message : String(err);
|
|
12585
|
-
console.error(`[data
|
|
12898
|
+
console.error(`[data-upload] op=error uid=${uid} err="${message}" token=${token} rel="${relpath ?? ""}"`);
|
|
12899
|
+
await cleanup();
|
|
12586
12900
|
return c.json({ error: message }, 500);
|
|
12587
12901
|
}
|
|
12588
|
-
const relativeDest = `${
|
|
12589
|
-
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}`);
|
|
12590
12904
|
void indexFile(accountId, relativeDest).catch((err) => {
|
|
12591
|
-
console.error(`[data
|
|
12905
|
+
console.error(`[data-upload] op=index-failed uid=${uid} dest="${relativeDest}" err="${err instanceof Error ? err.message : String(err)}"`);
|
|
12592
12906
|
});
|
|
12593
12907
|
return c.json({
|
|
12594
12908
|
path: relativeDest,
|
|
12595
12909
|
filename: finalName,
|
|
12596
|
-
sizeBytes:
|
|
12597
|
-
mimeType
|
|
12910
|
+
sizeBytes: received,
|
|
12911
|
+
mimeType
|
|
12598
12912
|
});
|
|
12599
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
|
+
}
|
|
12600
12943
|
app19.delete("/", requireAdminSession, async (c) => {
|
|
12601
12944
|
const cacheKey = c.var.cacheKey;
|
|
12602
12945
|
const accountId = getAccountIdForSession(cacheKey);
|
|
@@ -12634,7 +12977,7 @@ app19.delete("/", requireAdminSession, async (c) => {
|
|
|
12634
12977
|
}
|
|
12635
12978
|
const dot = base.lastIndexOf(".");
|
|
12636
12979
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
12637
|
-
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;
|
|
12638
12981
|
await unlink2(absolute);
|
|
12639
12982
|
if (sidecarPath) {
|
|
12640
12983
|
try {
|
|
@@ -14769,7 +15112,7 @@ var graph_default_view_default = app25;
|
|
|
14769
15112
|
// server/routes/admin/sidebar-artefacts.ts
|
|
14770
15113
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
14771
15114
|
import { resolve as resolve23, relative as relative3, isAbsolute, sep as sep7, basename as basename8 } from "path";
|
|
14772
|
-
import { existsSync as
|
|
15115
|
+
import { existsSync as existsSync23 } from "fs";
|
|
14773
15116
|
var LIMIT = 50;
|
|
14774
15117
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
14775
15118
|
function toDataRootRelPath(absPath) {
|
|
@@ -14876,7 +15219,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
14876
15219
|
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
14877
15220
|
const names = /* @__PURE__ */ new Set();
|
|
14878
15221
|
for (const dir of [overrideDir, bundledDir]) {
|
|
14879
|
-
if (!
|
|
15222
|
+
if (!existsSync23(dir)) continue;
|
|
14880
15223
|
try {
|
|
14881
15224
|
const entries = await readdir4(dir);
|
|
14882
15225
|
for (const entry of entries) {
|
|
@@ -14891,7 +15234,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
14891
15234
|
}
|
|
14892
15235
|
async function readAgentTemplateRow(inp) {
|
|
14893
15236
|
let chosenPath = null;
|
|
14894
|
-
if (
|
|
15237
|
+
if (existsSync23(inp.overridePath)) {
|
|
14895
15238
|
try {
|
|
14896
15239
|
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
14897
15240
|
chosenPath = inp.overridePath;
|
|
@@ -14902,7 +15245,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
14902
15245
|
);
|
|
14903
15246
|
return null;
|
|
14904
15247
|
}
|
|
14905
|
-
} else if (
|
|
15248
|
+
} else if (existsSync23(inp.bundledPath)) {
|
|
14906
15249
|
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
14907
15250
|
console.error(
|
|
14908
15251
|
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
@@ -15066,9 +15409,52 @@ app29.post("/", requireAdminSession, async (c) => {
|
|
|
15066
15409
|
});
|
|
15067
15410
|
var session_archive_default = app29;
|
|
15068
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
|
+
|
|
15069
15455
|
// server/routes/admin/session-rc-spawn.ts
|
|
15070
|
-
import { randomUUID as
|
|
15071
|
-
function resolveSpawnPlan(host, operatorDomains, body, mintId =
|
|
15456
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
15457
|
+
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID11, adminUserId, authenticatedName) {
|
|
15072
15458
|
const operator = isOperatorHost(host, operatorDomains);
|
|
15073
15459
|
const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
|
|
15074
15460
|
const name = typeof body.name === "string" && body.name.length > 0 ? body.name : void 0;
|
|
@@ -15101,8 +15487,8 @@ function shapeWebchatResponse(sessionId, manager) {
|
|
|
15101
15487
|
const landed = redirected ? manager.sessionId : sessionId;
|
|
15102
15488
|
return { sessionId: landed, outcome, target: `/chat?session=${landed}` };
|
|
15103
15489
|
}
|
|
15104
|
-
var
|
|
15105
|
-
|
|
15490
|
+
var app31 = new Hono();
|
|
15491
|
+
app31.post("/", requireAdminSession, async (c) => {
|
|
15106
15492
|
let body;
|
|
15107
15493
|
try {
|
|
15108
15494
|
body = await c.req.json();
|
|
@@ -15114,8 +15500,8 @@ app30.post("/", requireAdminSession, async (c) => {
|
|
|
15114
15500
|
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
15115
15501
|
const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
|
|
15116
15502
|
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
15117
|
-
const plan = resolveSpawnPlan(host, getOperatorDomains(), body,
|
|
15118
|
-
const spawnReqId =
|
|
15503
|
+
const plan = resolveSpawnPlan(host, getOperatorDomains(), body, randomUUID11, adminUserId, authenticatedName);
|
|
15504
|
+
const spawnReqId = randomUUID11();
|
|
15119
15505
|
console.log(
|
|
15120
15506
|
`[chat-spawn] op=request spawnReqId=${spawnReqId} origin=${plan.origin} kind=${plan.kind} sessionId=${plan.kind === "new" ? "new" : plan.sessionId}`
|
|
15121
15507
|
);
|
|
@@ -15157,10 +15543,10 @@ app30.post("/", requireAdminSession, async (c) => {
|
|
|
15157
15543
|
}
|
|
15158
15544
|
return c.json(parsed ?? {});
|
|
15159
15545
|
});
|
|
15160
|
-
var session_rc_spawn_default =
|
|
15546
|
+
var session_rc_spawn_default = app31;
|
|
15161
15547
|
|
|
15162
15548
|
// server/routes/admin/session-reseat.ts
|
|
15163
|
-
import { randomUUID as
|
|
15549
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
15164
15550
|
|
|
15165
15551
|
// ../lib/models/src/index.ts
|
|
15166
15552
|
var OPUS_MODEL = "claude-opus-4-8[1m]";
|
|
@@ -15182,7 +15568,7 @@ function isSelectableModel(id) {
|
|
|
15182
15568
|
}
|
|
15183
15569
|
|
|
15184
15570
|
// server/routes/admin/session-reseat.ts
|
|
15185
|
-
function resolveReseatPlan(body, mintId =
|
|
15571
|
+
function resolveReseatPlan(body, mintId = randomUUID12, adminUserId, authenticatedName) {
|
|
15186
15572
|
const sessionId = mintId();
|
|
15187
15573
|
const key = `session:${sessionId}`;
|
|
15188
15574
|
const payload = {
|
|
@@ -15199,9 +15585,9 @@ function resolveReseatPlan(body, mintId = randomUUID11, adminUserId, authenticat
|
|
|
15199
15585
|
if (authenticatedName) payload.authenticatedName = authenticatedName;
|
|
15200
15586
|
return { sessionId, payload };
|
|
15201
15587
|
}
|
|
15202
|
-
var
|
|
15588
|
+
var app32 = new Hono();
|
|
15203
15589
|
var reseatsInFlight = /* @__PURE__ */ new Set();
|
|
15204
|
-
|
|
15590
|
+
app32.post("/", requireAdminSession, async (c) => {
|
|
15205
15591
|
let body;
|
|
15206
15592
|
try {
|
|
15207
15593
|
body = await c.req.json();
|
|
@@ -15221,8 +15607,8 @@ app31.post("/", requireAdminSession, async (c) => {
|
|
|
15221
15607
|
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
15222
15608
|
const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
|
|
15223
15609
|
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
15224
|
-
const plan = resolveReseatPlan({ fromSessionId, model },
|
|
15225
|
-
const reseatReqId =
|
|
15610
|
+
const plan = resolveReseatPlan({ fromSessionId, model }, randomUUID12, adminUserId, authenticatedName);
|
|
15611
|
+
const reseatReqId = randomUUID12();
|
|
15226
15612
|
console.log(`[chat-reseat] op=request reseatReqId=${reseatReqId} from=${fromSessionId} to-model=${model} new=${plan.sessionId}`);
|
|
15227
15613
|
let res;
|
|
15228
15614
|
try {
|
|
@@ -15272,7 +15658,7 @@ app31.post("/", requireAdminSession, async (c) => {
|
|
|
15272
15658
|
reseatsInFlight.delete(fromSessionId);
|
|
15273
15659
|
}
|
|
15274
15660
|
});
|
|
15275
|
-
var session_reseat_default =
|
|
15661
|
+
var session_reseat_default = app32;
|
|
15276
15662
|
|
|
15277
15663
|
// server/routes/admin/system-stats.ts
|
|
15278
15664
|
import { readFile as readFile5 } from "fs/promises";
|
|
@@ -15369,8 +15755,8 @@ async function sample() {
|
|
|
15369
15755
|
if (process.platform === "linux") return sampleLinux();
|
|
15370
15756
|
return sampleOsFallback();
|
|
15371
15757
|
}
|
|
15372
|
-
var
|
|
15373
|
-
|
|
15758
|
+
var app33 = new Hono();
|
|
15759
|
+
app33.get("/", async (c) => {
|
|
15374
15760
|
const started = Date.now();
|
|
15375
15761
|
if (!inflight) {
|
|
15376
15762
|
inflight = sample().finally(() => {
|
|
@@ -15393,17 +15779,17 @@ app32.get("/", async (c) => {
|
|
|
15393
15779
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
15394
15780
|
}
|
|
15395
15781
|
});
|
|
15396
|
-
var system_stats_default =
|
|
15782
|
+
var system_stats_default = app33;
|
|
15397
15783
|
|
|
15398
15784
|
// server/routes/admin/health.ts
|
|
15399
|
-
import { existsSync as
|
|
15400
|
-
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";
|
|
15401
15787
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
|
|
15402
15788
|
var brandHostname = "maxy";
|
|
15403
|
-
var brandJsonPath =
|
|
15404
|
-
if (
|
|
15789
|
+
var brandJsonPath = join23(PLATFORM_ROOT6, "config", "brand.json");
|
|
15790
|
+
if (existsSync24(brandJsonPath)) {
|
|
15405
15791
|
try {
|
|
15406
|
-
const brand = JSON.parse(
|
|
15792
|
+
const brand = JSON.parse(readFileSync23(brandJsonPath, "utf-8"));
|
|
15407
15793
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
15408
15794
|
} catch {
|
|
15409
15795
|
}
|
|
@@ -15412,8 +15798,8 @@ var VERSION_FILE = resolve24(PLATFORM_ROOT6, `config/.${brandHostname}-version`)
|
|
|
15412
15798
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
15413
15799
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
15414
15800
|
function readVersion() {
|
|
15415
|
-
if (!
|
|
15416
|
-
return
|
|
15801
|
+
if (!existsSync24(VERSION_FILE)) return "unknown";
|
|
15802
|
+
return readFileSync23(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
15417
15803
|
}
|
|
15418
15804
|
async function probeConversationDb() {
|
|
15419
15805
|
let session;
|
|
@@ -15438,8 +15824,8 @@ async function probeConversationDb() {
|
|
|
15438
15824
|
});
|
|
15439
15825
|
}
|
|
15440
15826
|
}
|
|
15441
|
-
var
|
|
15442
|
-
|
|
15827
|
+
var app34 = new Hono();
|
|
15828
|
+
app34.get("/", async (c) => {
|
|
15443
15829
|
const version = readVersion();
|
|
15444
15830
|
const probe = await probeConversationDb();
|
|
15445
15831
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -15461,10 +15847,10 @@ app33.get("/", async (c) => {
|
|
|
15461
15847
|
uptimeMs
|
|
15462
15848
|
});
|
|
15463
15849
|
});
|
|
15464
|
-
var health_default2 =
|
|
15850
|
+
var health_default2 = app34;
|
|
15465
15851
|
|
|
15466
15852
|
// server/routes/admin/linkedin-ingest.ts
|
|
15467
|
-
import { randomUUID as
|
|
15853
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
15468
15854
|
var TAG26 = "[linkedin-ingest-route]";
|
|
15469
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}$/;
|
|
15470
15856
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
@@ -15563,8 +15949,8 @@ function buildInitialMessage(env) {
|
|
|
15563
15949
|
}
|
|
15564
15950
|
return header;
|
|
15565
15951
|
}
|
|
15566
|
-
var
|
|
15567
|
-
|
|
15952
|
+
var app35 = new Hono();
|
|
15953
|
+
app35.post("/", requireAdminSession, async (c) => {
|
|
15568
15954
|
let body;
|
|
15569
15955
|
try {
|
|
15570
15956
|
body = await c.req.json();
|
|
@@ -15590,7 +15976,7 @@ app34.post("/", requireAdminSession, async (c) => {
|
|
|
15590
15976
|
);
|
|
15591
15977
|
const initialMessage = buildInitialMessage(envelope);
|
|
15592
15978
|
const spawnStart = Date.now();
|
|
15593
|
-
const sessionId =
|
|
15979
|
+
const sessionId = randomUUID13();
|
|
15594
15980
|
console.log(TAG26 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
15595
15981
|
const spawned = await managerRcSpawn({
|
|
15596
15982
|
sessionId,
|
|
@@ -15609,7 +15995,7 @@ app34.post("/", requireAdminSession, async (c) => {
|
|
|
15609
15995
|
);
|
|
15610
15996
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
15611
15997
|
});
|
|
15612
|
-
var linkedin_ingest_default =
|
|
15998
|
+
var linkedin_ingest_default = app35;
|
|
15613
15999
|
|
|
15614
16000
|
// server/routes/admin/post-turn-context.ts
|
|
15615
16001
|
import neo4j3 from "neo4j-driver";
|
|
@@ -15651,8 +16037,8 @@ function pruneProperties(raw) {
|
|
|
15651
16037
|
}
|
|
15652
16038
|
return out;
|
|
15653
16039
|
}
|
|
15654
|
-
var
|
|
15655
|
-
|
|
16040
|
+
var app36 = new Hono();
|
|
16041
|
+
app36.get("/", async (c) => {
|
|
15656
16042
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15657
16043
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
15658
16044
|
console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -15712,7 +16098,7 @@ app35.get("/", async (c) => {
|
|
|
15712
16098
|
await session.close();
|
|
15713
16099
|
}
|
|
15714
16100
|
});
|
|
15715
|
-
var post_turn_context_default =
|
|
16101
|
+
var post_turn_context_default = app36;
|
|
15716
16102
|
|
|
15717
16103
|
// server/routes/admin/public-session-context.ts
|
|
15718
16104
|
import neo4j4 from "neo4j-driver";
|
|
@@ -15754,8 +16140,8 @@ function pruneProperties2(raw) {
|
|
|
15754
16140
|
}
|
|
15755
16141
|
return out;
|
|
15756
16142
|
}
|
|
15757
|
-
var
|
|
15758
|
-
|
|
16143
|
+
var app37 = new Hono();
|
|
16144
|
+
app37.get("/", async (c) => {
|
|
15759
16145
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15760
16146
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
15761
16147
|
console.error(`${TAG28} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -15814,15 +16200,15 @@ app36.get("/", async (c) => {
|
|
|
15814
16200
|
await session.close();
|
|
15815
16201
|
}
|
|
15816
16202
|
});
|
|
15817
|
-
var public_session_context_default =
|
|
16203
|
+
var public_session_context_default = app37;
|
|
15818
16204
|
|
|
15819
16205
|
// server/routes/admin/public-session-exit.ts
|
|
15820
16206
|
var TAG29 = "[public-session-exit-route]";
|
|
15821
16207
|
function isLoopbackAddr4(addr) {
|
|
15822
16208
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15823
16209
|
}
|
|
15824
|
-
var
|
|
15825
|
-
|
|
16210
|
+
var app38 = new Hono();
|
|
16211
|
+
app38.post("/", async (c) => {
|
|
15826
16212
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15827
16213
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
15828
16214
|
console.error(`${TAG29} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -15849,15 +16235,15 @@ app37.post("/", async (c) => {
|
|
|
15849
16235
|
handlePublicSessionExit(sessionId);
|
|
15850
16236
|
return c.json({ ok: true });
|
|
15851
16237
|
});
|
|
15852
|
-
var public_session_exit_default =
|
|
16238
|
+
var public_session_exit_default = app38;
|
|
15853
16239
|
|
|
15854
16240
|
// server/routes/admin/access-session-evict.ts
|
|
15855
16241
|
var TAG30 = "[access-session-evict]";
|
|
15856
16242
|
function isLoopbackAddr5(addr) {
|
|
15857
16243
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15858
16244
|
}
|
|
15859
|
-
var
|
|
15860
|
-
|
|
16245
|
+
var app39 = new Hono();
|
|
16246
|
+
app39.post("/", async (c) => {
|
|
15861
16247
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15862
16248
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
15863
16249
|
console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -15885,7 +16271,7 @@ app38.post("/", async (c) => {
|
|
|
15885
16271
|
console.log(`${TAG30} grantId=${grantId} dropped=${dropped}`);
|
|
15886
16272
|
return c.json({ ok: true, dropped });
|
|
15887
16273
|
});
|
|
15888
|
-
var access_session_evict_default =
|
|
16274
|
+
var access_session_evict_default = app39;
|
|
15889
16275
|
|
|
15890
16276
|
// server/routes/admin/enrol-person.ts
|
|
15891
16277
|
var TAG31 = "[enrol]";
|
|
@@ -15893,8 +16279,8 @@ function isLoopbackAddr6(addr) {
|
|
|
15893
16279
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15894
16280
|
}
|
|
15895
16281
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
15896
|
-
var
|
|
15897
|
-
|
|
16282
|
+
var app40 = new Hono();
|
|
16283
|
+
app40.post("/", async (c) => {
|
|
15898
16284
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15899
16285
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
15900
16286
|
console.error(`${TAG31} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -15957,11 +16343,11 @@ app39.post("/", async (c) => {
|
|
|
15957
16343
|
);
|
|
15958
16344
|
return c.json({ personId, grant }, 200);
|
|
15959
16345
|
});
|
|
15960
|
-
var enrol_person_default =
|
|
16346
|
+
var enrol_person_default = app40;
|
|
15961
16347
|
|
|
15962
16348
|
// server/routes/admin/browser.ts
|
|
15963
|
-
var
|
|
15964
|
-
|
|
16349
|
+
var app41 = new Hono();
|
|
16350
|
+
app41.post("/launch", requireAdminSession, async (c) => {
|
|
15965
16351
|
try {
|
|
15966
16352
|
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
15967
16353
|
console.error(`[admin/browser/launch] op=request transport=${transport}`);
|
|
@@ -15989,50 +16375,51 @@ app40.post("/launch", requireAdminSession, async (c) => {
|
|
|
15989
16375
|
);
|
|
15990
16376
|
}
|
|
15991
16377
|
});
|
|
15992
|
-
var browser_default =
|
|
16378
|
+
var browser_default = app41;
|
|
15993
16379
|
|
|
15994
16380
|
// server/routes/admin/index.ts
|
|
15995
|
-
var
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
|
|
16003
|
-
|
|
16004
|
-
|
|
16005
|
-
|
|
16006
|
-
|
|
16007
|
-
|
|
16008
|
-
|
|
16009
|
-
|
|
16010
|
-
|
|
16011
|
-
|
|
16012
|
-
|
|
16013
|
-
|
|
16014
|
-
|
|
16015
|
-
|
|
16016
|
-
|
|
16017
|
-
|
|
16018
|
-
|
|
16019
|
-
|
|
16020
|
-
|
|
16021
|
-
|
|
16022
|
-
|
|
16023
|
-
|
|
16024
|
-
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
|
|
16028
|
-
|
|
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;
|
|
16029
16416
|
|
|
16030
16417
|
// server/routes/access/verify-token.ts
|
|
16031
16418
|
var TAG32 = "[access-verify]";
|
|
16032
16419
|
var MINT_TAG = "[access-session-mint]";
|
|
16033
16420
|
var COOKIE_NAME = "__access_session";
|
|
16034
|
-
var
|
|
16035
|
-
|
|
16421
|
+
var app43 = new Hono();
|
|
16422
|
+
app43.post("/", async (c) => {
|
|
16036
16423
|
const ip = c.var.clientIp || "unknown";
|
|
16037
16424
|
let body;
|
|
16038
16425
|
try {
|
|
@@ -16114,7 +16501,7 @@ app42.post("/", async (c) => {
|
|
|
16114
16501
|
displayName: grant.displayName
|
|
16115
16502
|
});
|
|
16116
16503
|
});
|
|
16117
|
-
var verify_token_default =
|
|
16504
|
+
var verify_token_default = app43;
|
|
16118
16505
|
|
|
16119
16506
|
// app/lib/access-email.ts
|
|
16120
16507
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -16177,9 +16564,9 @@ async function sendMagicLinkEmail(payload) {
|
|
|
16177
16564
|
|
|
16178
16565
|
// server/routes/access/request-magic-link.ts
|
|
16179
16566
|
var TAG33 = "[access-request-link]";
|
|
16180
|
-
var
|
|
16567
|
+
var app44 = new Hono();
|
|
16181
16568
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
16182
|
-
|
|
16569
|
+
app44.post("/", async (c) => {
|
|
16183
16570
|
let body;
|
|
16184
16571
|
try {
|
|
16185
16572
|
body = await c.req.json();
|
|
@@ -16253,16 +16640,16 @@ app43.post("/", async (c) => {
|
|
|
16253
16640
|
);
|
|
16254
16641
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
16255
16642
|
});
|
|
16256
|
-
var request_magic_link_default =
|
|
16643
|
+
var request_magic_link_default = app44;
|
|
16257
16644
|
|
|
16258
16645
|
// server/routes/access/index.ts
|
|
16259
|
-
var
|
|
16260
|
-
|
|
16261
|
-
|
|
16262
|
-
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;
|
|
16263
16650
|
|
|
16264
16651
|
// server/routes/sites.ts
|
|
16265
|
-
import { existsSync as
|
|
16652
|
+
import { existsSync as existsSync25, readFileSync as readFileSync24, realpathSync as realpathSync5, statSync as statSync11 } from "fs";
|
|
16266
16653
|
import { resolve as resolve26 } from "path";
|
|
16267
16654
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
16268
16655
|
var MIME = {
|
|
@@ -16294,8 +16681,8 @@ function getExt(p) {
|
|
|
16294
16681
|
if (idx < p.lastIndexOf("/")) return "";
|
|
16295
16682
|
return p.slice(idx).toLowerCase();
|
|
16296
16683
|
}
|
|
16297
|
-
var
|
|
16298
|
-
|
|
16684
|
+
var app46 = new Hono();
|
|
16685
|
+
app46.get("/:rel{.*}", (c) => {
|
|
16299
16686
|
const reqPath = c.req.path;
|
|
16300
16687
|
const rawRel = c.req.param("rel") ?? "";
|
|
16301
16688
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -16328,7 +16715,7 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16328
16715
|
}
|
|
16329
16716
|
let stat7;
|
|
16330
16717
|
try {
|
|
16331
|
-
stat7 =
|
|
16718
|
+
stat7 = existsSync25(filePath) ? statSync11(filePath) : null;
|
|
16332
16719
|
} catch {
|
|
16333
16720
|
stat7 = null;
|
|
16334
16721
|
}
|
|
@@ -16347,7 +16734,7 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16347
16734
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
16348
16735
|
return c.text("Forbidden", 403);
|
|
16349
16736
|
}
|
|
16350
|
-
if (!
|
|
16737
|
+
if (!existsSync25(filePath)) {
|
|
16351
16738
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
16352
16739
|
return c.text("Not found", 404);
|
|
16353
16740
|
}
|
|
@@ -16366,7 +16753,7 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16366
16753
|
}
|
|
16367
16754
|
let body;
|
|
16368
16755
|
try {
|
|
16369
|
-
body =
|
|
16756
|
+
body = readFileSync24(realPath);
|
|
16370
16757
|
} catch (err) {
|
|
16371
16758
|
const code = err?.code;
|
|
16372
16759
|
if (code === "EISDIR") {
|
|
@@ -16398,11 +16785,11 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16398
16785
|
"X-Content-Type-Options": "nosniff"
|
|
16399
16786
|
});
|
|
16400
16787
|
});
|
|
16401
|
-
var sites_default =
|
|
16788
|
+
var sites_default = app46;
|
|
16402
16789
|
|
|
16403
16790
|
// app/lib/visitor-token.ts
|
|
16404
16791
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
16405
|
-
import { mkdirSync as
|
|
16792
|
+
import { mkdirSync as mkdirSync5, readFileSync as readFileSync25, writeFileSync as writeFileSync10 } from "fs";
|
|
16406
16793
|
import { dirname as dirname7 } from "path";
|
|
16407
16794
|
var TOKEN_PREFIX = "v1.";
|
|
16408
16795
|
var SECRET_BYTES = 32;
|
|
@@ -16411,7 +16798,7 @@ var cachedSecret = null;
|
|
|
16411
16798
|
function getSecret() {
|
|
16412
16799
|
if (cachedSecret) return cachedSecret;
|
|
16413
16800
|
try {
|
|
16414
|
-
const hex2 =
|
|
16801
|
+
const hex2 = readFileSync25(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
16415
16802
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
16416
16803
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
16417
16804
|
return cachedSecret;
|
|
@@ -16420,12 +16807,12 @@ function getSecret() {
|
|
|
16420
16807
|
}
|
|
16421
16808
|
const fresh = randomBytes(SECRET_BYTES).toString("hex");
|
|
16422
16809
|
try {
|
|
16423
|
-
|
|
16424
|
-
|
|
16810
|
+
mkdirSync5(dirname7(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
16811
|
+
writeFileSync10(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
16425
16812
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
16426
16813
|
} catch {
|
|
16427
16814
|
}
|
|
16428
|
-
const hex =
|
|
16815
|
+
const hex = readFileSync25(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
16429
16816
|
cachedSecret = Buffer.from(hex, "hex");
|
|
16430
16817
|
return cachedSecret;
|
|
16431
16818
|
}
|
|
@@ -16478,8 +16865,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
16478
16865
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
16479
16866
|
|
|
16480
16867
|
// app/lib/brand-config.ts
|
|
16481
|
-
import { existsSync as
|
|
16482
|
-
import { join as
|
|
16868
|
+
import { existsSync as existsSync26, readFileSync as readFileSync26 } from "fs";
|
|
16869
|
+
import { join as join24 } from "path";
|
|
16483
16870
|
var cached2 = null;
|
|
16484
16871
|
var cachedAttempted = false;
|
|
16485
16872
|
function readBrandConfig() {
|
|
@@ -16487,10 +16874,10 @@ function readBrandConfig() {
|
|
|
16487
16874
|
cachedAttempted = true;
|
|
16488
16875
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
|
|
16489
16876
|
if (!platformRoot2) return null;
|
|
16490
|
-
const brandPath =
|
|
16491
|
-
if (!
|
|
16877
|
+
const brandPath = join24(platformRoot2, "config", "brand.json");
|
|
16878
|
+
if (!existsSync26(brandPath)) return null;
|
|
16492
16879
|
try {
|
|
16493
|
-
cached2 = JSON.parse(
|
|
16880
|
+
cached2 = JSON.parse(readFileSync26(brandPath, "utf-8"));
|
|
16494
16881
|
return cached2;
|
|
16495
16882
|
} catch {
|
|
16496
16883
|
return null;
|
|
@@ -16498,7 +16885,7 @@ function readBrandConfig() {
|
|
|
16498
16885
|
}
|
|
16499
16886
|
|
|
16500
16887
|
// server/routes/visitor-consent.ts
|
|
16501
|
-
var
|
|
16888
|
+
var app47 = new Hono();
|
|
16502
16889
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
16503
16890
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
16504
16891
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -16543,17 +16930,17 @@ function siteSlugFromReferer(referer) {
|
|
|
16543
16930
|
return "";
|
|
16544
16931
|
}
|
|
16545
16932
|
}
|
|
16546
|
-
|
|
16933
|
+
app47.options("/consent", (c) => {
|
|
16547
16934
|
const origin = getOrigin(c);
|
|
16548
16935
|
setCorsHeaders(c, origin);
|
|
16549
16936
|
return c.body(null, 204);
|
|
16550
16937
|
});
|
|
16551
|
-
|
|
16938
|
+
app47.options("/brand-config", (c) => {
|
|
16552
16939
|
const origin = getOrigin(c);
|
|
16553
16940
|
setCorsHeaders(c, origin);
|
|
16554
16941
|
return c.body(null, 204);
|
|
16555
16942
|
});
|
|
16556
|
-
|
|
16943
|
+
app47.post("/consent", async (c) => {
|
|
16557
16944
|
const origin = getOrigin(c);
|
|
16558
16945
|
setCorsHeaders(c, origin);
|
|
16559
16946
|
let raw;
|
|
@@ -16593,7 +16980,7 @@ app46.post("/consent", async (c) => {
|
|
|
16593
16980
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
16594
16981
|
return c.body(null, 204);
|
|
16595
16982
|
});
|
|
16596
|
-
|
|
16983
|
+
app47.get("/brand-config", (c) => {
|
|
16597
16984
|
const origin = getOrigin(c);
|
|
16598
16985
|
setCorsHeaders(c, origin);
|
|
16599
16986
|
const brand = readBrandConfig();
|
|
@@ -16603,7 +16990,7 @@ app46.get("/brand-config", (c) => {
|
|
|
16603
16990
|
c.header("Cache-Control", "public, max-age=300");
|
|
16604
16991
|
return c.json({ consent: { copy, palette } });
|
|
16605
16992
|
});
|
|
16606
|
-
var visitor_consent_default =
|
|
16993
|
+
var visitor_consent_default = app47;
|
|
16607
16994
|
|
|
16608
16995
|
// server/routes/listings.ts
|
|
16609
16996
|
function getCookie(headerValue, name) {
|
|
@@ -16630,8 +17017,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
16630
17017
|
}
|
|
16631
17018
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
16632
17019
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
16633
|
-
var
|
|
16634
|
-
|
|
17020
|
+
var app48 = new Hono();
|
|
17021
|
+
app48.get("/:slug/click", async (c) => {
|
|
16635
17022
|
const slug = c.req.param("slug") ?? "";
|
|
16636
17023
|
const rawSession = c.req.query("session") ?? "";
|
|
16637
17024
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -16695,10 +17082,10 @@ app47.get("/:slug/click", async (c) => {
|
|
|
16695
17082
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
16696
17083
|
return c.redirect(redirectUrl, 302);
|
|
16697
17084
|
});
|
|
16698
|
-
var listings_default =
|
|
17085
|
+
var listings_default = app48;
|
|
16699
17086
|
|
|
16700
17087
|
// server/routes/visitor-event.ts
|
|
16701
|
-
var
|
|
17088
|
+
var app49 = new Hono();
|
|
16702
17089
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
16703
17090
|
var buckets = /* @__PURE__ */ new Map();
|
|
16704
17091
|
var RATE_LIMIT = 60;
|
|
@@ -16765,12 +17152,12 @@ function originAllowed(origin, allowlist) {
|
|
|
16765
17152
|
return false;
|
|
16766
17153
|
}
|
|
16767
17154
|
}
|
|
16768
|
-
|
|
17155
|
+
app49.options("/event", (c) => {
|
|
16769
17156
|
const origin = getOrigin2(c);
|
|
16770
17157
|
setCorsHeaders2(c, origin);
|
|
16771
17158
|
return c.body(null, 204);
|
|
16772
17159
|
});
|
|
16773
|
-
|
|
17160
|
+
app49.post("/event", async (c) => {
|
|
16774
17161
|
const origin = getOrigin2(c);
|
|
16775
17162
|
setCorsHeaders2(c, origin);
|
|
16776
17163
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -16975,17 +17362,17 @@ async function writeEvent(opts) {
|
|
|
16975
17362
|
);
|
|
16976
17363
|
}
|
|
16977
17364
|
}
|
|
16978
|
-
var visitor_event_default =
|
|
17365
|
+
var visitor_event_default = app49;
|
|
16979
17366
|
|
|
16980
17367
|
// server/routes/session.ts
|
|
16981
17368
|
import { resolve as resolve27 } from "path";
|
|
16982
|
-
import { existsSync as
|
|
17369
|
+
import { existsSync as existsSync27, writeFileSync as writeFileSync11, mkdirSync as mkdirSync6 } from "fs";
|
|
16983
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;
|
|
16984
17371
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
16985
17372
|
try {
|
|
16986
17373
|
const cacheDir = resolve27(MAXY_DIR, "branding-cache", accountId);
|
|
16987
|
-
|
|
16988
|
-
|
|
17374
|
+
mkdirSync6(cacheDir, { recursive: true });
|
|
17375
|
+
writeFileSync11(resolve27(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
16989
17376
|
} catch (err) {
|
|
16990
17377
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
16991
17378
|
}
|
|
@@ -17021,8 +17408,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
17021
17408
|
headers
|
|
17022
17409
|
});
|
|
17023
17410
|
}
|
|
17024
|
-
var
|
|
17025
|
-
|
|
17411
|
+
var app50 = new Hono();
|
|
17412
|
+
app50.post("/", async (c) => {
|
|
17026
17413
|
let body;
|
|
17027
17414
|
try {
|
|
17028
17415
|
body = await c.req.json();
|
|
@@ -17074,7 +17461,7 @@ app49.post("/", async (c) => {
|
|
|
17074
17461
|
let agentConfig = null;
|
|
17075
17462
|
if (account) {
|
|
17076
17463
|
const agentDir = resolve27(account.accountDir, "agents", agentSlug);
|
|
17077
|
-
if (!
|
|
17464
|
+
if (!existsSync27(agentDir) || !existsSync27(resolve27(agentDir, "config.json"))) {
|
|
17078
17465
|
return c.json({ error: "Agent not found" }, 404);
|
|
17079
17466
|
}
|
|
17080
17467
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -17233,7 +17620,7 @@ app49.post("/", async (c) => {
|
|
|
17233
17620
|
newVisitorId
|
|
17234
17621
|
);
|
|
17235
17622
|
});
|
|
17236
|
-
var session_default2 =
|
|
17623
|
+
var session_default2 = app50;
|
|
17237
17624
|
|
|
17238
17625
|
// app/lib/graph-health.ts
|
|
17239
17626
|
var import_dist4 = __toESM(require_dist3(), 1);
|
|
@@ -17579,9 +17966,9 @@ async function migrateUploads(opts = {}) {
|
|
|
17579
17966
|
}
|
|
17580
17967
|
|
|
17581
17968
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
17582
|
-
import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as
|
|
17583
|
-
import { existsSync as
|
|
17584
|
-
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";
|
|
17585
17972
|
var ADMIN_ROLE2 = "admin";
|
|
17586
17973
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
17587
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;
|
|
@@ -17606,11 +17993,11 @@ async function readRaw(path2) {
|
|
|
17606
17993
|
async function writeRaw(path2, obj) {
|
|
17607
17994
|
const tmp = `${path2}.tmp.${process.pid}.${Date.now()}`;
|
|
17608
17995
|
try {
|
|
17609
|
-
await
|
|
17996
|
+
await writeFile4(tmp, JSON.stringify(obj, null, 2), "utf8");
|
|
17610
17997
|
await rename3(tmp, path2);
|
|
17611
17998
|
} catch (err) {
|
|
17612
17999
|
try {
|
|
17613
|
-
if (
|
|
18000
|
+
if (existsSync28(tmp)) await unlink3(tmp);
|
|
17614
18001
|
} catch {
|
|
17615
18002
|
}
|
|
17616
18003
|
throw err;
|
|
@@ -17626,7 +18013,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17626
18013
|
}
|
|
17627
18014
|
for (const slug of slugs) {
|
|
17628
18015
|
if (!slug.isDirectory()) continue;
|
|
17629
|
-
const slugDir =
|
|
18016
|
+
const slugDir = join25(projectsRoot, slug.name);
|
|
17630
18017
|
let entries;
|
|
17631
18018
|
try {
|
|
17632
18019
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -17635,9 +18022,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17635
18022
|
}
|
|
17636
18023
|
for (const entry of entries) {
|
|
17637
18024
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
17638
|
-
out.push(
|
|
18025
|
+
out.push(join25(slugDir, entry.name));
|
|
17639
18026
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
17640
|
-
const subDir =
|
|
18027
|
+
const subDir = join25(slugDir, entry.name);
|
|
17641
18028
|
let subs;
|
|
17642
18029
|
try {
|
|
17643
18030
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -17645,7 +18032,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17645
18032
|
continue;
|
|
17646
18033
|
}
|
|
17647
18034
|
for (const s of subs) {
|
|
17648
|
-
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));
|
|
17649
18036
|
}
|
|
17650
18037
|
}
|
|
17651
18038
|
}
|
|
@@ -17657,7 +18044,7 @@ function shortId(path2) {
|
|
|
17657
18044
|
return base.slice(0, 8);
|
|
17658
18045
|
}
|
|
17659
18046
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
17660
|
-
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) ?? "";
|
|
17661
18048
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
17662
18049
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
17663
18050
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -17999,8 +18386,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
17999
18386
|
|
|
18000
18387
|
// app/lib/whatsapp/gateway/routes.ts
|
|
18001
18388
|
function createWaChannelRoutes(deps) {
|
|
18002
|
-
const
|
|
18003
|
-
|
|
18389
|
+
const app52 = new Hono();
|
|
18390
|
+
app52.get("/wa-channel/inbound", (c) => {
|
|
18004
18391
|
const senderId = c.req.query("senderId");
|
|
18005
18392
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
18006
18393
|
return streamSSE(c, async (stream2) => {
|
|
@@ -18018,7 +18405,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18018
18405
|
}
|
|
18019
18406
|
});
|
|
18020
18407
|
});
|
|
18021
|
-
|
|
18408
|
+
app52.post("/wa-channel/reply", async (c) => {
|
|
18022
18409
|
const body = await c.req.json().catch(() => null);
|
|
18023
18410
|
const senderId = body?.senderId;
|
|
18024
18411
|
const text = body?.text;
|
|
@@ -18039,7 +18426,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18039
18426
|
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
18040
18427
|
return c.json({ ok: true });
|
|
18041
18428
|
});
|
|
18042
|
-
|
|
18429
|
+
app52.post("/wa-channel/reply-document", async (c) => {
|
|
18043
18430
|
const body = await c.req.json().catch(() => null);
|
|
18044
18431
|
const senderId = body?.senderId;
|
|
18045
18432
|
const files = body?.files;
|
|
@@ -18078,7 +18465,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18078
18465
|
}
|
|
18079
18466
|
return c.json({ ok: true, results });
|
|
18080
18467
|
});
|
|
18081
|
-
|
|
18468
|
+
app52.post("/wa-channel/ready", async (c) => {
|
|
18082
18469
|
const body = await c.req.json().catch(() => null);
|
|
18083
18470
|
const senderId = body?.senderId;
|
|
18084
18471
|
if (typeof senderId !== "string") {
|
|
@@ -18087,7 +18474,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18087
18474
|
deps.onReady?.(senderId);
|
|
18088
18475
|
return c.json({ ok: true });
|
|
18089
18476
|
});
|
|
18090
|
-
|
|
18477
|
+
app52.post("/wa-channel/received", async (c) => {
|
|
18091
18478
|
const body = await c.req.json().catch(() => null);
|
|
18092
18479
|
const senderId = body?.senderId;
|
|
18093
18480
|
const waMessageId = body?.waMessageId;
|
|
@@ -18097,7 +18484,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18097
18484
|
deps.onReceived?.(senderId, waMessageId);
|
|
18098
18485
|
return c.json({ ok: true });
|
|
18099
18486
|
});
|
|
18100
|
-
|
|
18487
|
+
app52.post("/wa-channel/turn-end", async (c) => {
|
|
18101
18488
|
const body = await c.req.json().catch(() => null);
|
|
18102
18489
|
const senderId = body?.senderId;
|
|
18103
18490
|
const sessionId = body?.sessionId;
|
|
@@ -18128,7 +18515,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18128
18515
|
console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=fallback bytes=${bytes}`);
|
|
18129
18516
|
return c.json({ ok: true, delivered: "fallback" });
|
|
18130
18517
|
});
|
|
18131
|
-
return
|
|
18518
|
+
return app52;
|
|
18132
18519
|
}
|
|
18133
18520
|
|
|
18134
18521
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -18381,8 +18768,8 @@ var InboundHub2 = class {
|
|
|
18381
18768
|
|
|
18382
18769
|
// app/lib/webchat/gateway/routes.ts
|
|
18383
18770
|
function createWebchatChannelRoutes(deps) {
|
|
18384
|
-
const
|
|
18385
|
-
|
|
18771
|
+
const app52 = new Hono();
|
|
18772
|
+
app52.get("/webchat-channel/inbound", (c) => {
|
|
18386
18773
|
const key = c.req.query("key");
|
|
18387
18774
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
18388
18775
|
return streamSSE(c, async (stream2) => {
|
|
@@ -18400,7 +18787,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18400
18787
|
}
|
|
18401
18788
|
});
|
|
18402
18789
|
});
|
|
18403
|
-
|
|
18790
|
+
app52.post("/webchat-channel/reply", async (c) => {
|
|
18404
18791
|
const body = await c.req.json().catch(() => null);
|
|
18405
18792
|
const key = body?.key;
|
|
18406
18793
|
const text = body?.text;
|
|
@@ -18410,7 +18797,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18410
18797
|
deps.onReply?.(key, text);
|
|
18411
18798
|
return c.json({ ok: true });
|
|
18412
18799
|
});
|
|
18413
|
-
|
|
18800
|
+
app52.post("/webchat-channel/ready", async (c) => {
|
|
18414
18801
|
const body = await c.req.json().catch(() => null);
|
|
18415
18802
|
const key = body?.key;
|
|
18416
18803
|
if (typeof key !== "string") {
|
|
@@ -18419,7 +18806,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18419
18806
|
deps.onReady?.(key);
|
|
18420
18807
|
return c.json({ ok: true });
|
|
18421
18808
|
});
|
|
18422
|
-
|
|
18809
|
+
app52.post("/webchat-channel/received", async (c) => {
|
|
18423
18810
|
const body = await c.req.json().catch(() => null);
|
|
18424
18811
|
const key = body?.key;
|
|
18425
18812
|
const messageId = body?.messageId;
|
|
@@ -18429,7 +18816,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18429
18816
|
deps.onReceived?.(key, messageId);
|
|
18430
18817
|
return c.json({ ok: true });
|
|
18431
18818
|
});
|
|
18432
|
-
return
|
|
18819
|
+
return app52;
|
|
18433
18820
|
}
|
|
18434
18821
|
|
|
18435
18822
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -18742,7 +19129,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
18742
19129
|
|
|
18743
19130
|
// ../lib/entitlement/src/index.ts
|
|
18744
19131
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
18745
|
-
import { existsSync as
|
|
19132
|
+
import { existsSync as existsSync29, readFileSync as readFileSync27, statSync as statSync12 } from "fs";
|
|
18746
19133
|
import { resolve as resolve30 } from "path";
|
|
18747
19134
|
|
|
18748
19135
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -18791,7 +19178,7 @@ function resolveEntitlement(brand, account) {
|
|
|
18791
19178
|
return logResolved(implicitTrust(account), null);
|
|
18792
19179
|
}
|
|
18793
19180
|
const entitlementPath = resolve30(brand.configDir, "entitlement.json");
|
|
18794
|
-
if (!
|
|
19181
|
+
if (!existsSync29(entitlementPath)) {
|
|
18795
19182
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
18796
19183
|
}
|
|
18797
19184
|
const stat7 = statSync12(entitlementPath);
|
|
@@ -18806,7 +19193,7 @@ function resolveEntitlement(brand, account) {
|
|
|
18806
19193
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
18807
19194
|
let pubkeyPem;
|
|
18808
19195
|
try {
|
|
18809
|
-
pubkeyPem =
|
|
19196
|
+
pubkeyPem = readFileSync27(pubkeyPath(brand), "utf-8");
|
|
18810
19197
|
} catch (err) {
|
|
18811
19198
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
18812
19199
|
reason: "pubkey-missing"
|
|
@@ -18820,7 +19207,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
18820
19207
|
}
|
|
18821
19208
|
let envelope;
|
|
18822
19209
|
try {
|
|
18823
|
-
envelope = JSON.parse(
|
|
19210
|
+
envelope = JSON.parse(readFileSync27(entitlementPath, "utf-8"));
|
|
18824
19211
|
} catch {
|
|
18825
19212
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
18826
19213
|
}
|
|
@@ -18981,14 +19368,14 @@ function clientFrom(c) {
|
|
|
18981
19368
|
);
|
|
18982
19369
|
}
|
|
18983
19370
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
18984
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
19371
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join26(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
18985
19372
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
18986
|
-
if (BRAND_JSON_PATH && !
|
|
19373
|
+
if (BRAND_JSON_PATH && !existsSync30(BRAND_JSON_PATH)) {
|
|
18987
19374
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
18988
19375
|
}
|
|
18989
|
-
if (BRAND_JSON_PATH &&
|
|
19376
|
+
if (BRAND_JSON_PATH && existsSync30(BRAND_JSON_PATH)) {
|
|
18990
19377
|
try {
|
|
18991
|
-
const parsed = JSON.parse(
|
|
19378
|
+
const parsed = JSON.parse(readFileSync28(BRAND_JSON_PATH, "utf-8"));
|
|
18992
19379
|
BRAND = { ...BRAND, ...parsed };
|
|
18993
19380
|
} catch (err) {
|
|
18994
19381
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -19007,11 +19394,11 @@ var brandLoginOpts = {
|
|
|
19007
19394
|
bodyFont: BRAND.defaultFonts?.body,
|
|
19008
19395
|
logoContainsName: !!BRAND.logoContainsName
|
|
19009
19396
|
};
|
|
19010
|
-
var ALIAS_DOMAINS_PATH =
|
|
19397
|
+
var ALIAS_DOMAINS_PATH = join26(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
19011
19398
|
function loadAliasDomains() {
|
|
19012
19399
|
try {
|
|
19013
|
-
if (!
|
|
19014
|
-
const parsed = JSON.parse(
|
|
19400
|
+
if (!existsSync30(ALIAS_DOMAINS_PATH)) return null;
|
|
19401
|
+
const parsed = JSON.parse(readFileSync28(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
19015
19402
|
if (!Array.isArray(parsed)) {
|
|
19016
19403
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
19017
19404
|
return null;
|
|
@@ -19035,11 +19422,11 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
19035
19422
|
function isPublicHost(host) {
|
|
19036
19423
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
19037
19424
|
}
|
|
19038
|
-
var
|
|
19425
|
+
var app51 = new Hono();
|
|
19039
19426
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
19040
19427
|
var waGateway = new WaGateway({
|
|
19041
19428
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
19042
|
-
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"),
|
|
19043
19430
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
19044
19431
|
// account + path validation here and funnel through the shared send core.
|
|
19045
19432
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -19055,7 +19442,7 @@ var waGateway = new WaGateway({
|
|
|
19055
19442
|
caption,
|
|
19056
19443
|
accountId,
|
|
19057
19444
|
maxyAccountId,
|
|
19058
|
-
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ??
|
|
19445
|
+
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ?? join26(__dirname, ".."))
|
|
19059
19446
|
});
|
|
19060
19447
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
19061
19448
|
},
|
|
@@ -19085,7 +19472,7 @@ var waGateway = new WaGateway({
|
|
|
19085
19472
|
nativeFileFollowers.set(senderId, ac);
|
|
19086
19473
|
}
|
|
19087
19474
|
});
|
|
19088
|
-
|
|
19475
|
+
app51.route("/", waGateway.routes());
|
|
19089
19476
|
waGateway.startSweeper();
|
|
19090
19477
|
var webchatGateway = new WebchatGateway({
|
|
19091
19478
|
gatewayUrl: webchatGatewayUrl(),
|
|
@@ -19125,15 +19512,15 @@ var webchatGateway = new WebchatGateway({
|
|
|
19125
19512
|
deleteSession: (sessionId) => managerDelete(sessionId),
|
|
19126
19513
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
19127
19514
|
});
|
|
19128
|
-
|
|
19515
|
+
app51.route("/", webchatGateway.routes());
|
|
19129
19516
|
webchatGateway.startSweeper();
|
|
19130
19517
|
webchatGateway.startPublicReaper();
|
|
19131
19518
|
var chatRoutes = createChatRoutes({
|
|
19132
19519
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
19133
19520
|
awaitReply: (key, timeoutMs) => webchatGateway.awaitReply(key, timeoutMs)
|
|
19134
19521
|
});
|
|
19135
|
-
|
|
19136
|
-
|
|
19522
|
+
app51.use("*", clientIpMiddleware);
|
|
19523
|
+
app51.use("*", async (c, next) => {
|
|
19137
19524
|
await next();
|
|
19138
19525
|
c.header("X-Content-Type-Options", "nosniff");
|
|
19139
19526
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -19143,7 +19530,7 @@ app50.use("*", async (c, next) => {
|
|
|
19143
19530
|
);
|
|
19144
19531
|
});
|
|
19145
19532
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
19146
|
-
|
|
19533
|
+
app51.use("*", async (c, next) => {
|
|
19147
19534
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
19148
19535
|
await next();
|
|
19149
19536
|
return;
|
|
@@ -19161,7 +19548,7 @@ app50.use("*", async (c, next) => {
|
|
|
19161
19548
|
});
|
|
19162
19549
|
}
|
|
19163
19550
|
});
|
|
19164
|
-
|
|
19551
|
+
app51.use("*", async (c, next) => {
|
|
19165
19552
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19166
19553
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
19167
19554
|
await next();
|
|
@@ -19192,7 +19579,7 @@ function resolveRemoteAuthOpts() {
|
|
|
19192
19579
|
return brandLoginOpts;
|
|
19193
19580
|
}
|
|
19194
19581
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
19195
|
-
|
|
19582
|
+
app51.post("/__remote-auth/login", async (c) => {
|
|
19196
19583
|
const client = clientFrom(c);
|
|
19197
19584
|
const clientIp = client.ip || "unknown";
|
|
19198
19585
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -19237,7 +19624,7 @@ app50.post("/__remote-auth/login", async (c) => {
|
|
|
19237
19624
|
}
|
|
19238
19625
|
});
|
|
19239
19626
|
});
|
|
19240
|
-
|
|
19627
|
+
app51.get("/__remote-auth/logout", (c) => {
|
|
19241
19628
|
const client = clientFrom(c);
|
|
19242
19629
|
const clientIp = client.ip || "unknown";
|
|
19243
19630
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -19250,7 +19637,7 @@ app50.get("/__remote-auth/logout", (c) => {
|
|
|
19250
19637
|
}
|
|
19251
19638
|
});
|
|
19252
19639
|
});
|
|
19253
|
-
|
|
19640
|
+
app51.post("/__remote-auth/change-password", async (c) => {
|
|
19254
19641
|
const client = clientFrom(c);
|
|
19255
19642
|
const clientIp = client.ip || "unknown";
|
|
19256
19643
|
const rateLimited = checkRateLimit(client);
|
|
@@ -19309,13 +19696,13 @@ app50.post("/__remote-auth/change-password", async (c) => {
|
|
|
19309
19696
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
19310
19697
|
}
|
|
19311
19698
|
});
|
|
19312
|
-
|
|
19699
|
+
app51.get("/__remote-auth/setup", (c) => {
|
|
19313
19700
|
if (isRemoteAuthConfigured()) {
|
|
19314
19701
|
return c.redirect("/");
|
|
19315
19702
|
}
|
|
19316
19703
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
19317
19704
|
});
|
|
19318
|
-
|
|
19705
|
+
app51.post("/__remote-auth/set-initial-password", async (c) => {
|
|
19319
19706
|
if (isRemoteAuthConfigured()) {
|
|
19320
19707
|
return c.redirect("/");
|
|
19321
19708
|
}
|
|
@@ -19353,10 +19740,10 @@ app50.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
19353
19740
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
19354
19741
|
}
|
|
19355
19742
|
});
|
|
19356
|
-
|
|
19743
|
+
app51.get("/api/remote-auth/status", (c) => {
|
|
19357
19744
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
19358
19745
|
});
|
|
19359
|
-
|
|
19746
|
+
app51.post("/api/remote-auth/set-password", async (c) => {
|
|
19360
19747
|
let body;
|
|
19361
19748
|
try {
|
|
19362
19749
|
body = await c.req.json();
|
|
@@ -19395,10 +19782,10 @@ app50.post("/api/remote-auth/set-password", async (c) => {
|
|
|
19395
19782
|
return c.json({ error: "Failed to save password" }, 500);
|
|
19396
19783
|
}
|
|
19397
19784
|
});
|
|
19398
|
-
|
|
19785
|
+
app51.route("/api/_client-error", client_error_default);
|
|
19399
19786
|
console.log("[client-error-route] mounted");
|
|
19400
19787
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
19401
|
-
|
|
19788
|
+
app51.use("*", async (c, next) => {
|
|
19402
19789
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19403
19790
|
const path2 = c.req.path;
|
|
19404
19791
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") || PWA_PUBLIC_PATHS.has(path2)) {
|
|
@@ -19438,18 +19825,18 @@ app50.use("*", async (c, next) => {
|
|
|
19438
19825
|
}
|
|
19439
19826
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
19440
19827
|
});
|
|
19441
|
-
|
|
19442
|
-
|
|
19443
|
-
|
|
19444
|
-
|
|
19445
|
-
|
|
19446
|
-
|
|
19447
|
-
|
|
19448
|
-
|
|
19449
|
-
|
|
19450
|
-
|
|
19451
|
-
|
|
19452
|
-
|
|
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);
|
|
19453
19840
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
19454
19841
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
19455
19842
|
var IMAGE_MIME = {
|
|
@@ -19461,7 +19848,7 @@ var IMAGE_MIME = {
|
|
|
19461
19848
|
".svg": "image/svg+xml",
|
|
19462
19849
|
".ico": "image/x-icon"
|
|
19463
19850
|
};
|
|
19464
|
-
|
|
19851
|
+
app51.get("/agent-assets/:slug/:filename", (c) => {
|
|
19465
19852
|
const slug = c.req.param("slug");
|
|
19466
19853
|
const filename = c.req.param("filename");
|
|
19467
19854
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -19483,20 +19870,20 @@ app50.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
19483
19870
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
19484
19871
|
return c.text("Forbidden", 403);
|
|
19485
19872
|
}
|
|
19486
|
-
if (!
|
|
19873
|
+
if (!existsSync30(filePath)) {
|
|
19487
19874
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
19488
19875
|
return c.text("Not found", 404);
|
|
19489
19876
|
}
|
|
19490
19877
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
19491
19878
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
19492
19879
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
19493
|
-
const body =
|
|
19880
|
+
const body = readFileSync28(filePath);
|
|
19494
19881
|
return c.body(body, 200, {
|
|
19495
19882
|
"Content-Type": contentType,
|
|
19496
19883
|
"Cache-Control": "public, max-age=3600"
|
|
19497
19884
|
});
|
|
19498
19885
|
});
|
|
19499
|
-
|
|
19886
|
+
app51.get("/generated/:filename", (c) => {
|
|
19500
19887
|
const filename = c.req.param("filename");
|
|
19501
19888
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
19502
19889
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -19513,29 +19900,29 @@ app50.get("/generated/:filename", (c) => {
|
|
|
19513
19900
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
19514
19901
|
return c.text("Forbidden", 403);
|
|
19515
19902
|
}
|
|
19516
|
-
if (!
|
|
19903
|
+
if (!existsSync30(filePath)) {
|
|
19517
19904
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
19518
19905
|
return c.text("Not found", 404);
|
|
19519
19906
|
}
|
|
19520
19907
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
19521
19908
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
19522
19909
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
19523
|
-
const body =
|
|
19910
|
+
const body = readFileSync28(filePath);
|
|
19524
19911
|
return c.body(body, 200, {
|
|
19525
19912
|
"Content-Type": contentType,
|
|
19526
19913
|
"Cache-Control": "public, max-age=86400"
|
|
19527
19914
|
});
|
|
19528
19915
|
});
|
|
19529
|
-
|
|
19530
|
-
|
|
19531
|
-
|
|
19532
|
-
|
|
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);
|
|
19533
19920
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
19534
19921
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
19535
19922
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
19536
|
-
if (BRAND_JSON_PATH &&
|
|
19923
|
+
if (BRAND_JSON_PATH && existsSync30(BRAND_JSON_PATH)) {
|
|
19537
19924
|
try {
|
|
19538
|
-
const fullBrand = JSON.parse(
|
|
19925
|
+
const fullBrand = JSON.parse(readFileSync28(BRAND_JSON_PATH, "utf-8"));
|
|
19539
19926
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
19540
19927
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
19541
19928
|
} catch {
|
|
@@ -19552,10 +19939,10 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
19552
19939
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
19553
19940
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
19554
19941
|
var brandIconFsPath = resolve31(process.cwd(), "public", brandIconPath.replace(/^\//, ""));
|
|
19555
|
-
var brandIconExists =
|
|
19942
|
+
var brandIconExists = existsSync30(brandIconFsPath);
|
|
19556
19943
|
var SW_SOURCE = (() => {
|
|
19557
19944
|
try {
|
|
19558
|
-
return
|
|
19945
|
+
return readFileSync28(resolve31(process.cwd(), "public", "sw.js"), "utf-8");
|
|
19559
19946
|
} catch {
|
|
19560
19947
|
return null;
|
|
19561
19948
|
}
|
|
@@ -19563,9 +19950,9 @@ var SW_SOURCE = (() => {
|
|
|
19563
19950
|
function readInstalledVersion() {
|
|
19564
19951
|
try {
|
|
19565
19952
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
19566
|
-
const versionFile =
|
|
19567
|
-
if (!
|
|
19568
|
-
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();
|
|
19569
19956
|
return content || "unknown";
|
|
19570
19957
|
} catch {
|
|
19571
19958
|
return "unknown";
|
|
@@ -19606,7 +19993,7 @@ var clientErrorReporterScript = `<script>
|
|
|
19606
19993
|
function cachedHtml(file) {
|
|
19607
19994
|
let html = htmlCache.get(file);
|
|
19608
19995
|
if (!html) {
|
|
19609
|
-
html =
|
|
19996
|
+
html = readFileSync28(resolve31(process.cwd(), "public", file), "utf-8");
|
|
19610
19997
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
19611
19998
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
19612
19999
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -19624,13 +20011,13 @@ ${clientErrorReporterScript}
|
|
|
19624
20011
|
}
|
|
19625
20012
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
19626
20013
|
function loadBrandingCache(agentSlug) {
|
|
19627
|
-
const configDir2 =
|
|
20014
|
+
const configDir2 = join26(homedir3(), BRAND.configDir);
|
|
19628
20015
|
try {
|
|
19629
20016
|
const accountId = getDefaultAccountId();
|
|
19630
20017
|
if (!accountId) return null;
|
|
19631
|
-
const cachePath =
|
|
19632
|
-
if (!
|
|
19633
|
-
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"));
|
|
19634
20021
|
} catch {
|
|
19635
20022
|
return null;
|
|
19636
20023
|
}
|
|
@@ -19676,7 +20063,7 @@ function escapeHtml(s) {
|
|
|
19676
20063
|
function agentUnavailableHtml() {
|
|
19677
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>`;
|
|
19678
20065
|
}
|
|
19679
|
-
|
|
20066
|
+
app51.get("/", (c) => {
|
|
19680
20067
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19681
20068
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
19682
20069
|
if (klass === "operator") {
|
|
@@ -19699,13 +20086,13 @@ app50.get("/", (c) => {
|
|
|
19699
20086
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
19700
20087
|
return c.html(cachedHtml("index.html"));
|
|
19701
20088
|
});
|
|
19702
|
-
|
|
20089
|
+
app51.get("/public", (c) => {
|
|
19703
20090
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19704
20091
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19705
20092
|
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
19706
20093
|
return c.html(cachedHtml("public.html"));
|
|
19707
20094
|
});
|
|
19708
|
-
|
|
20095
|
+
app51.get("/public-chat", (c) => {
|
|
19709
20096
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19710
20097
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19711
20098
|
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
@@ -19725,12 +20112,12 @@ async function logViewerFetch(c, next) {
|
|
|
19725
20112
|
duration_ms: Date.now() - start
|
|
19726
20113
|
});
|
|
19727
20114
|
}
|
|
19728
|
-
|
|
19729
|
-
|
|
19730
|
-
|
|
20115
|
+
app51.use("/vnc-viewer.html", logViewerFetch);
|
|
20116
|
+
app51.use("/vnc-popout.html", logViewerFetch);
|
|
20117
|
+
app51.get("/vnc-popout.html", (c) => {
|
|
19731
20118
|
let html = htmlCache.get("vnc-popout.html");
|
|
19732
20119
|
if (!html) {
|
|
19733
|
-
html =
|
|
20120
|
+
html = readFileSync28(resolve31(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
19734
20121
|
const name = escapeHtml(BRAND.productName);
|
|
19735
20122
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
19736
20123
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -19740,7 +20127,7 @@ app50.get("/vnc-popout.html", (c) => {
|
|
|
19740
20127
|
}
|
|
19741
20128
|
return c.html(html);
|
|
19742
20129
|
});
|
|
19743
|
-
|
|
20130
|
+
app51.post("/api/vnc/client-event", async (c) => {
|
|
19744
20131
|
let body;
|
|
19745
20132
|
try {
|
|
19746
20133
|
body = await c.req.json();
|
|
@@ -19761,11 +20148,11 @@ app50.post("/api/vnc/client-event", async (c) => {
|
|
|
19761
20148
|
});
|
|
19762
20149
|
return c.json({ ok: true });
|
|
19763
20150
|
});
|
|
19764
|
-
|
|
20151
|
+
app51.get("/g/:slug", (c) => {
|
|
19765
20152
|
return c.html(brandedPublicHtml());
|
|
19766
20153
|
});
|
|
19767
20154
|
for (const pwa of PWA_SURFACES) {
|
|
19768
|
-
|
|
20155
|
+
app51.get(pwa.manifestPath, (c) => {
|
|
19769
20156
|
const manifest = buildManifest(pwa, {
|
|
19770
20157
|
productName: BRAND.productName,
|
|
19771
20158
|
iconPath: brandIconPath,
|
|
@@ -19779,7 +20166,7 @@ for (const pwa of PWA_SURFACES) {
|
|
|
19779
20166
|
return c.body(JSON.stringify(manifest));
|
|
19780
20167
|
});
|
|
19781
20168
|
}
|
|
19782
|
-
|
|
20169
|
+
app51.get("/sw.js", (c) => {
|
|
19783
20170
|
if (SW_SOURCE == null) {
|
|
19784
20171
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
19785
20172
|
return c.text("Service worker unavailable", 500);
|
|
@@ -19788,27 +20175,27 @@ app50.get("/sw.js", (c) => {
|
|
|
19788
20175
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
19789
20176
|
return c.body(SW_SOURCE);
|
|
19790
20177
|
});
|
|
19791
|
-
|
|
20178
|
+
app51.get("/graph", (c) => {
|
|
19792
20179
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19793
20180
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
19794
20181
|
return c.html(cachedHtml("graph.html"));
|
|
19795
20182
|
});
|
|
19796
|
-
|
|
20183
|
+
app51.get("/chat", (c) => {
|
|
19797
20184
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19798
20185
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19799
20186
|
return c.html(cachedHtml("chat.html"));
|
|
19800
20187
|
});
|
|
19801
|
-
|
|
20188
|
+
app51.get("/data", (c) => {
|
|
19802
20189
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19803
20190
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19804
20191
|
return c.html(cachedHtml("data.html"));
|
|
19805
20192
|
});
|
|
19806
|
-
|
|
20193
|
+
app51.get("/browser", (c) => {
|
|
19807
20194
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19808
20195
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
19809
20196
|
return c.html(cachedHtml("browser.html"));
|
|
19810
20197
|
});
|
|
19811
|
-
|
|
20198
|
+
app51.get("/:slug", async (c, next) => {
|
|
19812
20199
|
const slug = c.req.param("slug");
|
|
19813
20200
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
19814
20201
|
const account = resolveAccount();
|
|
@@ -19824,13 +20211,13 @@ app50.get("/:slug", async (c, next) => {
|
|
|
19824
20211
|
await next();
|
|
19825
20212
|
});
|
|
19826
20213
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
19827
|
-
|
|
20214
|
+
app51.get("/favicon.ico", (c) => {
|
|
19828
20215
|
c.header("Cache-Control", "public, max-age=300");
|
|
19829
20216
|
return c.redirect(brandFaviconPath, 302);
|
|
19830
20217
|
});
|
|
19831
20218
|
}
|
|
19832
|
-
|
|
19833
|
-
|
|
20219
|
+
app51.use("/*", serveStatic({ root: "./public" }));
|
|
20220
|
+
app51.all("*", (c) => {
|
|
19834
20221
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19835
20222
|
const path2 = c.req.path;
|
|
19836
20223
|
if (isPublicHost(host)) {
|
|
@@ -19844,7 +20231,7 @@ app50.all("*", (c) => {
|
|
|
19844
20231
|
});
|
|
19845
20232
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
19846
20233
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
19847
|
-
var httpServer = serve({ fetch:
|
|
20234
|
+
var httpServer = serve({ fetch: app51.fetch, port, hostname });
|
|
19848
20235
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
19849
20236
|
{
|
|
19850
20237
|
const census = pwaCensus({
|
|
@@ -19898,7 +20285,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
19898
20285
|
}
|
|
19899
20286
|
try {
|
|
19900
20287
|
const registered = [];
|
|
19901
|
-
for (const r of
|
|
20288
|
+
for (const r of app51.routes ?? []) {
|
|
19902
20289
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
19903
20290
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
19904
20291
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -19938,11 +20325,11 @@ try {
|
|
|
19938
20325
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
19939
20326
|
async function runAdminUserReconcileTick() {
|
|
19940
20327
|
try {
|
|
19941
|
-
if (!
|
|
20328
|
+
if (!existsSync30(USERS_FILE)) {
|
|
19942
20329
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
19943
20330
|
return;
|
|
19944
20331
|
}
|
|
19945
|
-
const usersRaw =
|
|
20332
|
+
const usersRaw = readFileSync28(USERS_FILE, "utf-8").trim();
|
|
19946
20333
|
if (!usersRaw) {
|
|
19947
20334
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
19948
20335
|
return;
|
|
@@ -19974,6 +20361,7 @@ void migrateUploads().catch((err) => console.error(`[uploads-migrate] failed err
|
|
|
19974
20361
|
console.error(`[file-watcher] start-failed err="${err instanceof Error ? err.message : String(err)}"`);
|
|
19975
20362
|
});
|
|
19976
20363
|
});
|
|
20364
|
+
void sweepStaleUploadTemps().catch((err) => console.error(`[data-upload] op=sweep-failed err="${err instanceof Error ? err.message : String(err)}"`));
|
|
19977
20365
|
void migrateAdminWebchatSidecars().catch((err) => console.error(`[sidecar-backfill] failed err="${err instanceof Error ? err.message : String(err)}"`));
|
|
19978
20366
|
try {
|
|
19979
20367
|
const accounts = enumerateValidAccountIds(getAccountsDirFromEnv());
|
|
@@ -20055,7 +20443,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
20055
20443
|
}
|
|
20056
20444
|
init({
|
|
20057
20445
|
configDir: configDirForWhatsApp,
|
|
20058
|
-
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ??
|
|
20446
|
+
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ?? join26(__dirname, "..")),
|
|
20059
20447
|
accountConfig: bootAccountConfig,
|
|
20060
20448
|
onMessage: async (msg) => {
|
|
20061
20449
|
if (msg.isOwnerMirror) {
|