@rubytech/create-realagent-code 0.1.196 → 0.1.200
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/config/brand.json +3 -1
- package/payload/platform/plugins/admin/PLUGIN.md +3 -0
- package/payload/platform/plugins/admin/skills/investigate/SKILL.md +286 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +3736 -0
- package/payload/platform/plugins/admin/skills/superpowers-sprint/SKILL.md +361 -0
- package/payload/platform/plugins/admin/skills/task/SKILL.md +283 -0
- package/payload/platform/plugins/docs/references/admin-ui.md +4 -1
- package/payload/platform/plugins/docs/references/internals.md +0 -2
- package/payload/platform/plugins/docs/references/investigate-and-task-skills.md +9 -0
- package/payload/platform/plugins/docs/references/platform.md +1 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +1 -1
- package/payload/platform/scripts/check-architecture-skill-no-drift.mjs +67 -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 +56 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +18 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +25 -15
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/templates/agents/admin/IDENTITY.md +4 -0
- package/payload/platform/templates/agents/public/IDENTITY.md +1 -1
- package/payload/premium-plugins/real-agent/BUNDLE.md +1 -1
- package/payload/premium-plugins/real-agent/agents/compliance.md +1 -1
- package/payload/premium-plugins/real-agent/agents/listing-curator.md +3 -3
- package/payload/premium-plugins/real-agent/agents/negotiator.md +1 -1
- package/payload/premium-plugins/real-agent/agents/valuer.md +1 -1
- package/payload/server/public/assets/AdminShell-OJlDJakR.js +1 -0
- package/payload/server/public/assets/{Checkbox-DTxJvyG7.js → Checkbox-DE_tsDq_.js} +1 -1
- package/payload/server/public/assets/{admin-tKgLki8m.js → admin-DbQw1TyC.js} +1 -1
- package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-CrQJbK3h.js → architectureDiagram-Q4EWVU46-DfZVWJVr.js} +1 -1
- package/payload/server/public/assets/{blockDiagram-DXYQGD6D-BLCbhL8K.js → blockDiagram-DXYQGD6D-Cd9vcTYg.js} +1 -1
- package/payload/server/public/assets/{brand-lZz3OVIE.css → brand-Ed5R2W5J.css} +1 -1
- package/payload/server/public/assets/{c4Diagram-AHTNJAMY-X34EilDe.js → c4Diagram-AHTNJAMY-zmNCfJ5F.js} +1 -1
- package/payload/server/public/assets/channel-DCJza6li.js +1 -0
- package/payload/server/public/assets/{chunk-336JU56O-CeRuGBQ2.js → chunk-336JU56O-DvHeoV7B.js} +2 -2
- package/payload/server/public/assets/{chunk-426QAEUC-CUZOrcMu.js → chunk-426QAEUC-IZknbXMM.js} +1 -1
- package/payload/server/public/assets/{chunk-4TB4RGXK-CdrIHRcy.js → chunk-4TB4RGXK-DN_qw6Oi.js} +1 -1
- package/payload/server/public/assets/{chunk-5FUZZQ4R-CenIbTIp.js → chunk-5FUZZQ4R-tt-46Rcq.js} +1 -1
- package/payload/server/public/assets/{chunk-5PVQY5BW-DGfzIUel.js → chunk-5PVQY5BW-Bl0mxmQP.js} +1 -1
- package/payload/server/public/assets/{chunk-EDXVE4YY-DSft5oIH.js → chunk-EDXVE4YY-v31HwKDb.js} +1 -1
- package/payload/server/public/assets/{chunk-ENJZ2VHE-Dn8FFfaI.js → chunk-ENJZ2VHE-D6T1RStj.js} +1 -1
- package/payload/server/public/assets/{chunk-ICPOFSXX-JrwcKV7r.js → chunk-ICPOFSXX-DVnIs_5A.js} +1 -1
- package/payload/server/public/assets/{chunk-OYMX7WX6-C0X2fcAm.js → chunk-OYMX7WX6-DiZNprr1.js} +1 -1
- package/payload/server/public/assets/{chunk-U2HBQHQK-DPdLe-f5.js → chunk-U2HBQHQK-Cy0qH3H0.js} +1 -1
- package/payload/server/public/assets/{chunk-X2U36JSP-Bw8pKkFu.js → chunk-X2U36JSP-wR3wBPyu.js} +1 -1
- package/payload/server/public/assets/{chunk-YZCP3GAM-DcAJR-EA.js → chunk-YZCP3GAM-BGOVJLky.js} +1 -1
- package/payload/server/public/assets/{chunk-ZZ45TVLE-DU374ZbR.js → chunk-ZZ45TVLE-14vtIjRh.js} +1 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-DEo4goqG.js +1 -0
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-CoAVCeH7.js +1 -0
- package/payload/server/public/assets/clone-CLnBlH9n.js +1 -0
- package/payload/server/public/assets/{dagre-DisbqNSB.js → dagre-CG1l6rfK.js} +1 -1
- package/payload/server/public/assets/{dagre-KV5264BT-D_n7R7V9.js → dagre-KV5264BT-DKFDl1Nz.js} +1 -1
- package/payload/server/public/assets/data-b1v7Pjly.js +1 -0
- package/payload/server/public/assets/{diagram-5BDNPKRD-CJID_5OR.js → diagram-5BDNPKRD-PJd29fkg.js} +1 -1
- package/payload/server/public/assets/{diagram-G4DWMVQ6-ByepjvdE.js → diagram-G4DWMVQ6-Bz7_SWJH.js} +1 -1
- package/payload/server/public/assets/{diagram-MMDJMWI5-DTkAHPHE.js → diagram-MMDJMWI5-CmWknm9v.js} +1 -1
- package/payload/server/public/assets/{diagram-TYMM5635-CnVRa9NJ.js → diagram-TYMM5635-CLYRluM2.js} +1 -1
- package/payload/server/public/assets/{erDiagram-SMLLAGMA-CRAGu7nV.js → erDiagram-SMLLAGMA-EWVKGrgT.js} +1 -1
- package/payload/server/public/assets/{flowDiagram-DWJPFMVM-BJusdlRz.js → flowDiagram-DWJPFMVM-CNtfJIG7.js} +1 -1
- package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BFMOBBnF.js → ganttDiagram-T4ZO3ILL-SIlymJ6A.js} +1 -1
- package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-CGWEzh7u.js → gitGraphDiagram-UUTBAWPF-DWVl6CUl.js} +1 -1
- package/payload/server/public/assets/{graph-D-iQdRDk.js → graph-BOcblKu9.js} +2 -2
- package/payload/server/public/assets/{graph-labels-u2_3Eyfh.js → graph-labels-CH-Tffon.js} +1 -1
- package/payload/server/public/assets/{graphlib-DNUvypOi.js → graphlib-i-qJjJM7.js} +1 -1
- package/payload/server/public/assets/{infoDiagram-42DDH7IO-CBDrnRTc.js → infoDiagram-42DDH7IO-D66Yr_7b.js} +1 -1
- package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-C7NwSQo_.js → ishikawaDiagram-UXIWVN3A-C4mQi7AB.js} +1 -1
- package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-DSaP7A3F.js → journeyDiagram-VCZTEJTY-7Vp2UBlF.js} +1 -1
- package/payload/server/public/assets/{kanban-definition-6JOO6SKY-DmixHCD4.js → kanban-definition-6JOO6SKY-nEDANSe9.js} +1 -1
- package/payload/server/public/assets/{line-CGGoTheL.js → line-BxGbTwly.js} +1 -1
- package/payload/server/public/assets/{mermaid-parser.core-BudFADW7.js → mermaid-parser.core-CAG4AdDd.js} +1 -1
- package/payload/server/public/assets/{mermaid.core-BBbdJxXY.js → mermaid.core-prtUaAsI.js} +3 -3
- package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CUiD9km1.js → mindmap-definition-QFDTVHPH-Dvcph8zi.js} +1 -1
- package/payload/server/public/assets/{pieDiagram-DEJITSTG-BlAWpMr8.js → pieDiagram-DEJITSTG-C4qHs6Vb.js} +1 -1
- package/payload/server/public/assets/{public-CjeEF2vf.js → public-DIyn-De4.js} +3 -3
- package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-CXmIwc4W.js → quadrantDiagram-34T5L4WZ-I9Et2l2H.js} +1 -1
- package/payload/server/public/assets/{requirementDiagram-MS252O5E-D_7_OeMC.js → requirementDiagram-MS252O5E-DLKlY81v.js} +1 -1
- package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-BKm_PqzT.js → sankeyDiagram-XADWPNL6-dX3pgMv_.js} +1 -1
- package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CBSR0Zst.js → sequenceDiagram-FGHM5R23-C4qTAl3F.js} +1 -1
- package/payload/server/public/assets/{stateDiagram-FHFEXIEX-CHNpT69M.js → stateDiagram-FHFEXIEX-DzA0NObk.js} +1 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Dsgd5hEe.js +1 -0
- package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-CxZoew5-.js → timeline-definition-GMOUNBTQ-D-DPUQCU.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-CwxXQzEI.js → useSelectionMode-C4HDuwDT.js} +1 -1
- package/payload/server/public/assets/{vennDiagram-DHZGUBPP-CKJdFDcG.js → vennDiagram-DHZGUBPP-C_RwTsUi.js} +1 -1
- package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-C-XBcm-g.js → wardleyDiagram-NUSXRM2D-BAftlsC2.js} +1 -1
- package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-Crb-ZtaP.js → xychartDiagram-5P7HB3ND-C_tKMCMd.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 +404 -325
- package/payload/server/public/assets/AdminShell-DtABh34v.js +0 -1
- package/payload/server/public/assets/channel-ChZECiuj.js +0 -1
- package/payload/server/public/assets/classDiagram-6PBFFD2Q-BpMBCYn6.js +0 -1
- package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BU3HoIr1.js +0 -1
- package/payload/server/public/assets/clone-C3j5j6ku.js +0 -1
- package/payload/server/public/assets/data-DwY26t_T.js +0 -1
- package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Kc8XO6yH.js +0 -1
- /package/payload/server/public/assets/{brand-CpGp9OyK.js → brand-CCOPpjM4.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 resolve23, join as
|
|
819
|
+
import { readFileSync as readFileSync22, existsSync as existsSync22, watchFile } from "fs";
|
|
820
|
+
import { resolve as resolve23, 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
|
|
|
@@ -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") {
|
|
@@ -7966,13 +7966,13 @@ ${fm}
|
|
|
7966
7966
|
}
|
|
7967
7967
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
7968
7968
|
const skills = [];
|
|
7969
|
-
for (const
|
|
7970
|
-
const skillPath = join10(dir,
|
|
7969
|
+
for (const relPath of skillPaths) {
|
|
7970
|
+
const skillPath = join10(dir, relPath);
|
|
7971
7971
|
const skillFm = readFrontmatter(skillPath);
|
|
7972
7972
|
if (!skillFm) continue;
|
|
7973
7973
|
const skillName = frontmatterField(`---
|
|
7974
7974
|
${skillFm}
|
|
7975
|
-
---`, "name") ??
|
|
7975
|
+
---`, "name") ?? relPath;
|
|
7976
7976
|
const skillDesc = frontmatterField(`---
|
|
7977
7977
|
${skillFm}
|
|
7978
7978
|
---`, "description");
|
|
@@ -8391,8 +8391,8 @@ var DATA_ROOT = resolve12(PLATFORM_ROOT5, "..", "data");
|
|
|
8391
8391
|
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve12(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
|
|
8392
8392
|
var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["uploads", "accounts"]);
|
|
8393
8393
|
var ACCOUNT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8394
|
-
function crossesForeignAccountPartition(
|
|
8395
|
-
const segs =
|
|
8394
|
+
function crossesForeignAccountPartition(relPath, accountId) {
|
|
8395
|
+
const segs = relPath.split("/").filter(Boolean);
|
|
8396
8396
|
if (segs.length < 2) return false;
|
|
8397
8397
|
if (!ACCOUNT_PARTITION_DIRS.has(segs[0])) return false;
|
|
8398
8398
|
const owner = segs[1];
|
|
@@ -8432,8 +8432,8 @@ function resolveUnderRoot(raw, rootAbs, rootLabel) {
|
|
|
8432
8432
|
if (resolvedReal !== rootReal && !resolvedReal.startsWith(rootReal + sep2)) {
|
|
8433
8433
|
return { ok: false, status: 403, error: `Path escapes ${rootLabel}`, resolved: resolvedReal };
|
|
8434
8434
|
}
|
|
8435
|
-
const
|
|
8436
|
-
return { ok: true, absolute: resolvedReal, dataRootReal: rootReal, relative:
|
|
8435
|
+
const relPath = relative(rootReal, resolvedReal) || ".";
|
|
8436
|
+
return { ok: true, absolute: resolvedReal, dataRootReal: rootReal, relative: relPath };
|
|
8437
8437
|
}
|
|
8438
8438
|
function resolveDataPath(raw) {
|
|
8439
8439
|
return resolveUnderRoot(raw, DATA_ROOT, "DATA_ROOT");
|
|
@@ -8680,8 +8680,8 @@ async function restoreNode(params) {
|
|
|
8680
8680
|
|
|
8681
8681
|
// app/lib/file-delete-cascade.ts
|
|
8682
8682
|
var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
8683
|
-
function parseAttachmentPath(
|
|
8684
|
-
const segments =
|
|
8683
|
+
function parseAttachmentPath(relPath) {
|
|
8684
|
+
const segments = relPath.split("/").filter(Boolean);
|
|
8685
8685
|
if (segments.length !== 4) return null;
|
|
8686
8686
|
if (segments[0] !== "uploads") return null;
|
|
8687
8687
|
const accountId = segments[1];
|
|
@@ -9246,9 +9246,9 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
9246
9246
|
}
|
|
9247
9247
|
}
|
|
9248
9248
|
}
|
|
9249
|
-
function buildDisplayPath(
|
|
9250
|
-
if (
|
|
9251
|
-
return
|
|
9249
|
+
function buildDisplayPath(relPath, accountNames) {
|
|
9250
|
+
if (relPath === "." || relPath === "") return [];
|
|
9251
|
+
return relPath.split("/").filter(Boolean).map((seg) => {
|
|
9252
9252
|
const dn = UUID_RE3.test(seg) ? accountNames.get(seg) : void 0;
|
|
9253
9253
|
return dn ? { name: seg, displayName: dn } : { name: seg };
|
|
9254
9254
|
});
|
|
@@ -9286,9 +9286,9 @@ app15.get("/", requireAdminSession, async (c) => {
|
|
|
9286
9286
|
}
|
|
9287
9287
|
return c.json({ error: resolution.error }, resolution.status);
|
|
9288
9288
|
}
|
|
9289
|
-
const { absolute, relative:
|
|
9290
|
-
if (crossesForeignAccountPartition(
|
|
9291
|
-
console.error(`[data] account-scope-blocked endpoint="/api/admin/files" path="${
|
|
9289
|
+
const { absolute, relative: relPath } = resolution;
|
|
9290
|
+
if (crossesForeignAccountPartition(relPath, accountId)) {
|
|
9291
|
+
console.error(`[data] account-scope-blocked endpoint="/api/admin/files" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
9292
9292
|
return c.json({ error: "Not found" }, 404);
|
|
9293
9293
|
}
|
|
9294
9294
|
try {
|
|
@@ -9297,7 +9297,7 @@ app15.get("/", requireAdminSession, async (c) => {
|
|
|
9297
9297
|
return c.json({ error: "Path is not a directory \u2014 use /api/admin/files/download for files" }, 400);
|
|
9298
9298
|
}
|
|
9299
9299
|
const names = await readdir3(absolute);
|
|
9300
|
-
const segs =
|
|
9300
|
+
const segs = relPath.split("/").filter(Boolean);
|
|
9301
9301
|
const isAccountParent = segs.length === 1 && (segs[0] === "accounts" || segs[0] === "uploads");
|
|
9302
9302
|
const entries = [];
|
|
9303
9303
|
for (const name of names) {
|
|
@@ -9328,17 +9328,17 @@ app15.get("/", requireAdminSession, async (c) => {
|
|
|
9328
9328
|
const bKey = b.displayName ?? b.name;
|
|
9329
9329
|
return aKey.localeCompare(bKey);
|
|
9330
9330
|
});
|
|
9331
|
-
const displayPath = buildDisplayPath(
|
|
9332
|
-
console.error(`[data] file-list path="${
|
|
9333
|
-
return c.json({ path:
|
|
9331
|
+
const displayPath = buildDisplayPath(relPath, accountNames);
|
|
9332
|
+
console.error(`[data] file-list path="${relPath}" entries=${entries.length}`);
|
|
9333
|
+
return c.json({ path: relPath, displayPath, entries });
|
|
9334
9334
|
} catch (err) {
|
|
9335
9335
|
const code = err.code;
|
|
9336
9336
|
if (code === "ENOENT") {
|
|
9337
|
-
console.error(`[data] file-list not-found path="${
|
|
9337
|
+
console.error(`[data] file-list not-found path="${relPath}"`);
|
|
9338
9338
|
return c.json({ error: "Not found" }, 404);
|
|
9339
9339
|
}
|
|
9340
9340
|
const message = err instanceof Error ? err.message : String(err);
|
|
9341
|
-
console.error(`[data] file-list error path="${
|
|
9341
|
+
console.error(`[data] file-list error path="${relPath}" err="${message}"`);
|
|
9342
9342
|
return c.json({ error: message }, 500);
|
|
9343
9343
|
}
|
|
9344
9344
|
});
|
|
@@ -9362,16 +9362,16 @@ app15.get("/download", requireAdminSession, async (c) => {
|
|
|
9362
9362
|
}
|
|
9363
9363
|
return c.json({ error: resolution.error }, resolution.status);
|
|
9364
9364
|
}
|
|
9365
|
-
const { absolute, relative:
|
|
9365
|
+
const { absolute, relative: relPath } = resolution;
|
|
9366
9366
|
if (root === "claude-uploads") {
|
|
9367
|
-
const attachmentId =
|
|
9367
|
+
const attachmentId = relPath.split("/").filter(Boolean)[0] ?? "";
|
|
9368
9368
|
const owned = await knowledgeDocOwnedByAccount(accountId, attachmentId);
|
|
9369
9369
|
if (!owned) {
|
|
9370
9370
|
console.error(`[data] account-scope-blocked root="claude-uploads" attachmentId="${attachmentId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
|
|
9371
9371
|
return c.json({ error: "Not found" }, 404);
|
|
9372
9372
|
}
|
|
9373
|
-
} else if (crossesForeignAccountPartition(
|
|
9374
|
-
console.error(`[data] account-scope-blocked endpoint="/api/admin/files/download" path="${
|
|
9373
|
+
} else if (crossesForeignAccountPartition(relPath, accountId)) {
|
|
9374
|
+
console.error(`[data] account-scope-blocked endpoint="/api/admin/files/download" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
9375
9375
|
return c.json({ error: "Not found" }, 404);
|
|
9376
9376
|
}
|
|
9377
9377
|
try {
|
|
@@ -9383,7 +9383,7 @@ app15.get("/download", requireAdminSession, async (c) => {
|
|
|
9383
9383
|
const mimeType = detectMimeType(absolute);
|
|
9384
9384
|
const nodeStream = createReadStream2(absolute);
|
|
9385
9385
|
const webStream = Readable2.toWeb(nodeStream);
|
|
9386
|
-
console.error(`[data] file-download root="${root}" path="${
|
|
9386
|
+
console.error(`[data] file-download root="${root}" path="${relPath}" size=${info.size}`);
|
|
9387
9387
|
const safeQuotedName = filename.replace(/[\r\n"\\]/g, "_");
|
|
9388
9388
|
const encodedName = encodeURIComponent(filename);
|
|
9389
9389
|
return new Response(webStream, {
|
|
@@ -9398,11 +9398,11 @@ app15.get("/download", requireAdminSession, async (c) => {
|
|
|
9398
9398
|
} catch (err) {
|
|
9399
9399
|
const code = err.code;
|
|
9400
9400
|
if (code === "ENOENT") {
|
|
9401
|
-
console.error(`[data] file-download not-found path="${
|
|
9401
|
+
console.error(`[data] file-download not-found path="${relPath}"`);
|
|
9402
9402
|
return c.json({ error: "Not found" }, 404);
|
|
9403
9403
|
}
|
|
9404
9404
|
const message = err instanceof Error ? err.message : String(err);
|
|
9405
|
-
console.error(`[data] file-download error path="${
|
|
9405
|
+
console.error(`[data] file-download error path="${relPath}" err="${message}"`);
|
|
9406
9406
|
return c.json({ error: message }, 500);
|
|
9407
9407
|
}
|
|
9408
9408
|
});
|
|
@@ -9483,15 +9483,15 @@ app15.delete("/", requireAdminSession, async (c) => {
|
|
|
9483
9483
|
}
|
|
9484
9484
|
return c.json({ error: resolution.error }, resolution.status);
|
|
9485
9485
|
}
|
|
9486
|
-
const { absolute, relative:
|
|
9487
|
-
if (crossesForeignAccountPartition(
|
|
9488
|
-
console.error(`[data] account-scope-blocked endpoint="DELETE /api/admin/files" path="${
|
|
9486
|
+
const { absolute, relative: relPath } = resolution;
|
|
9487
|
+
if (crossesForeignAccountPartition(relPath, accountId)) {
|
|
9488
|
+
console.error(`[data] account-scope-blocked endpoint="DELETE /api/admin/files" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
9489
9489
|
return c.json({ error: "Not found" }, 404);
|
|
9490
9490
|
}
|
|
9491
9491
|
const base = basename4(absolute);
|
|
9492
|
-
const segments =
|
|
9492
|
+
const segments = relPath.split("/").filter(Boolean);
|
|
9493
9493
|
if (base === "account.json" || segments.includes(".git")) {
|
|
9494
|
-
console.error(`[data] file-delete blocked path="${
|
|
9494
|
+
console.error(`[data] file-delete blocked path="${relPath}" reason="protected"`);
|
|
9495
9495
|
return c.json({ error: "Protected file \u2014 refusing to delete" }, 403);
|
|
9496
9496
|
}
|
|
9497
9497
|
try {
|
|
@@ -9512,34 +9512,34 @@ app15.delete("/", requireAdminSession, async (c) => {
|
|
|
9512
9512
|
} catch {
|
|
9513
9513
|
}
|
|
9514
9514
|
}
|
|
9515
|
-
console.error(`[data] file-delete path="${
|
|
9515
|
+
console.error(`[data] file-delete path="${relPath}" bytes=${info.size}`);
|
|
9516
9516
|
try {
|
|
9517
|
-
await dropFileIndex(accountId,
|
|
9517
|
+
await dropFileIndex(accountId, relPath);
|
|
9518
9518
|
} catch (err) {
|
|
9519
|
-
console.error(`[data] file-delete index-drop-failed path="${
|
|
9519
|
+
console.error(`[data] file-delete index-drop-failed path="${relPath}" err="${err instanceof Error ? err.message : String(err)}"`);
|
|
9520
9520
|
}
|
|
9521
|
-
const parsed = parseAttachmentPath(
|
|
9521
|
+
const parsed = parseAttachmentPath(relPath);
|
|
9522
9522
|
if (parsed) {
|
|
9523
9523
|
try {
|
|
9524
9524
|
const { nodes } = await cascadeDeleteDocument({
|
|
9525
9525
|
accountId,
|
|
9526
9526
|
attachmentId: parsed.attachmentId
|
|
9527
9527
|
});
|
|
9528
|
-
console.error(`[data] file-delete graph-cascade path="${
|
|
9528
|
+
console.error(`[data] file-delete graph-cascade path="${relPath}" nodes=${nodes}`);
|
|
9529
9529
|
} catch (err) {
|
|
9530
9530
|
const message = err instanceof Error ? err.message : String(err);
|
|
9531
|
-
console.error(`[data] file-delete graph-cascade-failed path="${
|
|
9531
|
+
console.error(`[data] file-delete graph-cascade-failed path="${relPath}" err="${message}"`);
|
|
9532
9532
|
}
|
|
9533
9533
|
}
|
|
9534
9534
|
return c.json({ ok: true });
|
|
9535
9535
|
} catch (err) {
|
|
9536
9536
|
const code = err.code;
|
|
9537
9537
|
if (code === "ENOENT") {
|
|
9538
|
-
console.error(`[data] file-delete not-found path="${
|
|
9538
|
+
console.error(`[data] file-delete not-found path="${relPath}"`);
|
|
9539
9539
|
return c.json({ error: "Not found" }, 404);
|
|
9540
9540
|
}
|
|
9541
9541
|
const message = err instanceof Error ? err.message : String(err);
|
|
9542
|
-
console.error(`[data] file-delete error path="${
|
|
9542
|
+
console.error(`[data] file-delete error path="${relPath}" err="${message}"`);
|
|
9543
9543
|
return c.json({ error: message }, 500);
|
|
9544
9544
|
}
|
|
9545
9545
|
});
|
|
@@ -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(",");
|
|
@@ -11601,7 +11601,6 @@ async function fetchOutputArtefacts(accountId) {
|
|
|
11601
11601
|
name: displayName ?? basename5(relativePath),
|
|
11602
11602
|
kind: "output-file",
|
|
11603
11603
|
updatedAt: modifiedAt,
|
|
11604
|
-
editable: false,
|
|
11605
11604
|
mimeType,
|
|
11606
11605
|
downloadPath: relativePath,
|
|
11607
11606
|
downloadRoot: "data"
|
|
@@ -11628,8 +11627,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
11628
11627
|
overridePath,
|
|
11629
11628
|
overrideRoot: accountDir,
|
|
11630
11629
|
bundledPath,
|
|
11631
|
-
bundledRoot: PLATFORM_ROOT
|
|
11632
|
-
editable: true
|
|
11630
|
+
bundledRoot: PLATFORM_ROOT
|
|
11633
11631
|
});
|
|
11634
11632
|
if (row) rows.push(row);
|
|
11635
11633
|
}
|
|
@@ -11646,8 +11644,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
11646
11644
|
overridePath,
|
|
11647
11645
|
overrideRoot: accountDir,
|
|
11648
11646
|
bundledPath,
|
|
11649
|
-
bundledRoot: PLATFORM_ROOT
|
|
11650
|
-
editable: false
|
|
11647
|
+
bundledRoot: PLATFORM_ROOT
|
|
11651
11648
|
});
|
|
11652
11649
|
if (row) rows.push(row);
|
|
11653
11650
|
}
|
|
@@ -11700,7 +11697,6 @@ async function readAgentTemplateRow(inp) {
|
|
|
11700
11697
|
name: inp.displayName,
|
|
11701
11698
|
kind: "agent-template",
|
|
11702
11699
|
updatedAt: st.mtime.toISOString(),
|
|
11703
|
-
editable: inp.editable,
|
|
11704
11700
|
mimeType: "text/markdown",
|
|
11705
11701
|
// Override paths live under <accountDir> (inside DATA_ROOT) and are
|
|
11706
11702
|
// downloadable; bundled-fallback templates live under PLATFORM_ROOT
|
|
@@ -11724,83 +11720,13 @@ function isWithin(target, root) {
|
|
|
11724
11720
|
}
|
|
11725
11721
|
var sidebar_artefacts_default = app22;
|
|
11726
11722
|
|
|
11727
|
-
// server/routes/admin/sidebar-artefact-save.ts
|
|
11728
|
-
import { mkdir as mkdir4, stat as stat6, writeFile as writeFile5 } from "fs/promises";
|
|
11729
|
-
import { resolve as resolve16 } from "path";
|
|
11730
|
-
var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
|
|
11731
|
-
var app23 = new Hono();
|
|
11732
|
-
app23.post("/", requireAdminSession, async (c) => {
|
|
11733
|
-
const cacheKey = c.var.cacheKey;
|
|
11734
|
-
const accountId = getAccountIdForSession(cacheKey);
|
|
11735
|
-
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
11736
|
-
const body = await safeJson(c);
|
|
11737
|
-
if (!body || typeof body.id !== "string" || typeof body.content !== "string") {
|
|
11738
|
-
return c.json({ error: "id and content required" }, 400);
|
|
11739
|
-
}
|
|
11740
|
-
const accountDir = resolve16(ACCOUNTS_DIR, accountId);
|
|
11741
|
-
const resolved = await resolveSavePath(body.id, accountDir);
|
|
11742
|
-
if (resolved.kind === "reject") {
|
|
11743
|
-
console.error(
|
|
11744
|
-
`[admin/sidebar-artefact-save] auth-rejected reason=${resolved.reason} path=${body.id}`
|
|
11745
|
-
);
|
|
11746
|
-
return c.json({ error: resolved.reason }, resolved.status);
|
|
11747
|
-
}
|
|
11748
|
-
const start = Date.now();
|
|
11749
|
-
try {
|
|
11750
|
-
await writeFile5(resolved.path, body.content, "utf-8");
|
|
11751
|
-
} catch (err) {
|
|
11752
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
11753
|
-
console.error(
|
|
11754
|
-
`[admin/sidebar-artefact-save] write-failed path=${relPath(resolved.path, accountDir)} error="${message}"`
|
|
11755
|
-
);
|
|
11756
|
-
return c.json({ error: "Write failed" }, 500);
|
|
11757
|
-
}
|
|
11758
|
-
let updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
11759
|
-
try {
|
|
11760
|
-
const st = await stat6(resolved.path);
|
|
11761
|
-
updatedAt = st.mtime.toISOString();
|
|
11762
|
-
} catch {
|
|
11763
|
-
}
|
|
11764
|
-
const ms = Date.now() - start;
|
|
11765
|
-
console.log(
|
|
11766
|
-
`[admin/sidebar-artefact-save] account=${accountId} path=${relPath(resolved.path, accountDir)} bytes=${body.content.length} ms=${ms}`
|
|
11767
|
-
);
|
|
11768
|
-
return c.json({ updatedAt });
|
|
11769
|
-
});
|
|
11770
|
-
async function resolveSavePath(id, accountDir) {
|
|
11771
|
-
if (!id.startsWith("agent-template:")) {
|
|
11772
|
-
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11773
|
-
}
|
|
11774
|
-
const parts = id.split(":");
|
|
11775
|
-
if (parts.length !== 3) return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11776
|
-
const [, role, filename] = parts;
|
|
11777
|
-
if (role === "specialist") {
|
|
11778
|
-
return { kind: "reject", status: 403, reason: "specialist-write-blocked" };
|
|
11779
|
-
}
|
|
11780
|
-
if (role !== "admin" || !ADMIN_AGENT_FILES2.has(filename)) {
|
|
11781
|
-
return { kind: "reject", status: 400, reason: "invalid-id" };
|
|
11782
|
-
}
|
|
11783
|
-
const parent = resolve16(accountDir, "agents", "admin");
|
|
11784
|
-
await mkdir4(parent, { recursive: true });
|
|
11785
|
-
try {
|
|
11786
|
-
validateFilePathInAccount(parent, accountDir);
|
|
11787
|
-
} catch {
|
|
11788
|
-
return { kind: "reject", status: 400, reason: "containment-rejected" };
|
|
11789
|
-
}
|
|
11790
|
-
return { kind: "admin-template", path: resolve16(parent, filename) };
|
|
11791
|
-
}
|
|
11792
|
-
function relPath(absPath, root) {
|
|
11793
|
-
return absPath.startsWith(root) ? absPath.slice(root.length + 1) : absPath;
|
|
11794
|
-
}
|
|
11795
|
-
var sidebar_artefact_save_default = app23;
|
|
11796
|
-
|
|
11797
11723
|
// server/routes/admin/sidebar-sessions.ts
|
|
11798
11724
|
import { readdirSync as readdirSync8, readFileSync as readFileSync14, statSync as statSync7 } from "fs";
|
|
11799
11725
|
import { join as join13 } from "path";
|
|
11800
|
-
var RC_URL_RE = /https:\/\/claude\.ai\/code\/session_[A-Za-z0-9_-]+/;
|
|
11801
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$/;
|
|
11802
11728
|
var TITLE_MAX = 80;
|
|
11803
|
-
var
|
|
11729
|
+
var app23 = new Hono();
|
|
11804
11730
|
function claudeConfigDir() {
|
|
11805
11731
|
return process.env.CLAUDE_CONFIG_DIR ?? null;
|
|
11806
11732
|
}
|
|
@@ -11846,8 +11772,8 @@ function enumerateJsonls(projectsRoot) {
|
|
|
11846
11772
|
}
|
|
11847
11773
|
return out;
|
|
11848
11774
|
}
|
|
11849
|
-
function
|
|
11850
|
-
const out = /* @__PURE__ */ new
|
|
11775
|
+
function sessionIdToPidMap(configDir2) {
|
|
11776
|
+
const out = /* @__PURE__ */ new Map();
|
|
11851
11777
|
const sessionsDir = join13(configDir2, "sessions");
|
|
11852
11778
|
let entries;
|
|
11853
11779
|
try {
|
|
@@ -11856,7 +11782,11 @@ function liveSessionIdSet(configDir2) {
|
|
|
11856
11782
|
return out;
|
|
11857
11783
|
}
|
|
11858
11784
|
for (const entry of entries) {
|
|
11859
|
-
if (!entry.isFile()
|
|
11785
|
+
if (!entry.isFile()) continue;
|
|
11786
|
+
const m = entry.name.match(PID_FILE_RE);
|
|
11787
|
+
if (!m) continue;
|
|
11788
|
+
const pid = Number(m[1]);
|
|
11789
|
+
if (!Number.isFinite(pid) || pid <= 0) continue;
|
|
11860
11790
|
let body;
|
|
11861
11791
|
try {
|
|
11862
11792
|
body = readFileSync14(join13(sessionsDir, entry.name), "utf8");
|
|
@@ -11871,7 +11801,7 @@ function liveSessionIdSet(configDir2) {
|
|
|
11871
11801
|
}
|
|
11872
11802
|
if (!parsed || typeof parsed !== "object") continue;
|
|
11873
11803
|
const sid = parsed.sessionId;
|
|
11874
|
-
if (typeof sid === "string" && sid.length > 0) out.
|
|
11804
|
+
if (typeof sid === "string" && sid.length > 0) out.set(sid, pid);
|
|
11875
11805
|
}
|
|
11876
11806
|
return out;
|
|
11877
11807
|
}
|
|
@@ -11895,22 +11825,24 @@ function firstUserMessage(body) {
|
|
|
11895
11825
|
}
|
|
11896
11826
|
return null;
|
|
11897
11827
|
}
|
|
11898
|
-
|
|
11828
|
+
app23.get("/", requireAdminSession, async (c) => {
|
|
11829
|
+
const accountId = process.env.ACCOUNT_ID ?? null;
|
|
11899
11830
|
const configDir2 = claudeConfigDir();
|
|
11900
11831
|
if (!configDir2) {
|
|
11901
11832
|
console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
|
|
11902
|
-
return c.json({ sessions: [] });
|
|
11833
|
+
return c.json({ sessions: [], accountId });
|
|
11903
11834
|
}
|
|
11904
11835
|
const projectsRoot = join13(configDir2, "projects");
|
|
11905
11836
|
const jsonls = enumerateJsonls(projectsRoot);
|
|
11906
|
-
const
|
|
11837
|
+
const pidsBySession = sessionIdToPidMap(configDir2);
|
|
11907
11838
|
const rows = [];
|
|
11908
11839
|
const seenIds = /* @__PURE__ */ new Set();
|
|
11909
11840
|
let liveCount = 0;
|
|
11910
|
-
let rcCount = 0;
|
|
11911
11841
|
let subagentCount = 0;
|
|
11912
11842
|
for (const { path: path2, isSubagent } of jsonls) {
|
|
11913
|
-
const
|
|
11843
|
+
const lastSlash = path2.lastIndexOf("/");
|
|
11844
|
+
const base = path2.slice(lastSlash + 1);
|
|
11845
|
+
const projectDir = path2.slice(0, lastSlash);
|
|
11914
11846
|
const sessionId = base.slice(0, -".jsonl".length);
|
|
11915
11847
|
if (seenIds.has(sessionId)) {
|
|
11916
11848
|
console.error(`[admin-sessions-list] duplicate-sessionId sessionId=${sessionId} path=${path2}`);
|
|
@@ -11925,29 +11857,175 @@ app24.get("/", requireAdminSession, async (c) => {
|
|
|
11925
11857
|
} catch {
|
|
11926
11858
|
continue;
|
|
11927
11859
|
}
|
|
11928
|
-
const
|
|
11929
|
-
const live =
|
|
11860
|
+
const pid = pidsBySession.get(sessionId) ?? null;
|
|
11861
|
+
const live = pid !== null;
|
|
11930
11862
|
const title = firstUserMessage(body) ?? sessionId.slice(0, 8);
|
|
11931
|
-
|
|
11863
|
+
rows.push({
|
|
11932
11864
|
sessionId,
|
|
11933
11865
|
title,
|
|
11934
11866
|
startedAt: new Date(mtimeMs).toISOString(),
|
|
11935
11867
|
live,
|
|
11936
|
-
isSubagent
|
|
11937
|
-
|
|
11938
|
-
|
|
11939
|
-
|
|
11868
|
+
isSubagent,
|
|
11869
|
+
pid,
|
|
11870
|
+
projectDir
|
|
11871
|
+
});
|
|
11940
11872
|
if (live) liveCount += 1;
|
|
11941
|
-
if (urlMatch) rcCount += 1;
|
|
11942
11873
|
if (isSubagent) subagentCount += 1;
|
|
11943
11874
|
}
|
|
11944
11875
|
rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
|
|
11945
11876
|
console.log(
|
|
11946
|
-
`[admin-sessions-list] rows=${rows.length} live=${liveCount}
|
|
11877
|
+
`[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
|
|
11947
11878
|
);
|
|
11948
|
-
return c.json({ sessions: rows });
|
|
11879
|
+
return c.json({ sessions: rows, accountId });
|
|
11949
11880
|
});
|
|
11950
|
-
var sidebar_sessions_default =
|
|
11881
|
+
var sidebar_sessions_default = app23;
|
|
11882
|
+
|
|
11883
|
+
// server/routes/admin/session-delete.ts
|
|
11884
|
+
import { existsSync as existsSync17, readdirSync as readdirSync9, readFileSync as readFileSync15, unlinkSync as unlinkSync2 } from "fs";
|
|
11885
|
+
import { join as join14, resolve as resolve16 } from "path";
|
|
11886
|
+
var app24 = new Hono();
|
|
11887
|
+
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;
|
|
11888
|
+
var PID_FILE_RE2 = /^([0-9]+)\.json$/;
|
|
11889
|
+
function findPidForSession(configDir2, sessionId) {
|
|
11890
|
+
const sessionsDir = join14(configDir2, "sessions");
|
|
11891
|
+
let entries;
|
|
11892
|
+
try {
|
|
11893
|
+
entries = readdirSync9(sessionsDir, { withFileTypes: true });
|
|
11894
|
+
} catch {
|
|
11895
|
+
return null;
|
|
11896
|
+
}
|
|
11897
|
+
for (const entry of entries) {
|
|
11898
|
+
if (!entry.isFile()) continue;
|
|
11899
|
+
const m = entry.name.match(PID_FILE_RE2);
|
|
11900
|
+
if (!m) continue;
|
|
11901
|
+
const pid = Number(m[1]);
|
|
11902
|
+
if (!Number.isFinite(pid) || pid <= 0) continue;
|
|
11903
|
+
let body;
|
|
11904
|
+
try {
|
|
11905
|
+
body = readFileSync15(join14(sessionsDir, entry.name), "utf8");
|
|
11906
|
+
} catch {
|
|
11907
|
+
continue;
|
|
11908
|
+
}
|
|
11909
|
+
let parsed;
|
|
11910
|
+
try {
|
|
11911
|
+
parsed = JSON.parse(body);
|
|
11912
|
+
} catch {
|
|
11913
|
+
continue;
|
|
11914
|
+
}
|
|
11915
|
+
if (!parsed || typeof parsed !== "object") continue;
|
|
11916
|
+
if (parsed.sessionId === sessionId) return pid;
|
|
11917
|
+
}
|
|
11918
|
+
return null;
|
|
11919
|
+
}
|
|
11920
|
+
function killBestEffort(pid) {
|
|
11921
|
+
try {
|
|
11922
|
+
process.kill(pid, "SIGTERM");
|
|
11923
|
+
return true;
|
|
11924
|
+
} catch {
|
|
11925
|
+
return false;
|
|
11926
|
+
}
|
|
11927
|
+
}
|
|
11928
|
+
app24.post("/", requireAdminSession, async (c) => {
|
|
11929
|
+
let body;
|
|
11930
|
+
try {
|
|
11931
|
+
body = await c.req.json();
|
|
11932
|
+
} catch {
|
|
11933
|
+
return c.json({ error: "invalid JSON body" }, 400);
|
|
11934
|
+
}
|
|
11935
|
+
const sessionId = typeof body.sessionId === "string" ? body.sessionId : "";
|
|
11936
|
+
const projectDir = typeof body.projectDir === "string" ? body.projectDir : "";
|
|
11937
|
+
if (!SESSION_ID_RE2.test(sessionId)) {
|
|
11938
|
+
return c.json({ error: "sessionId must be a v4 UUID" }, 400);
|
|
11939
|
+
}
|
|
11940
|
+
if (!projectDir) {
|
|
11941
|
+
return c.json({ error: "projectDir is required" }, 400);
|
|
11942
|
+
}
|
|
11943
|
+
const configDir2 = process.env.CLAUDE_CONFIG_DIR;
|
|
11944
|
+
if (!configDir2) {
|
|
11945
|
+
return c.json({ error: "CLAUDE_CONFIG_DIR not set" }, 500);
|
|
11946
|
+
}
|
|
11947
|
+
const projectsRoot = resolve16(join14(configDir2, "projects")) + "/";
|
|
11948
|
+
const resolvedProject = resolve16(projectDir) + "/";
|
|
11949
|
+
if (!resolvedProject.startsWith(projectsRoot)) {
|
|
11950
|
+
console.error(`[sessions-delete] reject reason=projectDir-outside-tree projectDir=${projectDir}`);
|
|
11951
|
+
return c.json({ error: "projectDir is not under CLAUDE_CONFIG_DIR/projects/" }, 400);
|
|
11952
|
+
}
|
|
11953
|
+
const jsonlPath = join14(projectDir, `${sessionId}.jsonl`);
|
|
11954
|
+
const sidecarPath = join14(projectDir, `${sessionId}.meta.json`);
|
|
11955
|
+
const pid = findPidForSession(configDir2, sessionId);
|
|
11956
|
+
let pidKilled;
|
|
11957
|
+
if (pid === null) {
|
|
11958
|
+
pidKilled = "absent";
|
|
11959
|
+
} else {
|
|
11960
|
+
pidKilled = killBestEffort(pid) ? "true" : "false";
|
|
11961
|
+
}
|
|
11962
|
+
let deleted = false;
|
|
11963
|
+
try {
|
|
11964
|
+
if (existsSync17(jsonlPath)) {
|
|
11965
|
+
unlinkSync2(jsonlPath);
|
|
11966
|
+
deleted = true;
|
|
11967
|
+
}
|
|
11968
|
+
} catch (err) {
|
|
11969
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
11970
|
+
console.error(`[sessions-delete] unlink-failed path=${jsonlPath} err=${msg}`);
|
|
11971
|
+
console.log(
|
|
11972
|
+
`[sessions-delete] sessionId=${sessionId} pidKilled=${pidKilled} jsonlPath=${jsonlPath} deleted=false`
|
|
11973
|
+
);
|
|
11974
|
+
return c.json({ error: `unlink failed: ${msg}` }, 500);
|
|
11975
|
+
}
|
|
11976
|
+
try {
|
|
11977
|
+
if (existsSync17(sidecarPath)) unlinkSync2(sidecarPath);
|
|
11978
|
+
} catch {
|
|
11979
|
+
}
|
|
11980
|
+
console.log(
|
|
11981
|
+
`[sessions-delete] sessionId=${sessionId} pidKilled=${pidKilled} jsonlPath=${jsonlPath} deleted=${deleted}`
|
|
11982
|
+
);
|
|
11983
|
+
return c.json({ deleted, pidKilled, jsonlPath });
|
|
11984
|
+
});
|
|
11985
|
+
var session_delete_default = app24;
|
|
11986
|
+
|
|
11987
|
+
// server/routes/admin/session-rc-spawn.ts
|
|
11988
|
+
var app25 = new Hono();
|
|
11989
|
+
function managerBase4() {
|
|
11990
|
+
const port2 = process.env.CLAUDE_SESSION_MANAGER_PORT;
|
|
11991
|
+
if (!port2) throw new Error("CLAUDE_SESSION_MANAGER_PORT is not set");
|
|
11992
|
+
return `http://127.0.0.1:${port2}`;
|
|
11993
|
+
}
|
|
11994
|
+
app25.post("/", requireAdminSession, async (c) => {
|
|
11995
|
+
let body;
|
|
11996
|
+
try {
|
|
11997
|
+
body = await c.req.json();
|
|
11998
|
+
} catch {
|
|
11999
|
+
body = {};
|
|
12000
|
+
}
|
|
12001
|
+
const payload = {};
|
|
12002
|
+
if (typeof body.sessionId === "string" && body.sessionId.length > 0) payload.sessionId = body.sessionId;
|
|
12003
|
+
if (typeof body.name === "string" && body.name.length > 0) payload.name = body.name;
|
|
12004
|
+
let res;
|
|
12005
|
+
try {
|
|
12006
|
+
res = await fetch(`${managerBase4()}/rc-spawn`, {
|
|
12007
|
+
method: "POST",
|
|
12008
|
+
headers: { "content-type": "application/json" },
|
|
12009
|
+
body: JSON.stringify(payload)
|
|
12010
|
+
});
|
|
12011
|
+
} catch (err) {
|
|
12012
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
12013
|
+
console.error(`[session-rc-spawn] manager-unreachable err=${msg}`);
|
|
12014
|
+
return c.json({ error: `session manager unreachable: ${msg}` }, 502);
|
|
12015
|
+
}
|
|
12016
|
+
const text = await res.text();
|
|
12017
|
+
let parsed = null;
|
|
12018
|
+
try {
|
|
12019
|
+
parsed = JSON.parse(text);
|
|
12020
|
+
} catch {
|
|
12021
|
+
}
|
|
12022
|
+
if (!res.ok) {
|
|
12023
|
+
console.error(`[session-rc-spawn] manager-error status=${res.status} body=${text.slice(0, 200)}`);
|
|
12024
|
+
return c.json(parsed ?? { error: text }, res.status);
|
|
12025
|
+
}
|
|
12026
|
+
return c.json(parsed ?? {});
|
|
12027
|
+
});
|
|
12028
|
+
var session_rc_spawn_default = app25;
|
|
11951
12029
|
|
|
11952
12030
|
// server/routes/admin/system-stats.ts
|
|
11953
12031
|
import { readFile as readFile5 } from "fs/promises";
|
|
@@ -12044,8 +12122,8 @@ async function sample() {
|
|
|
12044
12122
|
if (process.platform === "linux") return sampleLinux();
|
|
12045
12123
|
return sampleOsFallback();
|
|
12046
12124
|
}
|
|
12047
|
-
var
|
|
12048
|
-
|
|
12125
|
+
var app26 = new Hono();
|
|
12126
|
+
app26.get("/", async (c) => {
|
|
12049
12127
|
const started = Date.now();
|
|
12050
12128
|
if (!inflight) {
|
|
12051
12129
|
inflight = sample().finally(() => {
|
|
@@ -12068,17 +12146,17 @@ app25.get("/", async (c) => {
|
|
|
12068
12146
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
12069
12147
|
}
|
|
12070
12148
|
});
|
|
12071
|
-
var system_stats_default =
|
|
12149
|
+
var system_stats_default = app26;
|
|
12072
12150
|
|
|
12073
12151
|
// server/routes/admin/health.ts
|
|
12074
|
-
import { existsSync as
|
|
12075
|
-
import { resolve as resolve17, join as
|
|
12152
|
+
import { existsSync as existsSync18, readFileSync as readFileSync16 } from "fs";
|
|
12153
|
+
import { resolve as resolve17, join as join15 } from "path";
|
|
12076
12154
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
|
|
12077
12155
|
var brandHostname = "maxy";
|
|
12078
|
-
var brandJsonPath =
|
|
12079
|
-
if (
|
|
12156
|
+
var brandJsonPath = join15(PLATFORM_ROOT6, "config", "brand.json");
|
|
12157
|
+
if (existsSync18(brandJsonPath)) {
|
|
12080
12158
|
try {
|
|
12081
|
-
const brand = JSON.parse(
|
|
12159
|
+
const brand = JSON.parse(readFileSync16(brandJsonPath, "utf-8"));
|
|
12082
12160
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
12083
12161
|
} catch {
|
|
12084
12162
|
}
|
|
@@ -12087,8 +12165,8 @@ var VERSION_FILE = resolve17(PLATFORM_ROOT6, `config/.${brandHostname}-version`)
|
|
|
12087
12165
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
12088
12166
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
12089
12167
|
function readVersion() {
|
|
12090
|
-
if (!
|
|
12091
|
-
return
|
|
12168
|
+
if (!existsSync18(VERSION_FILE)) return "unknown";
|
|
12169
|
+
return readFileSync16(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
12092
12170
|
}
|
|
12093
12171
|
async function probeConversationDb() {
|
|
12094
12172
|
let session;
|
|
@@ -12113,8 +12191,8 @@ async function probeConversationDb() {
|
|
|
12113
12191
|
});
|
|
12114
12192
|
}
|
|
12115
12193
|
}
|
|
12116
|
-
var
|
|
12117
|
-
|
|
12194
|
+
var app27 = new Hono();
|
|
12195
|
+
app27.get("/", async (c) => {
|
|
12118
12196
|
const version = readVersion();
|
|
12119
12197
|
const probe = await probeConversationDb();
|
|
12120
12198
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -12136,7 +12214,7 @@ app26.get("/", async (c) => {
|
|
|
12136
12214
|
uptimeMs
|
|
12137
12215
|
});
|
|
12138
12216
|
});
|
|
12139
|
-
var health_default2 =
|
|
12217
|
+
var health_default2 = app27;
|
|
12140
12218
|
|
|
12141
12219
|
// server/routes/admin/linkedin-ingest.ts
|
|
12142
12220
|
var TAG20 = "[linkedin-ingest-route]";
|
|
@@ -12232,8 +12310,8 @@ function buildInitialMessage(env) {
|
|
|
12232
12310
|
}
|
|
12233
12311
|
return header;
|
|
12234
12312
|
}
|
|
12235
|
-
var
|
|
12236
|
-
|
|
12313
|
+
var app28 = new Hono();
|
|
12314
|
+
app28.post("/", requireAdminSession, async (c) => {
|
|
12237
12315
|
let body;
|
|
12238
12316
|
try {
|
|
12239
12317
|
body = await c.req.json();
|
|
@@ -12287,7 +12365,7 @@ app27.post("/", requireAdminSession, async (c) => {
|
|
|
12287
12365
|
);
|
|
12288
12366
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: claudeSessionId }, 202);
|
|
12289
12367
|
});
|
|
12290
|
-
var linkedin_ingest_default =
|
|
12368
|
+
var linkedin_ingest_default = app28;
|
|
12291
12369
|
|
|
12292
12370
|
// server/routes/admin/post-turn-context.ts
|
|
12293
12371
|
import neo4j2 from "neo4j-driver";
|
|
@@ -12329,8 +12407,8 @@ function pruneProperties(raw) {
|
|
|
12329
12407
|
}
|
|
12330
12408
|
return out;
|
|
12331
12409
|
}
|
|
12332
|
-
var
|
|
12333
|
-
|
|
12410
|
+
var app29 = new Hono();
|
|
12411
|
+
app29.get("/", async (c) => {
|
|
12334
12412
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12335
12413
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
12336
12414
|
console.error(`${TAG21} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12390,7 +12468,7 @@ app28.get("/", async (c) => {
|
|
|
12390
12468
|
await session.close();
|
|
12391
12469
|
}
|
|
12392
12470
|
});
|
|
12393
|
-
var post_turn_context_default =
|
|
12471
|
+
var post_turn_context_default = app29;
|
|
12394
12472
|
|
|
12395
12473
|
// server/routes/admin/public-session-context.ts
|
|
12396
12474
|
import neo4j3 from "neo4j-driver";
|
|
@@ -12432,8 +12510,8 @@ function pruneProperties2(raw) {
|
|
|
12432
12510
|
}
|
|
12433
12511
|
return out;
|
|
12434
12512
|
}
|
|
12435
|
-
var
|
|
12436
|
-
|
|
12513
|
+
var app30 = new Hono();
|
|
12514
|
+
app30.get("/", async (c) => {
|
|
12437
12515
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12438
12516
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
12439
12517
|
console.error(`${TAG22} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12492,15 +12570,15 @@ app29.get("/", async (c) => {
|
|
|
12492
12570
|
await session.close();
|
|
12493
12571
|
}
|
|
12494
12572
|
});
|
|
12495
|
-
var public_session_context_default =
|
|
12573
|
+
var public_session_context_default = app30;
|
|
12496
12574
|
|
|
12497
12575
|
// server/routes/admin/public-session-exit.ts
|
|
12498
12576
|
var TAG23 = "[public-session-exit-route]";
|
|
12499
12577
|
function isLoopbackAddr4(addr) {
|
|
12500
12578
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12501
12579
|
}
|
|
12502
|
-
var
|
|
12503
|
-
|
|
12580
|
+
var app31 = new Hono();
|
|
12581
|
+
app31.post("/", async (c) => {
|
|
12504
12582
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12505
12583
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
12506
12584
|
console.error(`${TAG23} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12527,15 +12605,15 @@ app30.post("/", async (c) => {
|
|
|
12527
12605
|
handlePublicSessionExit(sessionId);
|
|
12528
12606
|
return c.json({ ok: true });
|
|
12529
12607
|
});
|
|
12530
|
-
var public_session_exit_default =
|
|
12608
|
+
var public_session_exit_default = app31;
|
|
12531
12609
|
|
|
12532
12610
|
// server/routes/admin/access-session-evict.ts
|
|
12533
12611
|
var TAG24 = "[access-session-evict]";
|
|
12534
12612
|
function isLoopbackAddr5(addr) {
|
|
12535
12613
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
12536
12614
|
}
|
|
12537
|
-
var
|
|
12538
|
-
|
|
12615
|
+
var app32 = new Hono();
|
|
12616
|
+
app32.post("/", async (c) => {
|
|
12539
12617
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
12540
12618
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
12541
12619
|
console.error(`${TAG24} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
@@ -12563,41 +12641,42 @@ app31.post("/", async (c) => {
|
|
|
12563
12641
|
console.log(`${TAG24} grantId=${grantId} dropped=${dropped}`);
|
|
12564
12642
|
return c.json({ ok: true, dropped });
|
|
12565
12643
|
});
|
|
12566
|
-
var access_session_evict_default =
|
|
12644
|
+
var access_session_evict_default = app32;
|
|
12567
12645
|
|
|
12568
12646
|
// server/routes/admin/index.ts
|
|
12569
|
-
var
|
|
12570
|
-
|
|
12571
|
-
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12575
|
-
|
|
12576
|
-
|
|
12577
|
-
|
|
12578
|
-
|
|
12579
|
-
|
|
12580
|
-
|
|
12581
|
-
|
|
12582
|
-
|
|
12583
|
-
|
|
12584
|
-
|
|
12585
|
-
|
|
12586
|
-
|
|
12587
|
-
|
|
12588
|
-
|
|
12589
|
-
|
|
12590
|
-
|
|
12591
|
-
|
|
12592
|
-
|
|
12593
|
-
|
|
12594
|
-
|
|
12595
|
-
|
|
12596
|
-
|
|
12647
|
+
var app33 = new Hono();
|
|
12648
|
+
app33.route("/session", session_default);
|
|
12649
|
+
app33.route("/logs", logs_default);
|
|
12650
|
+
app33.route("/claude-info", claude_info_default);
|
|
12651
|
+
app33.route("/attachment", attachment_default);
|
|
12652
|
+
app33.route("/agents", agents_default);
|
|
12653
|
+
app33.route("/sessions", sessions_default);
|
|
12654
|
+
app33.route("/claude-sessions", claude_sessions_default);
|
|
12655
|
+
app33.route("/log-ingest", log_ingest_default);
|
|
12656
|
+
app33.route("/events", events_default);
|
|
12657
|
+
app33.route("/files", files_default);
|
|
12658
|
+
app33.route("/graph-search", graph_search_default);
|
|
12659
|
+
app33.route("/graph-subgraph", graph_subgraph_default);
|
|
12660
|
+
app33.route("/graph-delete", graph_delete_default);
|
|
12661
|
+
app33.route("/graph-restore", graph_restore_default);
|
|
12662
|
+
app33.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
12663
|
+
app33.route("/graph-default-view", graph_default_view_default);
|
|
12664
|
+
app33.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
12665
|
+
app33.route("/sidebar-sessions", sidebar_sessions_default);
|
|
12666
|
+
app33.route("/session-delete", session_delete_default);
|
|
12667
|
+
app33.route("/session-rc-spawn", session_rc_spawn_default);
|
|
12668
|
+
app33.route("/system-stats", system_stats_default);
|
|
12669
|
+
app33.route("/health-brand", health_default2);
|
|
12670
|
+
app33.route("/linkedin-ingest", linkedin_ingest_default);
|
|
12671
|
+
app33.route("/post-turn-context", post_turn_context_default);
|
|
12672
|
+
app33.route("/public-session-context", public_session_context_default);
|
|
12673
|
+
app33.route("/public-session-exit", public_session_exit_default);
|
|
12674
|
+
app33.route("/access-session-evict", access_session_evict_default);
|
|
12675
|
+
var admin_default = app33;
|
|
12597
12676
|
|
|
12598
12677
|
// app/lib/access-gate.ts
|
|
12599
12678
|
import neo4j4 from "neo4j-driver";
|
|
12600
|
-
import { readFileSync as
|
|
12679
|
+
import { readFileSync as readFileSync17 } from "fs";
|
|
12601
12680
|
import { resolve as resolve18 } from "path";
|
|
12602
12681
|
import { randomUUID as randomUUID8 } from "crypto";
|
|
12603
12682
|
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "..");
|
|
@@ -12606,7 +12685,7 @@ function readPassword() {
|
|
|
12606
12685
|
if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
|
|
12607
12686
|
const passwordFile = resolve18(PLATFORM_ROOT7, "config/.neo4j-password");
|
|
12608
12687
|
try {
|
|
12609
|
-
return
|
|
12688
|
+
return readFileSync17(passwordFile, "utf-8").trim();
|
|
12610
12689
|
} catch {
|
|
12611
12690
|
throw new Error(
|
|
12612
12691
|
`Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
|
|
@@ -12807,8 +12886,8 @@ async function generateNewMagicToken(grantId) {
|
|
|
12807
12886
|
var TAG25 = "[access-verify]";
|
|
12808
12887
|
var MINT_TAG = "[access-session-mint]";
|
|
12809
12888
|
var COOKIE_NAME = "__access_session";
|
|
12810
|
-
var
|
|
12811
|
-
|
|
12889
|
+
var app34 = new Hono();
|
|
12890
|
+
app34.post("/", async (c) => {
|
|
12812
12891
|
const ip = c.var.clientIp || "unknown";
|
|
12813
12892
|
let body;
|
|
12814
12893
|
try {
|
|
@@ -12890,7 +12969,7 @@ app33.post("/", async (c) => {
|
|
|
12890
12969
|
displayName: grant.displayName
|
|
12891
12970
|
});
|
|
12892
12971
|
});
|
|
12893
|
-
var verify_token_default =
|
|
12972
|
+
var verify_token_default = app34;
|
|
12894
12973
|
|
|
12895
12974
|
// app/lib/access-email.ts
|
|
12896
12975
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -12953,9 +13032,9 @@ async function sendMagicLinkEmail(payload) {
|
|
|
12953
13032
|
|
|
12954
13033
|
// server/routes/access/request-magic-link.ts
|
|
12955
13034
|
var TAG26 = "[access-request-link]";
|
|
12956
|
-
var
|
|
13035
|
+
var app35 = new Hono();
|
|
12957
13036
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
12958
|
-
|
|
13037
|
+
app35.post("/", async (c) => {
|
|
12959
13038
|
let body;
|
|
12960
13039
|
try {
|
|
12961
13040
|
body = await c.req.json();
|
|
@@ -13029,16 +13108,16 @@ app34.post("/", async (c) => {
|
|
|
13029
13108
|
);
|
|
13030
13109
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
13031
13110
|
});
|
|
13032
|
-
var request_magic_link_default =
|
|
13111
|
+
var request_magic_link_default = app35;
|
|
13033
13112
|
|
|
13034
13113
|
// server/routes/access/index.ts
|
|
13035
|
-
var
|
|
13036
|
-
|
|
13037
|
-
|
|
13038
|
-
var access_default =
|
|
13114
|
+
var app36 = new Hono();
|
|
13115
|
+
app36.route("/verify-token", verify_token_default);
|
|
13116
|
+
app36.route("/request-magic-link", request_magic_link_default);
|
|
13117
|
+
var access_default = app36;
|
|
13039
13118
|
|
|
13040
13119
|
// server/routes/sites.ts
|
|
13041
|
-
import { existsSync as
|
|
13120
|
+
import { existsSync as existsSync19, readFileSync as readFileSync18, realpathSync as realpathSync5, statSync as statSync8 } from "fs";
|
|
13042
13121
|
import { resolve as resolve20 } from "path";
|
|
13043
13122
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
13044
13123
|
var MIME = {
|
|
@@ -13070,8 +13149,8 @@ function getExt(p) {
|
|
|
13070
13149
|
if (idx < p.lastIndexOf("/")) return "";
|
|
13071
13150
|
return p.slice(idx).toLowerCase();
|
|
13072
13151
|
}
|
|
13073
|
-
var
|
|
13074
|
-
|
|
13152
|
+
var app37 = new Hono();
|
|
13153
|
+
app37.get("/:rel{.*}", (c) => {
|
|
13075
13154
|
const reqPath = c.req.path;
|
|
13076
13155
|
const rawRel = c.req.param("rel") ?? "";
|
|
13077
13156
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -13102,13 +13181,13 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
13102
13181
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
13103
13182
|
return c.text("Forbidden", 403);
|
|
13104
13183
|
}
|
|
13105
|
-
let
|
|
13184
|
+
let stat7;
|
|
13106
13185
|
try {
|
|
13107
|
-
|
|
13186
|
+
stat7 = existsSync19(filePath) ? statSync8(filePath) : null;
|
|
13108
13187
|
} catch {
|
|
13109
|
-
|
|
13188
|
+
stat7 = null;
|
|
13110
13189
|
}
|
|
13111
|
-
if (
|
|
13190
|
+
if (stat7?.isDirectory() && !reqPath.endsWith("/")) {
|
|
13112
13191
|
const search = new URL(c.req.url).search;
|
|
13113
13192
|
const target = `${reqPath}/${search}`;
|
|
13114
13193
|
console.log(
|
|
@@ -13116,14 +13195,14 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
13116
13195
|
);
|
|
13117
13196
|
return c.redirect(target, 301);
|
|
13118
13197
|
}
|
|
13119
|
-
if (
|
|
13198
|
+
if (stat7?.isDirectory()) {
|
|
13120
13199
|
filePath = resolve20(filePath, "index.html");
|
|
13121
13200
|
}
|
|
13122
13201
|
if (!filePath.startsWith(rootDir + "/")) {
|
|
13123
13202
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
13124
13203
|
return c.text("Forbidden", 403);
|
|
13125
13204
|
}
|
|
13126
|
-
if (!
|
|
13205
|
+
if (!existsSync19(filePath)) {
|
|
13127
13206
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
13128
13207
|
return c.text("Not found", 404);
|
|
13129
13208
|
}
|
|
@@ -13142,7 +13221,7 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
13142
13221
|
}
|
|
13143
13222
|
let body;
|
|
13144
13223
|
try {
|
|
13145
|
-
body =
|
|
13224
|
+
body = readFileSync18(realPath);
|
|
13146
13225
|
} catch (err) {
|
|
13147
13226
|
const code = err?.code;
|
|
13148
13227
|
if (code === "EISDIR") {
|
|
@@ -13174,11 +13253,11 @@ app36.get("/:rel{.*}", (c) => {
|
|
|
13174
13253
|
"X-Content-Type-Options": "nosniff"
|
|
13175
13254
|
});
|
|
13176
13255
|
});
|
|
13177
|
-
var sites_default =
|
|
13256
|
+
var sites_default = app37;
|
|
13178
13257
|
|
|
13179
13258
|
// app/lib/visitor-token.ts
|
|
13180
13259
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
13181
|
-
import { mkdirSync as mkdirSync4, readFileSync as
|
|
13260
|
+
import { mkdirSync as mkdirSync4, readFileSync as readFileSync19, writeFileSync as writeFileSync6 } from "fs";
|
|
13182
13261
|
import { dirname as dirname4 } from "path";
|
|
13183
13262
|
var TOKEN_PREFIX = "v1.";
|
|
13184
13263
|
var SECRET_BYTES = 32;
|
|
@@ -13187,7 +13266,7 @@ var cachedSecret = null;
|
|
|
13187
13266
|
function getSecret() {
|
|
13188
13267
|
if (cachedSecret) return cachedSecret;
|
|
13189
13268
|
try {
|
|
13190
|
-
const hex2 =
|
|
13269
|
+
const hex2 = readFileSync19(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
13191
13270
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
13192
13271
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
13193
13272
|
return cachedSecret;
|
|
@@ -13201,7 +13280,7 @@ function getSecret() {
|
|
|
13201
13280
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
13202
13281
|
} catch {
|
|
13203
13282
|
}
|
|
13204
|
-
const hex =
|
|
13283
|
+
const hex = readFileSync19(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
13205
13284
|
cachedSecret = Buffer.from(hex, "hex");
|
|
13206
13285
|
return cachedSecret;
|
|
13207
13286
|
}
|
|
@@ -13254,8 +13333,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
13254
13333
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
13255
13334
|
|
|
13256
13335
|
// app/lib/brand-config.ts
|
|
13257
|
-
import { existsSync as
|
|
13258
|
-
import { join as
|
|
13336
|
+
import { existsSync as existsSync20, readFileSync as readFileSync20 } from "fs";
|
|
13337
|
+
import { join as join16 } from "path";
|
|
13259
13338
|
var cached2 = null;
|
|
13260
13339
|
var cachedAttempted = false;
|
|
13261
13340
|
function readBrandConfig() {
|
|
@@ -13263,10 +13342,10 @@ function readBrandConfig() {
|
|
|
13263
13342
|
cachedAttempted = true;
|
|
13264
13343
|
const platformRoot = process.env.MAXY_PLATFORM_ROOT;
|
|
13265
13344
|
if (!platformRoot) return null;
|
|
13266
|
-
const brandPath =
|
|
13267
|
-
if (!
|
|
13345
|
+
const brandPath = join16(platformRoot, "config", "brand.json");
|
|
13346
|
+
if (!existsSync20(brandPath)) return null;
|
|
13268
13347
|
try {
|
|
13269
|
-
cached2 = JSON.parse(
|
|
13348
|
+
cached2 = JSON.parse(readFileSync20(brandPath, "utf-8"));
|
|
13270
13349
|
return cached2;
|
|
13271
13350
|
} catch {
|
|
13272
13351
|
return null;
|
|
@@ -13274,7 +13353,7 @@ function readBrandConfig() {
|
|
|
13274
13353
|
}
|
|
13275
13354
|
|
|
13276
13355
|
// server/routes/visitor-consent.ts
|
|
13277
|
-
var
|
|
13356
|
+
var app38 = new Hono();
|
|
13278
13357
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
13279
13358
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
13280
13359
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -13319,17 +13398,17 @@ function siteSlugFromReferer(referer) {
|
|
|
13319
13398
|
return "";
|
|
13320
13399
|
}
|
|
13321
13400
|
}
|
|
13322
|
-
|
|
13401
|
+
app38.options("/consent", (c) => {
|
|
13323
13402
|
const origin = getOrigin(c);
|
|
13324
13403
|
setCorsHeaders(c, origin);
|
|
13325
13404
|
return c.body(null, 204);
|
|
13326
13405
|
});
|
|
13327
|
-
|
|
13406
|
+
app38.options("/brand-config", (c) => {
|
|
13328
13407
|
const origin = getOrigin(c);
|
|
13329
13408
|
setCorsHeaders(c, origin);
|
|
13330
13409
|
return c.body(null, 204);
|
|
13331
13410
|
});
|
|
13332
|
-
|
|
13411
|
+
app38.post("/consent", async (c) => {
|
|
13333
13412
|
const origin = getOrigin(c);
|
|
13334
13413
|
setCorsHeaders(c, origin);
|
|
13335
13414
|
let raw;
|
|
@@ -13369,7 +13448,7 @@ app37.post("/consent", async (c) => {
|
|
|
13369
13448
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
13370
13449
|
return c.body(null, 204);
|
|
13371
13450
|
});
|
|
13372
|
-
|
|
13451
|
+
app38.get("/brand-config", (c) => {
|
|
13373
13452
|
const origin = getOrigin(c);
|
|
13374
13453
|
setCorsHeaders(c, origin);
|
|
13375
13454
|
const brand = readBrandConfig();
|
|
@@ -13379,7 +13458,7 @@ app37.get("/brand-config", (c) => {
|
|
|
13379
13458
|
c.header("Cache-Control", "public, max-age=300");
|
|
13380
13459
|
return c.json({ consent: { copy, palette } });
|
|
13381
13460
|
});
|
|
13382
|
-
var visitor_consent_default =
|
|
13461
|
+
var visitor_consent_default = app38;
|
|
13383
13462
|
|
|
13384
13463
|
// server/routes/listings.ts
|
|
13385
13464
|
function getCookie(headerValue, name) {
|
|
@@ -13406,8 +13485,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
13406
13485
|
}
|
|
13407
13486
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
13408
13487
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
13409
|
-
var
|
|
13410
|
-
|
|
13488
|
+
var app39 = new Hono();
|
|
13489
|
+
app39.get("/:slug/click", async (c) => {
|
|
13411
13490
|
const slug = c.req.param("slug") ?? "";
|
|
13412
13491
|
const rawSession = c.req.query("session") ?? "";
|
|
13413
13492
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -13471,10 +13550,10 @@ app38.get("/:slug/click", async (c) => {
|
|
|
13471
13550
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
13472
13551
|
return c.redirect(redirectUrl, 302);
|
|
13473
13552
|
});
|
|
13474
|
-
var listings_default =
|
|
13553
|
+
var listings_default = app39;
|
|
13475
13554
|
|
|
13476
13555
|
// server/routes/visitor-event.ts
|
|
13477
|
-
var
|
|
13556
|
+
var app40 = new Hono();
|
|
13478
13557
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
13479
13558
|
var buckets = /* @__PURE__ */ new Map();
|
|
13480
13559
|
var RATE_LIMIT = 60;
|
|
@@ -13541,12 +13620,12 @@ function originAllowed(origin, allowlist) {
|
|
|
13541
13620
|
return false;
|
|
13542
13621
|
}
|
|
13543
13622
|
}
|
|
13544
|
-
|
|
13623
|
+
app40.options("/event", (c) => {
|
|
13545
13624
|
const origin = getOrigin2(c);
|
|
13546
13625
|
setCorsHeaders2(c, origin);
|
|
13547
13626
|
return c.body(null, 204);
|
|
13548
13627
|
});
|
|
13549
|
-
|
|
13628
|
+
app40.post("/event", async (c) => {
|
|
13550
13629
|
const origin = getOrigin2(c);
|
|
13551
13630
|
setCorsHeaders2(c, origin);
|
|
13552
13631
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -13751,7 +13830,7 @@ async function writeEvent(opts) {
|
|
|
13751
13830
|
);
|
|
13752
13831
|
}
|
|
13753
13832
|
}
|
|
13754
|
-
var visitor_event_default =
|
|
13833
|
+
var visitor_event_default = app40;
|
|
13755
13834
|
|
|
13756
13835
|
// app/lib/graph-health.ts
|
|
13757
13836
|
var HOUR_MS = 60 * 60 * 1e3;
|
|
@@ -13998,7 +14077,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
13998
14077
|
|
|
13999
14078
|
// ../lib/entitlement/src/index.ts
|
|
14000
14079
|
import { createPublicKey, createHash as createHash4, verify as cryptoVerify } from "crypto";
|
|
14001
|
-
import { existsSync as
|
|
14080
|
+
import { existsSync as existsSync21, readFileSync as readFileSync21, statSync as statSync9 } from "fs";
|
|
14002
14081
|
import { resolve as resolve22 } from "path";
|
|
14003
14082
|
|
|
14004
14083
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -14047,11 +14126,11 @@ function resolveEntitlement(brand, account) {
|
|
|
14047
14126
|
return logResolved(implicitTrust(account), null);
|
|
14048
14127
|
}
|
|
14049
14128
|
const entitlementPath = resolve22(brand.configDir, "entitlement.json");
|
|
14050
|
-
if (!
|
|
14129
|
+
if (!existsSync21(entitlementPath)) {
|
|
14051
14130
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
14052
14131
|
}
|
|
14053
|
-
const
|
|
14054
|
-
const key = memoKey(
|
|
14132
|
+
const stat7 = statSync9(entitlementPath);
|
|
14133
|
+
const key = memoKey(stat7.mtimeMs, account);
|
|
14055
14134
|
if (memo && memo.key === key) {
|
|
14056
14135
|
return memo.result;
|
|
14057
14136
|
}
|
|
@@ -14062,7 +14141,7 @@ function resolveEntitlement(brand, account) {
|
|
|
14062
14141
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
14063
14142
|
let pubkeyPem;
|
|
14064
14143
|
try {
|
|
14065
|
-
pubkeyPem =
|
|
14144
|
+
pubkeyPem = readFileSync21(pubkeyPath(brand), "utf-8");
|
|
14066
14145
|
} catch (err) {
|
|
14067
14146
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
14068
14147
|
reason: "pubkey-missing"
|
|
@@ -14076,7 +14155,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
14076
14155
|
}
|
|
14077
14156
|
let envelope;
|
|
14078
14157
|
try {
|
|
14079
|
-
envelope = JSON.parse(
|
|
14158
|
+
envelope = JSON.parse(readFileSync21(entitlementPath, "utf-8"));
|
|
14080
14159
|
} catch {
|
|
14081
14160
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
14082
14161
|
}
|
|
@@ -14237,14 +14316,14 @@ function clientFrom(c) {
|
|
|
14237
14316
|
);
|
|
14238
14317
|
}
|
|
14239
14318
|
var PLATFORM_ROOT9 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
14240
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT9 ?
|
|
14319
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT9 ? join17(PLATFORM_ROOT9, "config", "brand.json") : "";
|
|
14241
14320
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
14242
|
-
if (BRAND_JSON_PATH && !
|
|
14321
|
+
if (BRAND_JSON_PATH && !existsSync22(BRAND_JSON_PATH)) {
|
|
14243
14322
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
14244
14323
|
}
|
|
14245
|
-
if (BRAND_JSON_PATH &&
|
|
14324
|
+
if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
|
|
14246
14325
|
try {
|
|
14247
|
-
const parsed = JSON.parse(
|
|
14326
|
+
const parsed = JSON.parse(readFileSync22(BRAND_JSON_PATH, "utf-8"));
|
|
14248
14327
|
BRAND = { ...BRAND, ...parsed };
|
|
14249
14328
|
} catch (err) {
|
|
14250
14329
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -14263,11 +14342,11 @@ var brandLoginOpts = {
|
|
|
14263
14342
|
bodyFont: BRAND.defaultFonts?.body,
|
|
14264
14343
|
logoContainsName: !!BRAND.logoContainsName
|
|
14265
14344
|
};
|
|
14266
|
-
var ALIAS_DOMAINS_PATH =
|
|
14345
|
+
var ALIAS_DOMAINS_PATH = join17(homedir2(), BRAND.configDir, "alias-domains.json");
|
|
14267
14346
|
function loadAliasDomains() {
|
|
14268
14347
|
try {
|
|
14269
|
-
if (!
|
|
14270
|
-
const parsed = JSON.parse(
|
|
14348
|
+
if (!existsSync22(ALIAS_DOMAINS_PATH)) return null;
|
|
14349
|
+
const parsed = JSON.parse(readFileSync22(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
14271
14350
|
if (!Array.isArray(parsed)) {
|
|
14272
14351
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
14273
14352
|
return null;
|
|
@@ -14291,9 +14370,9 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
14291
14370
|
function isPublicHost(host) {
|
|
14292
14371
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
14293
14372
|
}
|
|
14294
|
-
var
|
|
14295
|
-
|
|
14296
|
-
|
|
14373
|
+
var app41 = new Hono();
|
|
14374
|
+
app41.use("*", clientIpMiddleware);
|
|
14375
|
+
app41.use("*", async (c, next) => {
|
|
14297
14376
|
await next();
|
|
14298
14377
|
c.header("X-Content-Type-Options", "nosniff");
|
|
14299
14378
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -14303,7 +14382,7 @@ app40.use("*", async (c, next) => {
|
|
|
14303
14382
|
);
|
|
14304
14383
|
});
|
|
14305
14384
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
14306
|
-
|
|
14385
|
+
app41.use("*", async (c, next) => {
|
|
14307
14386
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
14308
14387
|
await next();
|
|
14309
14388
|
return;
|
|
@@ -14336,7 +14415,7 @@ var PUBLIC_ALLOWED_PREFIXES = [
|
|
|
14336
14415
|
"/sites/"
|
|
14337
14416
|
];
|
|
14338
14417
|
var PUBLIC_ALLOWED_EXACT = ["/favicon.ico"];
|
|
14339
|
-
|
|
14418
|
+
app41.use("*", async (c, next) => {
|
|
14340
14419
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14341
14420
|
if (!isPublicHost(host)) {
|
|
14342
14421
|
await next();
|
|
@@ -14376,7 +14455,7 @@ function resolveRemoteAuthOpts() {
|
|
|
14376
14455
|
return brandLoginOpts;
|
|
14377
14456
|
}
|
|
14378
14457
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
14379
|
-
|
|
14458
|
+
app41.post("/__remote-auth/login", async (c) => {
|
|
14380
14459
|
const client = clientFrom(c);
|
|
14381
14460
|
const clientIp = client.ip || "unknown";
|
|
14382
14461
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -14421,7 +14500,7 @@ app40.post("/__remote-auth/login", async (c) => {
|
|
|
14421
14500
|
}
|
|
14422
14501
|
});
|
|
14423
14502
|
});
|
|
14424
|
-
|
|
14503
|
+
app41.get("/__remote-auth/logout", (c) => {
|
|
14425
14504
|
const client = clientFrom(c);
|
|
14426
14505
|
const clientIp = client.ip || "unknown";
|
|
14427
14506
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -14434,7 +14513,7 @@ app40.get("/__remote-auth/logout", (c) => {
|
|
|
14434
14513
|
}
|
|
14435
14514
|
});
|
|
14436
14515
|
});
|
|
14437
|
-
|
|
14516
|
+
app41.post("/__remote-auth/change-password", async (c) => {
|
|
14438
14517
|
const client = clientFrom(c);
|
|
14439
14518
|
const clientIp = client.ip || "unknown";
|
|
14440
14519
|
const rateLimited = checkRateLimit(client);
|
|
@@ -14485,13 +14564,13 @@ app40.post("/__remote-auth/change-password", async (c) => {
|
|
|
14485
14564
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
14486
14565
|
}
|
|
14487
14566
|
});
|
|
14488
|
-
|
|
14567
|
+
app41.get("/__remote-auth/setup", (c) => {
|
|
14489
14568
|
if (isRemoteAuthConfigured()) {
|
|
14490
14569
|
return c.redirect("/");
|
|
14491
14570
|
}
|
|
14492
14571
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
14493
14572
|
});
|
|
14494
|
-
|
|
14573
|
+
app41.post("/__remote-auth/set-initial-password", async (c) => {
|
|
14495
14574
|
if (isRemoteAuthConfigured()) {
|
|
14496
14575
|
return c.redirect("/");
|
|
14497
14576
|
}
|
|
@@ -14529,10 +14608,10 @@ app40.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
14529
14608
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
14530
14609
|
}
|
|
14531
14610
|
});
|
|
14532
|
-
|
|
14611
|
+
app41.get("/api/remote-auth/status", (c) => {
|
|
14533
14612
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
14534
14613
|
});
|
|
14535
|
-
|
|
14614
|
+
app41.post("/api/remote-auth/set-password", async (c) => {
|
|
14536
14615
|
let body;
|
|
14537
14616
|
try {
|
|
14538
14617
|
body = await c.req.json();
|
|
@@ -14563,9 +14642,9 @@ app40.post("/api/remote-auth/set-password", async (c) => {
|
|
|
14563
14642
|
return c.json({ error: "Failed to save password" }, 500);
|
|
14564
14643
|
}
|
|
14565
14644
|
});
|
|
14566
|
-
|
|
14645
|
+
app41.route("/api/_client-error", client_error_default);
|
|
14567
14646
|
console.log("[client-error-route] mounted");
|
|
14568
|
-
|
|
14647
|
+
app41.use("*", async (c, next) => {
|
|
14569
14648
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14570
14649
|
const path2 = c.req.path;
|
|
14571
14650
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/")) {
|
|
@@ -14598,12 +14677,12 @@ app40.use("*", async (c, next) => {
|
|
|
14598
14677
|
console.error(`[remote-auth] login required ip=${clientIp} path=${path2} ${disambig}`);
|
|
14599
14678
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
14600
14679
|
});
|
|
14601
|
-
|
|
14602
|
-
|
|
14603
|
-
|
|
14604
|
-
|
|
14605
|
-
|
|
14606
|
-
|
|
14680
|
+
app41.route("/api/health", health_default);
|
|
14681
|
+
app41.route("/api/chat", chat_default);
|
|
14682
|
+
app41.route("/api/whatsapp", whatsapp_default);
|
|
14683
|
+
app41.route("/api/onboarding", onboarding_default);
|
|
14684
|
+
app41.route("/api/admin", admin_default);
|
|
14685
|
+
app41.route("/api/access", access_default);
|
|
14607
14686
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
14608
14687
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
14609
14688
|
var IMAGE_MIME = {
|
|
@@ -14615,7 +14694,7 @@ var IMAGE_MIME = {
|
|
|
14615
14694
|
".svg": "image/svg+xml",
|
|
14616
14695
|
".ico": "image/x-icon"
|
|
14617
14696
|
};
|
|
14618
|
-
|
|
14697
|
+
app41.get("/agent-assets/:slug/:filename", (c) => {
|
|
14619
14698
|
const slug = c.req.param("slug");
|
|
14620
14699
|
const filename = c.req.param("filename");
|
|
14621
14700
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -14637,20 +14716,20 @@ app40.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
14637
14716
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
14638
14717
|
return c.text("Forbidden", 403);
|
|
14639
14718
|
}
|
|
14640
|
-
if (!
|
|
14719
|
+
if (!existsSync22(filePath)) {
|
|
14641
14720
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
14642
14721
|
return c.text("Not found", 404);
|
|
14643
14722
|
}
|
|
14644
14723
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
14645
14724
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
14646
14725
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
14647
|
-
const body =
|
|
14726
|
+
const body = readFileSync22(filePath);
|
|
14648
14727
|
return c.body(body, 200, {
|
|
14649
14728
|
"Content-Type": contentType,
|
|
14650
14729
|
"Cache-Control": "public, max-age=3600"
|
|
14651
14730
|
});
|
|
14652
14731
|
});
|
|
14653
|
-
|
|
14732
|
+
app41.get("/generated/:filename", (c) => {
|
|
14654
14733
|
const filename = c.req.param("filename");
|
|
14655
14734
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
14656
14735
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -14667,29 +14746,29 @@ app40.get("/generated/:filename", (c) => {
|
|
|
14667
14746
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
14668
14747
|
return c.text("Forbidden", 403);
|
|
14669
14748
|
}
|
|
14670
|
-
if (!
|
|
14749
|
+
if (!existsSync22(filePath)) {
|
|
14671
14750
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
14672
14751
|
return c.text("Not found", 404);
|
|
14673
14752
|
}
|
|
14674
14753
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
14675
14754
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
14676
14755
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
14677
|
-
const body =
|
|
14756
|
+
const body = readFileSync22(filePath);
|
|
14678
14757
|
return c.body(body, 200, {
|
|
14679
14758
|
"Content-Type": contentType,
|
|
14680
14759
|
"Cache-Control": "public, max-age=86400"
|
|
14681
14760
|
});
|
|
14682
14761
|
});
|
|
14683
|
-
|
|
14684
|
-
|
|
14685
|
-
|
|
14686
|
-
|
|
14762
|
+
app41.route("/sites", sites_default);
|
|
14763
|
+
app41.route("/listings", listings_default);
|
|
14764
|
+
app41.route("/v", visitor_event_default);
|
|
14765
|
+
app41.route("/v", visitor_consent_default);
|
|
14687
14766
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
14688
14767
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
14689
14768
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
14690
|
-
if (BRAND_JSON_PATH &&
|
|
14769
|
+
if (BRAND_JSON_PATH && existsSync22(BRAND_JSON_PATH)) {
|
|
14691
14770
|
try {
|
|
14692
|
-
const fullBrand = JSON.parse(
|
|
14771
|
+
const fullBrand = JSON.parse(readFileSync22(BRAND_JSON_PATH, "utf-8"));
|
|
14693
14772
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
14694
14773
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
14695
14774
|
} catch {
|
|
@@ -14706,9 +14785,9 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
14706
14785
|
function readInstalledVersion() {
|
|
14707
14786
|
try {
|
|
14708
14787
|
if (!PLATFORM_ROOT9) return "unknown";
|
|
14709
|
-
const versionFile =
|
|
14710
|
-
if (!
|
|
14711
|
-
const content =
|
|
14788
|
+
const versionFile = join17(PLATFORM_ROOT9, "config", `.${BRAND.hostname}-version`);
|
|
14789
|
+
if (!existsSync22(versionFile)) return "unknown";
|
|
14790
|
+
const content = readFileSync22(versionFile, "utf-8").trim();
|
|
14712
14791
|
return content || "unknown";
|
|
14713
14792
|
} catch {
|
|
14714
14793
|
return "unknown";
|
|
@@ -14749,7 +14828,7 @@ var clientErrorReporterScript = `<script>
|
|
|
14749
14828
|
function cachedHtml(file) {
|
|
14750
14829
|
let html = htmlCache.get(file);
|
|
14751
14830
|
if (!html) {
|
|
14752
|
-
html =
|
|
14831
|
+
html = readFileSync22(resolve23(process.cwd(), "public", file), "utf-8");
|
|
14753
14832
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
14754
14833
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
14755
14834
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -14765,26 +14844,26 @@ ${clientErrorReporterScript}
|
|
|
14765
14844
|
}
|
|
14766
14845
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
14767
14846
|
function loadBrandingCache(agentSlug) {
|
|
14768
|
-
const configDir2 =
|
|
14847
|
+
const configDir2 = join17(homedir2(), BRAND.configDir);
|
|
14769
14848
|
try {
|
|
14770
|
-
const accountJsonPath =
|
|
14771
|
-
if (!
|
|
14772
|
-
const account = JSON.parse(
|
|
14849
|
+
const accountJsonPath = join17(configDir2, "account.json");
|
|
14850
|
+
if (!existsSync22(accountJsonPath)) return null;
|
|
14851
|
+
const account = JSON.parse(readFileSync22(accountJsonPath, "utf-8"));
|
|
14773
14852
|
const accountId = account.accountId;
|
|
14774
14853
|
if (!accountId) return null;
|
|
14775
|
-
const cachePath =
|
|
14776
|
-
if (!
|
|
14777
|
-
return JSON.parse(
|
|
14854
|
+
const cachePath = join17(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
14855
|
+
if (!existsSync22(cachePath)) return null;
|
|
14856
|
+
return JSON.parse(readFileSync22(cachePath, "utf-8"));
|
|
14778
14857
|
} catch {
|
|
14779
14858
|
return null;
|
|
14780
14859
|
}
|
|
14781
14860
|
}
|
|
14782
14861
|
function resolveDefaultSlug() {
|
|
14783
14862
|
try {
|
|
14784
|
-
const configDir2 =
|
|
14785
|
-
const accountJsonPath =
|
|
14786
|
-
if (!
|
|
14787
|
-
const account = JSON.parse(
|
|
14863
|
+
const configDir2 = join17(homedir2(), BRAND.configDir);
|
|
14864
|
+
const accountJsonPath = join17(configDir2, "account.json");
|
|
14865
|
+
if (!existsSync22(accountJsonPath)) return null;
|
|
14866
|
+
const account = JSON.parse(readFileSync22(accountJsonPath, "utf-8"));
|
|
14788
14867
|
return account.defaultAgent || null;
|
|
14789
14868
|
} catch {
|
|
14790
14869
|
return null;
|
|
@@ -14820,7 +14899,7 @@ function brandedPublicHtml(agentSlug) {
|
|
|
14820
14899
|
function escapeHtml(s) {
|
|
14821
14900
|
return s.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
14822
14901
|
}
|
|
14823
|
-
|
|
14902
|
+
app41.get("/", (c) => {
|
|
14824
14903
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14825
14904
|
if (isPublicHost(host)) {
|
|
14826
14905
|
const defaultSlug = resolveDefaultSlug();
|
|
@@ -14828,12 +14907,12 @@ app40.get("/", (c) => {
|
|
|
14828
14907
|
}
|
|
14829
14908
|
return c.html(cachedHtml("index.html"));
|
|
14830
14909
|
});
|
|
14831
|
-
|
|
14910
|
+
app41.get("/public", (c) => {
|
|
14832
14911
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14833
14912
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14834
14913
|
return c.html(cachedHtml("public.html"));
|
|
14835
14914
|
});
|
|
14836
|
-
|
|
14915
|
+
app41.get("/chat", (c) => {
|
|
14837
14916
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14838
14917
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14839
14918
|
return c.html(cachedHtml("public.html"));
|
|
@@ -14852,12 +14931,12 @@ async function logViewerFetch(c, next) {
|
|
|
14852
14931
|
duration_ms: Date.now() - start
|
|
14853
14932
|
});
|
|
14854
14933
|
}
|
|
14855
|
-
|
|
14856
|
-
|
|
14857
|
-
|
|
14934
|
+
app41.use("/vnc-viewer.html", logViewerFetch);
|
|
14935
|
+
app41.use("/vnc-popout.html", logViewerFetch);
|
|
14936
|
+
app41.get("/vnc-popout.html", (c) => {
|
|
14858
14937
|
let html = htmlCache.get("vnc-popout.html");
|
|
14859
14938
|
if (!html) {
|
|
14860
|
-
html =
|
|
14939
|
+
html = readFileSync22(resolve23(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
14861
14940
|
const name = escapeHtml(BRAND.productName);
|
|
14862
14941
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
14863
14942
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -14867,7 +14946,7 @@ app40.get("/vnc-popout.html", (c) => {
|
|
|
14867
14946
|
}
|
|
14868
14947
|
return c.html(html);
|
|
14869
14948
|
});
|
|
14870
|
-
|
|
14949
|
+
app41.post("/api/vnc/client-event", async (c) => {
|
|
14871
14950
|
let body;
|
|
14872
14951
|
try {
|
|
14873
14952
|
body = await c.req.json();
|
|
@@ -14888,25 +14967,25 @@ app40.post("/api/vnc/client-event", async (c) => {
|
|
|
14888
14967
|
});
|
|
14889
14968
|
return c.json({ ok: true });
|
|
14890
14969
|
});
|
|
14891
|
-
|
|
14970
|
+
app41.get("/g/:slug", (c) => {
|
|
14892
14971
|
return c.html(brandedPublicHtml());
|
|
14893
14972
|
});
|
|
14894
|
-
|
|
14973
|
+
app41.get("/graph", (c) => {
|
|
14895
14974
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14896
14975
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14897
14976
|
return c.html(cachedHtml("graph.html"));
|
|
14898
14977
|
});
|
|
14899
|
-
|
|
14978
|
+
app41.get("/sessions", (c) => {
|
|
14900
14979
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14901
14980
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14902
14981
|
return c.html(cachedHtml("sessions.html"));
|
|
14903
14982
|
});
|
|
14904
|
-
|
|
14983
|
+
app41.get("/data", (c) => {
|
|
14905
14984
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
14906
14985
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
14907
14986
|
return c.html(cachedHtml("data.html"));
|
|
14908
14987
|
});
|
|
14909
|
-
|
|
14988
|
+
app41.get("/:slug", async (c, next) => {
|
|
14910
14989
|
const slug = c.req.param("slug");
|
|
14911
14990
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
14912
14991
|
const branding = loadBrandingCache(slug);
|
|
@@ -14916,15 +14995,15 @@ app40.get("/:slug", async (c, next) => {
|
|
|
14916
14995
|
await next();
|
|
14917
14996
|
});
|
|
14918
14997
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
14919
|
-
|
|
14998
|
+
app41.get("/favicon.ico", (c) => {
|
|
14920
14999
|
c.header("Cache-Control", "public, max-age=300");
|
|
14921
15000
|
return c.redirect(brandFaviconPath, 302);
|
|
14922
15001
|
});
|
|
14923
15002
|
}
|
|
14924
|
-
|
|
15003
|
+
app41.use("/*", serveStatic({ root: "./public" }));
|
|
14925
15004
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
14926
15005
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
14927
|
-
var httpServer = serve({ fetch:
|
|
15006
|
+
var httpServer = serve({ fetch: app41.fetch, port, hostname });
|
|
14928
15007
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
14929
15008
|
{
|
|
14930
15009
|
const loopHist = monitorEventLoopDelay({ resolution: 50 });
|
|
@@ -14960,7 +15039,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
14960
15039
|
}
|
|
14961
15040
|
try {
|
|
14962
15041
|
const registered = [];
|
|
14963
|
-
for (const r of
|
|
15042
|
+
for (const r of app41.routes ?? []) {
|
|
14964
15043
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
14965
15044
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
14966
15045
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -14982,8 +15061,8 @@ try {
|
|
|
14982
15061
|
}
|
|
14983
15062
|
(async () => {
|
|
14984
15063
|
try {
|
|
14985
|
-
if (!
|
|
14986
|
-
const usersRaw =
|
|
15064
|
+
if (!existsSync22(USERS_FILE)) return;
|
|
15065
|
+
const usersRaw = readFileSync22(USERS_FILE, "utf-8").trim();
|
|
14987
15066
|
if (!usersRaw) return;
|
|
14988
15067
|
const users = JSON.parse(usersRaw);
|
|
14989
15068
|
const userId = users[0]?.userId;
|
|
@@ -15078,7 +15157,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
15078
15157
|
}
|
|
15079
15158
|
init({
|
|
15080
15159
|
configDir: configDirForWhatsApp,
|
|
15081
|
-
platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ??
|
|
15160
|
+
platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join17(__dirname, "..")),
|
|
15082
15161
|
accountConfig: bootAccountConfig,
|
|
15083
15162
|
onMessage: async (msg) => {
|
|
15084
15163
|
if (process.env.WHATSAPP_PTY_BRIDGE_ENABLED === "true" && msg.text && !msg.isOwnerMirror) {
|