@rubytech/create-maxy-code 0.1.198 → 0.1.203
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 +2 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +3736 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +3 -1
- package/payload/platform/scripts/check-architecture-skill-no-drift.mjs +67 -0
- package/payload/platform/scripts/check-no-esm-require.mjs +3 -0
- package/payload/platform/scripts/check-specialist-tool-surface.mjs +323 -0
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +7 -7
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +13 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +126 -7
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +9 -1
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts +2 -12
- package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js +14 -67
- package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +6 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.js +30 -0
- package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +4 -0
- package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +33 -3
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +88 -57
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +19 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +42 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/systemd-spawn.d.ts +62 -0
- package/payload/platform/services/claude-session-manager/dist/systemd-spawn.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/systemd-spawn.js +173 -0
- package/payload/platform/services/claude-session-manager/dist/systemd-spawn.js.map +1 -0
- package/payload/platform/templates/agents/admin/IDENTITY.md +4 -0
- package/payload/platform/templates/agents/public/IDENTITY.md +1 -1
- package/payload/platform/templates/specialists/agents/coding-assistant.md +73 -0
- package/payload/server/public/assets/AdminShell-BcxEZnpu.js +1 -0
- package/payload/server/public/assets/{Checkbox-Bh3kwzxP.js → Checkbox-DL-HdT29.js} +1 -1
- package/payload/server/public/assets/{admin-BWzKAudL.js → admin-DMo5DWKH.js} +1 -1
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-Boys2mT1.js → architectureDiagram-Q4EWVU46-BoUw4oYz.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-CvHqp46r.js → blockDiagram-DXYQGD6D-DOscnO3m.js} +1 -1
- package/payload/server/public/assets/{brand-VQtREmts.css → brand-SZW-27T7.css} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-DiNQ95F6.js → c4Diagram-AHTNJAMY-aZ1IuZ_F.js} +1 -1
- package/payload/server/public/assets/channel-CzcSNxDm.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-9nS9-05M.js → chunk-336JU56O-DS3ksXBG.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-B2__9lRY.js → chunk-426QAEUC-BLRn2STO.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-R5F8rS0Z.js → chunk-4TB4RGXK-BrhOvJ01.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-B8HhJce-.js → chunk-5FUZZQ4R-BZZwZX5Q.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-Bjb08lbL.js → chunk-5PVQY5BW-YXZKnPCz.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-he0qCF3s.js → chunk-EDXVE4YY-DAMCJHKQ.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-BTArFW5l.js → chunk-ENJZ2VHE-DsD95Bqn.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-CoyIL4q_.js → chunk-ICPOFSXX-DxtrRClx.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-DjLEhNFe.js → chunk-OYMX7WX6-CN4kLK-H.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-tac2uvW1.js → chunk-U2HBQHQK-BPTv3Oj1.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-DIWD9i88.js → chunk-X2U36JSP-DxBry33v.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-Ac7ogADz.js → chunk-YZCP3GAM-BZ4N75oy.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-QgqDaY9-.js → chunk-ZZ45TVLE-Dqr161Q1.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DFOM3vCn.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-HplDfaL1.js +1 -0
- package/payload/server/public/assets/clone-G-2rqnSR.js +1 -0
- package/payload/server/public/assets/{dagre-D6qN4nkK.js → dagre-DtZ0wKkH.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-C6TRKOg0.js → dagre-KV5264BT-BPKhT-ZX.js} +1 -1
- package/payload/server/public/assets/{data-CaZbNF-j.js → data-D6IQdm0R.js} +1 -1
- package/payload/server/public/assets/{diagram-5BDNPKRD-BVk_J8Pt.js → diagram-5BDNPKRD-CATnafi7.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-BdV1IgwS.js → diagram-G4DWMVQ6-ChZYQfji.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-OsvBkN6u.js → diagram-MMDJMWI5-DHW6kYd3.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-BQmKPyrb.js → diagram-TYMM5635-CnS4Zci8.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-ChEx5_3C.js → erDiagram-SMLLAGMA-DKYv2YWp.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-B7sf6AG3.js → flowDiagram-DWJPFMVM-BWvoZWlh.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-DbpSraax.js → ganttDiagram-T4ZO3ILL-CpCb-xKy.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-BnxDElDh.js → gitGraphDiagram-UUTBAWPF-CvHrDKQ-.js} +1 -1
- package/payload/server/public/assets/{graph-CBP5yppq.js → graph-PkZKVkWD.js} +1 -1
- package/payload/server/public/assets/{graph-labels-BsZNScfa.js → graph-labels-CWJy0O4w.js} +1 -1
- package/payload/server/public/assets/{graphlib-Dux06enE.js → graphlib-DjnyHqGy.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-BLWb6oKx.js → infoDiagram-42DDH7IO-D_MywcVn.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-AFiRuE6G.js → ishikawaDiagram-UXIWVN3A-N9m-f-Eb.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-CxHBRGGu.js → journeyDiagram-VCZTEJTY-DE0q7uSM.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-CGugF0N8.js → kanban-definition-6JOO6SKY-Dj5hb9Bq.js} +1 -1
- package/payload/server/public/assets/{line-COFloj-X.js → line-C6ph0i4M.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-CxXuCDQf.js → mermaid-parser.core-BrfmEvCA.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-BRBNvNup.js → mermaid.core-DYnHKfDv.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-DarW5Wwq.js → mindmap-definition-QFDTVHPH-DaSaZfhR.js} +1 -1
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-CTokFAkN.js → pieDiagram-DEJITSTG-BAu9Ezbv.js} +1 -1
- package/payload/server/public/assets/{public-Bq-eOUu9.js → public-UKgkJxKv.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-BNawkg3I.js → quadrantDiagram-34T5L4WZ-DRsbL1Xd.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-CWnO56oR.js → requirementDiagram-MS252O5E-B9QcsXV6.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-D9c-EZfV.js → sankeyDiagram-XADWPNL6-DsZbvIlD.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-In5lxCT5.js → sequenceDiagram-FGHM5R23-BlT4O2N8.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CYb5js-u.js → stateDiagram-FHFEXIEX-JFgk1K3Y.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-NXz27DaV.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-Cje-BY9v.js → timeline-definition-GMOUNBTQ-DOsHw1ip.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-B_2EQ2CC.js → useSelectionMode-JDGvwvIk.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-BqeuoPr1.js → vennDiagram-DHZGUBPP-CQWIhqZY.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-DE7xAnoq.js → wardleyDiagram-NUSXRM2D-D5Fh7YVL.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-JE4x8YEZ.js → xychartDiagram-5P7HB3ND-C-tINQEs.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +6 -6
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +566 -256
- package/payload/server/public/assets/AdminShell-DPk5UgEJ.js +0 -1
- package/payload/server/public/assets/channel-BgwH_qhE.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-CwdV1-c8.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CS_jtevB.js +0 -1
- package/payload/server/public/assets/clone-BTishuSs.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-z-TVJfRt.js +0 -1
- /package/payload/server/public/assets/{brand-CzeO4m4J.js → brand-SzZmKKjz.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -816,8 +816,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
816
816
|
};
|
|
817
817
|
|
|
818
818
|
// server/index.ts
|
|
819
|
-
import { readFileSync as
|
|
820
|
-
import { resolve as
|
|
819
|
+
import { readFileSync as readFileSync22, existsSync as existsSync22, watchFile } from "fs";
|
|
820
|
+
import { resolve as resolve24, join as join17, basename as basename6 } from "path";
|
|
821
821
|
import { homedir as homedir2 } from "os";
|
|
822
822
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
823
823
|
|
|
@@ -1275,7 +1275,7 @@ var credsSaveQueue = Promise.resolve();
|
|
|
1275
1275
|
async function drainCredsSaveQueue(timeoutMs = 5e3) {
|
|
1276
1276
|
console.error(`${TAG2} draining credential save queue\u2026`);
|
|
1277
1277
|
const timer2 = new Promise(
|
|
1278
|
-
(
|
|
1278
|
+
(resolve25) => setTimeout(() => resolve25("timeout"), timeoutMs)
|
|
1279
1279
|
);
|
|
1280
1280
|
const result = await Promise.race([
|
|
1281
1281
|
credsSaveQueue.then(() => "drained"),
|
|
@@ -1403,11 +1403,11 @@ async function createWaSocket(opts) {
|
|
|
1403
1403
|
return sock;
|
|
1404
1404
|
}
|
|
1405
1405
|
async function waitForConnection(sock) {
|
|
1406
|
-
return new Promise((
|
|
1406
|
+
return new Promise((resolve25, reject) => {
|
|
1407
1407
|
const handler = (update) => {
|
|
1408
1408
|
if (update.connection === "open") {
|
|
1409
1409
|
sock.ev.off("connection.update", handler);
|
|
1410
|
-
|
|
1410
|
+
resolve25();
|
|
1411
1411
|
}
|
|
1412
1412
|
if (update.connection === "close") {
|
|
1413
1413
|
sock.ev.off("connection.update", handler);
|
|
@@ -1521,14 +1521,14 @@ ${inspected}`;
|
|
|
1521
1521
|
return inspect2(err, INSPECT_OPTS2);
|
|
1522
1522
|
}
|
|
1523
1523
|
function withTimeout(label, promise, timeoutMs) {
|
|
1524
|
-
return new Promise((
|
|
1524
|
+
return new Promise((resolve25, reject) => {
|
|
1525
1525
|
const timer2 = setTimeout(() => {
|
|
1526
1526
|
reject(new Error(`${label} timed out after ${timeoutMs}ms`));
|
|
1527
1527
|
}, timeoutMs);
|
|
1528
1528
|
promise.then(
|
|
1529
1529
|
(value) => {
|
|
1530
1530
|
clearTimeout(timer2);
|
|
1531
|
-
|
|
1531
|
+
resolve25(value);
|
|
1532
1532
|
},
|
|
1533
1533
|
(err) => {
|
|
1534
1534
|
clearTimeout(timer2);
|
|
@@ -2063,8 +2063,8 @@ async function persistWhatsAppMessage(input) {
|
|
|
2063
2063
|
const { givenName, familyName } = splitName(input.pushName);
|
|
2064
2064
|
const prev = sessionWriteLocks.get(input.cacheKey);
|
|
2065
2065
|
let release;
|
|
2066
|
-
const mine = new Promise((
|
|
2067
|
-
release =
|
|
2066
|
+
const mine = new Promise((resolve25) => {
|
|
2067
|
+
release = resolve25;
|
|
2068
2068
|
});
|
|
2069
2069
|
const chained = (prev ?? Promise.resolve()).then(() => mine);
|
|
2070
2070
|
sessionWriteLocks.set(input.cacheKey, chained);
|
|
@@ -3100,11 +3100,11 @@ async function connectWithReconnect(conn) {
|
|
|
3100
3100
|
console.error(
|
|
3101
3101
|
`${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
|
|
3102
3102
|
);
|
|
3103
|
-
await new Promise((
|
|
3104
|
-
const timer2 = setTimeout(
|
|
3103
|
+
await new Promise((resolve25) => {
|
|
3104
|
+
const timer2 = setTimeout(resolve25, delay);
|
|
3105
3105
|
conn.abortController.signal.addEventListener("abort", () => {
|
|
3106
3106
|
clearTimeout(timer2);
|
|
3107
|
-
|
|
3107
|
+
resolve25();
|
|
3108
3108
|
}, { once: true });
|
|
3109
3109
|
});
|
|
3110
3110
|
}
|
|
@@ -3112,16 +3112,16 @@ async function connectWithReconnect(conn) {
|
|
|
3112
3112
|
}
|
|
3113
3113
|
}
|
|
3114
3114
|
function waitForDisconnectEvent(conn) {
|
|
3115
|
-
return new Promise((
|
|
3115
|
+
return new Promise((resolve25) => {
|
|
3116
3116
|
if (!conn.sock) {
|
|
3117
|
-
|
|
3117
|
+
resolve25();
|
|
3118
3118
|
return;
|
|
3119
3119
|
}
|
|
3120
3120
|
const sock = conn.sock;
|
|
3121
3121
|
const handler = (update) => {
|
|
3122
3122
|
if (update.connection === "close") {
|
|
3123
3123
|
sock.ev.off("connection.update", handler);
|
|
3124
|
-
|
|
3124
|
+
resolve25();
|
|
3125
3125
|
}
|
|
3126
3126
|
};
|
|
3127
3127
|
sock.ev.on("connection.update", handler);
|
|
@@ -3383,8 +3383,8 @@ async function handleInboundMessage(conn, msg) {
|
|
|
3383
3383
|
const conversationKey = isGroup ? remoteJid : senderPhone;
|
|
3384
3384
|
const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
|
|
3385
3385
|
let resolvePending;
|
|
3386
|
-
const sttPending = new Promise((
|
|
3387
|
-
resolvePending =
|
|
3386
|
+
const sttPending = new Promise((resolve25) => {
|
|
3387
|
+
resolvePending = resolve25;
|
|
3388
3388
|
});
|
|
3389
3389
|
if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
|
|
3390
3390
|
try {
|
|
@@ -3788,20 +3788,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
|
|
|
3788
3788
|
|
|
3789
3789
|
// server/routes/health.ts
|
|
3790
3790
|
function checkPort(port2, timeoutMs = 500) {
|
|
3791
|
-
return new Promise((
|
|
3791
|
+
return new Promise((resolve25) => {
|
|
3792
3792
|
const socket = createConnection2(port2, "127.0.0.1");
|
|
3793
3793
|
socket.setTimeout(timeoutMs);
|
|
3794
3794
|
socket.once("connect", () => {
|
|
3795
3795
|
socket.destroy();
|
|
3796
|
-
|
|
3796
|
+
resolve25(true);
|
|
3797
3797
|
});
|
|
3798
3798
|
socket.once("error", () => {
|
|
3799
3799
|
socket.destroy();
|
|
3800
|
-
|
|
3800
|
+
resolve25(false);
|
|
3801
3801
|
});
|
|
3802
3802
|
socket.once("timeout", () => {
|
|
3803
3803
|
socket.destroy();
|
|
3804
|
-
|
|
3804
|
+
resolve25(false);
|
|
3805
3805
|
});
|
|
3806
3806
|
});
|
|
3807
3807
|
}
|
|
@@ -4537,12 +4537,12 @@ async function dispatchOnce(input) {
|
|
|
4537
4537
|
});
|
|
4538
4538
|
if (!entry) return { error: "spawn-failed" };
|
|
4539
4539
|
entry.lastInboundAt = Date.now();
|
|
4540
|
-
let
|
|
4540
|
+
let resolve25;
|
|
4541
4541
|
const turnPromise = new Promise((r) => {
|
|
4542
|
-
|
|
4542
|
+
resolve25 = r;
|
|
4543
4543
|
});
|
|
4544
4544
|
const listener = (text) => {
|
|
4545
|
-
|
|
4545
|
+
resolve25(text);
|
|
4546
4546
|
};
|
|
4547
4547
|
entry.subscribers.add(listener);
|
|
4548
4548
|
const writeOk = await writeInput(entry, input.text);
|
|
@@ -4984,8 +4984,8 @@ async function startLogin(opts) {
|
|
|
4984
4984
|
resetActiveLogin(accountId);
|
|
4985
4985
|
let resolveQr = null;
|
|
4986
4986
|
let rejectQr = null;
|
|
4987
|
-
const qrPromise = new Promise((
|
|
4988
|
-
resolveQr =
|
|
4987
|
+
const qrPromise = new Promise((resolve25, reject) => {
|
|
4988
|
+
resolveQr = resolve25;
|
|
4989
4989
|
rejectQr = reject;
|
|
4990
4990
|
});
|
|
4991
4991
|
const qrTimer = setTimeout(
|
|
@@ -7458,11 +7458,11 @@ app11.delete("/:id", requireAdminSession, async (c) => {
|
|
|
7458
7458
|
const owned = await verifyConversationOwnership(sessionId, accountId);
|
|
7459
7459
|
if (!owned) return c.json({ error: "Conversation not found" }, 404);
|
|
7460
7460
|
const managerPort = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "admin-conversation-delete" });
|
|
7461
|
-
const
|
|
7461
|
+
const managerBase5 = `http://127.0.0.1:${managerPort}`;
|
|
7462
7462
|
const outcome = await cascadeAdminConversationDelete({
|
|
7463
7463
|
sessionId,
|
|
7464
7464
|
accountId,
|
|
7465
|
-
managerBase:
|
|
7465
|
+
managerBase: managerBase5
|
|
7466
7466
|
});
|
|
7467
7467
|
if (outcome.ok) return c.json({ ok: true, claudeSessionIds: outcome.claudeSessionIds });
|
|
7468
7468
|
if (outcome.reason === "pty-still-alive") {
|
|
@@ -11159,7 +11159,7 @@ app18.post("/", requireAdminSession, async (c) => {
|
|
|
11159
11159
|
return c.json({ error: "AdminConversation node is missing sessionId" }, 500);
|
|
11160
11160
|
}
|
|
11161
11161
|
const managerPort = requirePortEnv("CLAUDE_SESSION_MANAGER_PORT", { tag: "graph-page-cascade" });
|
|
11162
|
-
const
|
|
11162
|
+
const managerBase5 = `http://127.0.0.1:${managerPort}`;
|
|
11163
11163
|
try {
|
|
11164
11164
|
await session.close();
|
|
11165
11165
|
} catch {
|
|
@@ -11167,7 +11167,7 @@ app18.post("/", requireAdminSession, async (c) => {
|
|
|
11167
11167
|
const outcome = await cascadeAdminConversationDelete({
|
|
11168
11168
|
sessionId,
|
|
11169
11169
|
accountId,
|
|
11170
|
-
managerBase:
|
|
11170
|
+
managerBase: managerBase5
|
|
11171
11171
|
});
|
|
11172
11172
|
const elapsed2 = Date.now() - started;
|
|
11173
11173
|
const labelSummary2 = preflightLabels.join(",");
|
|
@@ -11722,10 +11722,11 @@ var sidebar_artefacts_default = app22;
|
|
|
11722
11722
|
|
|
11723
11723
|
// server/routes/admin/sidebar-sessions.ts
|
|
11724
11724
|
import { readdirSync as readdirSync8, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
|
|
11725
|
-
import { join as join13 } from "path";
|
|
11726
|
-
var RC_URL_RE = /https:\/\/claude\.ai\/code\/session_[A-Za-z0-9_-]+/;
|
|
11725
|
+
import { join as join13, resolve as resolve16 } from "path";
|
|
11727
11726
|
var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
|
|
11727
|
+
var PID_FILE_RE = /^([0-9]+)\.json$/;
|
|
11728
11728
|
var TITLE_MAX = 80;
|
|
11729
|
+
var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
|
|
11729
11730
|
var app23 = new Hono();
|
|
11730
11731
|
function claudeConfigDir() {
|
|
11731
11732
|
return process.env.CLAUDE_CONFIG_DIR ?? null;
|
|
@@ -11772,8 +11773,8 @@ function enumerateJsonls(projectsRoot) {
|
|
|
11772
11773
|
}
|
|
11773
11774
|
return out;
|
|
11774
11775
|
}
|
|
11775
|
-
function
|
|
11776
|
-
const out = /* @__PURE__ */ new
|
|
11776
|
+
function sessionIdToPidMap(configDir2) {
|
|
11777
|
+
const out = /* @__PURE__ */ new Map();
|
|
11777
11778
|
const sessionsDir = join13(configDir2, "sessions");
|
|
11778
11779
|
let entries;
|
|
11779
11780
|
try {
|
|
@@ -11782,7 +11783,11 @@ function liveSessionIdSet(configDir2) {
|
|
|
11782
11783
|
return out;
|
|
11783
11784
|
}
|
|
11784
11785
|
for (const entry of entries) {
|
|
11785
|
-
if (!entry.isFile()
|
|
11786
|
+
if (!entry.isFile()) continue;
|
|
11787
|
+
const m = entry.name.match(PID_FILE_RE);
|
|
11788
|
+
if (!m) continue;
|
|
11789
|
+
const pid = Number(m[1]);
|
|
11790
|
+
if (!Number.isFinite(pid) || pid <= 0) continue;
|
|
11786
11791
|
let body;
|
|
11787
11792
|
try {
|
|
11788
11793
|
body = readFileSync14(join13(sessionsDir, entry.name), "utf8");
|
|
@@ -11797,11 +11802,69 @@ function liveSessionIdSet(configDir2) {
|
|
|
11797
11802
|
}
|
|
11798
11803
|
if (!parsed || typeof parsed !== "object") continue;
|
|
11799
11804
|
const sid = parsed.sessionId;
|
|
11800
|
-
if (typeof sid === "string" && sid.length > 0) out.
|
|
11805
|
+
if (typeof sid === "string" && sid.length > 0) out.set(sid, pid);
|
|
11801
11806
|
}
|
|
11802
11807
|
return out;
|
|
11803
11808
|
}
|
|
11804
|
-
function
|
|
11809
|
+
function loadUserTitles(accountDir) {
|
|
11810
|
+
const out = /* @__PURE__ */ new Map();
|
|
11811
|
+
if (!accountDir) return out;
|
|
11812
|
+
const path2 = join13(accountDir, "session-titles.json");
|
|
11813
|
+
let raw;
|
|
11814
|
+
try {
|
|
11815
|
+
raw = readFileSync14(path2, "utf8");
|
|
11816
|
+
} catch {
|
|
11817
|
+
return out;
|
|
11818
|
+
}
|
|
11819
|
+
let parsed;
|
|
11820
|
+
try {
|
|
11821
|
+
parsed = JSON.parse(raw);
|
|
11822
|
+
} catch {
|
|
11823
|
+
return out;
|
|
11824
|
+
}
|
|
11825
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return out;
|
|
11826
|
+
for (const [sessionId, value] of Object.entries(parsed)) {
|
|
11827
|
+
if (!sessionId) continue;
|
|
11828
|
+
if (!value || typeof value !== "object") continue;
|
|
11829
|
+
const v = value;
|
|
11830
|
+
if (typeof v.title !== "string") continue;
|
|
11831
|
+
const trimmed = v.title.trim();
|
|
11832
|
+
if (!trimmed) continue;
|
|
11833
|
+
out.set(sessionId, trimmed);
|
|
11834
|
+
}
|
|
11835
|
+
return out;
|
|
11836
|
+
}
|
|
11837
|
+
function readBridgeIds(metaPath) {
|
|
11838
|
+
let raw;
|
|
11839
|
+
try {
|
|
11840
|
+
raw = readFileSync14(metaPath, "utf8");
|
|
11841
|
+
} catch {
|
|
11842
|
+
return [];
|
|
11843
|
+
}
|
|
11844
|
+
let parsed;
|
|
11845
|
+
try {
|
|
11846
|
+
parsed = JSON.parse(raw);
|
|
11847
|
+
} catch {
|
|
11848
|
+
return [];
|
|
11849
|
+
}
|
|
11850
|
+
if (!parsed || typeof parsed !== "object") return [];
|
|
11851
|
+
const ids = parsed.bridgeIds;
|
|
11852
|
+
if (!Array.isArray(ids)) return [];
|
|
11853
|
+
return ids.filter((b) => typeof b === "string" && b.length > 0);
|
|
11854
|
+
}
|
|
11855
|
+
function startsWithCliMarker(s) {
|
|
11856
|
+
for (const p of CLI_MARKER_PREFIXES) if (s.startsWith(p)) return true;
|
|
11857
|
+
return false;
|
|
11858
|
+
}
|
|
11859
|
+
function trimToTitle(raw) {
|
|
11860
|
+
const trimmed = raw.trim().replace(/\s+/g, " ");
|
|
11861
|
+
return trimmed.length > TITLE_MAX ? trimmed.slice(0, TITLE_MAX - 1) + "\u2026" : trimmed;
|
|
11862
|
+
}
|
|
11863
|
+
function resolveTitle(body, sessionId, userTitles) {
|
|
11864
|
+
const userTitle = userTitles.get(sessionId);
|
|
11865
|
+
if (userTitle) return { title: trimToTitle(userTitle), source: "user" };
|
|
11866
|
+
let aiTitle = null;
|
|
11867
|
+
let firstUserMessage = null;
|
|
11805
11868
|
for (const line of body.split("\n")) {
|
|
11806
11869
|
if (!line || line[0] !== "{") continue;
|
|
11807
11870
|
let parsed;
|
|
@@ -11812,31 +11875,45 @@ function firstUserMessage(body) {
|
|
|
11812
11875
|
}
|
|
11813
11876
|
if (!parsed || typeof parsed !== "object") continue;
|
|
11814
11877
|
const row = parsed;
|
|
11815
|
-
if (row.type
|
|
11816
|
-
|
|
11817
|
-
|
|
11818
|
-
|
|
11819
|
-
|
|
11820
|
-
|
|
11878
|
+
if (row.type === "ai-title" && typeof row.aiTitle === "string") {
|
|
11879
|
+
const t = row.aiTitle.trim();
|
|
11880
|
+
if (t) aiTitle = t;
|
|
11881
|
+
continue;
|
|
11882
|
+
}
|
|
11883
|
+
if (firstUserMessage === null && row.type === "user" && row.message && row.message.role === "user") {
|
|
11884
|
+
const content = row.message.content;
|
|
11885
|
+
if (typeof content !== "string") continue;
|
|
11886
|
+
const trimmed = content.trim();
|
|
11887
|
+
if (!trimmed) continue;
|
|
11888
|
+
if (startsWithCliMarker(trimmed)) continue;
|
|
11889
|
+
firstUserMessage = trimmed;
|
|
11890
|
+
}
|
|
11821
11891
|
}
|
|
11822
|
-
return
|
|
11892
|
+
if (aiTitle) return { title: trimToTitle(aiTitle), source: "ai" };
|
|
11893
|
+
if (firstUserMessage) return { title: trimToTitle(firstUserMessage), source: "first-message" };
|
|
11894
|
+
return { title: sessionId.slice(0, 8), source: "prefix" };
|
|
11823
11895
|
}
|
|
11824
11896
|
app23.get("/", requireAdminSession, async (c) => {
|
|
11897
|
+
const accountId = process.env.ACCOUNT_ID ?? null;
|
|
11825
11898
|
const configDir2 = claudeConfigDir();
|
|
11826
11899
|
if (!configDir2) {
|
|
11827
11900
|
console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
|
|
11828
|
-
return c.json({ sessions: [] });
|
|
11901
|
+
return c.json({ sessions: [], accountId });
|
|
11829
11902
|
}
|
|
11830
11903
|
const projectsRoot = join13(configDir2, "projects");
|
|
11831
11904
|
const jsonls = enumerateJsonls(projectsRoot);
|
|
11832
|
-
const
|
|
11905
|
+
const pidsBySession = sessionIdToPidMap(configDir2);
|
|
11906
|
+
const accountDir = accountId ? resolve16(ACCOUNTS_DIR, accountId) : null;
|
|
11907
|
+
const userTitles = loadUserTitles(accountDir);
|
|
11833
11908
|
const rows = [];
|
|
11834
11909
|
const seenIds = /* @__PURE__ */ new Set();
|
|
11835
11910
|
let liveCount = 0;
|
|
11836
|
-
let rcCount = 0;
|
|
11837
11911
|
let subagentCount = 0;
|
|
11912
|
+
const titleSourceCounts = { user: 0, ai: 0, "first-message": 0, prefix: 0 };
|
|
11838
11913
|
for (const { path: path2, isSubagent } of jsonls) {
|
|
11839
|
-
const
|
|
11914
|
+
const lastSlash = path2.lastIndexOf("/");
|
|
11915
|
+
const base = path2.slice(lastSlash + 1);
|
|
11916
|
+
const projectDir = path2.slice(0, lastSlash);
|
|
11840
11917
|
const sessionId = base.slice(0, -".jsonl".length);
|
|
11841
11918
|
if (seenIds.has(sessionId)) {
|
|
11842
11919
|
console.error(`[admin-sessions-list] duplicate-sessionId sessionId=${sessionId} path=${path2}`);
|
|
@@ -11851,30 +11928,261 @@ app23.get("/", requireAdminSession, async (c) => {
|
|
|
11851
11928
|
} catch {
|
|
11852
11929
|
continue;
|
|
11853
11930
|
}
|
|
11854
|
-
const
|
|
11855
|
-
const live =
|
|
11856
|
-
const
|
|
11857
|
-
|
|
11931
|
+
const pid = pidsBySession.get(sessionId) ?? null;
|
|
11932
|
+
const live = pid !== null;
|
|
11933
|
+
const resolved = resolveTitle(body, sessionId, userTitles);
|
|
11934
|
+
titleSourceCounts[resolved.source] += 1;
|
|
11935
|
+
const bridgeIds = readBridgeIds(join13(projectDir, `${sessionId}.meta.json`));
|
|
11936
|
+
rows.push({
|
|
11858
11937
|
sessionId,
|
|
11859
|
-
title,
|
|
11938
|
+
title: resolved.title,
|
|
11939
|
+
titleSource: resolved.source,
|
|
11860
11940
|
startedAt: new Date(mtimeMs).toISOString(),
|
|
11861
11941
|
live,
|
|
11862
|
-
isSubagent
|
|
11863
|
-
|
|
11864
|
-
|
|
11865
|
-
|
|
11942
|
+
isSubagent,
|
|
11943
|
+
pid,
|
|
11944
|
+
projectDir,
|
|
11945
|
+
bridgeIds
|
|
11946
|
+
});
|
|
11866
11947
|
if (live) liveCount += 1;
|
|
11867
|
-
if (urlMatch) rcCount += 1;
|
|
11868
11948
|
if (isSubagent) subagentCount += 1;
|
|
11869
11949
|
}
|
|
11870
11950
|
rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
|
|
11871
11951
|
console.log(
|
|
11872
|
-
`[admin-sessions-list] rows=${rows.length} live=${liveCount}
|
|
11952
|
+
`[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
|
|
11873
11953
|
);
|
|
11874
|
-
return c.json({ sessions: rows });
|
|
11954
|
+
return c.json({ sessions: rows, accountId });
|
|
11875
11955
|
});
|
|
11876
11956
|
var sidebar_sessions_default = app23;
|
|
11877
11957
|
|
|
11958
|
+
// server/routes/admin/session-delete.ts
|
|
11959
|
+
import { existsSync as existsSync17, readdirSync as readdirSync9, readFileSync as readFileSync15, unlinkSync as unlinkSync2 } from "fs";
|
|
11960
|
+
import { join as join14, resolve as resolve17 } from "path";
|
|
11961
|
+
var app24 = new Hono();
|
|
11962
|
+
var SESSION_ID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11963
|
+
var PID_FILE_RE2 = /^([0-9]+)\.json$/;
|
|
11964
|
+
var SIGTERM_WAIT_MS = 2e3;
|
|
11965
|
+
var SIGKILL_WAIT_MS = 1e3;
|
|
11966
|
+
var POLL_INTERVAL_MS = 50;
|
|
11967
|
+
function findPidForSession(configDir2, sessionId) {
|
|
11968
|
+
const sessionsDir = join14(configDir2, "sessions");
|
|
11969
|
+
let entries;
|
|
11970
|
+
try {
|
|
11971
|
+
entries = readdirSync9(sessionsDir, { withFileTypes: true });
|
|
11972
|
+
} catch {
|
|
11973
|
+
return null;
|
|
11974
|
+
}
|
|
11975
|
+
for (const entry of entries) {
|
|
11976
|
+
if (!entry.isFile()) continue;
|
|
11977
|
+
const m = entry.name.match(PID_FILE_RE2);
|
|
11978
|
+
if (!m) continue;
|
|
11979
|
+
const pid = Number(m[1]);
|
|
11980
|
+
if (!Number.isFinite(pid) || pid <= 0) continue;
|
|
11981
|
+
let body;
|
|
11982
|
+
try {
|
|
11983
|
+
body = readFileSync15(join14(sessionsDir, entry.name), "utf8");
|
|
11984
|
+
} catch {
|
|
11985
|
+
continue;
|
|
11986
|
+
}
|
|
11987
|
+
let parsed;
|
|
11988
|
+
try {
|
|
11989
|
+
parsed = JSON.parse(body);
|
|
11990
|
+
} catch {
|
|
11991
|
+
continue;
|
|
11992
|
+
}
|
|
11993
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
11994
|
+
if (parsed.sessionId === sessionId) return pid;
|
|
11995
|
+
}
|
|
11996
|
+
return null;
|
|
11997
|
+
}
|
|
11998
|
+
function isPidAlive(pid) {
|
|
11999
|
+
try {
|
|
12000
|
+
process.kill(pid, 0);
|
|
12001
|
+
return true;
|
|
12002
|
+
} catch (err) {
|
|
12003
|
+
const code = err.code;
|
|
12004
|
+
if (code === "ESRCH") return false;
|
|
12005
|
+
return true;
|
|
12006
|
+
}
|
|
12007
|
+
}
|
|
12008
|
+
function sleep2(ms) {
|
|
12009
|
+
return new Promise((resolve25) => setTimeout(resolve25, ms));
|
|
12010
|
+
}
|
|
12011
|
+
function sendSignal(pid, signal) {
|
|
12012
|
+
try {
|
|
12013
|
+
process.kill(pid, signal);
|
|
12014
|
+
return true;
|
|
12015
|
+
} catch (err) {
|
|
12016
|
+
const code = err.code;
|
|
12017
|
+
if (code === "ESRCH") return true;
|
|
12018
|
+
return false;
|
|
12019
|
+
}
|
|
12020
|
+
}
|
|
12021
|
+
async function killAndWait(pid) {
|
|
12022
|
+
const startedAt = Date.now();
|
|
12023
|
+
let escalated = false;
|
|
12024
|
+
const termSent = sendSignal(pid, "SIGTERM");
|
|
12025
|
+
const termDeadline = Date.now() + SIGTERM_WAIT_MS;
|
|
12026
|
+
while (Date.now() < termDeadline) {
|
|
12027
|
+
if (!isPidAlive(pid)) {
|
|
12028
|
+
return {
|
|
12029
|
+
pidKilled: termSent ? "true" : "false",
|
|
12030
|
+
waitForExitMs: Date.now() - startedAt,
|
|
12031
|
+
escalatedToSIGKILL: false,
|
|
12032
|
+
exited: true
|
|
12033
|
+
};
|
|
12034
|
+
}
|
|
12035
|
+
await sleep2(POLL_INTERVAL_MS);
|
|
12036
|
+
}
|
|
12037
|
+
escalated = true;
|
|
12038
|
+
sendSignal(pid, "SIGKILL");
|
|
12039
|
+
const killDeadline = Date.now() + SIGKILL_WAIT_MS;
|
|
12040
|
+
while (Date.now() < killDeadline) {
|
|
12041
|
+
if (!isPidAlive(pid)) {
|
|
12042
|
+
return {
|
|
12043
|
+
pidKilled: "true",
|
|
12044
|
+
waitForExitMs: Date.now() - startedAt,
|
|
12045
|
+
escalatedToSIGKILL: true,
|
|
12046
|
+
exited: true
|
|
12047
|
+
};
|
|
12048
|
+
}
|
|
12049
|
+
await sleep2(POLL_INTERVAL_MS);
|
|
12050
|
+
}
|
|
12051
|
+
return {
|
|
12052
|
+
pidKilled: "false",
|
|
12053
|
+
waitForExitMs: Date.now() - startedAt,
|
|
12054
|
+
escalatedToSIGKILL: escalated,
|
|
12055
|
+
exited: false
|
|
12056
|
+
};
|
|
12057
|
+
}
|
|
12058
|
+
app24.post("/", requireAdminSession, async (c) => {
|
|
12059
|
+
let body;
|
|
12060
|
+
try {
|
|
12061
|
+
body = await c.req.json();
|
|
12062
|
+
} catch {
|
|
12063
|
+
return c.json({ error: "invalid JSON body" }, 400);
|
|
12064
|
+
}
|
|
12065
|
+
const sessionId = typeof body.sessionId === "string" ? body.sessionId : "";
|
|
12066
|
+
const projectDir = typeof body.projectDir === "string" ? body.projectDir : "";
|
|
12067
|
+
if (!SESSION_ID_RE2.test(sessionId)) {
|
|
12068
|
+
return c.json({ error: "sessionId must be a v4 UUID" }, 400);
|
|
12069
|
+
}
|
|
12070
|
+
if (!projectDir) {
|
|
12071
|
+
return c.json({ error: "projectDir is required" }, 400);
|
|
12072
|
+
}
|
|
12073
|
+
const configDir2 = process.env.CLAUDE_CONFIG_DIR;
|
|
12074
|
+
if (!configDir2) {
|
|
12075
|
+
return c.json({ error: "CLAUDE_CONFIG_DIR not set" }, 500);
|
|
12076
|
+
}
|
|
12077
|
+
const projectsRoot = resolve17(join14(configDir2, "projects")) + "/";
|
|
12078
|
+
const resolvedProject = resolve17(projectDir) + "/";
|
|
12079
|
+
if (!resolvedProject.startsWith(projectsRoot)) {
|
|
12080
|
+
console.error(`[sessions-delete] reject reason=projectDir-outside-tree projectDir=${projectDir}`);
|
|
12081
|
+
return c.json({ error: "projectDir is not under CLAUDE_CONFIG_DIR/projects/" }, 400);
|
|
12082
|
+
}
|
|
12083
|
+
const jsonlPath = join14(projectDir, `${sessionId}.jsonl`);
|
|
12084
|
+
const sidecarPath = join14(projectDir, `${sessionId}.meta.json`);
|
|
12085
|
+
const pid = findPidForSession(configDir2, sessionId);
|
|
12086
|
+
let pidKilled = "absent";
|
|
12087
|
+
let waitForExitMs = 0;
|
|
12088
|
+
let escalatedToSIGKILL = false;
|
|
12089
|
+
if (pid !== null) {
|
|
12090
|
+
const r = await killAndWait(pid);
|
|
12091
|
+
pidKilled = r.pidKilled;
|
|
12092
|
+
waitForExitMs = r.waitForExitMs;
|
|
12093
|
+
escalatedToSIGKILL = r.escalatedToSIGKILL;
|
|
12094
|
+
if (!r.exited) {
|
|
12095
|
+
console.error(
|
|
12096
|
+
`[sessions-delete] kill-failed sessionId=${sessionId} pid=${pid} waitForExit=${waitForExitMs} escalatedToSIGKILL=${escalatedToSIGKILL}`
|
|
12097
|
+
);
|
|
12098
|
+
return c.json(
|
|
12099
|
+
{ error: "kill-failed", pid, waitForExitMs, escalatedToSIGKILL },
|
|
12100
|
+
500
|
|
12101
|
+
);
|
|
12102
|
+
}
|
|
12103
|
+
}
|
|
12104
|
+
let deleted = false;
|
|
12105
|
+
try {
|
|
12106
|
+
if (existsSync17(jsonlPath)) {
|
|
12107
|
+
unlinkSync2(jsonlPath);
|
|
12108
|
+
deleted = true;
|
|
12109
|
+
}
|
|
12110
|
+
} catch (err) {
|
|
12111
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12112
|
+
console.error(`[sessions-delete] unlink-failed path=${jsonlPath} err=${msg}`);
|
|
12113
|
+
console.log(
|
|
12114
|
+
`[sessions-delete] sessionId=${sessionId} pidKilled=${pidKilled} jsonlPath=${jsonlPath} deleted=false waitForExit=${waitForExitMs} escalatedToSIGKILL=${escalatedToSIGKILL}`
|
|
12115
|
+
);
|
|
12116
|
+
return c.json({ error: `unlink failed: ${msg}` }, 500);
|
|
12117
|
+
}
|
|
12118
|
+
try {
|
|
12119
|
+
if (existsSync17(sidecarPath)) unlinkSync2(sidecarPath);
|
|
12120
|
+
} catch {
|
|
12121
|
+
}
|
|
12122
|
+
if (pid !== null) {
|
|
12123
|
+
try {
|
|
12124
|
+
const pidFile = join14(configDir2, "sessions", `${pid}.json`);
|
|
12125
|
+
if (existsSync17(pidFile)) unlinkSync2(pidFile);
|
|
12126
|
+
} catch {
|
|
12127
|
+
}
|
|
12128
|
+
}
|
|
12129
|
+
if (existsSync17(jsonlPath)) {
|
|
12130
|
+
console.error(`[sessions-delete] resurrection jsonlPath=${jsonlPath} sessionId=${sessionId}`);
|
|
12131
|
+
return c.json(
|
|
12132
|
+
{ error: "jsonl-resurrected", jsonlPath, pidKilled, waitForExitMs, escalatedToSIGKILL },
|
|
12133
|
+
500
|
|
12134
|
+
);
|
|
12135
|
+
}
|
|
12136
|
+
console.log(
|
|
12137
|
+
`[sessions-delete] sessionId=${sessionId} pidKilled=${pidKilled} jsonlPath=${jsonlPath} deleted=${deleted} waitForExit=${waitForExitMs} escalatedToSIGKILL=${escalatedToSIGKILL}`
|
|
12138
|
+
);
|
|
12139
|
+
return c.json({ deleted, pidKilled, jsonlPath, waitForExitMs, escalatedToSIGKILL });
|
|
12140
|
+
});
|
|
12141
|
+
var session_delete_default = app24;
|
|
12142
|
+
|
|
12143
|
+
// server/routes/admin/session-rc-spawn.ts
|
|
12144
|
+
var app25 = new Hono();
|
|
12145
|
+
function managerBase4() {
|
|
12146
|
+
const port2 = process.env.CLAUDE_SESSION_MANAGER_PORT;
|
|
12147
|
+
if (!port2) throw new Error("CLAUDE_SESSION_MANAGER_PORT is not set");
|
|
12148
|
+
return `http://127.0.0.1:${port2}`;
|
|
12149
|
+
}
|
|
12150
|
+
app25.post("/", requireAdminSession, async (c) => {
|
|
12151
|
+
let body;
|
|
12152
|
+
try {
|
|
12153
|
+
body = await c.req.json();
|
|
12154
|
+
} catch {
|
|
12155
|
+
body = {};
|
|
12156
|
+
}
|
|
12157
|
+
const payload = {};
|
|
12158
|
+
if (typeof body.sessionId === "string" && body.sessionId.length > 0) payload.sessionId = body.sessionId;
|
|
12159
|
+
if (typeof body.name === "string" && body.name.length > 0) payload.name = body.name;
|
|
12160
|
+
let res;
|
|
12161
|
+
try {
|
|
12162
|
+
res = await fetch(`${managerBase4()}/rc-spawn`, {
|
|
12163
|
+
method: "POST",
|
|
12164
|
+
headers: { "content-type": "application/json" },
|
|
12165
|
+
body: JSON.stringify(payload)
|
|
12166
|
+
});
|
|
12167
|
+
} catch (err) {
|
|
12168
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12169
|
+
console.error(`[session-rc-spawn] manager-unreachable err=${msg}`);
|
|
12170
|
+
return c.json({ error: `session manager unreachable: ${msg}` }, 502);
|
|
12171
|
+
}
|
|
12172
|
+
const text = await res.text();
|
|
12173
|
+
let parsed = null;
|
|
12174
|
+
try {
|
|
12175
|
+
parsed = JSON.parse(text);
|
|
12176
|
+
} catch {
|
|
12177
|
+
}
|
|
12178
|
+
if (!res.ok) {
|
|
12179
|
+
console.error(`[session-rc-spawn] manager-error status=${res.status} body=${text.slice(0, 200)}`);
|
|
12180
|
+
return c.json(parsed ?? { error: text }, res.status);
|
|
12181
|
+
}
|
|
12182
|
+
return c.json(parsed ?? {});
|
|
12183
|
+
});
|
|
12184
|
+
var session_rc_spawn_default = app25;
|
|
12185
|
+
|
|
11878
12186
|
// server/routes/admin/system-stats.ts
|
|
11879
12187
|
import { readFile as readFile5 } from "fs/promises";
|
|
11880
12188
|
import { cpus, loadavg, totalmem, freemem } from "os";
|
|
@@ -11970,8 +12278,8 @@ async function sample() {
|
|
|
11970
12278
|
if (process.platform === "linux") return sampleLinux();
|
|
11971
12279
|
return sampleOsFallback();
|
|
11972
12280
|
}
|
|
11973
|
-
var
|
|
11974
|
-
|
|
12281
|
+
var app26 = new Hono();
|
|
12282
|
+
app26.get("/", async (c) => {
|
|
11975
12283
|
const started = Date.now();
|
|
11976
12284
|
if (!inflight) {
|
|
11977
12285
|
inflight = sample().finally(() => {
|
|
@@ -11994,27 +12302,27 @@ app24.get("/", async (c) => {
|
|
|
11994
12302
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
11995
12303
|
}
|
|
11996
12304
|
});
|
|
11997
|
-
var system_stats_default =
|
|
12305
|
+
var system_stats_default = app26;
|
|
11998
12306
|
|
|
11999
12307
|
// server/routes/admin/health.ts
|
|
12000
|
-
import { existsSync as
|
|
12001
|
-
import { resolve as
|
|
12002
|
-
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ??
|
|
12308
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16 } from "fs";
|
|
12309
|
+
import { resolve as resolve18, join as join15 } from "path";
|
|
12310
|
+
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "..");
|
|
12003
12311
|
var brandHostname = "maxy";
|
|
12004
|
-
var brandJsonPath =
|
|
12005
|
-
if (
|
|
12312
|
+
var brandJsonPath = join15(PLATFORM_ROOT6, "config", "brand.json");
|
|
12313
|
+
if (existsSync18(brandJsonPath)) {
|
|
12006
12314
|
try {
|
|
12007
|
-
const brand = JSON.parse(
|
|
12315
|
+
const brand = JSON.parse(readFileSync16(brandJsonPath, "utf-8"));
|
|
12008
12316
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
12009
12317
|
} catch {
|
|
12010
12318
|
}
|
|
12011
12319
|
}
|
|
12012
|
-
var VERSION_FILE =
|
|
12320
|
+
var VERSION_FILE = resolve18(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
|
|
12013
12321
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
12014
12322
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
12015
12323
|
function readVersion() {
|
|
12016
|
-
if (!
|
|
12017
|
-
return
|
|
12324
|
+
if (!existsSync18(VERSION_FILE)) return "unknown";
|
|
12325
|
+
return readFileSync16(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
12018
12326
|
}
|
|
12019
12327
|
async function probeConversationDb() {
|
|
12020
12328
|
let session;
|
|
@@ -12039,8 +12347,8 @@ async function probeConversationDb() {
|
|
|
12039
12347
|
});
|
|
12040
12348
|
}
|
|
12041
12349
|
}
|
|
12042
|
-
var
|
|
12043
|
-
|
|
12350
|
+
var app27 = new Hono();
|
|
12351
|
+
app27.get("/", async (c) => {
|
|
12044
12352
|
const version = readVersion();
|
|
12045
12353
|
const probe = await probeConversationDb();
|
|
12046
12354
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -12062,7 +12370,7 @@ app25.get("/", async (c) => {
|
|
|
12062
12370
|
uptimeMs
|
|
12063
12371
|
});
|
|
12064
12372
|
});
|
|
12065
|
-
var health_default2 =
|
|
12373
|
+
var health_default2 = app27;
|
|
12066
12374
|
|
|
12067
12375
|
// server/routes/admin/linkedin-ingest.ts
|
|
12068
12376
|
var TAG20 = "[linkedin-ingest-route]";
|
|
@@ -12158,8 +12466,8 @@ function buildInitialMessage(env) {
|
|
|
12158
12466
|
}
|
|
12159
12467
|
return header;
|
|
12160
12468
|
}
|
|
12161
|
-
var
|
|
12162
|
-
|
|
12469
|
+
var app28 = new Hono();
|
|
12470
|
+
app28.post("/", requireAdminSession, async (c) => {
|
|
12163
12471
|
let body;
|
|
12164
12472
|
try {
|
|
12165
12473
|
body = await c.req.json();
|
|
@@ -12213,7 +12521,7 @@ app26.post("/", requireAdminSession, async (c) => {
|
|
|
12213
12521
|
);
|
|
12214
12522
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: claudeSessionId }, 202);
|
|
12215
12523
|
});
|
|
12216
|
-
var linkedin_ingest_default =
|
|
12524
|
+
var linkedin_ingest_default = app28;
|
|
12217
12525
|
|
|
12218
12526
|
// server/routes/admin/post-turn-context.ts
|
|
12219
12527
|
import neo4j2 from "neo4j-driver";
|
|
@@ -12255,8 +12563,8 @@ function pruneProperties(raw) {
|
|
|
12255
12563
|
}
|
|
12256
12564
|
return out;
|
|
12257
12565
|
}
|
|
12258
|
-
var
|
|
12259
|
-
|
|
12566
|
+
var app29 = new Hono();
|
|
12567
|
+
app29.get("/", async (c) => {
|
|
12260
12568
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12261
12569
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
12262
12570
|
console.error(`${TAG21} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12316,7 +12624,7 @@ app27.get("/", async (c) => {
|
|
|
12316
12624
|
await session.close();
|
|
12317
12625
|
}
|
|
12318
12626
|
});
|
|
12319
|
-
var post_turn_context_default =
|
|
12627
|
+
var post_turn_context_default = app29;
|
|
12320
12628
|
|
|
12321
12629
|
// server/routes/admin/public-session-context.ts
|
|
12322
12630
|
import neo4j3 from "neo4j-driver";
|
|
@@ -12358,8 +12666,8 @@ function pruneProperties2(raw) {
|
|
|
12358
12666
|
}
|
|
12359
12667
|
return out;
|
|
12360
12668
|
}
|
|
12361
|
-
var
|
|
12362
|
-
|
|
12669
|
+
var app30 = new Hono();
|
|
12670
|
+
app30.get("/", async (c) => {
|
|
12363
12671
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12364
12672
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
12365
12673
|
console.error(`${TAG22} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12418,15 +12726,15 @@ app28.get("/", async (c) => {
|
|
|
12418
12726
|
await session.close();
|
|
12419
12727
|
}
|
|
12420
12728
|
});
|
|
12421
|
-
var public_session_context_default =
|
|
12729
|
+
var public_session_context_default = app30;
|
|
12422
12730
|
|
|
12423
12731
|
// server/routes/admin/public-session-exit.ts
|
|
12424
12732
|
var TAG23 = "[public-session-exit-route]";
|
|
12425
12733
|
function isLoopbackAddr4(addr) {
|
|
12426
12734
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12427
12735
|
}
|
|
12428
|
-
var
|
|
12429
|
-
|
|
12736
|
+
var app31 = new Hono();
|
|
12737
|
+
app31.post("/", async (c) => {
|
|
12430
12738
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12431
12739
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
12432
12740
|
console.error(`${TAG23} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12453,15 +12761,15 @@ app29.post("/", async (c) => {
|
|
|
12453
12761
|
handlePublicSessionExit(sessionId);
|
|
12454
12762
|
return c.json({ ok: true });
|
|
12455
12763
|
});
|
|
12456
|
-
var public_session_exit_default =
|
|
12764
|
+
var public_session_exit_default = app31;
|
|
12457
12765
|
|
|
12458
12766
|
// server/routes/admin/access-session-evict.ts
|
|
12459
12767
|
var TAG24 = "[access-session-evict]";
|
|
12460
12768
|
function isLoopbackAddr5(addr) {
|
|
12461
12769
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12462
12770
|
}
|
|
12463
|
-
var
|
|
12464
|
-
|
|
12771
|
+
var app32 = new Hono();
|
|
12772
|
+
app32.post("/", async (c) => {
|
|
12465
12773
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12466
12774
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
12467
12775
|
console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12489,49 +12797,51 @@ app30.post("/", async (c) => {
|
|
|
12489
12797
|
console.log(`${TAG24} grantId=${grantId} dropped=${dropped}`);
|
|
12490
12798
|
return c.json({ ok: true, dropped });
|
|
12491
12799
|
});
|
|
12492
|
-
var access_session_evict_default =
|
|
12800
|
+
var access_session_evict_default = app32;
|
|
12493
12801
|
|
|
12494
12802
|
// server/routes/admin/index.ts
|
|
12495
|
-
var
|
|
12496
|
-
|
|
12497
|
-
|
|
12498
|
-
|
|
12499
|
-
|
|
12500
|
-
|
|
12501
|
-
|
|
12502
|
-
|
|
12503
|
-
|
|
12504
|
-
|
|
12505
|
-
|
|
12506
|
-
|
|
12507
|
-
|
|
12508
|
-
|
|
12509
|
-
|
|
12510
|
-
|
|
12511
|
-
|
|
12512
|
-
|
|
12513
|
-
|
|
12514
|
-
|
|
12515
|
-
|
|
12516
|
-
|
|
12517
|
-
|
|
12518
|
-
|
|
12519
|
-
|
|
12520
|
-
|
|
12521
|
-
|
|
12803
|
+
var app33 = new Hono();
|
|
12804
|
+
app33.route("/session", session_default);
|
|
12805
|
+
app33.route("/logs", logs_default);
|
|
12806
|
+
app33.route("/claude-info", claude_info_default);
|
|
12807
|
+
app33.route("/attachment", attachment_default);
|
|
12808
|
+
app33.route("/agents", agents_default);
|
|
12809
|
+
app33.route("/sessions", sessions_default);
|
|
12810
|
+
app33.route("/claude-sessions", claude_sessions_default);
|
|
12811
|
+
app33.route("/log-ingest", log_ingest_default);
|
|
12812
|
+
app33.route("/events", events_default);
|
|
12813
|
+
app33.route("/files", files_default);
|
|
12814
|
+
app33.route("/graph-search", graph_search_default);
|
|
12815
|
+
app33.route("/graph-subgraph", graph_subgraph_default);
|
|
12816
|
+
app33.route("/graph-delete", graph_delete_default);
|
|
12817
|
+
app33.route("/graph-restore", graph_restore_default);
|
|
12818
|
+
app33.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
12819
|
+
app33.route("/graph-default-view", graph_default_view_default);
|
|
12820
|
+
app33.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
12821
|
+
app33.route("/sidebar-sessions", sidebar_sessions_default);
|
|
12822
|
+
app33.route("/session-delete", session_delete_default);
|
|
12823
|
+
app33.route("/session-rc-spawn", session_rc_spawn_default);
|
|
12824
|
+
app33.route("/system-stats", system_stats_default);
|
|
12825
|
+
app33.route("/health-brand", health_default2);
|
|
12826
|
+
app33.route("/linkedin-ingest", linkedin_ingest_default);
|
|
12827
|
+
app33.route("/post-turn-context", post_turn_context_default);
|
|
12828
|
+
app33.route("/public-session-context", public_session_context_default);
|
|
12829
|
+
app33.route("/public-session-exit", public_session_exit_default);
|
|
12830
|
+
app33.route("/access-session-evict", access_session_evict_default);
|
|
12831
|
+
var admin_default = app33;
|
|
12522
12832
|
|
|
12523
12833
|
// app/lib/access-gate.ts
|
|
12524
12834
|
import neo4j4 from "neo4j-driver";
|
|
12525
|
-
import { readFileSync as
|
|
12526
|
-
import { resolve as
|
|
12835
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
12836
|
+
import { resolve as resolve19 } from "path";
|
|
12527
12837
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
12528
|
-
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ??
|
|
12838
|
+
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
|
|
12529
12839
|
var driver = null;
|
|
12530
12840
|
function readPassword() {
|
|
12531
12841
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
12532
|
-
const passwordFile =
|
|
12842
|
+
const passwordFile = resolve19(PLATFORM_ROOT7, "config/.neo4j-password");
|
|
12533
12843
|
try {
|
|
12534
|
-
return
|
|
12844
|
+
return readFileSync17(passwordFile, "utf-8").trim();
|
|
12535
12845
|
} catch {
|
|
12536
12846
|
throw new Error(
|
|
12537
12847
|
`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
|
|
@@ -12732,8 +13042,8 @@ async function generateNewMagicToken(grantId) {
|
|
|
12732
13042
|
var TAG25 = "[access-verify]";
|
|
12733
13043
|
var MINT_TAG = "[access-session-mint]";
|
|
12734
13044
|
var COOKIE_NAME = "__access_session";
|
|
12735
|
-
var
|
|
12736
|
-
|
|
13045
|
+
var app34 = new Hono();
|
|
13046
|
+
app34.post("/", async (c) => {
|
|
12737
13047
|
const ip = c.var.clientIp || "unknown";
|
|
12738
13048
|
let body;
|
|
12739
13049
|
try {
|
|
@@ -12815,13 +13125,13 @@ app32.post("/", async (c) => {
|
|
|
12815
13125
|
displayName: grant.displayName
|
|
12816
13126
|
});
|
|
12817
13127
|
});
|
|
12818
|
-
var verify_token_default =
|
|
13128
|
+
var verify_token_default = app34;
|
|
12819
13129
|
|
|
12820
13130
|
// app/lib/access-email.ts
|
|
12821
13131
|
import { spawn as spawn2 } from "child_process";
|
|
12822
|
-
import { resolve as
|
|
12823
|
-
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ??
|
|
12824
|
-
var SEND_SCRIPT =
|
|
13132
|
+
import { resolve as resolve20 } from "path";
|
|
13133
|
+
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
13134
|
+
var SEND_SCRIPT = resolve20(
|
|
12825
13135
|
PLATFORM_ROOT8,
|
|
12826
13136
|
"plugins",
|
|
12827
13137
|
"email",
|
|
@@ -12878,9 +13188,9 @@ async function sendMagicLinkEmail(payload) {
|
|
|
12878
13188
|
|
|
12879
13189
|
// server/routes/access/request-magic-link.ts
|
|
12880
13190
|
var TAG26 = "[access-request-link]";
|
|
12881
|
-
var
|
|
13191
|
+
var app35 = new Hono();
|
|
12882
13192
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
12883
|
-
|
|
13193
|
+
app35.post("/", async (c) => {
|
|
12884
13194
|
let body;
|
|
12885
13195
|
try {
|
|
12886
13196
|
body = await c.req.json();
|
|
@@ -12954,17 +13264,17 @@ app33.post("/", async (c) => {
|
|
|
12954
13264
|
);
|
|
12955
13265
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
12956
13266
|
});
|
|
12957
|
-
var request_magic_link_default =
|
|
13267
|
+
var request_magic_link_default = app35;
|
|
12958
13268
|
|
|
12959
13269
|
// server/routes/access/index.ts
|
|
12960
|
-
var
|
|
12961
|
-
|
|
12962
|
-
|
|
12963
|
-
var access_default =
|
|
13270
|
+
var app36 = new Hono();
|
|
13271
|
+
app36.route("/verify-token", verify_token_default);
|
|
13272
|
+
app36.route("/request-magic-link", request_magic_link_default);
|
|
13273
|
+
var access_default = app36;
|
|
12964
13274
|
|
|
12965
13275
|
// server/routes/sites.ts
|
|
12966
|
-
import { existsSync as
|
|
12967
|
-
import { resolve as
|
|
13276
|
+
import { existsSync as existsSync19, readFileSync as readFileSync18, realpathSync as realpathSync5, statSync as statSync8 } from "fs";
|
|
13277
|
+
import { resolve as resolve21 } from "path";
|
|
12968
13278
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
12969
13279
|
var MIME = {
|
|
12970
13280
|
".html": "text/html; charset=utf-8",
|
|
@@ -12995,8 +13305,8 @@ function getExt(p) {
|
|
|
12995
13305
|
if (idx < p.lastIndexOf("/")) return "";
|
|
12996
13306
|
return p.slice(idx).toLowerCase();
|
|
12997
13307
|
}
|
|
12998
|
-
var
|
|
12999
|
-
|
|
13308
|
+
var app37 = new Hono();
|
|
13309
|
+
app37.get("/:rel{.*}", (c) => {
|
|
13000
13310
|
const reqPath = c.req.path;
|
|
13001
13311
|
const rawRel = c.req.param("rel") ?? "";
|
|
13002
13312
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -13021,15 +13331,15 @@ app35.get("/:rel{.*}", (c) => {
|
|
|
13021
13331
|
}
|
|
13022
13332
|
segments.push(seg);
|
|
13023
13333
|
}
|
|
13024
|
-
const rootDir =
|
|
13025
|
-
let filePath = segments.length === 0 ? rootDir :
|
|
13334
|
+
const rootDir = resolve21(account.accountDir, "sites");
|
|
13335
|
+
let filePath = segments.length === 0 ? rootDir : resolve21(rootDir, ...segments);
|
|
13026
13336
|
if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
|
|
13027
13337
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
13028
13338
|
return c.text("Forbidden", 403);
|
|
13029
13339
|
}
|
|
13030
13340
|
let stat7;
|
|
13031
13341
|
try {
|
|
13032
|
-
stat7 =
|
|
13342
|
+
stat7 = existsSync19(filePath) ? statSync8(filePath) : null;
|
|
13033
13343
|
} catch {
|
|
13034
13344
|
stat7 = null;
|
|
13035
13345
|
}
|
|
@@ -13042,13 +13352,13 @@ app35.get("/:rel{.*}", (c) => {
|
|
|
13042
13352
|
return c.redirect(target, 301);
|
|
13043
13353
|
}
|
|
13044
13354
|
if (stat7?.isDirectory()) {
|
|
13045
|
-
filePath =
|
|
13355
|
+
filePath = resolve21(filePath, "index.html");
|
|
13046
13356
|
}
|
|
13047
13357
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
13048
13358
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
13049
13359
|
return c.text("Forbidden", 403);
|
|
13050
13360
|
}
|
|
13051
|
-
if (!
|
|
13361
|
+
if (!existsSync19(filePath)) {
|
|
13052
13362
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
13053
13363
|
return c.text("Not found", 404);
|
|
13054
13364
|
}
|
|
@@ -13067,7 +13377,7 @@ app35.get("/:rel{.*}", (c) => {
|
|
|
13067
13377
|
}
|
|
13068
13378
|
let body;
|
|
13069
13379
|
try {
|
|
13070
|
-
body =
|
|
13380
|
+
body = readFileSync18(realPath);
|
|
13071
13381
|
} catch (err) {
|
|
13072
13382
|
const code = err?.code;
|
|
13073
13383
|
if (code === "EISDIR") {
|
|
@@ -13099,11 +13409,11 @@ app35.get("/:rel{.*}", (c) => {
|
|
|
13099
13409
|
"X-Content-Type-Options": "nosniff"
|
|
13100
13410
|
});
|
|
13101
13411
|
});
|
|
13102
|
-
var sites_default =
|
|
13412
|
+
var sites_default = app37;
|
|
13103
13413
|
|
|
13104
13414
|
// app/lib/visitor-token.ts
|
|
13105
13415
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
13106
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
13416
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync19, writeFileSync as writeFileSync6 } from "fs";
|
|
13107
13417
|
import { dirname as dirname4 } from "path";
|
|
13108
13418
|
var TOKEN_PREFIX = "v1.";
|
|
13109
13419
|
var SECRET_BYTES = 32;
|
|
@@ -13112,7 +13422,7 @@ var cachedSecret = null;
|
|
|
13112
13422
|
function getSecret() {
|
|
13113
13423
|
if (cachedSecret) return cachedSecret;
|
|
13114
13424
|
try {
|
|
13115
|
-
const hex2 =
|
|
13425
|
+
const hex2 = readFileSync19(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
13116
13426
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
13117
13427
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
13118
13428
|
return cachedSecret;
|
|
@@ -13126,7 +13436,7 @@ function getSecret() {
|
|
|
13126
13436
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
13127
13437
|
} catch {
|
|
13128
13438
|
}
|
|
13129
|
-
const hex =
|
|
13439
|
+
const hex = readFileSync19(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
13130
13440
|
cachedSecret = Buffer.from(hex, "hex");
|
|
13131
13441
|
return cachedSecret;
|
|
13132
13442
|
}
|
|
@@ -13179,8 +13489,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
13179
13489
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
13180
13490
|
|
|
13181
13491
|
// app/lib/brand-config.ts
|
|
13182
|
-
import { existsSync as
|
|
13183
|
-
import { join as
|
|
13492
|
+
import { existsSync as existsSync20, readFileSync as readFileSync20 } from "fs";
|
|
13493
|
+
import { join as join16 } from "path";
|
|
13184
13494
|
var cached2 = null;
|
|
13185
13495
|
var cachedAttempted = false;
|
|
13186
13496
|
function readBrandConfig() {
|
|
@@ -13188,10 +13498,10 @@ function readBrandConfig() {
|
|
|
13188
13498
|
cachedAttempted = true;
|
|
13189
13499
|
const platformRoot = process.env.MAXY_PLATFORM_ROOT;
|
|
13190
13500
|
if (!platformRoot) return null;
|
|
13191
|
-
const brandPath =
|
|
13192
|
-
if (!
|
|
13501
|
+
const brandPath = join16(platformRoot, "config", "brand.json");
|
|
13502
|
+
if (!existsSync20(brandPath)) return null;
|
|
13193
13503
|
try {
|
|
13194
|
-
cached2 = JSON.parse(
|
|
13504
|
+
cached2 = JSON.parse(readFileSync20(brandPath, "utf-8"));
|
|
13195
13505
|
return cached2;
|
|
13196
13506
|
} catch {
|
|
13197
13507
|
return null;
|
|
@@ -13199,7 +13509,7 @@ function readBrandConfig() {
|
|
|
13199
13509
|
}
|
|
13200
13510
|
|
|
13201
13511
|
// server/routes/visitor-consent.ts
|
|
13202
|
-
var
|
|
13512
|
+
var app38 = new Hono();
|
|
13203
13513
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
13204
13514
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
13205
13515
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -13244,17 +13554,17 @@ function siteSlugFromReferer(referer) {
|
|
|
13244
13554
|
return "";
|
|
13245
13555
|
}
|
|
13246
13556
|
}
|
|
13247
|
-
|
|
13557
|
+
app38.options("/consent", (c) => {
|
|
13248
13558
|
const origin = getOrigin(c);
|
|
13249
13559
|
setCorsHeaders(c, origin);
|
|
13250
13560
|
return c.body(null, 204);
|
|
13251
13561
|
});
|
|
13252
|
-
|
|
13562
|
+
app38.options("/brand-config", (c) => {
|
|
13253
13563
|
const origin = getOrigin(c);
|
|
13254
13564
|
setCorsHeaders(c, origin);
|
|
13255
13565
|
return c.body(null, 204);
|
|
13256
13566
|
});
|
|
13257
|
-
|
|
13567
|
+
app38.post("/consent", async (c) => {
|
|
13258
13568
|
const origin = getOrigin(c);
|
|
13259
13569
|
setCorsHeaders(c, origin);
|
|
13260
13570
|
let raw;
|
|
@@ -13294,7 +13604,7 @@ app36.post("/consent", async (c) => {
|
|
|
13294
13604
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
13295
13605
|
return c.body(null, 204);
|
|
13296
13606
|
});
|
|
13297
|
-
|
|
13607
|
+
app38.get("/brand-config", (c) => {
|
|
13298
13608
|
const origin = getOrigin(c);
|
|
13299
13609
|
setCorsHeaders(c, origin);
|
|
13300
13610
|
const brand = readBrandConfig();
|
|
@@ -13304,7 +13614,7 @@ app36.get("/brand-config", (c) => {
|
|
|
13304
13614
|
c.header("Cache-Control", "public, max-age=300");
|
|
13305
13615
|
return c.json({ consent: { copy, palette } });
|
|
13306
13616
|
});
|
|
13307
|
-
var visitor_consent_default =
|
|
13617
|
+
var visitor_consent_default = app38;
|
|
13308
13618
|
|
|
13309
13619
|
// server/routes/listings.ts
|
|
13310
13620
|
function getCookie(headerValue, name) {
|
|
@@ -13331,8 +13641,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
13331
13641
|
}
|
|
13332
13642
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
13333
13643
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
13334
|
-
var
|
|
13335
|
-
|
|
13644
|
+
var app39 = new Hono();
|
|
13645
|
+
app39.get("/:slug/click", async (c) => {
|
|
13336
13646
|
const slug = c.req.param("slug") ?? "";
|
|
13337
13647
|
const rawSession = c.req.query("session") ?? "";
|
|
13338
13648
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -13396,10 +13706,10 @@ app37.get("/:slug/click", async (c) => {
|
|
|
13396
13706
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
13397
13707
|
return c.redirect(redirectUrl, 302);
|
|
13398
13708
|
});
|
|
13399
|
-
var listings_default =
|
|
13709
|
+
var listings_default = app39;
|
|
13400
13710
|
|
|
13401
13711
|
// server/routes/visitor-event.ts
|
|
13402
|
-
var
|
|
13712
|
+
var app40 = new Hono();
|
|
13403
13713
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
13404
13714
|
var buckets = /* @__PURE__ */ new Map();
|
|
13405
13715
|
var RATE_LIMIT = 60;
|
|
@@ -13466,12 +13776,12 @@ function originAllowed(origin, allowlist) {
|
|
|
13466
13776
|
return false;
|
|
13467
13777
|
}
|
|
13468
13778
|
}
|
|
13469
|
-
|
|
13779
|
+
app40.options("/event", (c) => {
|
|
13470
13780
|
const origin = getOrigin2(c);
|
|
13471
13781
|
setCorsHeaders2(c, origin);
|
|
13472
13782
|
return c.body(null, 204);
|
|
13473
13783
|
});
|
|
13474
|
-
|
|
13784
|
+
app40.post("/event", async (c) => {
|
|
13475
13785
|
const origin = getOrigin2(c);
|
|
13476
13786
|
setCorsHeaders2(c, origin);
|
|
13477
13787
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -13676,7 +13986,7 @@ async function writeEvent(opts) {
|
|
|
13676
13986
|
);
|
|
13677
13987
|
}
|
|
13678
13988
|
}
|
|
13679
|
-
var visitor_event_default =
|
|
13989
|
+
var visitor_event_default = app40;
|
|
13680
13990
|
|
|
13681
13991
|
// app/lib/graph-health.ts
|
|
13682
13992
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -13761,7 +14071,7 @@ function startGraphHealthTimer() {
|
|
|
13761
14071
|
|
|
13762
14072
|
// app/lib/file-watcher.ts
|
|
13763
14073
|
import * as fsp2 from "fs/promises";
|
|
13764
|
-
import { resolve as
|
|
14074
|
+
import { resolve as resolve22, sep as sep6 } from "path";
|
|
13765
14075
|
var ACCOUNT_UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
13766
14076
|
var DEFAULT_COALESCE_MS = 500;
|
|
13767
14077
|
var ROOTS = ["uploads", "accounts"];
|
|
@@ -13780,7 +14090,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
13780
14090
|
const dropFn = opts.drop ?? dropFileIndex;
|
|
13781
14091
|
for (const r of ROOTS) {
|
|
13782
14092
|
try {
|
|
13783
|
-
await fsp2.mkdir(
|
|
14093
|
+
await fsp2.mkdir(resolve22(dataRoot, r), { recursive: true });
|
|
13784
14094
|
} catch (err) {
|
|
13785
14095
|
console.error(
|
|
13786
14096
|
`[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
|
|
@@ -13801,7 +14111,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
13801
14111
|
timers.set(relativePath, t);
|
|
13802
14112
|
}
|
|
13803
14113
|
async function runHook(relativePath, accountId) {
|
|
13804
|
-
const absolute =
|
|
14114
|
+
const absolute = resolve22(dataRoot, relativePath);
|
|
13805
14115
|
let exists = false;
|
|
13806
14116
|
try {
|
|
13807
14117
|
const st = await fsp2.stat(absolute);
|
|
@@ -13825,7 +14135,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
13825
14135
|
}
|
|
13826
14136
|
}
|
|
13827
14137
|
async function watchRoot(rootName) {
|
|
13828
|
-
const absRoot =
|
|
14138
|
+
const absRoot = resolve22(dataRoot, rootName);
|
|
13829
14139
|
try {
|
|
13830
14140
|
const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
|
|
13831
14141
|
for await (const event of iter) {
|
|
@@ -13923,8 +14233,8 @@ function broadcastAdminShutdown(reason) {
|
|
|
13923
14233
|
|
|
13924
14234
|
// ../lib/entitlement/src/index.ts
|
|
13925
14235
|
import { createPublicKey, createHash as createHash4, verify as cryptoVerify } from "crypto";
|
|
13926
|
-
import { existsSync as
|
|
13927
|
-
import { resolve as
|
|
14236
|
+
import { existsSync as existsSync21, readFileSync as readFileSync21, statSync as statSync9 } from "fs";
|
|
14237
|
+
import { resolve as resolve23 } from "path";
|
|
13928
14238
|
|
|
13929
14239
|
// ../lib/entitlement/src/canonicalize.ts
|
|
13930
14240
|
function canonicalize(value) {
|
|
@@ -13959,7 +14269,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
|
|
|
13959
14269
|
var GRACE_DAYS = 7;
|
|
13960
14270
|
var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
|
|
13961
14271
|
function pubkeyPath(brand) {
|
|
13962
|
-
return
|
|
14272
|
+
return resolve23(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
|
|
13963
14273
|
}
|
|
13964
14274
|
var memo = null;
|
|
13965
14275
|
function memoKey(mtimeMs, account) {
|
|
@@ -13971,8 +14281,8 @@ function resolveEntitlement(brand, account) {
|
|
|
13971
14281
|
if (brand.commercialMode !== true) {
|
|
13972
14282
|
return logResolved(implicitTrust(account), null);
|
|
13973
14283
|
}
|
|
13974
|
-
const entitlementPath =
|
|
13975
|
-
if (!
|
|
14284
|
+
const entitlementPath = resolve23(brand.configDir, "entitlement.json");
|
|
14285
|
+
if (!existsSync21(entitlementPath)) {
|
|
13976
14286
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
13977
14287
|
}
|
|
13978
14288
|
const stat7 = statSync9(entitlementPath);
|
|
@@ -13987,7 +14297,7 @@ function resolveEntitlement(brand, account) {
|
|
|
13987
14297
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
13988
14298
|
let pubkeyPem;
|
|
13989
14299
|
try {
|
|
13990
|
-
pubkeyPem =
|
|
14300
|
+
pubkeyPem = readFileSync21(pubkeyPath(brand), "utf-8");
|
|
13991
14301
|
} catch (err) {
|
|
13992
14302
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
13993
14303
|
reason: "pubkey-missing"
|
|
@@ -14001,7 +14311,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
14001
14311
|
}
|
|
14002
14312
|
let envelope;
|
|
14003
14313
|
try {
|
|
14004
|
-
envelope = JSON.parse(
|
|
14314
|
+
envelope = JSON.parse(readFileSync21(entitlementPath, "utf-8"));
|
|
14005
14315
|
} catch {
|
|
14006
14316
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
14007
14317
|
}
|
|
@@ -14162,14 +14472,14 @@ function clientFrom(c) {
|
|
|
14162
14472
|
);
|
|
14163
14473
|
}
|
|
14164
14474
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
14165
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT9 ?
|
|
14475
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join17(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
14166
14476
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
14167
|
-
if (BRAND_JSON_PATH && !
|
|
14477
|
+
if (BRAND_JSON_PATH && !existsSync22(BRAND_JSON_PATH)) {
|
|
14168
14478
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
14169
14479
|
}
|
|
14170
|
-
if (BRAND_JSON_PATH &&
|
|
14480
|
+
if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
|
|
14171
14481
|
try {
|
|
14172
|
-
const parsed = JSON.parse(
|
|
14482
|
+
const parsed = JSON.parse(readFileSync22(BRAND_JSON_PATH, "utf-8"));
|
|
14173
14483
|
BRAND = { ...BRAND, ...parsed };
|
|
14174
14484
|
} catch (err) {
|
|
14175
14485
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -14188,11 +14498,11 @@ var brandLoginOpts = {
|
|
|
14188
14498
|
bodyFont: BRAND.defaultFonts?.body,
|
|
14189
14499
|
logoContainsName: !!BRAND.logoContainsName
|
|
14190
14500
|
};
|
|
14191
|
-
var ALIAS_DOMAINS_PATH =
|
|
14501
|
+
var ALIAS_DOMAINS_PATH = join17(homedir2(), BRAND.configDir, "alias-domains.json");
|
|
14192
14502
|
function loadAliasDomains() {
|
|
14193
14503
|
try {
|
|
14194
|
-
if (!
|
|
14195
|
-
const parsed = JSON.parse(
|
|
14504
|
+
if (!existsSync22(ALIAS_DOMAINS_PATH)) return null;
|
|
14505
|
+
const parsed = JSON.parse(readFileSync22(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
14196
14506
|
if (!Array.isArray(parsed)) {
|
|
14197
14507
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
14198
14508
|
return null;
|
|
@@ -14216,9 +14526,9 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
14216
14526
|
function isPublicHost(host) {
|
|
14217
14527
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
14218
14528
|
}
|
|
14219
|
-
var
|
|
14220
|
-
|
|
14221
|
-
|
|
14529
|
+
var app41 = new Hono();
|
|
14530
|
+
app41.use("*", clientIpMiddleware);
|
|
14531
|
+
app41.use("*", async (c, next) => {
|
|
14222
14532
|
await next();
|
|
14223
14533
|
c.header("X-Content-Type-Options", "nosniff");
|
|
14224
14534
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -14228,7 +14538,7 @@ app39.use("*", async (c, next) => {
|
|
|
14228
14538
|
);
|
|
14229
14539
|
});
|
|
14230
14540
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
14231
|
-
|
|
14541
|
+
app41.use("*", async (c, next) => {
|
|
14232
14542
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
14233
14543
|
await next();
|
|
14234
14544
|
return;
|
|
@@ -14261,7 +14571,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
14261
14571
|
"/sites/"
|
|
14262
14572
|
];
|
|
14263
14573
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
14264
|
-
|
|
14574
|
+
app41.use("*", async (c, next) => {
|
|
14265
14575
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14266
14576
|
if (!isPublicHost(host)) {
|
|
14267
14577
|
await next();
|
|
@@ -14301,7 +14611,7 @@ function resolveRemoteAuthOpts() {
|
|
|
14301
14611
|
return brandLoginOpts;
|
|
14302
14612
|
}
|
|
14303
14613
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
14304
|
-
|
|
14614
|
+
app41.post("/__remote-auth/login", async (c) => {
|
|
14305
14615
|
const client = clientFrom(c);
|
|
14306
14616
|
const clientIp = client.ip || "unknown";
|
|
14307
14617
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -14346,7 +14656,7 @@ app39.post("/__remote-auth/login", async (c) => {
|
|
|
14346
14656
|
}
|
|
14347
14657
|
});
|
|
14348
14658
|
});
|
|
14349
|
-
|
|
14659
|
+
app41.get("/__remote-auth/logout", (c) => {
|
|
14350
14660
|
const client = clientFrom(c);
|
|
14351
14661
|
const clientIp = client.ip || "unknown";
|
|
14352
14662
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -14359,7 +14669,7 @@ app39.get("/__remote-auth/logout", (c) => {
|
|
|
14359
14669
|
}
|
|
14360
14670
|
});
|
|
14361
14671
|
});
|
|
14362
|
-
|
|
14672
|
+
app41.post("/__remote-auth/change-password", async (c) => {
|
|
14363
14673
|
const client = clientFrom(c);
|
|
14364
14674
|
const clientIp = client.ip || "unknown";
|
|
14365
14675
|
const rateLimited = checkRateLimit(client);
|
|
@@ -14410,13 +14720,13 @@ app39.post("/__remote-auth/change-password", async (c) => {
|
|
|
14410
14720
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
14411
14721
|
}
|
|
14412
14722
|
});
|
|
14413
|
-
|
|
14723
|
+
app41.get("/__remote-auth/setup", (c) => {
|
|
14414
14724
|
if (isRemoteAuthConfigured()) {
|
|
14415
14725
|
return c.redirect("/");
|
|
14416
14726
|
}
|
|
14417
14727
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
14418
14728
|
});
|
|
14419
|
-
|
|
14729
|
+
app41.post("/__remote-auth/set-initial-password", async (c) => {
|
|
14420
14730
|
if (isRemoteAuthConfigured()) {
|
|
14421
14731
|
return c.redirect("/");
|
|
14422
14732
|
}
|
|
@@ -14454,10 +14764,10 @@ app39.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
14454
14764
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
14455
14765
|
}
|
|
14456
14766
|
});
|
|
14457
|
-
|
|
14767
|
+
app41.get("/api/remote-auth/status", (c) => {
|
|
14458
14768
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
14459
14769
|
});
|
|
14460
|
-
|
|
14770
|
+
app41.post("/api/remote-auth/set-password", async (c) => {
|
|
14461
14771
|
let body;
|
|
14462
14772
|
try {
|
|
14463
14773
|
body = await c.req.json();
|
|
@@ -14488,9 +14798,9 @@ app39.post("/api/remote-auth/set-password", async (c) => {
|
|
|
14488
14798
|
return c.json({ error: "Failed to save password" }, 500);
|
|
14489
14799
|
}
|
|
14490
14800
|
});
|
|
14491
|
-
|
|
14801
|
+
app41.route("/api/_client-error", client_error_default);
|
|
14492
14802
|
console.log("[client-error-route] mounted");
|
|
14493
|
-
|
|
14803
|
+
app41.use("*", async (c, next) => {
|
|
14494
14804
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14495
14805
|
const path2 = c.req.path;
|
|
14496
14806
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -14523,12 +14833,12 @@ app39.use("*", async (c, next) => {
|
|
|
14523
14833
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
14524
14834
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
14525
14835
|
});
|
|
14526
|
-
|
|
14527
|
-
|
|
14528
|
-
|
|
14529
|
-
|
|
14530
|
-
|
|
14531
|
-
|
|
14836
|
+
app41.route("/api/health", health_default);
|
|
14837
|
+
app41.route("/api/chat", chat_default);
|
|
14838
|
+
app41.route("/api/whatsapp", whatsapp_default);
|
|
14839
|
+
app41.route("/api/onboarding", onboarding_default);
|
|
14840
|
+
app41.route("/api/admin", admin_default);
|
|
14841
|
+
app41.route("/api/access", access_default);
|
|
14532
14842
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
14533
14843
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
14534
14844
|
var IMAGE_MIME = {
|
|
@@ -14540,7 +14850,7 @@ var IMAGE_MIME = {
|
|
|
14540
14850
|
".svg": "image/svg+xml",
|
|
14541
14851
|
".ico": "image/x-icon"
|
|
14542
14852
|
};
|
|
14543
|
-
|
|
14853
|
+
app41.get("/agent-assets/:slug/:filename", (c) => {
|
|
14544
14854
|
const slug = c.req.param("slug");
|
|
14545
14855
|
const filename = c.req.param("filename");
|
|
14546
14856
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -14556,26 +14866,26 @@ app39.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
14556
14866
|
console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
|
|
14557
14867
|
return c.text("Not found", 404);
|
|
14558
14868
|
}
|
|
14559
|
-
const filePath =
|
|
14560
|
-
const expectedDir =
|
|
14869
|
+
const filePath = resolve24(account.accountDir, "agents", slug, "assets", filename);
|
|
14870
|
+
const expectedDir = resolve24(account.accountDir, "agents", slug, "assets");
|
|
14561
14871
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
14562
14872
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
14563
14873
|
return c.text("Forbidden", 403);
|
|
14564
14874
|
}
|
|
14565
|
-
if (!
|
|
14875
|
+
if (!existsSync22(filePath)) {
|
|
14566
14876
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
14567
14877
|
return c.text("Not found", 404);
|
|
14568
14878
|
}
|
|
14569
14879
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
14570
14880
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
14571
14881
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
14572
|
-
const body =
|
|
14882
|
+
const body = readFileSync22(filePath);
|
|
14573
14883
|
return c.body(body, 200, {
|
|
14574
14884
|
"Content-Type": contentType,
|
|
14575
14885
|
"Cache-Control": "public, max-age=3600"
|
|
14576
14886
|
});
|
|
14577
14887
|
});
|
|
14578
|
-
|
|
14888
|
+
app41.get("/generated/:filename", (c) => {
|
|
14579
14889
|
const filename = c.req.param("filename");
|
|
14580
14890
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
14581
14891
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -14586,35 +14896,35 @@ app39.get("/generated/:filename", (c) => {
|
|
|
14586
14896
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
14587
14897
|
return c.text("Not found", 404);
|
|
14588
14898
|
}
|
|
14589
|
-
const filePath =
|
|
14590
|
-
const expectedDir =
|
|
14899
|
+
const filePath = resolve24(account.accountDir, "generated", filename);
|
|
14900
|
+
const expectedDir = resolve24(account.accountDir, "generated");
|
|
14591
14901
|
if (!filePath.startsWith(expectedDir + "/")) {
|
|
14592
14902
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
14593
14903
|
return c.text("Forbidden", 403);
|
|
14594
14904
|
}
|
|
14595
|
-
if (!
|
|
14905
|
+
if (!existsSync22(filePath)) {
|
|
14596
14906
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
14597
14907
|
return c.text("Not found", 404);
|
|
14598
14908
|
}
|
|
14599
14909
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
14600
14910
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
14601
14911
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
14602
|
-
const body =
|
|
14912
|
+
const body = readFileSync22(filePath);
|
|
14603
14913
|
return c.body(body, 200, {
|
|
14604
14914
|
"Content-Type": contentType,
|
|
14605
14915
|
"Cache-Control": "public, max-age=86400"
|
|
14606
14916
|
});
|
|
14607
14917
|
});
|
|
14608
|
-
|
|
14609
|
-
|
|
14610
|
-
|
|
14611
|
-
|
|
14918
|
+
app41.route("/sites", sites_default);
|
|
14919
|
+
app41.route("/listings", listings_default);
|
|
14920
|
+
app41.route("/v", visitor_event_default);
|
|
14921
|
+
app41.route("/v", visitor_consent_default);
|
|
14612
14922
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
14613
14923
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
14614
14924
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
14615
|
-
if (BRAND_JSON_PATH &&
|
|
14925
|
+
if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
|
|
14616
14926
|
try {
|
|
14617
|
-
const fullBrand = JSON.parse(
|
|
14927
|
+
const fullBrand = JSON.parse(readFileSync22(BRAND_JSON_PATH, "utf-8"));
|
|
14618
14928
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
14619
14929
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
14620
14930
|
} catch {
|
|
@@ -14631,9 +14941,9 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
14631
14941
|
function readInstalledVersion() {
|
|
14632
14942
|
try {
|
|
14633
14943
|
if (!PLATFORM_ROOT9) return "unknown";
|
|
14634
|
-
const versionFile =
|
|
14635
|
-
if (!
|
|
14636
|
-
const content =
|
|
14944
|
+
const versionFile = join17(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
|
|
14945
|
+
if (!existsSync22(versionFile)) return "unknown";
|
|
14946
|
+
const content = readFileSync22(versionFile, "utf-8").trim();
|
|
14637
14947
|
return content || "unknown";
|
|
14638
14948
|
} catch {
|
|
14639
14949
|
return "unknown";
|
|
@@ -14674,7 +14984,7 @@ var clientErrorReporterScript = `<script>
|
|
|
14674
14984
|
function cachedHtml(file) {
|
|
14675
14985
|
let html = htmlCache.get(file);
|
|
14676
14986
|
if (!html) {
|
|
14677
|
-
html =
|
|
14987
|
+
html = readFileSync22(resolve24(process.cwd(), "public", file), "utf-8");
|
|
14678
14988
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
14679
14989
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
14680
14990
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -14690,26 +15000,26 @@ ${clientErrorReporterScript}
|
|
|
14690
15000
|
}
|
|
14691
15001
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
14692
15002
|
function loadBrandingCache(agentSlug) {
|
|
14693
|
-
const configDir2 =
|
|
15003
|
+
const configDir2 = join17(homedir2(), BRAND.configDir);
|
|
14694
15004
|
try {
|
|
14695
|
-
const accountJsonPath =
|
|
14696
|
-
if (!
|
|
14697
|
-
const account = JSON.parse(
|
|
15005
|
+
const accountJsonPath = join17(configDir2, "account.json");
|
|
15006
|
+
if (!existsSync22(accountJsonPath)) return null;
|
|
15007
|
+
const account = JSON.parse(readFileSync22(accountJsonPath, "utf-8"));
|
|
14698
15008
|
const accountId = account.accountId;
|
|
14699
15009
|
if (!accountId) return null;
|
|
14700
|
-
const cachePath =
|
|
14701
|
-
if (!
|
|
14702
|
-
return JSON.parse(
|
|
15010
|
+
const cachePath = join17(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
15011
|
+
if (!existsSync22(cachePath)) return null;
|
|
15012
|
+
return JSON.parse(readFileSync22(cachePath, "utf-8"));
|
|
14703
15013
|
} catch {
|
|
14704
15014
|
return null;
|
|
14705
15015
|
}
|
|
14706
15016
|
}
|
|
14707
15017
|
function resolveDefaultSlug() {
|
|
14708
15018
|
try {
|
|
14709
|
-
const configDir2 =
|
|
14710
|
-
const accountJsonPath =
|
|
14711
|
-
if (!
|
|
14712
|
-
const account = JSON.parse(
|
|
15019
|
+
const configDir2 = join17(homedir2(), BRAND.configDir);
|
|
15020
|
+
const accountJsonPath = join17(configDir2, "account.json");
|
|
15021
|
+
if (!existsSync22(accountJsonPath)) return null;
|
|
15022
|
+
const account = JSON.parse(readFileSync22(accountJsonPath, "utf-8"));
|
|
14713
15023
|
return account.defaultAgent || null;
|
|
14714
15024
|
} catch {
|
|
14715
15025
|
return null;
|
|
@@ -14745,7 +15055,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
14745
15055
|
function escapeHtml(s) {
|
|
14746
15056
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
14747
15057
|
}
|
|
14748
|
-
|
|
15058
|
+
app41.get("/", (c) => {
|
|
14749
15059
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14750
15060
|
if (isPublicHost(host)) {
|
|
14751
15061
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -14753,12 +15063,12 @@ app39.get("/", (c) => {
|
|
|
14753
15063
|
}
|
|
14754
15064
|
return c.html(cachedHtml("index.html"));
|
|
14755
15065
|
});
|
|
14756
|
-
|
|
15066
|
+
app41.get("/public", (c) => {
|
|
14757
15067
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14758
15068
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14759
15069
|
return c.html(cachedHtml("public.html"));
|
|
14760
15070
|
});
|
|
14761
|
-
|
|
15071
|
+
app41.get("/chat", (c) => {
|
|
14762
15072
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14763
15073
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14764
15074
|
return c.html(cachedHtml("public.html"));
|
|
@@ -14777,12 +15087,12 @@ async function logViewerFetch(c, next) {
|
|
|
14777
15087
|
duration_ms: Date.now() - start
|
|
14778
15088
|
});
|
|
14779
15089
|
}
|
|
14780
|
-
|
|
14781
|
-
|
|
14782
|
-
|
|
15090
|
+
app41.use("/vnc-viewer.html", logViewerFetch);
|
|
15091
|
+
app41.use("/vnc-popout.html", logViewerFetch);
|
|
15092
|
+
app41.get("/vnc-popout.html", (c) => {
|
|
14783
15093
|
let html = htmlCache.get("vnc-popout.html");
|
|
14784
15094
|
if (!html) {
|
|
14785
|
-
html =
|
|
15095
|
+
html = readFileSync22(resolve24(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
14786
15096
|
const name = escapeHtml(BRAND.productName);
|
|
14787
15097
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
14788
15098
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -14792,7 +15102,7 @@ app39.get("/vnc-popout.html", (c) => {
|
|
|
14792
15102
|
}
|
|
14793
15103
|
return c.html(html);
|
|
14794
15104
|
});
|
|
14795
|
-
|
|
15105
|
+
app41.post("/api/vnc/client-event", async (c) => {
|
|
14796
15106
|
let body;
|
|
14797
15107
|
try {
|
|
14798
15108
|
body = await c.req.json();
|
|
@@ -14813,25 +15123,25 @@ app39.post("/api/vnc/client-event", async (c) => {
|
|
|
14813
15123
|
});
|
|
14814
15124
|
return c.json({ ok: true });
|
|
14815
15125
|
});
|
|
14816
|
-
|
|
15126
|
+
app41.get("/g/:slug", (c) => {
|
|
14817
15127
|
return c.html(brandedPublicHtml());
|
|
14818
15128
|
});
|
|
14819
|
-
|
|
15129
|
+
app41.get("/graph", (c) => {
|
|
14820
15130
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14821
15131
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14822
15132
|
return c.html(cachedHtml("graph.html"));
|
|
14823
15133
|
});
|
|
14824
|
-
|
|
15134
|
+
app41.get("/sessions", (c) => {
|
|
14825
15135
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14826
15136
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14827
15137
|
return c.html(cachedHtml("sessions.html"));
|
|
14828
15138
|
});
|
|
14829
|
-
|
|
15139
|
+
app41.get("/data", (c) => {
|
|
14830
15140
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14831
15141
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14832
15142
|
return c.html(cachedHtml("data.html"));
|
|
14833
15143
|
});
|
|
14834
|
-
|
|
15144
|
+
app41.get("/:slug", async (c, next) => {
|
|
14835
15145
|
const slug = c.req.param("slug");
|
|
14836
15146
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
14837
15147
|
const branding = loadBrandingCache(slug);
|
|
@@ -14841,15 +15151,15 @@ app39.get("/:slug", async (c, next) => {
|
|
|
14841
15151
|
await next();
|
|
14842
15152
|
});
|
|
14843
15153
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
14844
|
-
|
|
15154
|
+
app41.get("/favicon.ico", (c) => {
|
|
14845
15155
|
c.header("Cache-Control", "public, max-age=300");
|
|
14846
15156
|
return c.redirect(brandFaviconPath, 302);
|
|
14847
15157
|
});
|
|
14848
15158
|
}
|
|
14849
|
-
|
|
15159
|
+
app41.use("/*", serveStatic({ root: "./public" }));
|
|
14850
15160
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
14851
15161
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
14852
|
-
var httpServer = serve({ fetch:
|
|
15162
|
+
var httpServer = serve({ fetch: app41.fetch, port, hostname });
|
|
14853
15163
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
14854
15164
|
{
|
|
14855
15165
|
const loopHist = monitorEventLoopDelay({ resolution: 50 });
|
|
@@ -14885,7 +15195,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
14885
15195
|
}
|
|
14886
15196
|
try {
|
|
14887
15197
|
const registered = [];
|
|
14888
|
-
for (const r of
|
|
15198
|
+
for (const r of app41.routes ?? []) {
|
|
14889
15199
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
14890
15200
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
14891
15201
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -14907,8 +15217,8 @@ try {
|
|
|
14907
15217
|
}
|
|
14908
15218
|
(async () => {
|
|
14909
15219
|
try {
|
|
14910
|
-
if (!
|
|
14911
|
-
const usersRaw =
|
|
15220
|
+
if (!existsSync22(USERS_FILE)) return;
|
|
15221
|
+
const usersRaw = readFileSync22(USERS_FILE, "utf-8").trim();
|
|
14912
15222
|
if (!usersRaw) return;
|
|
14913
15223
|
const users = JSON.parse(usersRaw);
|
|
14914
15224
|
const userId = users[0]?.userId;
|
|
@@ -15003,7 +15313,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
15003
15313
|
}
|
|
15004
15314
|
init({
|
|
15005
15315
|
configDir: configDirForWhatsApp,
|
|
15006
|
-
platformRoot:
|
|
15316
|
+
platformRoot: resolve24(process.env.MAXY_PLATFORM_ROOT ?? join17(__dirname, "..")),
|
|
15007
15317
|
accountConfig: bootAccountConfig,
|
|
15008
15318
|
onMessage: async (msg) => {
|
|
15009
15319
|
if (process.env.WHATSAPP_PTY_BRIDGE_ENABLED === "true" && msg.text && !msg.isOwnerMirror) {
|