@rubytech/create-maxy-code 0.1.311 → 0.1.313
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/lib/graph-style/dist/index.d.ts +5 -2
- package/payload/platform/lib/graph-style/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/graph-style/dist/index.js +65 -2
- package/payload/platform/lib/graph-style/dist/index.js.map +1 -1
- package/payload/platform/lib/graph-style/src/__tests__/parity.test.ts +218 -0
- package/payload/platform/lib/graph-style/src/index.ts +53 -2
- package/payload/platform/plugins/.claude-plugin/marketplace.json +5 -0
- package/payload/platform/plugins/admin/hooks/lib/maxy-mcp-plugins.txt +1 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +56 -4
- package/payload/platform/plugins/docs/references/admin-ui.md +21 -3
- package/payload/platform/plugins/docs/references/quickbooks.md +29 -0
- package/payload/platform/plugins/quickbooks/.claude-plugin/plugin.json +21 -0
- package/payload/platform/plugins/quickbooks/PLUGIN.md +91 -0
- package/payload/platform/plugins/quickbooks/lib/mcp-spawn-tee/index.js +159 -0
- package/payload/platform/plugins/quickbooks/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/index.d.ts +2 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/index.d.ts.map +1 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/index.js +218 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/index.js.map +1 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/oauth.d.ts +37 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/oauth.d.ts.map +1 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/oauth.js +75 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/oauth.js.map +1 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/qbo-client.d.ts +39 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/qbo-client.d.ts.map +1 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/qbo-client.js +178 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/qbo-client.js.map +1 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/secrets.d.ts +36 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/secrets.d.ts.map +1 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/secrets.js +107 -0
- package/payload/platform/plugins/quickbooks/mcp/dist/lib/secrets.js.map +1 -0
- package/payload/platform/plugins/quickbooks/mcp/package.json +19 -0
- package/payload/platform/plugins/quickbooks/skills/quickbooks/SKILL.md +37 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js +16 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts +10 -0
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js +62 -53
- package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/scope-record.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/scope-record.js +35 -53
- package/payload/platform/services/claude-session-manager/dist/scope-record.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/sidecar-store.d.ts +45 -0
- package/payload/platform/services/claude-session-manager/dist/sidecar-store.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/sidecar-store.js +118 -0
- package/payload/platform/services/claude-session-manager/dist/sidecar-store.js.map +1 -0
- package/payload/server/{chunk-J6WDAWFJ.js → chunk-Q7EWROVN.js} +4 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/{AccessGate-ChFLk-rp.js → AccessGate-Byskkf47.js} +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-DU6zgbk5.js → AdminLoginScreens-DgwQi3HN.js} +1 -1
- package/payload/server/public/assets/AdminShell-DQfL2c_L.js +1 -0
- package/payload/server/public/assets/{Checkbox-CQGLKMXu.js → Checkbox-C54JSreC.js} +1 -1
- package/payload/server/public/assets/OperatorConversations-DulQyF8c.js +1 -0
- package/payload/server/public/assets/{admin-COHPIWdb.js → admin-B25rkI9Q.js} +1 -1
- package/payload/server/public/assets/{audio-attachment-mime-DL06xo72.js → audio-attachment-mime-BlwrgPQa.js} +1 -1
- package/payload/server/public/assets/{brand-CN7uSSKl.css → brand-TWflEl22.css} +1 -1
- package/payload/server/public/assets/{browser-L7N4tAOl.js → browser-C9Z5dLlN.js} +1 -1
- package/payload/server/public/assets/chat-CGNWDmid.js +1 -0
- package/payload/server/public/assets/data-DCQDh0-Y.js +1 -0
- package/payload/server/public/assets/graph-labels-BBtL--_M.js +1 -0
- package/payload/server/public/assets/{graph-Cro3-mgY.js → graph-sMzOI71g.js} +2 -2
- package/payload/server/public/assets/operator-hI6kJi0I.js +1 -0
- package/payload/server/public/assets/page-DbsqlpuX.js +1 -0
- package/payload/server/public/assets/{public-CX148JKi.js → public-Cs5N4-Az.js} +1 -1
- package/payload/server/public/assets/{public-next-BCItsUbZ.js → public-next-DoGPYX6T.js} +1 -1
- package/payload/server/public/assets/{useSelectionMode-BHAAhkDg.js → useSelectionMode-Cs-vtuKI.js} +1 -1
- package/payload/server/public/browser.html +6 -6
- package/payload/server/public/chat.html +8 -8
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +8 -8
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/operator.html +10 -10
- package/payload/server/public/public-next.html +9 -9
- package/payload/server/public/public.html +7 -7
- package/payload/server/server.js +1091 -594
- package/payload/server/public/assets/AdminShell-BJCYb1v5.js +0 -1
- package/payload/server/public/assets/OperatorConversations-CHEQTz20.js +0 -1
- package/payload/server/public/assets/chat-B_jYIH9a.js +0 -1
- package/payload/server/public/assets/data-BmSTKHR1.js +0 -1
- package/payload/server/public/assets/graph-labels-WQQn6JIJ.js +0 -1
- package/payload/server/public/assets/operator-B4I25isQ.js +0 -1
- package/payload/server/public/assets/page-B-6ZQ4JG.js +0 -1
- /package/payload/server/public/assets/{brand-MKGM8WZp.js → brand-CYjs10m-.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -110,7 +110,7 @@ import {
|
|
|
110
110
|
vncLog,
|
|
111
111
|
walkPremiumBundles,
|
|
112
112
|
writeAdminUserAndPerson
|
|
113
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-Q7EWROVN.js";
|
|
114
114
|
import {
|
|
115
115
|
__commonJS,
|
|
116
116
|
__toESM
|
|
@@ -562,6 +562,30 @@ var require_dist2 = __commonJS({
|
|
|
562
562
|
if (v.length > 0) {
|
|
563
563
|
return v.length > 24 ? v.slice(0, 24) + "\u2026" : v;
|
|
564
564
|
}
|
|
565
|
+
} else if (primaryLabel === "Job") {
|
|
566
|
+
const client = typeof props.client === "string" ? props.client : "";
|
|
567
|
+
const jobId = typeof props.jobId === "string" ? props.jobId : "";
|
|
568
|
+
const composed = [client, jobId.length > 0 ? `#${jobId}` : ""].filter((s) => s.length > 0).join(" ");
|
|
569
|
+
if (composed.length > 0) {
|
|
570
|
+
return composed.length > 24 ? composed.slice(0, 24) + "\u2026" : composed;
|
|
571
|
+
}
|
|
572
|
+
} else if (primaryLabel === "QuoteDocument") {
|
|
573
|
+
const ref = typeof props.ref === "string" ? props.ref : "";
|
|
574
|
+
if (ref.length > 0) {
|
|
575
|
+
return ref.length > 24 ? ref.slice(0, 24) + "\u2026" : ref;
|
|
576
|
+
}
|
|
577
|
+
} else if (primaryLabel === "InboundInvoice") {
|
|
578
|
+
const supplier = typeof props.supplier === "string" ? props.supplier : "";
|
|
579
|
+
const conf = typeof props.confirmationNumber === "string" ? props.confirmationNumber : "";
|
|
580
|
+
const composed = [supplier, conf.length > 0 ? `#${conf}` : ""].filter((s) => s.length > 0).join(" ");
|
|
581
|
+
if (composed.length > 0) {
|
|
582
|
+
return composed.length > 24 ? composed.slice(0, 24) + "\u2026" : composed;
|
|
583
|
+
}
|
|
584
|
+
} else if (primaryLabel === "WhatsAppGroup") {
|
|
585
|
+
const clientName = typeof props.clientName === "string" ? props.clientName : "";
|
|
586
|
+
if (clientName.length > 0) {
|
|
587
|
+
return clientName.length > 24 ? clientName.slice(0, 24) + "\u2026" : clientName;
|
|
588
|
+
}
|
|
565
589
|
} else if (primaryLabel === "Message") {
|
|
566
590
|
const role = typeof props.role === "string" ? props.role : "";
|
|
567
591
|
const roleShort = role === "user" ? "user" : role === "assistant" ? "asst" : role === "system" ? "sys" : role === "tool" ? "tool" : null;
|
|
@@ -615,6 +639,26 @@ var require_dist2 = __commonJS({
|
|
|
615
639
|
const v = dn.length > 0 ? dn : slug;
|
|
616
640
|
if (v.length > 0)
|
|
617
641
|
return v;
|
|
642
|
+
} else if (primaryLabel === "Job") {
|
|
643
|
+
const client = typeof props.client === "string" ? props.client : "";
|
|
644
|
+
const jobId = typeof props.jobId === "string" ? props.jobId : "";
|
|
645
|
+
const composed = [client, jobId.length > 0 ? `#${jobId}` : ""].filter((s) => s.length > 0).join(" ");
|
|
646
|
+
if (composed.length > 0)
|
|
647
|
+
return composed;
|
|
648
|
+
} else if (primaryLabel === "QuoteDocument") {
|
|
649
|
+
const ref = typeof props.ref === "string" ? props.ref : "";
|
|
650
|
+
if (ref.length > 0)
|
|
651
|
+
return ref;
|
|
652
|
+
} else if (primaryLabel === "InboundInvoice") {
|
|
653
|
+
const supplier = typeof props.supplier === "string" ? props.supplier : "";
|
|
654
|
+
const conf = typeof props.confirmationNumber === "string" ? props.confirmationNumber : "";
|
|
655
|
+
const composed = [supplier, conf.length > 0 ? `#${conf}` : ""].filter((s) => s.length > 0).join(" ");
|
|
656
|
+
if (composed.length > 0)
|
|
657
|
+
return composed;
|
|
658
|
+
} else if (primaryLabel === "WhatsAppGroup") {
|
|
659
|
+
const clientName = typeof props.clientName === "string" ? props.clientName : "";
|
|
660
|
+
if (clientName.length > 0)
|
|
661
|
+
return clientName;
|
|
618
662
|
}
|
|
619
663
|
for (const k of ["name", "title", "summary", "givenName", "subject", "text"]) {
|
|
620
664
|
const v = props[k];
|
|
@@ -1227,8 +1271,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1227
1271
|
};
|
|
1228
1272
|
|
|
1229
1273
|
// server/index.ts
|
|
1230
|
-
import { readFileSync as
|
|
1231
|
-
import { resolve as resolve31, join as
|
|
1274
|
+
import { readFileSync as readFileSync29, existsSync as existsSync31, watchFile } from "fs";
|
|
1275
|
+
import { resolve as resolve31, join as join27, basename as basename9 } from "path";
|
|
1232
1276
|
import { homedir as homedir3 } from "os";
|
|
1233
1277
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1234
1278
|
|
|
@@ -4941,6 +4985,7 @@ var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
|
4941
4985
|
]);
|
|
4942
4986
|
var MAX_FILE_SIZE_BYTES = 50 * 1024 * 1024;
|
|
4943
4987
|
var MAX_FILES_PER_MESSAGE = 5;
|
|
4988
|
+
var MAX_DATA_UPLOAD_BYTES = 2 * 1024 * 1024 * 1024;
|
|
4944
4989
|
var MAX_ZIP_UNCOMPRESSED_BYTES = 100 * 1024 * 1024;
|
|
4945
4990
|
function assertSupportedMime(mimeType) {
|
|
4946
4991
|
if (!SUPPORTED_MIME_TYPES.has(mimeType)) {
|
|
@@ -5180,8 +5225,8 @@ function webchatTurnTimeoutMs() {
|
|
|
5180
5225
|
return Number(process.env.WEBCHAT_TURN_TIMEOUT_MS ?? String(2 * 6e4));
|
|
5181
5226
|
}
|
|
5182
5227
|
function createChatRoutes(deps) {
|
|
5183
|
-
const
|
|
5184
|
-
|
|
5228
|
+
const app53 = new Hono();
|
|
5229
|
+
app53.post("/", async (c) => {
|
|
5185
5230
|
console.log(`[chat-route] entered route=public method=POST`);
|
|
5186
5231
|
const contentType = c.req.header("content-type") ?? "";
|
|
5187
5232
|
const account = resolveAccount();
|
|
@@ -5404,7 +5449,7 @@ ${result.result.text}` : result.result.text;
|
|
|
5404
5449
|
}
|
|
5405
5450
|
});
|
|
5406
5451
|
});
|
|
5407
|
-
return
|
|
5452
|
+
return app53;
|
|
5408
5453
|
}
|
|
5409
5454
|
|
|
5410
5455
|
// server/routes/whatsapp.ts
|
|
@@ -7065,6 +7110,20 @@ function unwrapChannel(text) {
|
|
|
7065
7110
|
}
|
|
7066
7111
|
return source ? { text: inner, source } : { text: inner };
|
|
7067
7112
|
}
|
|
7113
|
+
var COMPOSED_ADMIN_FRAME = /^## Context\n([\s\S]*)\n\n## Instruction\n[\s\S]*$/;
|
|
7114
|
+
function rawFromComposedAdminFrame(text) {
|
|
7115
|
+
return text.match(COMPOSED_ADMIN_FRAME)?.[1];
|
|
7116
|
+
}
|
|
7117
|
+
function operatorInboundTurn(u, ts) {
|
|
7118
|
+
const rawBody = rawFromComposedAdminFrame(u.text);
|
|
7119
|
+
return {
|
|
7120
|
+
kind: "operator-inbound",
|
|
7121
|
+
text: u.text,
|
|
7122
|
+
ts,
|
|
7123
|
+
...u.source ? { source: u.source } : {},
|
|
7124
|
+
...rawBody !== void 0 ? { rawBody } : {}
|
|
7125
|
+
};
|
|
7126
|
+
}
|
|
7068
7127
|
function asString(content) {
|
|
7069
7128
|
return typeof content === "string" ? content : null;
|
|
7070
7129
|
}
|
|
@@ -7127,6 +7186,14 @@ function lastTurnTs(turns) {
|
|
|
7127
7186
|
function isModelGated(turns) {
|
|
7128
7187
|
return turns.some((t) => t.kind === "agent-error" && t.code === "model_unavailable");
|
|
7129
7188
|
}
|
|
7189
|
+
function renderOrSuppressChannelInbound(u, ts, out, queuedPendingSuppress) {
|
|
7190
|
+
const armed = queuedPendingSuppress.get(u.text) ?? 0;
|
|
7191
|
+
if (armed > 0) {
|
|
7192
|
+
queuedPendingSuppress.set(u.text, armed - 1);
|
|
7193
|
+
} else {
|
|
7194
|
+
out.push(operatorInboundTurn(u, ts));
|
|
7195
|
+
}
|
|
7196
|
+
}
|
|
7130
7197
|
function parseTranscript(lines) {
|
|
7131
7198
|
const out = [];
|
|
7132
7199
|
const queuedPendingSuppress = /* @__PURE__ */ new Map();
|
|
@@ -7158,7 +7225,7 @@ function parseTranscript(lines) {
|
|
|
7158
7225
|
const content = asString(row.content);
|
|
7159
7226
|
if (content !== null && CHANNEL_WRAPPER2.test(content)) {
|
|
7160
7227
|
const u = unwrapChannel(content);
|
|
7161
|
-
out.push(
|
|
7228
|
+
out.push(operatorInboundTurn(u, ts));
|
|
7162
7229
|
queuedPendingSuppress.set(u.text, (queuedPendingSuppress.get(u.text) ?? 0) + 1);
|
|
7163
7230
|
}
|
|
7164
7231
|
continue;
|
|
@@ -7167,13 +7234,7 @@ function parseTranscript(lines) {
|
|
|
7167
7234
|
const att = row.attachment;
|
|
7168
7235
|
const isChannelQueued = att?.type === "queued_command" && att.isMeta === true && typeof att.origin === "object" && att.origin !== null && att.origin.kind === "channel" && typeof att.prompt === "string";
|
|
7169
7236
|
if (isChannelQueued) {
|
|
7170
|
-
|
|
7171
|
-
const armed = queuedPendingSuppress.get(u.text) ?? 0;
|
|
7172
|
-
if (armed > 0) {
|
|
7173
|
-
queuedPendingSuppress.set(u.text, armed - 1);
|
|
7174
|
-
} else {
|
|
7175
|
-
out.push({ kind: "operator-inbound", text: u.text, ts, ...u.source ? { source: u.source } : {} });
|
|
7176
|
-
}
|
|
7237
|
+
renderOrSuppressChannelInbound(unwrapChannel(att.prompt), ts, out, queuedPendingSuppress);
|
|
7177
7238
|
}
|
|
7178
7239
|
continue;
|
|
7179
7240
|
}
|
|
@@ -7187,8 +7248,7 @@ function parseTranscript(lines) {
|
|
|
7187
7248
|
if (CLI_MARKER_PREFIXES2.some((p) => text.startsWith(p))) continue;
|
|
7188
7249
|
const isChannel = row.isMeta === true && typeof row.origin === "object" && row.origin !== null && row.origin.kind === "channel";
|
|
7189
7250
|
if (isChannel) {
|
|
7190
|
-
|
|
7191
|
-
out.push({ kind: "operator-inbound", text: u.text, ts, ...u.source ? { source: u.source } : {} });
|
|
7251
|
+
renderOrSuppressChannelInbound(unwrapChannel(text), ts, out, queuedPendingSuppress);
|
|
7192
7252
|
} else {
|
|
7193
7253
|
out.push({ kind: "operator-typed", text, ts });
|
|
7194
7254
|
}
|
|
@@ -7650,8 +7710,8 @@ var public_reader_default = app5;
|
|
|
7650
7710
|
|
|
7651
7711
|
// server/routes/webchat.ts
|
|
7652
7712
|
import { basename as basename4, dirname as dirname3 } from "path";
|
|
7653
|
-
import { join as
|
|
7654
|
-
import { existsSync as
|
|
7713
|
+
import { join as join14 } from "path";
|
|
7714
|
+
import { existsSync as existsSync9, readdirSync as readdirSync8, readFileSync as readFileSync14, renameSync as renameSync3, statSync as statSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
7655
7715
|
|
|
7656
7716
|
// server/canonical-webchat-override.ts
|
|
7657
7717
|
import { readFileSync as readFileSync12, writeFileSync as writeFileSync5, renameSync } from "fs";
|
|
@@ -7688,16 +7748,141 @@ function adminSessionIdFor(accountId, senderId, personId) {
|
|
|
7688
7748
|
return `${h.slice(0, 8)}-${h.slice(8, 12)}-${h.slice(12, 16)}-${h.slice(16, 20)}-${h.slice(20, 32)}`;
|
|
7689
7749
|
}
|
|
7690
7750
|
|
|
7751
|
+
// ../services/claude-session-manager/src/sidecar-store.ts
|
|
7752
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readdirSync as readdirSync7, readFileSync as readFileSync13, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
|
|
7753
|
+
import { join as join13 } from "path";
|
|
7754
|
+
function escapeRegExp(s) {
|
|
7755
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7756
|
+
}
|
|
7757
|
+
function createSidecarStore(config) {
|
|
7758
|
+
const { suffix, validate: validate2 } = config;
|
|
7759
|
+
const suffixRe = new RegExp(`${escapeRegExp(suffix)}$`);
|
|
7760
|
+
function pathFor(sessionsDir, id) {
|
|
7761
|
+
return join13(sessionsDir, `${id}${suffix}`);
|
|
7762
|
+
}
|
|
7763
|
+
function write(sessionsDir, id, record) {
|
|
7764
|
+
mkdirSync2(sessionsDir, { recursive: true });
|
|
7765
|
+
const path2 = pathFor(sessionsDir, id);
|
|
7766
|
+
const tmp = `${path2}.tmp.${process.pid}`;
|
|
7767
|
+
try {
|
|
7768
|
+
writeFileSync6(tmp, JSON.stringify(record), "utf8");
|
|
7769
|
+
renameSync2(tmp, path2);
|
|
7770
|
+
return { ok: true };
|
|
7771
|
+
} catch (error) {
|
|
7772
|
+
try {
|
|
7773
|
+
if (existsSync8(tmp)) unlinkSync(tmp);
|
|
7774
|
+
} catch {
|
|
7775
|
+
}
|
|
7776
|
+
return { ok: false, error };
|
|
7777
|
+
}
|
|
7778
|
+
}
|
|
7779
|
+
function readFileAt(path2) {
|
|
7780
|
+
let raw;
|
|
7781
|
+
try {
|
|
7782
|
+
raw = readFileSync13(path2, "utf8");
|
|
7783
|
+
} catch {
|
|
7784
|
+
return null;
|
|
7785
|
+
}
|
|
7786
|
+
try {
|
|
7787
|
+
return validate2(JSON.parse(raw));
|
|
7788
|
+
} catch {
|
|
7789
|
+
return null;
|
|
7790
|
+
}
|
|
7791
|
+
}
|
|
7792
|
+
function read(sessionsDir, id) {
|
|
7793
|
+
return readFileAt(pathFor(sessionsDir, id));
|
|
7794
|
+
}
|
|
7795
|
+
function readAll(sessionsDir, onSkip) {
|
|
7796
|
+
let names;
|
|
7797
|
+
try {
|
|
7798
|
+
names = readdirSync7(sessionsDir, { withFileTypes: true }).filter((entry) => entry.isFile()).map((entry) => entry.name);
|
|
7799
|
+
} catch {
|
|
7800
|
+
return [];
|
|
7801
|
+
}
|
|
7802
|
+
const out = [];
|
|
7803
|
+
for (const name of names) {
|
|
7804
|
+
if (!suffixRe.test(name)) continue;
|
|
7805
|
+
const path2 = join13(sessionsDir, name);
|
|
7806
|
+
let raw;
|
|
7807
|
+
try {
|
|
7808
|
+
raw = readFileSync13(path2, "utf8");
|
|
7809
|
+
} catch {
|
|
7810
|
+
onSkip?.(name, "unreadable");
|
|
7811
|
+
continue;
|
|
7812
|
+
}
|
|
7813
|
+
let parsed;
|
|
7814
|
+
try {
|
|
7815
|
+
parsed = JSON.parse(raw);
|
|
7816
|
+
} catch {
|
|
7817
|
+
onSkip?.(name, "unreadable");
|
|
7818
|
+
continue;
|
|
7819
|
+
}
|
|
7820
|
+
const record = validate2(parsed);
|
|
7821
|
+
if (record) out.push(record);
|
|
7822
|
+
else onSkip?.(name, "invalid");
|
|
7823
|
+
}
|
|
7824
|
+
return out;
|
|
7825
|
+
}
|
|
7826
|
+
function clear(sessionsDir, id) {
|
|
7827
|
+
const path2 = pathFor(sessionsDir, id);
|
|
7828
|
+
try {
|
|
7829
|
+
if (existsSync8(path2)) {
|
|
7830
|
+
unlinkSync(path2);
|
|
7831
|
+
return { ok: true, removed: true };
|
|
7832
|
+
}
|
|
7833
|
+
return { ok: true, removed: false };
|
|
7834
|
+
} catch (error) {
|
|
7835
|
+
return { ok: false, error };
|
|
7836
|
+
}
|
|
7837
|
+
}
|
|
7838
|
+
return { pathFor, write, read, readAll, clear };
|
|
7839
|
+
}
|
|
7840
|
+
|
|
7841
|
+
// ../services/claude-session-manager/src/reseat-ledger.ts
|
|
7842
|
+
var RESEAT_CHAIN_MAX_DEPTH = 16;
|
|
7843
|
+
var store = createSidecarStore({
|
|
7844
|
+
suffix: ".reseated.json",
|
|
7845
|
+
validate: (raw) => {
|
|
7846
|
+
if (!raw || typeof raw !== "object") return null;
|
|
7847
|
+
const r = raw;
|
|
7848
|
+
if (typeof r.sourceSessionId === "string" && typeof r.forkSessionId === "string" && typeof r.at === "number") {
|
|
7849
|
+
return { sourceSessionId: r.sourceSessionId, forkSessionId: r.forkSessionId, at: r.at };
|
|
7850
|
+
}
|
|
7851
|
+
return null;
|
|
7852
|
+
}
|
|
7853
|
+
});
|
|
7854
|
+
function readAllReseatMarkers(sessionsDir, logger) {
|
|
7855
|
+
return store.readAll(sessionsDir, (name) => logger(`[reseat-ledger] skip-unreadable file=${name}`));
|
|
7856
|
+
}
|
|
7857
|
+
function resolveBridgeSource(sessionsDir, forkSessionId, jsonlExists, maxDepth = RESEAT_CHAIN_MAX_DEPTH) {
|
|
7858
|
+
const sourceOf = /* @__PURE__ */ new Map();
|
|
7859
|
+
for (const m of readAllReseatMarkers(sessionsDir, () => {
|
|
7860
|
+
})) {
|
|
7861
|
+
sourceOf.set(m.forkSessionId, m.sourceSessionId);
|
|
7862
|
+
}
|
|
7863
|
+
const visited = /* @__PURE__ */ new Set([forkSessionId]);
|
|
7864
|
+
let current = forkSessionId;
|
|
7865
|
+
for (let depth = 0; depth < maxDepth; depth++) {
|
|
7866
|
+
const source = sourceOf.get(current);
|
|
7867
|
+
if (source === void 0) return null;
|
|
7868
|
+
if (visited.has(source)) return null;
|
|
7869
|
+
visited.add(source);
|
|
7870
|
+
if (jsonlExists(source)) return source;
|
|
7871
|
+
current = source;
|
|
7872
|
+
}
|
|
7873
|
+
return null;
|
|
7874
|
+
}
|
|
7875
|
+
|
|
7691
7876
|
// server/routes/webchat.ts
|
|
7692
7877
|
var WEBCHAT_ADMIN_KEY = "webchat-admin";
|
|
7693
7878
|
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
7694
7879
|
function locateSession(sessionId) {
|
|
7695
7880
|
const cfg = claudeConfigDir();
|
|
7696
7881
|
if (!cfg) return { projectDir: null, channel: null };
|
|
7697
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
7882
|
+
for (const { path: path2 } of enumerateJsonls(join14(cfg, "projects"))) {
|
|
7698
7883
|
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
7699
7884
|
const dir = dirname3(path2);
|
|
7700
|
-
const meta = readSidecarMeta(
|
|
7885
|
+
const meta = readSidecarMeta(join14(dir, `${sessionId}.meta.json`));
|
|
7701
7886
|
return { projectDir: dir, channel: meta.channel };
|
|
7702
7887
|
}
|
|
7703
7888
|
}
|
|
@@ -7706,16 +7891,16 @@ function locateSession(sessionId) {
|
|
|
7706
7891
|
function locateSidecar(sessionId) {
|
|
7707
7892
|
const cfg = claudeConfigDir();
|
|
7708
7893
|
if (!cfg) return null;
|
|
7709
|
-
const projectsRoot =
|
|
7894
|
+
const projectsRoot = join14(cfg, "projects");
|
|
7710
7895
|
let slugs;
|
|
7711
7896
|
try {
|
|
7712
|
-
slugs =
|
|
7897
|
+
slugs = readdirSync8(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
7713
7898
|
} catch {
|
|
7714
7899
|
return null;
|
|
7715
7900
|
}
|
|
7716
7901
|
for (const slug of slugs) {
|
|
7717
|
-
const metaPath =
|
|
7718
|
-
if (
|
|
7902
|
+
const metaPath = join14(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
7903
|
+
if (existsSync9(metaPath)) {
|
|
7719
7904
|
return { channel: readSidecarMeta(metaPath).channel };
|
|
7720
7905
|
}
|
|
7721
7906
|
}
|
|
@@ -7727,7 +7912,7 @@ function sessionSidecarExists(sessionId) {
|
|
|
7727
7912
|
function jsonlSizeBytes(projectDir, sessionId) {
|
|
7728
7913
|
if (projectDir === null) return null;
|
|
7729
7914
|
try {
|
|
7730
|
-
return statSync6(
|
|
7915
|
+
return statSync6(join14(projectDir, `${sessionId}.jsonl`)).size;
|
|
7731
7916
|
} catch {
|
|
7732
7917
|
return null;
|
|
7733
7918
|
}
|
|
@@ -7792,14 +7977,38 @@ function readLevers(preResolved) {
|
|
|
7792
7977
|
leverMode: typeof mode === "string" && PERMISSION_MODE_VALUES.has(mode) ? mode : null
|
|
7793
7978
|
};
|
|
7794
7979
|
}
|
|
7795
|
-
function
|
|
7980
|
+
function latestAdminWebchatSessionId() {
|
|
7981
|
+
const cfg = claudeConfigDir();
|
|
7982
|
+
if (!cfg) return null;
|
|
7983
|
+
let best = null;
|
|
7984
|
+
for (const { path: path2, isSubagent, archived } of enumerateJsonls(join14(cfg, "projects"))) {
|
|
7985
|
+
if (isSubagent || archived) continue;
|
|
7986
|
+
const id = basename4(path2).slice(0, -".jsonl".length);
|
|
7987
|
+
const meta = readSidecarMeta(join14(dirname3(path2), `${id}.meta.json`));
|
|
7988
|
+
if (meta.role !== "admin" || meta.channel !== "webchat") continue;
|
|
7989
|
+
let mtimeMs;
|
|
7990
|
+
try {
|
|
7991
|
+
mtimeMs = statSync6(path2).mtimeMs;
|
|
7992
|
+
} catch {
|
|
7993
|
+
continue;
|
|
7994
|
+
}
|
|
7995
|
+
if (best === null || mtimeMs > best.mtimeMs) best = { id, mtimeMs };
|
|
7996
|
+
}
|
|
7997
|
+
return best === null ? null : best.id;
|
|
7998
|
+
}
|
|
7999
|
+
function overrideKnownNonArchived(id) {
|
|
8000
|
+
const { projectDir } = locateSession(id);
|
|
8001
|
+
if (projectDir === null) return sessionSidecarExists(id);
|
|
8002
|
+
return basename4(projectDir) !== "archive";
|
|
8003
|
+
}
|
|
8004
|
+
function resolveCanonical(accountId, accountDir) {
|
|
8005
|
+
const latest = latestAdminWebchatSessionId();
|
|
8006
|
+
if (latest !== null) return { sessionId: latest, source: "latest" };
|
|
7796
8007
|
if (accountDir) {
|
|
7797
8008
|
const override = readCanonicalOverrideId(accountDir);
|
|
7798
|
-
if (override && (
|
|
7799
|
-
return override;
|
|
7800
|
-
}
|
|
8009
|
+
if (override && overrideKnownNonArchived(override)) return { sessionId: override, source: "override" };
|
|
7801
8010
|
}
|
|
7802
|
-
return adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY);
|
|
8011
|
+
return { sessionId: adminSessionIdFor(accountId, WEBCHAT_ADMIN_KEY), source: "canonical-empty" };
|
|
7803
8012
|
}
|
|
7804
8013
|
var REAPPLY_TIMEOUT_MS = 1500;
|
|
7805
8014
|
async function reapplyLeversViaManager() {
|
|
@@ -7822,8 +8031,8 @@ async function reapplyLeversViaManager() {
|
|
|
7822
8031
|
var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
|
|
7823
8032
|
var sendSeq = 0;
|
|
7824
8033
|
function createWebchatRoutes(deps) {
|
|
7825
|
-
const
|
|
7826
|
-
|
|
8034
|
+
const app53 = new Hono();
|
|
8035
|
+
app53.post("/send", requireAdminSession, async (c) => {
|
|
7827
8036
|
let accountId;
|
|
7828
8037
|
try {
|
|
7829
8038
|
accountId = resolvePlatformAccountId();
|
|
@@ -7872,6 +8081,10 @@ function createWebchatRoutes(deps) {
|
|
|
7872
8081
|
}
|
|
7873
8082
|
let deliveryKey = WEBCHAT_ADMIN_KEY;
|
|
7874
8083
|
let deliverySessionId;
|
|
8084
|
+
if (target === void 0) {
|
|
8085
|
+
const latest = latestAdminWebchatSessionId();
|
|
8086
|
+
if (latest !== null) target = latest;
|
|
8087
|
+
}
|
|
7875
8088
|
if (target !== void 0) {
|
|
7876
8089
|
let { projectDir, channel } = locateSession(target);
|
|
7877
8090
|
if (projectDir === null) {
|
|
@@ -7961,7 +8174,7 @@ ${note}` : note;
|
|
|
7961
8174
|
} catch {
|
|
7962
8175
|
canonAccount = null;
|
|
7963
8176
|
}
|
|
7964
|
-
turnSessionId =
|
|
8177
|
+
turnSessionId = resolveCanonical(accountId, canonAccount?.accountDir ?? null).sessionId;
|
|
7965
8178
|
}
|
|
7966
8179
|
const keyDisplay2 = deliveryKey.startsWith("session:") ? deliveryKey.slice(0, "session:".length + 8) : WEBCHAT_ADMIN_KEY;
|
|
7967
8180
|
const baseline = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
|
|
@@ -7978,7 +8191,7 @@ ${note}` : note;
|
|
|
7978
8191
|
if (turnTimer.unref) turnTimer.unref();
|
|
7979
8192
|
return c.json({ ok: true });
|
|
7980
8193
|
});
|
|
7981
|
-
|
|
8194
|
+
app53.post("/settings", requireAdminSession, async (c) => {
|
|
7982
8195
|
const body = await c.req.json().catch(() => null);
|
|
7983
8196
|
const op = body?.op;
|
|
7984
8197
|
const value = body?.value;
|
|
@@ -8000,15 +8213,15 @@ ${note}` : note;
|
|
|
8000
8213
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-unresolved`);
|
|
8001
8214
|
return c.json({ error: "account unresolved" }, 503);
|
|
8002
8215
|
}
|
|
8003
|
-
const accountJsonPath =
|
|
8216
|
+
const accountJsonPath = join14(account.accountDir, "account.json");
|
|
8004
8217
|
try {
|
|
8005
|
-
const parsed = JSON.parse(
|
|
8218
|
+
const parsed = JSON.parse(readFileSync14(accountJsonPath, "utf8"));
|
|
8006
8219
|
if (op === "model") parsed.adminModel = value;
|
|
8007
8220
|
else if (op === "effort") parsed.effort = value;
|
|
8008
8221
|
else parsed.adminPermissionMode = value;
|
|
8009
8222
|
const tmp = `${accountJsonPath}.${process.pid}.tmp`;
|
|
8010
|
-
|
|
8011
|
-
|
|
8223
|
+
writeFileSync7(tmp, JSON.stringify(parsed, null, 2), "utf8");
|
|
8224
|
+
renameSync3(tmp, accountJsonPath);
|
|
8012
8225
|
} catch (err) {
|
|
8013
8226
|
const detail = err instanceof Error ? err.message : String(err);
|
|
8014
8227
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=write-failed detail=${detail}`);
|
|
@@ -8018,7 +8231,7 @@ ${note}` : note;
|
|
|
8018
8231
|
console.log(`[webchat:settings] op=${op} outcome=accepted value=${value} settingsApplied=${settingsApplied}`);
|
|
8019
8232
|
return c.json({ ok: true, settingsApplied });
|
|
8020
8233
|
});
|
|
8021
|
-
|
|
8234
|
+
app53.get("/session", requireAdminSession, async (c) => {
|
|
8022
8235
|
let accountId;
|
|
8023
8236
|
try {
|
|
8024
8237
|
accountId = resolvePlatformAccountId();
|
|
@@ -8033,9 +8246,26 @@ ${note}` : note;
|
|
|
8033
8246
|
return c.json({ error: "invalid session id" }, 400);
|
|
8034
8247
|
}
|
|
8035
8248
|
const { projectDir: projectDir2, channel } = locateSession(target);
|
|
8036
|
-
|
|
8249
|
+
let resolvedProjectDir = projectDir2;
|
|
8250
|
+
let transcriptSessionId = target;
|
|
8251
|
+
if (projectDir2 === null) {
|
|
8252
|
+
const cfg2 = claudeConfigDir();
|
|
8253
|
+
if (cfg2) {
|
|
8254
|
+
const source2 = resolveBridgeSource(
|
|
8255
|
+
join14(cfg2, "sessions"),
|
|
8256
|
+
target,
|
|
8257
|
+
(id) => locateSession(id).projectDir !== null
|
|
8258
|
+
);
|
|
8259
|
+
if (source2) {
|
|
8260
|
+
resolvedProjectDir = locateSession(source2).projectDir;
|
|
8261
|
+
transcriptSessionId = source2;
|
|
8262
|
+
console.log(`[chat-reseat] op=bridge fork=${target.slice(0, 8)} source=${source2.slice(0, 8)}`);
|
|
8263
|
+
}
|
|
8264
|
+
}
|
|
8265
|
+
}
|
|
8266
|
+
const known = resolvedProjectDir !== null || sessionSidecarExists(target);
|
|
8037
8267
|
const indicators2 = await fetchComposerIndicators(target);
|
|
8038
|
-
return c.json({ sessionId: target, projectDir:
|
|
8268
|
+
return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), ...indicators2, ...readLevers() });
|
|
8039
8269
|
}
|
|
8040
8270
|
let account;
|
|
8041
8271
|
try {
|
|
@@ -8043,11 +8273,15 @@ ${note}` : note;
|
|
|
8043
8273
|
} catch {
|
|
8044
8274
|
account = null;
|
|
8045
8275
|
}
|
|
8046
|
-
const sessionId =
|
|
8276
|
+
const { sessionId, source } = resolveCanonical(accountId, account?.accountDir ?? null);
|
|
8277
|
+
if (source === "latest" && account?.accountDir) {
|
|
8278
|
+
writeCanonicalOverrideId(account.accountDir, sessionId);
|
|
8279
|
+
}
|
|
8280
|
+
console.log(`[webchat:inbound] op=session-resolve key=${sessionId.slice(0, 8)} source=${source}`);
|
|
8047
8281
|
const cfg = claudeConfigDir();
|
|
8048
8282
|
let projectDir = null;
|
|
8049
8283
|
if (cfg) {
|
|
8050
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
8284
|
+
for (const { path: path2 } of enumerateJsonls(join14(cfg, "projects"))) {
|
|
8051
8285
|
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
8052
8286
|
projectDir = dirname3(path2);
|
|
8053
8287
|
break;
|
|
@@ -8057,15 +8291,15 @@ ${note}` : note;
|
|
|
8057
8291
|
const indicators = await fetchComposerIndicators(sessionId);
|
|
8058
8292
|
return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), ...indicators, ...readLevers(account) });
|
|
8059
8293
|
});
|
|
8060
|
-
return
|
|
8294
|
+
return app53;
|
|
8061
8295
|
}
|
|
8062
8296
|
|
|
8063
8297
|
// server/routes/webchat-greeting.ts
|
|
8064
8298
|
import { resolve as resolve13 } from "path";
|
|
8065
8299
|
|
|
8066
8300
|
// app/lib/claude-agent/specialist-roster.ts
|
|
8067
|
-
import { existsSync as
|
|
8068
|
-
import { join as
|
|
8301
|
+
import { existsSync as existsSync10, readFileSync as readFileSync15, readdirSync as readdirSync9 } from "fs";
|
|
8302
|
+
import { join as join15 } from "path";
|
|
8069
8303
|
function field(fm, name) {
|
|
8070
8304
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
8071
8305
|
if (!m) return null;
|
|
@@ -8076,15 +8310,15 @@ function field(fm, name) {
|
|
|
8076
8310
|
return value || null;
|
|
8077
8311
|
}
|
|
8078
8312
|
function readSpecialistRoster(specialistsDir) {
|
|
8079
|
-
if (!
|
|
8080
|
-
const entries =
|
|
8313
|
+
if (!existsSync10(specialistsDir)) return { specialists: [], skipped: [] };
|
|
8314
|
+
const entries = readdirSync9(specialistsDir);
|
|
8081
8315
|
const specialists = [];
|
|
8082
8316
|
const skipped = [];
|
|
8083
8317
|
for (const file of entries.sort()) {
|
|
8084
8318
|
if (!file.endsWith(".md")) continue;
|
|
8085
8319
|
let raw;
|
|
8086
8320
|
try {
|
|
8087
|
-
raw =
|
|
8321
|
+
raw = readFileSync15(join15(specialistsDir, file), "utf-8");
|
|
8088
8322
|
} catch (err) {
|
|
8089
8323
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
8090
8324
|
continue;
|
|
@@ -8201,8 +8435,8 @@ var webchat_greeting_default = app6;
|
|
|
8201
8435
|
|
|
8202
8436
|
// server/routes/telegram.ts
|
|
8203
8437
|
import { homedir } from "os";
|
|
8204
|
-
import { resolve as resolve15, join as
|
|
8205
|
-
import { existsSync as
|
|
8438
|
+
import { resolve as resolve15, join as join16 } from "path";
|
|
8439
|
+
import { existsSync as existsSync11, readFileSync as readFileSync16 } from "fs";
|
|
8206
8440
|
|
|
8207
8441
|
// app/lib/channel-pty-bridge/bridge.ts
|
|
8208
8442
|
import { resolve as resolve14 } from "path";
|
|
@@ -9090,10 +9324,10 @@ var TAG23 = "[telegram-inbound]";
|
|
|
9090
9324
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
9091
9325
|
function configDirName() {
|
|
9092
9326
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve15(process.cwd(), "..");
|
|
9093
|
-
const brandPath =
|
|
9094
|
-
if (
|
|
9327
|
+
const brandPath = join16(platformRoot2, "config", "brand.json");
|
|
9328
|
+
if (existsSync11(brandPath)) {
|
|
9095
9329
|
try {
|
|
9096
|
-
return JSON.parse(
|
|
9330
|
+
return JSON.parse(readFileSync16(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
9097
9331
|
} catch {
|
|
9098
9332
|
}
|
|
9099
9333
|
}
|
|
@@ -9125,11 +9359,11 @@ app7.post("/", async (c) => {
|
|
|
9125
9359
|
return c.json({ ok: false }, 400);
|
|
9126
9360
|
}
|
|
9127
9361
|
const sp = secretPath(botType);
|
|
9128
|
-
if (!
|
|
9362
|
+
if (!existsSync11(sp)) {
|
|
9129
9363
|
console.error(`${TAG23} op=reject reason=no-secret-file botType=${botType}`);
|
|
9130
9364
|
return c.json({ ok: false }, 401);
|
|
9131
9365
|
}
|
|
9132
|
-
const expected =
|
|
9366
|
+
const expected = readFileSync16(sp, "utf-8").trim();
|
|
9133
9367
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
9134
9368
|
if (got !== expected) {
|
|
9135
9369
|
console.error(`${TAG23} op=reject reason=bad-secret botType=${botType}`);
|
|
@@ -9190,14 +9424,122 @@ app7.post("/", async (c) => {
|
|
|
9190
9424
|
});
|
|
9191
9425
|
var telegram_default = app7;
|
|
9192
9426
|
|
|
9427
|
+
// server/routes/quickbooks.ts
|
|
9428
|
+
import { join as join17 } from "path";
|
|
9429
|
+
import { existsSync as existsSync12, readFileSync as readFileSync17, writeFileSync as writeFileSync8, mkdirSync as mkdirSync3, rmSync, renameSync as renameSync4 } from "fs";
|
|
9430
|
+
var TAG24 = "[quickbooks]";
|
|
9431
|
+
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
9432
|
+
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
9433
|
+
function pendingPath(accountDir, state) {
|
|
9434
|
+
return join17(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
|
|
9435
|
+
}
|
|
9436
|
+
function storePath(accountDir) {
|
|
9437
|
+
return join17(accountDir, "secrets", "quickbooks.json");
|
|
9438
|
+
}
|
|
9439
|
+
async function completeConsent(args) {
|
|
9440
|
+
const { accountDir, code, realmId } = args;
|
|
9441
|
+
const state = args.state;
|
|
9442
|
+
if (!state || !STATE_RE.test(state) || !existsSync12(pendingPath(accountDir, state))) {
|
|
9443
|
+
console.error(`${TAG24} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
|
|
9444
|
+
return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
|
|
9445
|
+
}
|
|
9446
|
+
const claimFile = `${pendingPath(accountDir, state)}.claimed`;
|
|
9447
|
+
try {
|
|
9448
|
+
renameSync4(pendingPath(accountDir, state), claimFile);
|
|
9449
|
+
} catch {
|
|
9450
|
+
console.error(`${TAG24} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
9451
|
+
return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
|
|
9452
|
+
}
|
|
9453
|
+
try {
|
|
9454
|
+
let pending;
|
|
9455
|
+
try {
|
|
9456
|
+
pending = JSON.parse(readFileSync17(claimFile, "utf-8"));
|
|
9457
|
+
} catch {
|
|
9458
|
+
console.error(`${TAG24} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
9459
|
+
return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
|
|
9460
|
+
}
|
|
9461
|
+
if (Date.now() > pending.expiresAt) {
|
|
9462
|
+
console.error(`${TAG24} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
9463
|
+
return { ok: false, status: 400, message: "Authorization request expired. Generate a new consent link.", stateValid: false };
|
|
9464
|
+
}
|
|
9465
|
+
console.error(`${TAG24} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
|
|
9466
|
+
if (!code || !realmId) {
|
|
9467
|
+
return { ok: false, status: 400, message: "Missing code or realmId in the callback.", stateValid: true };
|
|
9468
|
+
}
|
|
9469
|
+
if (!existsSync12(storePath(accountDir))) {
|
|
9470
|
+
return { ok: false, status: 500, message: "No QuickBooks credentials are stored for this account.", stateValid: true };
|
|
9471
|
+
}
|
|
9472
|
+
const store2 = JSON.parse(readFileSync17(storePath(accountDir), "utf-8"));
|
|
9473
|
+
const form = new URLSearchParams({
|
|
9474
|
+
grant_type: "authorization_code",
|
|
9475
|
+
code,
|
|
9476
|
+
redirect_uri: pending.redirectUri
|
|
9477
|
+
});
|
|
9478
|
+
const res = await fetch(args.tokenUrl ?? INTUIT_TOKEN_URL, {
|
|
9479
|
+
method: "POST",
|
|
9480
|
+
headers: {
|
|
9481
|
+
Authorization: "Basic " + Buffer.from(`${store2.clientId}:${store2.clientSecret}`).toString("base64"),
|
|
9482
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
9483
|
+
Accept: "application/json"
|
|
9484
|
+
},
|
|
9485
|
+
body: form.toString()
|
|
9486
|
+
});
|
|
9487
|
+
const text = await res.text();
|
|
9488
|
+
if (!res.ok) {
|
|
9489
|
+
console.error(`${TAG24} op=token-exchange realmId=${realmId} persisted=false`);
|
|
9490
|
+
return { ok: false, status: 502, message: `Token exchange failed (${res.status}). Generate a new consent link to retry.`, stateValid: true };
|
|
9491
|
+
}
|
|
9492
|
+
const body = JSON.parse(text);
|
|
9493
|
+
if (!body.refresh_token) {
|
|
9494
|
+
console.error(`${TAG24} op=token-exchange realmId=${realmId} persisted=false`);
|
|
9495
|
+
return { ok: false, status: 502, message: "Token exchange returned no refresh token.", stateValid: true };
|
|
9496
|
+
}
|
|
9497
|
+
const now = Date.now();
|
|
9498
|
+
store2.connections = store2.connections ?? {};
|
|
9499
|
+
store2.connections[realmId] = {
|
|
9500
|
+
refreshToken: body.refresh_token,
|
|
9501
|
+
refreshTokenExpiry: now + (body.x_refresh_token_expires_in ?? 864e4) * 1e3,
|
|
9502
|
+
lastRefresh: now
|
|
9503
|
+
};
|
|
9504
|
+
mkdirSync3(join17(accountDir, "secrets"), { recursive: true });
|
|
9505
|
+
writeFileSync8(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
9506
|
+
const persisted = JSON.parse(readFileSync17(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
9507
|
+
console.error(`${TAG24} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
9508
|
+
return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
|
|
9509
|
+
} finally {
|
|
9510
|
+
rmSync(claimFile, { force: true });
|
|
9511
|
+
}
|
|
9512
|
+
}
|
|
9513
|
+
function page(title, detail) {
|
|
9514
|
+
return `<!doctype html><html><head><meta charset="utf-8"><title>${title}</title></head><body style="font-family:system-ui;max-width:32rem;margin:4rem auto;text-align:center"><h1>${title}</h1><p>${detail}</p><p>You can close this tab.</p></body></html>`;
|
|
9515
|
+
}
|
|
9516
|
+
var app8 = new Hono();
|
|
9517
|
+
app8.get("/callback", async (c) => {
|
|
9518
|
+
const account = resolveAccount();
|
|
9519
|
+
if (!account) {
|
|
9520
|
+
console.error(`${TAG24} op=callback stateValid=false realmId= reason=no-account`);
|
|
9521
|
+
return c.html(page("QuickBooks", "This install has no account configured."), 500);
|
|
9522
|
+
}
|
|
9523
|
+
const result = await completeConsent({
|
|
9524
|
+
accountDir: account.accountDir,
|
|
9525
|
+
code: c.req.query("code"),
|
|
9526
|
+
state: c.req.query("state"),
|
|
9527
|
+
realmId: c.req.query("realmId"),
|
|
9528
|
+
tokenUrl: process.env.QUICKBOOKS_TOKEN_URL
|
|
9529
|
+
});
|
|
9530
|
+
const title = result.ok ? "QuickBooks connected" : "QuickBooks authorization failed";
|
|
9531
|
+
return c.html(page(title, result.message), result.status);
|
|
9532
|
+
});
|
|
9533
|
+
var quickbooks_default = app8;
|
|
9534
|
+
|
|
9193
9535
|
// server/routes/onboarding.ts
|
|
9194
9536
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
|
|
9195
|
-
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as
|
|
9537
|
+
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeFileSync10, writeSync, existsSync as existsSync14, readFileSync as readFileSync19, unlinkSync as unlinkSync2 } from "fs";
|
|
9196
9538
|
import { createHash as createHash3, randomUUID as randomUUID8 } from "crypto";
|
|
9197
9539
|
|
|
9198
9540
|
// ../lib/admins-write/src/index.ts
|
|
9199
|
-
import { existsSync as
|
|
9200
|
-
import { dirname as dirname4, join as
|
|
9541
|
+
import { existsSync as existsSync13, readFileSync as readFileSync18, writeFileSync as writeFileSync9, renameSync as renameSync5, mkdirSync as mkdirSync4, readdirSync as readdirSync10, statSync as statSync7 } from "fs";
|
|
9542
|
+
import { dirname as dirname4, join as join18 } from "path";
|
|
9201
9543
|
function logLine(input, result) {
|
|
9202
9544
|
const userIdShort = input.userId.slice(0, 8);
|
|
9203
9545
|
console.error(
|
|
@@ -9205,17 +9547,17 @@ function logLine(input, result) {
|
|
|
9205
9547
|
);
|
|
9206
9548
|
}
|
|
9207
9549
|
function writeFileAtomic(filePath, contents, mode) {
|
|
9208
|
-
|
|
9550
|
+
mkdirSync4(dirname4(filePath), { recursive: true });
|
|
9209
9551
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
9210
|
-
|
|
9211
|
-
|
|
9552
|
+
writeFileSync9(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
9553
|
+
renameSync5(tempPath, filePath);
|
|
9212
9554
|
}
|
|
9213
9555
|
function writeAdminEntry(input) {
|
|
9214
9556
|
const result = { usersJsonResult: "noop", accountJsonResult: "noop" };
|
|
9215
9557
|
try {
|
|
9216
9558
|
let users = [];
|
|
9217
|
-
if (
|
|
9218
|
-
const raw =
|
|
9559
|
+
if (existsSync13(input.usersFile)) {
|
|
9560
|
+
const raw = readFileSync18(input.usersFile, "utf-8").trim();
|
|
9219
9561
|
if (raw) {
|
|
9220
9562
|
const parsed = JSON.parse(raw);
|
|
9221
9563
|
if (!Array.isArray(parsed)) {
|
|
@@ -9239,11 +9581,11 @@ function writeAdminEntry(input) {
|
|
|
9239
9581
|
return result;
|
|
9240
9582
|
}
|
|
9241
9583
|
try {
|
|
9242
|
-
const accountJsonPath =
|
|
9243
|
-
if (!
|
|
9584
|
+
const accountJsonPath = join18(input.accountDir, "account.json");
|
|
9585
|
+
if (!existsSync13(accountJsonPath)) {
|
|
9244
9586
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
9245
9587
|
}
|
|
9246
|
-
const config = JSON.parse(
|
|
9588
|
+
const config = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
|
|
9247
9589
|
const admins = config.admins ?? [];
|
|
9248
9590
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
9249
9591
|
result.accountJsonResult = "noop";
|
|
@@ -9267,9 +9609,9 @@ function checkAdminAuthInvariant(input) {
|
|
|
9267
9609
|
usersWithoutAccount: []
|
|
9268
9610
|
};
|
|
9269
9611
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
9270
|
-
if (
|
|
9612
|
+
if (existsSync13(input.usersFile)) {
|
|
9271
9613
|
try {
|
|
9272
|
-
const raw =
|
|
9614
|
+
const raw = readFileSync18(input.usersFile, "utf-8").trim();
|
|
9273
9615
|
if (raw) {
|
|
9274
9616
|
const users = JSON.parse(raw);
|
|
9275
9617
|
for (const u of users) {
|
|
@@ -9282,10 +9624,10 @@ function checkAdminAuthInvariant(input) {
|
|
|
9282
9624
|
}
|
|
9283
9625
|
}
|
|
9284
9626
|
const accountUserIds = /* @__PURE__ */ new Set();
|
|
9285
|
-
if (
|
|
9627
|
+
if (existsSync13(input.accountsDir)) {
|
|
9286
9628
|
let entries;
|
|
9287
9629
|
try {
|
|
9288
|
-
entries =
|
|
9630
|
+
entries = readdirSync10(input.accountsDir);
|
|
9289
9631
|
} catch (err) {
|
|
9290
9632
|
const msg = err instanceof Error ? err.message : String(err);
|
|
9291
9633
|
console.error(`[${input.tag}] accounts-dir unreadable accountsDir=${input.accountsDir} error=${msg}`);
|
|
@@ -9294,17 +9636,17 @@ function checkAdminAuthInvariant(input) {
|
|
|
9294
9636
|
}
|
|
9295
9637
|
for (const entry of entries) {
|
|
9296
9638
|
if (entry.startsWith(".")) continue;
|
|
9297
|
-
const accountDir =
|
|
9639
|
+
const accountDir = join18(input.accountsDir, entry);
|
|
9298
9640
|
try {
|
|
9299
9641
|
if (!statSync7(accountDir).isDirectory()) continue;
|
|
9300
9642
|
} catch {
|
|
9301
9643
|
continue;
|
|
9302
9644
|
}
|
|
9303
|
-
const accountJsonPath =
|
|
9304
|
-
if (!
|
|
9645
|
+
const accountJsonPath = join18(accountDir, "account.json");
|
|
9646
|
+
if (!existsSync13(accountJsonPath)) continue;
|
|
9305
9647
|
let admins = [];
|
|
9306
9648
|
try {
|
|
9307
|
-
const config = JSON.parse(
|
|
9649
|
+
const config = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
|
|
9308
9650
|
admins = config.admins ?? [];
|
|
9309
9651
|
} catch (err) {
|
|
9310
9652
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -9344,8 +9686,8 @@ function hashPin2(pin) {
|
|
|
9344
9686
|
return createHash3("sha256").update(pin).digest("hex");
|
|
9345
9687
|
}
|
|
9346
9688
|
function readUsersFile2() {
|
|
9347
|
-
if (!
|
|
9348
|
-
const raw =
|
|
9689
|
+
if (!existsSync14(USERS_FILE)) return null;
|
|
9690
|
+
const raw = readFileSync19(USERS_FILE, "utf-8").trim();
|
|
9349
9691
|
if (!raw) return [];
|
|
9350
9692
|
return JSON.parse(raw);
|
|
9351
9693
|
}
|
|
@@ -9375,11 +9717,11 @@ async function waitForAuthPage(timeoutMs = 2e4) {
|
|
|
9375
9717
|
}
|
|
9376
9718
|
return false;
|
|
9377
9719
|
}
|
|
9378
|
-
var
|
|
9379
|
-
|
|
9720
|
+
var app9 = new Hono();
|
|
9721
|
+
app9.get("/claude-auth", async (c) => {
|
|
9380
9722
|
return c.json({ authenticated: await checkAuthStatus() });
|
|
9381
9723
|
});
|
|
9382
|
-
|
|
9724
|
+
app9.post("/claude-auth", async (c) => {
|
|
9383
9725
|
let body = {};
|
|
9384
9726
|
try {
|
|
9385
9727
|
body = await c.req.json();
|
|
@@ -9398,7 +9740,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
9398
9740
|
} catch (err) {
|
|
9399
9741
|
logoutError = err instanceof Error ? err.message : String(err);
|
|
9400
9742
|
}
|
|
9401
|
-
const credentialsPresent =
|
|
9743
|
+
const credentialsPresent = existsSync14(CLAUDE_CREDENTIALS_FILE);
|
|
9402
9744
|
const ranMs = Date.now() - start;
|
|
9403
9745
|
console.log(`[onboarding] op=claude-logout credentialsPresent=${credentialsPresent} ranMs=${ranMs} logoutError=${logoutError ? JSON.stringify(logoutError.slice(0, 120)) : "none"}`);
|
|
9404
9746
|
return c.json({ logged_out: !credentialsPresent });
|
|
@@ -9416,7 +9758,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
9416
9758
|
return c.json({ launched: cdpReady });
|
|
9417
9759
|
}
|
|
9418
9760
|
ensureLogDir();
|
|
9419
|
-
|
|
9761
|
+
writeFileSync10(logPath("claude-auth"), "");
|
|
9420
9762
|
const claudeAuthLogFd = openSync3(logPath("claude-auth"), "a");
|
|
9421
9763
|
const onClaudeOutput = (chunk) => writeSync(claudeAuthLogFd, chunk);
|
|
9422
9764
|
if (process.platform === "darwin") {
|
|
@@ -9449,7 +9791,7 @@ app8.post("/claude-auth", async (c) => {
|
|
|
9449
9791
|
await waitForAuthPage(2e4);
|
|
9450
9792
|
return c.json({ started: true, transport });
|
|
9451
9793
|
});
|
|
9452
|
-
|
|
9794
|
+
app9.post("/set-pin", async (c) => {
|
|
9453
9795
|
let existingUsers = null;
|
|
9454
9796
|
try {
|
|
9455
9797
|
existingUsers = readUsersFile2();
|
|
@@ -9505,9 +9847,9 @@ app8.post("/set-pin", async (c) => {
|
|
|
9505
9847
|
console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
|
|
9506
9848
|
if (process.platform === "linux") {
|
|
9507
9849
|
let installOwner = null;
|
|
9508
|
-
if (
|
|
9850
|
+
if (existsSync14(INSTALL_OWNER_FILE)) {
|
|
9509
9851
|
try {
|
|
9510
|
-
const raw =
|
|
9852
|
+
const raw = readFileSync19(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
9511
9853
|
if (raw.length > 0) installOwner = raw;
|
|
9512
9854
|
} catch (err) {
|
|
9513
9855
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -9551,7 +9893,7 @@ ${body.pin}
|
|
|
9551
9893
|
}
|
|
9552
9894
|
return c.json({ ok: true });
|
|
9553
9895
|
});
|
|
9554
|
-
|
|
9896
|
+
app9.delete("/set-pin", async (c) => {
|
|
9555
9897
|
let users = null;
|
|
9556
9898
|
try {
|
|
9557
9899
|
users = readUsersFile2();
|
|
@@ -9577,20 +9919,20 @@ app8.delete("/set-pin", async (c) => {
|
|
|
9577
9919
|
}
|
|
9578
9920
|
const remaining = users.filter((u) => u.userId !== matchedUser.userId);
|
|
9579
9921
|
if (remaining.length === 0) {
|
|
9580
|
-
|
|
9922
|
+
unlinkSync2(USERS_FILE);
|
|
9581
9923
|
console.log(`[set-pin] cleared users.json (last entry removed): userId=${matchedUser.userId.slice(0, 8)}\u2026`);
|
|
9582
9924
|
} else {
|
|
9583
|
-
|
|
9925
|
+
writeFileSync10(USERS_FILE, JSON.stringify(remaining), { mode: 384 });
|
|
9584
9926
|
console.log(`[set-pin] removed entry from users.json: userId=${matchedUser.userId.slice(0, 8)}\u2026 remaining=${remaining.length}`);
|
|
9585
9927
|
}
|
|
9586
9928
|
return c.json({ ok: true });
|
|
9587
9929
|
});
|
|
9588
|
-
var onboarding_default =
|
|
9930
|
+
var onboarding_default = app9;
|
|
9589
9931
|
|
|
9590
9932
|
// server/routes/client-error.ts
|
|
9591
|
-
import { appendFileSync, existsSync as
|
|
9592
|
-
import { join as
|
|
9593
|
-
var CLIENT_ERRORS_LOG =
|
|
9933
|
+
import { appendFileSync, existsSync as existsSync15, renameSync as renameSync6, statSync as statSync8 } from "fs";
|
|
9934
|
+
import { join as join19 } from "path";
|
|
9935
|
+
var CLIENT_ERRORS_LOG = join19(LOG_DIR, "client-errors.log");
|
|
9594
9936
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
9595
9937
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
9596
9938
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -9633,16 +9975,16 @@ function stackHead(stack) {
|
|
|
9633
9975
|
}
|
|
9634
9976
|
function rotateIfNeeded() {
|
|
9635
9977
|
try {
|
|
9636
|
-
if (!
|
|
9978
|
+
if (!existsSync15(CLIENT_ERRORS_LOG)) return;
|
|
9637
9979
|
const stats = statSync8(CLIENT_ERRORS_LOG);
|
|
9638
9980
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
9639
|
-
|
|
9981
|
+
renameSync6(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
9640
9982
|
} catch (err) {
|
|
9641
9983
|
console.error(`[client-error] log rotation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
9642
9984
|
}
|
|
9643
9985
|
}
|
|
9644
|
-
var
|
|
9645
|
-
|
|
9986
|
+
var app10 = new Hono();
|
|
9987
|
+
app10.post("/", async (c) => {
|
|
9646
9988
|
const client = resolveClientIp(
|
|
9647
9989
|
c.env?.incoming?.socket?.remoteAddress,
|
|
9648
9990
|
c.req.header("x-forwarded-for")
|
|
@@ -9744,7 +10086,7 @@ app9.post("/", async (c) => {
|
|
|
9744
10086
|
}
|
|
9745
10087
|
return c.json({ ok: true });
|
|
9746
10088
|
});
|
|
9747
|
-
var client_error_default =
|
|
10089
|
+
var client_error_default = app10;
|
|
9748
10090
|
|
|
9749
10091
|
// server/routes/admin/session.ts
|
|
9750
10092
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
@@ -9802,8 +10144,8 @@ async function createAdminSession(accountId, thinkingView, userId, userName, rol
|
|
|
9802
10144
|
sessionId: initialSessionId
|
|
9803
10145
|
};
|
|
9804
10146
|
}
|
|
9805
|
-
var
|
|
9806
|
-
|
|
10147
|
+
var app11 = new Hono();
|
|
10148
|
+
app11.get("/", async (c) => {
|
|
9807
10149
|
const signedSessionToken = c.req.query("session_key");
|
|
9808
10150
|
if (!signedSessionToken) {
|
|
9809
10151
|
return c.json({ error: "Invalid or expired admin session" }, 401);
|
|
@@ -9849,7 +10191,7 @@ app10.get("/", async (c) => {
|
|
|
9849
10191
|
sessionId: getSessionIdForSession(cacheKey) ?? null
|
|
9850
10192
|
});
|
|
9851
10193
|
});
|
|
9852
|
-
|
|
10194
|
+
app11.post("/", async (c) => {
|
|
9853
10195
|
let body;
|
|
9854
10196
|
try {
|
|
9855
10197
|
body = await c.req.json();
|
|
@@ -9912,21 +10254,21 @@ app10.post("/", async (c) => {
|
|
|
9912
10254
|
const payload = await createAdminSession(selected.accountId, selected.config.thinkingView, userId, userName, selected.role, avatar);
|
|
9913
10255
|
return c.json(payload);
|
|
9914
10256
|
});
|
|
9915
|
-
var session_default =
|
|
10257
|
+
var session_default = app11;
|
|
9916
10258
|
|
|
9917
10259
|
// server/routes/admin/logs.ts
|
|
9918
|
-
import { existsSync as
|
|
10260
|
+
import { existsSync as existsSync17, readdirSync as readdirSync11, readFileSync as readFileSync20, statSync as statSync9 } from "fs";
|
|
9919
10261
|
import { resolve as resolve16, basename as basename5 } from "path";
|
|
9920
10262
|
|
|
9921
10263
|
// app/lib/logs-read-resolve.ts
|
|
9922
|
-
import { existsSync as
|
|
9923
|
-
import { join as
|
|
10264
|
+
import { existsSync as existsSync16 } from "fs";
|
|
10265
|
+
import { join as join20 } from "path";
|
|
9924
10266
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
9925
10267
|
const tried = [filename];
|
|
9926
10268
|
const hits = [];
|
|
9927
10269
|
for (const dir of logDirs) {
|
|
9928
|
-
const fullPath =
|
|
9929
|
-
if (
|
|
10270
|
+
const fullPath = join20(dir, filename);
|
|
10271
|
+
if (existsSync16(fullPath)) {
|
|
9930
10272
|
hits.push({ path: fullPath, dir });
|
|
9931
10273
|
}
|
|
9932
10274
|
}
|
|
@@ -9935,8 +10277,8 @@ function resolveSessionLogPaths(filename, logDirs) {
|
|
|
9935
10277
|
|
|
9936
10278
|
// server/routes/admin/logs.ts
|
|
9937
10279
|
var TAIL_BYTES = 8192;
|
|
9938
|
-
var
|
|
9939
|
-
|
|
10280
|
+
var app12 = new Hono();
|
|
10281
|
+
app12.get("/", async (c) => {
|
|
9940
10282
|
const fileParam = c.req.query("file");
|
|
9941
10283
|
const typeParam = c.req.query("type");
|
|
9942
10284
|
const sessionIdParam = c.req.query("sessionId");
|
|
@@ -9954,7 +10296,7 @@ app11.get("/", async (c) => {
|
|
|
9954
10296
|
const filePath = resolve16(dir, safe);
|
|
9955
10297
|
searched.push(filePath);
|
|
9956
10298
|
try {
|
|
9957
|
-
const buffer =
|
|
10299
|
+
const buffer = readFileSync20(filePath);
|
|
9958
10300
|
const onDiskBytes = statSync9(filePath).size;
|
|
9959
10301
|
const headers = {
|
|
9960
10302
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -10019,7 +10361,7 @@ app11.get("/", async (c) => {
|
|
|
10019
10361
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
10020
10362
|
try {
|
|
10021
10363
|
const filename = basename5(hit.path);
|
|
10022
|
-
const buffer =
|
|
10364
|
+
const buffer = readFileSync20(hit.path);
|
|
10023
10365
|
const onDiskBytes = statSync9(hit.path).size;
|
|
10024
10366
|
const headers = {
|
|
10025
10367
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -10054,10 +10396,10 @@ app11.get("/", async (c) => {
|
|
|
10054
10396
|
const seen = /* @__PURE__ */ new Set();
|
|
10055
10397
|
const logs = {};
|
|
10056
10398
|
for (const dir of logDirs) {
|
|
10057
|
-
if (!
|
|
10399
|
+
if (!existsSync17(dir)) continue;
|
|
10058
10400
|
let files;
|
|
10059
10401
|
try {
|
|
10060
|
-
files =
|
|
10402
|
+
files = readdirSync11(dir).filter((f) => f.endsWith(".log"));
|
|
10061
10403
|
} catch (err) {
|
|
10062
10404
|
const reason = err instanceof Error ? err.message : String(err);
|
|
10063
10405
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
@@ -10066,7 +10408,7 @@ app11.get("/", async (c) => {
|
|
|
10066
10408
|
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync9(resolve16(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
10067
10409
|
seen.add(name);
|
|
10068
10410
|
try {
|
|
10069
|
-
const content =
|
|
10411
|
+
const content = readFileSync20(resolve16(dir, name));
|
|
10070
10412
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
10071
10413
|
logs[name] = tail.trim() || "(empty)";
|
|
10072
10414
|
} catch (err) {
|
|
@@ -10078,12 +10420,12 @@ app11.get("/", async (c) => {
|
|
|
10078
10420
|
}
|
|
10079
10421
|
return c.json({ logs });
|
|
10080
10422
|
});
|
|
10081
|
-
var logs_default =
|
|
10423
|
+
var logs_default = app12;
|
|
10082
10424
|
|
|
10083
10425
|
// server/routes/admin/claude-info.ts
|
|
10084
10426
|
import { execFileSync as execFileSync3 } from "child_process";
|
|
10085
|
-
var
|
|
10086
|
-
|
|
10427
|
+
var app13 = new Hono();
|
|
10428
|
+
app13.get("/", (c) => {
|
|
10087
10429
|
let version = "unknown";
|
|
10088
10430
|
try {
|
|
10089
10431
|
const raw = execFileSync3("claude", ["--version"], { encoding: "utf-8", timeout: 5e3 });
|
|
@@ -10101,14 +10443,14 @@ app12.get("/", (c) => {
|
|
|
10101
10443
|
const thinkingView = resolvedAccount?.config.thinkingView ?? "default";
|
|
10102
10444
|
return c.json({ version, account, model, thinkingView });
|
|
10103
10445
|
});
|
|
10104
|
-
var claude_info_default =
|
|
10446
|
+
var claude_info_default = app13;
|
|
10105
10447
|
|
|
10106
10448
|
// server/routes/admin/attachment.ts
|
|
10107
10449
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
10108
|
-
import { existsSync as
|
|
10450
|
+
import { existsSync as existsSync18 } from "fs";
|
|
10109
10451
|
import { resolve as resolve17 } from "path";
|
|
10110
|
-
var
|
|
10111
|
-
|
|
10452
|
+
var app14 = new Hono();
|
|
10453
|
+
app14.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
10112
10454
|
const attachmentId = c.req.param("attachmentId");
|
|
10113
10455
|
const cacheKey = c.var.cacheKey;
|
|
10114
10456
|
const accountId = getAccountIdForSession(cacheKey);
|
|
@@ -10119,11 +10461,11 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
10119
10461
|
return new Response("Not found", { status: 404 });
|
|
10120
10462
|
}
|
|
10121
10463
|
const dir = resolve17(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
|
|
10122
|
-
if (!
|
|
10464
|
+
if (!existsSync18(dir)) {
|
|
10123
10465
|
return new Response("Not found", { status: 404 });
|
|
10124
10466
|
}
|
|
10125
10467
|
const metaPath = resolve17(dir, `${attachmentId}.meta.json`);
|
|
10126
|
-
if (!
|
|
10468
|
+
if (!existsSync18(metaPath)) {
|
|
10127
10469
|
return new Response("Not found", { status: 404 });
|
|
10128
10470
|
}
|
|
10129
10471
|
let meta;
|
|
@@ -10147,27 +10489,27 @@ app13.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
10147
10489
|
}
|
|
10148
10490
|
});
|
|
10149
10491
|
});
|
|
10150
|
-
var attachment_default =
|
|
10492
|
+
var attachment_default = app14;
|
|
10151
10493
|
|
|
10152
10494
|
// server/routes/admin/agents.ts
|
|
10153
10495
|
import { resolve as resolve18 } from "path";
|
|
10154
|
-
import { readdirSync as
|
|
10155
|
-
var
|
|
10156
|
-
|
|
10496
|
+
import { readdirSync as readdirSync12, readFileSync as readFileSync21, existsSync as existsSync19, rmSync as rmSync2 } from "fs";
|
|
10497
|
+
var app15 = new Hono();
|
|
10498
|
+
app15.get("/", (c) => {
|
|
10157
10499
|
const account = resolveAccount();
|
|
10158
10500
|
if (!account) return c.json({ agents: [] });
|
|
10159
10501
|
const agentsDir = resolve18(account.accountDir, "agents");
|
|
10160
|
-
if (!
|
|
10502
|
+
if (!existsSync19(agentsDir)) return c.json({ agents: [] });
|
|
10161
10503
|
const agents = [];
|
|
10162
10504
|
try {
|
|
10163
|
-
const entries =
|
|
10505
|
+
const entries = readdirSync12(agentsDir, { withFileTypes: true });
|
|
10164
10506
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
10165
10507
|
if (!entry.isDirectory()) continue;
|
|
10166
10508
|
if (entry.name === "admin") continue;
|
|
10167
10509
|
const configPath2 = resolve18(agentsDir, entry.name, "config.json");
|
|
10168
|
-
if (!
|
|
10510
|
+
if (!existsSync19(configPath2)) continue;
|
|
10169
10511
|
try {
|
|
10170
|
-
const config = JSON.parse(
|
|
10512
|
+
const config = JSON.parse(readFileSync21(configPath2, "utf-8"));
|
|
10171
10513
|
agents.push({
|
|
10172
10514
|
slug: entry.name,
|
|
10173
10515
|
displayName: config.displayName ?? entry.name,
|
|
@@ -10183,7 +10525,7 @@ app14.get("/", (c) => {
|
|
|
10183
10525
|
}
|
|
10184
10526
|
return c.json({ agents });
|
|
10185
10527
|
});
|
|
10186
|
-
|
|
10528
|
+
app15.delete("/:slug", async (c) => {
|
|
10187
10529
|
const slug = c.req.param("slug");
|
|
10188
10530
|
const account = resolveAccount();
|
|
10189
10531
|
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
@@ -10194,7 +10536,7 @@ app14.delete("/:slug", async (c) => {
|
|
|
10194
10536
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
10195
10537
|
}
|
|
10196
10538
|
const agentDir = resolve18(account.accountDir, "agents", slug);
|
|
10197
|
-
if (!
|
|
10539
|
+
if (!existsSync19(agentDir)) {
|
|
10198
10540
|
return c.json({ error: "Agent not found" }, 404);
|
|
10199
10541
|
}
|
|
10200
10542
|
try {
|
|
@@ -10205,7 +10547,7 @@ app14.delete("/:slug", async (c) => {
|
|
|
10205
10547
|
return c.json({ error: `Graph cleanup failed: ${msg}` }, 500);
|
|
10206
10548
|
}
|
|
10207
10549
|
try {
|
|
10208
|
-
|
|
10550
|
+
rmSync2(agentDir, { recursive: true, force: true });
|
|
10209
10551
|
console.log(`[admin/agents] deleted agent "${slug}"`);
|
|
10210
10552
|
return c.json({ ok: true });
|
|
10211
10553
|
} catch (err) {
|
|
@@ -10213,7 +10555,7 @@ app14.delete("/:slug", async (c) => {
|
|
|
10213
10555
|
return c.json({ error: "Failed to delete agent" }, 500);
|
|
10214
10556
|
}
|
|
10215
10557
|
});
|
|
10216
|
-
|
|
10558
|
+
app15.post("/:slug/project", async (c) => {
|
|
10217
10559
|
const slug = c.req.param("slug");
|
|
10218
10560
|
const account = resolveAccount();
|
|
10219
10561
|
if (!account) return c.json({ error: "No account resolved" }, 400);
|
|
@@ -10224,7 +10566,7 @@ app14.post("/:slug/project", async (c) => {
|
|
|
10224
10566
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
10225
10567
|
}
|
|
10226
10568
|
const agentDir = resolve18(account.accountDir, "agents", slug);
|
|
10227
|
-
if (!
|
|
10569
|
+
if (!existsSync19(agentDir)) {
|
|
10228
10570
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
10229
10571
|
}
|
|
10230
10572
|
try {
|
|
@@ -10235,12 +10577,12 @@ app14.post("/:slug/project", async (c) => {
|
|
|
10235
10577
|
return c.json({ error: `Projection failed: ${msg}` }, 500);
|
|
10236
10578
|
}
|
|
10237
10579
|
});
|
|
10238
|
-
var agents_default =
|
|
10580
|
+
var agents_default = app15;
|
|
10239
10581
|
|
|
10240
10582
|
// server/routes/admin/sessions.ts
|
|
10241
10583
|
import crypto2 from "crypto";
|
|
10242
10584
|
import { resolve as resolvePath } from "path";
|
|
10243
|
-
import { existsSync as
|
|
10585
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync5, createWriteStream } from "fs";
|
|
10244
10586
|
|
|
10245
10587
|
// ../lib/admin-conversation-purge/src/index.ts
|
|
10246
10588
|
async function purgeAdminConversationJsonls(args) {
|
|
@@ -10387,7 +10729,7 @@ var pickComponentBytes = (..._args) => null;
|
|
|
10387
10729
|
function openResumeStreamLog(accountId, sessionId) {
|
|
10388
10730
|
const dir = resolvePath(ACCOUNTS_DIR, accountId, "resume-logs");
|
|
10389
10731
|
try {
|
|
10390
|
-
|
|
10732
|
+
mkdirSync5(dir, { recursive: true });
|
|
10391
10733
|
} catch {
|
|
10392
10734
|
}
|
|
10393
10735
|
return createWriteStream(resolvePath(dir, `${sessionId}.log`), { flags: "a" });
|
|
@@ -10400,7 +10742,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
|
|
|
10400
10742
|
let reason = null;
|
|
10401
10743
|
if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
|
|
10402
10744
|
else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
|
|
10403
|
-
else if (!
|
|
10745
|
+
else if (!existsSync20(a.storagePath)) reason = "missing-file";
|
|
10404
10746
|
if (reason) {
|
|
10405
10747
|
invalid++;
|
|
10406
10748
|
try {
|
|
@@ -10507,8 +10849,8 @@ function formatAge(updatedAtStr) {
|
|
|
10507
10849
|
return "unknown";
|
|
10508
10850
|
}
|
|
10509
10851
|
}
|
|
10510
|
-
var
|
|
10511
|
-
|
|
10852
|
+
var app16 = new Hono();
|
|
10853
|
+
app16.get("/", requireAdminSession, async (c) => {
|
|
10512
10854
|
const cacheKey = c.var.cacheKey;
|
|
10513
10855
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10514
10856
|
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
@@ -10538,7 +10880,7 @@ app15.get("/", requireAdminSession, async (c) => {
|
|
|
10538
10880
|
return c.json({ error: "Failed to fetch sessions" }, 500);
|
|
10539
10881
|
}
|
|
10540
10882
|
});
|
|
10541
|
-
|
|
10883
|
+
app16.post("/new", requireAdminSession, async (c) => {
|
|
10542
10884
|
const oldCacheKey = c.var.cacheKey;
|
|
10543
10885
|
console.log(`[admin-chat] new-conversation outcome=ingress cacheKey=${oldCacheKey.slice(0, 8)}`);
|
|
10544
10886
|
const accountId = getAccountIdForSession(oldCacheKey);
|
|
@@ -10555,7 +10897,7 @@ app15.post("/new", requireAdminSession, async (c) => {
|
|
|
10555
10897
|
console.log(`[admin-chat] new-conversation outcome=ok oldKey=${oldCacheKey.slice(0, 8)} newKey=${newCacheKey.slice(0, 8)}`);
|
|
10556
10898
|
return c.json({ session_key: newSignedSessionToken, sessionId: null });
|
|
10557
10899
|
});
|
|
10558
|
-
|
|
10900
|
+
app16.post("/switch", requireAdminSession, async (c) => {
|
|
10559
10901
|
const cacheKey = c.var.cacheKey;
|
|
10560
10902
|
const accountId = getAccountIdForSession(cacheKey);
|
|
10561
10903
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -10583,7 +10925,7 @@ app15.post("/switch", requireAdminSession, async (c) => {
|
|
|
10583
10925
|
console.log(`[session-switch] from=${cacheKey.slice(0, 8)} to=${targetCacheKey.slice(0, 8)} targetConvId=${targetSessionId?.slice(0, 8) ?? "none"} accountId=${accountId.slice(0, 8)}`);
|
|
10584
10926
|
return c.json({ session_key: targetSignedSessionToken, sessionId: targetSessionId });
|
|
10585
10927
|
});
|
|
10586
|
-
|
|
10928
|
+
app16.delete("/:id", requireAdminSession, async (c) => {
|
|
10587
10929
|
const sessionId = c.req.param("id");
|
|
10588
10930
|
const cacheKey = c.var.cacheKey;
|
|
10589
10931
|
const accountId = getAccountIdForSession(cacheKey);
|
|
@@ -10628,7 +10970,7 @@ app15.delete("/:id", requireAdminSession, async (c) => {
|
|
|
10628
10970
|
500
|
|
10629
10971
|
);
|
|
10630
10972
|
});
|
|
10631
|
-
|
|
10973
|
+
app16.post("/:id/resume", async (c) => {
|
|
10632
10974
|
const sessionId = c.req.param("id");
|
|
10633
10975
|
const t0 = Date.now();
|
|
10634
10976
|
const signedSessionToken = c.req.query("session_key") ?? "";
|
|
@@ -10897,7 +11239,7 @@ app15.post("/:id/resume", async (c) => {
|
|
|
10897
11239
|
}
|
|
10898
11240
|
});
|
|
10899
11241
|
});
|
|
10900
|
-
|
|
11242
|
+
app16.put("/:id/label", requireAdminSession, async (c) => {
|
|
10901
11243
|
const sessionId = c.req.param("id");
|
|
10902
11244
|
const cacheKey = c.var.cacheKey;
|
|
10903
11245
|
let body;
|
|
@@ -10923,11 +11265,11 @@ app15.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
10923
11265
|
return c.json({ error: "Failed to rename session" }, 500);
|
|
10924
11266
|
}
|
|
10925
11267
|
});
|
|
10926
|
-
var sessions_default =
|
|
11268
|
+
var sessions_default = app16;
|
|
10927
11269
|
|
|
10928
11270
|
// app/lib/claude-agent/spawn-context.ts
|
|
10929
|
-
import { existsSync as
|
|
10930
|
-
import { dirname as dirname5, resolve as resolve19, join as
|
|
11271
|
+
import { existsSync as existsSync21, readFileSync as readFileSync22, readdirSync as readdirSync13, statSync as statSync10 } from "fs";
|
|
11272
|
+
import { dirname as dirname5, resolve as resolve19, join as join21 } from "path";
|
|
10931
11273
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
10932
11274
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
10933
11275
|
try {
|
|
@@ -10968,14 +11310,14 @@ function frontmatterField(manifest, field2) {
|
|
|
10968
11310
|
function extractPluginToolDescriptions(pluginDir) {
|
|
10969
11311
|
const out = /* @__PURE__ */ new Map();
|
|
10970
11312
|
const candidates = [
|
|
10971
|
-
|
|
10972
|
-
|
|
11313
|
+
join21(pluginDir, "mcp/dist/index.js"),
|
|
11314
|
+
join21(pluginDir, "mcp/src/index.ts")
|
|
10973
11315
|
];
|
|
10974
11316
|
let raw = null;
|
|
10975
11317
|
for (const path2 of candidates) {
|
|
10976
|
-
if (!
|
|
11318
|
+
if (!existsSync21(path2)) continue;
|
|
10977
11319
|
try {
|
|
10978
|
-
raw =
|
|
11320
|
+
raw = readFileSync22(path2, "utf-8");
|
|
10979
11321
|
break;
|
|
10980
11322
|
} catch {
|
|
10981
11323
|
}
|
|
@@ -11025,9 +11367,9 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
11025
11367
|
function listPluginDirs() {
|
|
11026
11368
|
const out = /* @__PURE__ */ new Map();
|
|
11027
11369
|
const platformPlugins = resolve19(PLATFORM_ROOT, "plugins");
|
|
11028
|
-
if (
|
|
11029
|
-
for (const name of
|
|
11030
|
-
const dir =
|
|
11370
|
+
if (existsSync21(platformPlugins)) {
|
|
11371
|
+
for (const name of readdirSync13(platformPlugins)) {
|
|
11372
|
+
const dir = join21(platformPlugins, name);
|
|
11031
11373
|
try {
|
|
11032
11374
|
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
11033
11375
|
} catch {
|
|
@@ -11035,13 +11377,13 @@ function listPluginDirs() {
|
|
|
11035
11377
|
}
|
|
11036
11378
|
}
|
|
11037
11379
|
const premiumRoot = resolve19(dirname5(PLATFORM_ROOT), "premium-plugins");
|
|
11038
|
-
if (
|
|
11039
|
-
for (const bundle of
|
|
11040
|
-
const bundlePlugins =
|
|
11041
|
-
if (!
|
|
11380
|
+
if (existsSync21(premiumRoot)) {
|
|
11381
|
+
for (const bundle of readdirSync13(premiumRoot)) {
|
|
11382
|
+
const bundlePlugins = join21(premiumRoot, bundle, "plugins");
|
|
11383
|
+
if (!existsSync21(bundlePlugins)) continue;
|
|
11042
11384
|
try {
|
|
11043
|
-
for (const name of
|
|
11044
|
-
const dir =
|
|
11385
|
+
for (const name of readdirSync13(bundlePlugins)) {
|
|
11386
|
+
const dir = join21(bundlePlugins, name);
|
|
11045
11387
|
try {
|
|
11046
11388
|
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
11047
11389
|
} catch {
|
|
@@ -11055,9 +11397,9 @@ function listPluginDirs() {
|
|
|
11055
11397
|
}
|
|
11056
11398
|
function readEnabledPlugins(accountId) {
|
|
11057
11399
|
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
11058
|
-
if (!
|
|
11400
|
+
if (!existsSync21(accountFile)) return /* @__PURE__ */ new Set();
|
|
11059
11401
|
try {
|
|
11060
|
-
const parsed = JSON.parse(
|
|
11402
|
+
const parsed = JSON.parse(readFileSync22(accountFile, "utf-8"));
|
|
11061
11403
|
return new Set(
|
|
11062
11404
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
11063
11405
|
);
|
|
@@ -11066,10 +11408,10 @@ function readEnabledPlugins(accountId) {
|
|
|
11066
11408
|
}
|
|
11067
11409
|
}
|
|
11068
11410
|
function readFrontmatter(path2) {
|
|
11069
|
-
if (!
|
|
11411
|
+
if (!existsSync21(path2)) return null;
|
|
11070
11412
|
let raw;
|
|
11071
11413
|
try {
|
|
11072
|
-
raw =
|
|
11414
|
+
raw = readFileSync22(path2, "utf-8");
|
|
11073
11415
|
} catch {
|
|
11074
11416
|
return null;
|
|
11075
11417
|
}
|
|
@@ -11084,7 +11426,7 @@ function computeActivePlugins(accountId) {
|
|
|
11084
11426
|
for (const name of Array.from(enabled).sort()) {
|
|
11085
11427
|
const dir = pluginDirs.get(name);
|
|
11086
11428
|
if (!dir) continue;
|
|
11087
|
-
const fm = readFrontmatter(
|
|
11429
|
+
const fm = readFrontmatter(join21(dir, "PLUGIN.md"));
|
|
11088
11430
|
if (!fm) continue;
|
|
11089
11431
|
const description = frontmatterField(`---
|
|
11090
11432
|
${fm}
|
|
@@ -11101,7 +11443,7 @@ ${fm}
|
|
|
11101
11443
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
11102
11444
|
);
|
|
11103
11445
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
11104
|
-
const hasSource =
|
|
11446
|
+
const hasSource = existsSync21(join21(dir, "mcp/dist/index.js")) || existsSync21(join21(dir, "mcp/src/index.ts"));
|
|
11105
11447
|
if (hasSource) {
|
|
11106
11448
|
console.warn(
|
|
11107
11449
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -11111,7 +11453,7 @@ ${fm}
|
|
|
11111
11453
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
11112
11454
|
const skills = [];
|
|
11113
11455
|
for (const relPath of skillPaths) {
|
|
11114
|
-
const skillPath =
|
|
11456
|
+
const skillPath = join21(dir, relPath);
|
|
11115
11457
|
const skillFm = readFrontmatter(skillPath);
|
|
11116
11458
|
if (!skillFm) continue;
|
|
11117
11459
|
const skillName = frontmatterField(`---
|
|
@@ -11128,10 +11470,10 @@ ${skillFm}
|
|
|
11128
11470
|
}
|
|
11129
11471
|
function computeSpecialistDomains(accountId) {
|
|
11130
11472
|
const specialistsDir = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
11131
|
-
if (!
|
|
11473
|
+
if (!existsSync21(specialistsDir)) return [];
|
|
11132
11474
|
let entries;
|
|
11133
11475
|
try {
|
|
11134
|
-
entries =
|
|
11476
|
+
entries = readdirSync13(specialistsDir);
|
|
11135
11477
|
} catch {
|
|
11136
11478
|
return [];
|
|
11137
11479
|
}
|
|
@@ -11155,7 +11497,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
11155
11497
|
const out = [];
|
|
11156
11498
|
for (const file of entries.sort()) {
|
|
11157
11499
|
if (!file.endsWith(".md")) continue;
|
|
11158
|
-
const fm = readFrontmatter(
|
|
11500
|
+
const fm = readFrontmatter(join21(specialistsDir, file));
|
|
11159
11501
|
if (!fm) continue;
|
|
11160
11502
|
const wrapped = `---
|
|
11161
11503
|
${fm}
|
|
@@ -11174,10 +11516,10 @@ ${fm}
|
|
|
11174
11516
|
}
|
|
11175
11517
|
function computeDormantPlugins(accountId) {
|
|
11176
11518
|
const accountFile = resolve19(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
11177
|
-
if (!
|
|
11519
|
+
if (!existsSync21(accountFile)) return [];
|
|
11178
11520
|
let enabled;
|
|
11179
11521
|
try {
|
|
11180
|
-
const raw =
|
|
11522
|
+
const raw = readFileSync22(accountFile, "utf-8");
|
|
11181
11523
|
const parsed = JSON.parse(raw);
|
|
11182
11524
|
enabled = new Set(
|
|
11183
11525
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -11189,10 +11531,10 @@ function computeDormantPlugins(accountId) {
|
|
|
11189
11531
|
return [];
|
|
11190
11532
|
}
|
|
11191
11533
|
const pluginsDir = resolve19(PLATFORM_ROOT, "plugins");
|
|
11192
|
-
if (!
|
|
11534
|
+
if (!existsSync21(pluginsDir)) return [];
|
|
11193
11535
|
let entries;
|
|
11194
11536
|
try {
|
|
11195
|
-
entries =
|
|
11537
|
+
entries = readdirSync13(pluginsDir);
|
|
11196
11538
|
} catch {
|
|
11197
11539
|
return [];
|
|
11198
11540
|
}
|
|
@@ -11200,10 +11542,10 @@ function computeDormantPlugins(accountId) {
|
|
|
11200
11542
|
for (const name of entries) {
|
|
11201
11543
|
if (enabled.has(name)) continue;
|
|
11202
11544
|
const manifestPath = resolve19(pluginsDir, name, "PLUGIN.md");
|
|
11203
|
-
if (!
|
|
11545
|
+
if (!existsSync21(manifestPath)) continue;
|
|
11204
11546
|
let manifest;
|
|
11205
11547
|
try {
|
|
11206
|
-
manifest =
|
|
11548
|
+
manifest = readFileSync22(manifestPath, "utf-8");
|
|
11207
11549
|
} catch {
|
|
11208
11550
|
continue;
|
|
11209
11551
|
}
|
|
@@ -11217,13 +11559,13 @@ function computeDormantPlugins(accountId) {
|
|
|
11217
11559
|
}
|
|
11218
11560
|
|
|
11219
11561
|
// server/routes/admin/claude-sessions.ts
|
|
11220
|
-
import { existsSync as
|
|
11562
|
+
import { existsSync as existsSync22, readFileSync as readFileSync23 } from "fs";
|
|
11221
11563
|
import { resolve as resolve20 } from "path";
|
|
11222
11564
|
function readTunnelState(brandConfigDir) {
|
|
11223
11565
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
11224
|
-
if (!
|
|
11566
|
+
if (!existsSync22(statePath)) return null;
|
|
11225
11567
|
try {
|
|
11226
|
-
const parsed = JSON.parse(
|
|
11568
|
+
const parsed = JSON.parse(readFileSync23(statePath, "utf-8"));
|
|
11227
11569
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
11228
11570
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
11229
11571
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -11237,7 +11579,7 @@ function resolveTunnelUrl() {
|
|
|
11237
11579
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
|
|
11238
11580
|
let brand;
|
|
11239
11581
|
try {
|
|
11240
|
-
brand = JSON.parse(
|
|
11582
|
+
brand = JSON.parse(readFileSync23(resolve20(platformRoot2, "config", "brand.json"), "utf-8"));
|
|
11241
11583
|
} catch {
|
|
11242
11584
|
return null;
|
|
11243
11585
|
}
|
|
@@ -11248,7 +11590,7 @@ function resolveTunnelUrl() {
|
|
|
11248
11590
|
if (!state) return null;
|
|
11249
11591
|
return `https://${hostname2}.${state.domain}`;
|
|
11250
11592
|
}
|
|
11251
|
-
var
|
|
11593
|
+
var TAG25 = "[claude-session-manager:wrapper]";
|
|
11252
11594
|
async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
11253
11595
|
const auth = await ensureAuth();
|
|
11254
11596
|
if (auth.status !== "dead" && auth.status !== "missing") return null;
|
|
@@ -11260,18 +11602,18 @@ async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
|
11260
11602
|
503
|
|
11261
11603
|
);
|
|
11262
11604
|
}
|
|
11263
|
-
var
|
|
11605
|
+
var app17 = new Hono();
|
|
11264
11606
|
async function performSpawnWithInitialMessage(args) {
|
|
11265
11607
|
const ownerStart = Date.now();
|
|
11266
11608
|
const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
|
|
11267
11609
|
const ownerMs = Date.now() - ownerStart;
|
|
11268
11610
|
const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
|
|
11269
|
-
console.log(`${
|
|
11611
|
+
console.log(`${TAG25} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
|
|
11270
11612
|
const dormantPlugins = computeDormantPlugins(args.senderId);
|
|
11271
11613
|
const activePlugins = computeActivePlugins(args.senderId);
|
|
11272
11614
|
const specialistDomains = computeSpecialistDomains(args.senderId);
|
|
11273
11615
|
const tunnelUrl = resolveTunnelUrl();
|
|
11274
|
-
console.log(`${
|
|
11616
|
+
console.log(`${TAG25} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
|
|
11275
11617
|
const upstreamPayload = JSON.stringify({
|
|
11276
11618
|
senderId: args.senderId,
|
|
11277
11619
|
// Task 205 — pass userId through to the manager so it lands as
|
|
@@ -11298,24 +11640,24 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
11298
11640
|
// unshapely values.
|
|
11299
11641
|
conversationNodeId: args.conversationNodeId
|
|
11300
11642
|
});
|
|
11301
|
-
console.log(`${
|
|
11643
|
+
console.log(`${TAG25} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
|
|
11302
11644
|
const forwardStart = Date.now();
|
|
11303
11645
|
const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
|
|
11304
11646
|
method: "POST",
|
|
11305
11647
|
headers: { "content-type": "application/json" },
|
|
11306
11648
|
body: upstreamPayload
|
|
11307
11649
|
}).catch((err) => {
|
|
11308
|
-
console.error(`${
|
|
11650
|
+
console.error(`${TAG25} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
|
|
11309
11651
|
return null;
|
|
11310
11652
|
});
|
|
11311
11653
|
if (!upstream) return {
|
|
11312
11654
|
response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
|
|
11313
11655
|
claudeSessionId: null
|
|
11314
11656
|
};
|
|
11315
|
-
console.log(`${
|
|
11657
|
+
console.log(`${TAG25} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
|
|
11316
11658
|
if (args.initialMessage) {
|
|
11317
11659
|
const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
|
|
11318
|
-
console.log(`${
|
|
11660
|
+
console.log(`${TAG25} initial-message-inlined bytes=${inputBytes}`);
|
|
11319
11661
|
}
|
|
11320
11662
|
const bodyText = await upstream.text().catch(() => "");
|
|
11321
11663
|
let claudeSessionId = null;
|
|
@@ -11337,8 +11679,8 @@ function mintTranscriptEdge(sessionId, claudeSessionId, accountId) {
|
|
|
11337
11679
|
if (!sessionId || !claudeSessionId) return;
|
|
11338
11680
|
void linkConversationTranscript(sessionId, claudeSessionId, accountId);
|
|
11339
11681
|
}
|
|
11340
|
-
|
|
11341
|
-
|
|
11682
|
+
app17.use("*", requireAdminSession);
|
|
11683
|
+
app17.post("/", async (c) => {
|
|
11342
11684
|
const routeStart = Date.now();
|
|
11343
11685
|
const cacheKey = c.get("cacheKey") ?? "";
|
|
11344
11686
|
let body = {};
|
|
@@ -11350,7 +11692,7 @@ app16.post("/", async (c) => {
|
|
|
11350
11692
|
if (refusal) return refusal;
|
|
11351
11693
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
11352
11694
|
if (!senderId) {
|
|
11353
|
-
console.error(`${
|
|
11695
|
+
console.error(`${TAG25} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
|
|
11354
11696
|
return c.json({ error: "admin-account-not-resolved" }, 500);
|
|
11355
11697
|
}
|
|
11356
11698
|
const userId = getUserIdForSession(cacheKey) ?? void 0;
|
|
@@ -11359,7 +11701,7 @@ app16.post("/", async (c) => {
|
|
|
11359
11701
|
const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
|
|
11360
11702
|
const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
|
|
11361
11703
|
const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
|
|
11362
|
-
console.log(`${
|
|
11704
|
+
console.log(`${TAG25} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
|
|
11363
11705
|
const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
|
|
11364
11706
|
const { response, claudeSessionId } = await performSpawnWithInitialMessage({
|
|
11365
11707
|
senderId,
|
|
@@ -11378,24 +11720,24 @@ app16.post("/", async (c) => {
|
|
|
11378
11720
|
claudeSessionId,
|
|
11379
11721
|
senderId
|
|
11380
11722
|
);
|
|
11381
|
-
console.log(`${
|
|
11723
|
+
console.log(`${TAG25} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
|
|
11382
11724
|
return response;
|
|
11383
11725
|
});
|
|
11384
|
-
var claude_sessions_default =
|
|
11726
|
+
var claude_sessions_default = app17;
|
|
11385
11727
|
|
|
11386
11728
|
// server/routes/admin/log-ingest.ts
|
|
11387
|
-
var
|
|
11729
|
+
var TAG26 = "[log-ingest]";
|
|
11388
11730
|
var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
|
|
11389
11731
|
var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
|
|
11390
11732
|
var MAX_LINE_BYTES = 4096;
|
|
11391
|
-
var
|
|
11733
|
+
var app18 = new Hono();
|
|
11392
11734
|
function isLoopbackAddr(addr) {
|
|
11393
11735
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
11394
11736
|
}
|
|
11395
|
-
|
|
11737
|
+
app18.post("/", async (c) => {
|
|
11396
11738
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
11397
11739
|
if (!isLoopbackAddr(remoteAddr)) {
|
|
11398
|
-
console.error(`${
|
|
11740
|
+
console.error(`${TAG26} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
11399
11741
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
11400
11742
|
}
|
|
11401
11743
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -11404,7 +11746,7 @@ app17.post("/", async (c) => {
|
|
|
11404
11746
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
11405
11747
|
const offender = tokens.find((t) => !isLoopbackAddr(t));
|
|
11406
11748
|
if (offender !== void 0) {
|
|
11407
|
-
console.error(`${
|
|
11749
|
+
console.error(`${TAG26} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
11408
11750
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
11409
11751
|
}
|
|
11410
11752
|
}
|
|
@@ -11435,7 +11777,7 @@ app17.post("/", async (c) => {
|
|
|
11435
11777
|
else console.log(formatted);
|
|
11436
11778
|
return c.json({ ok: true }, 200);
|
|
11437
11779
|
});
|
|
11438
|
-
var log_ingest_default =
|
|
11780
|
+
var log_ingest_default = app18;
|
|
11439
11781
|
|
|
11440
11782
|
// server/routes/admin/events.ts
|
|
11441
11783
|
var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
@@ -11444,20 +11786,20 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
11444
11786
|
"device-url:vnc-surface-shown",
|
|
11445
11787
|
"device-url:malformed"
|
|
11446
11788
|
]);
|
|
11447
|
-
var
|
|
11448
|
-
|
|
11449
|
-
const
|
|
11789
|
+
var app19 = new Hono();
|
|
11790
|
+
app19.post("/", async (c) => {
|
|
11791
|
+
const TAG35 = "[admin:events]";
|
|
11450
11792
|
let body;
|
|
11451
11793
|
try {
|
|
11452
11794
|
body = await c.req.json();
|
|
11453
11795
|
} catch (err) {
|
|
11454
11796
|
const detail = err instanceof Error ? err.message : String(err);
|
|
11455
|
-
console.error(`${
|
|
11797
|
+
console.error(`${TAG35} reject reason=body-not-json detail=${detail}`);
|
|
11456
11798
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
11457
11799
|
}
|
|
11458
11800
|
const event = typeof body.event === "string" ? body.event : "";
|
|
11459
11801
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
11460
|
-
console.error(`${
|
|
11802
|
+
console.error(`${TAG35} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
11461
11803
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
11462
11804
|
}
|
|
11463
11805
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -11476,13 +11818,14 @@ app18.post("/", async (c) => {
|
|
|
11476
11818
|
console.error(`[${event}] ${formatted}`);
|
|
11477
11819
|
return c.json({ ok: true });
|
|
11478
11820
|
});
|
|
11479
|
-
var events_default =
|
|
11821
|
+
var events_default = app19;
|
|
11480
11822
|
|
|
11481
11823
|
// server/routes/admin/files.ts
|
|
11482
|
-
import { createReadStream as createReadStream2 } from "fs";
|
|
11483
|
-
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3,
|
|
11824
|
+
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync23 } from "fs";
|
|
11825
|
+
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename } from "fs/promises";
|
|
11484
11826
|
import { realpathSync as realpathSync4 } from "fs";
|
|
11485
|
-
import {
|
|
11827
|
+
import { randomUUID as randomUUID10 } from "crypto";
|
|
11828
|
+
import { basename as basename7, dirname as dirname6, join as join23, resolve as resolve22, sep as sep6 } from "path";
|
|
11486
11829
|
import { Readable as Readable2 } from "stream";
|
|
11487
11830
|
|
|
11488
11831
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -11800,7 +12143,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
11800
12143
|
|
|
11801
12144
|
// app/lib/file-index.ts
|
|
11802
12145
|
import * as fsp from "fs/promises";
|
|
11803
|
-
import { resolve as resolve21, relative as relative2, join as
|
|
12146
|
+
import { resolve as resolve21, relative as relative2, join as join22, basename as basename6, extname as extname2, sep as sep5 } from "path";
|
|
11804
12147
|
import { tmpdir as tmpdir2 } from "os";
|
|
11805
12148
|
import { execFile as execFile2 } from "child_process";
|
|
11806
12149
|
import { promisify as promisify2 } from "util";
|
|
@@ -11882,7 +12225,7 @@ async function extractPdf(absolute) {
|
|
|
11882
12225
|
return stdout.trim();
|
|
11883
12226
|
}
|
|
11884
12227
|
async function ocrPdf(absolute) {
|
|
11885
|
-
const outPdf =
|
|
12228
|
+
const outPdf = join22(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
11886
12229
|
try {
|
|
11887
12230
|
await execFileAsync2(
|
|
11888
12231
|
"ocrmypdf",
|
|
@@ -11944,7 +12287,7 @@ async function readDisplayName(absolute) {
|
|
|
11944
12287
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
11945
12288
|
if (base === `${stem}.meta.json`) return null;
|
|
11946
12289
|
try {
|
|
11947
|
-
const raw = await fsp.readFile(
|
|
12290
|
+
const raw = await fsp.readFile(join22(dir, `${stem}.meta.json`), "utf-8");
|
|
11948
12291
|
const meta = JSON.parse(raw);
|
|
11949
12292
|
const dn = meta.displayName ?? meta.filename;
|
|
11950
12293
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -11964,7 +12307,8 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
11964
12307
|
let clean = true;
|
|
11965
12308
|
for (const entry of entries) {
|
|
11966
12309
|
if (entry.isSymbolicLink()) continue;
|
|
11967
|
-
|
|
12310
|
+
if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
|
|
12311
|
+
const abs = join22(root, entry.name);
|
|
11968
12312
|
if (entry.isDirectory()) {
|
|
11969
12313
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
11970
12314
|
if (!sub.clean) clean = false;
|
|
@@ -12233,10 +12577,11 @@ async function dropFileIndex(accountId, relativePath, opts) {
|
|
|
12233
12577
|
}
|
|
12234
12578
|
|
|
12235
12579
|
// server/routes/admin/files.ts
|
|
12580
|
+
var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
12236
12581
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12237
12582
|
async function readMeta(absDir, baseName) {
|
|
12238
12583
|
try {
|
|
12239
|
-
const raw = await readFile4(
|
|
12584
|
+
const raw = await readFile4(join23(absDir, `${baseName}.meta.json`), "utf8");
|
|
12240
12585
|
const parsed = JSON.parse(raw);
|
|
12241
12586
|
if (typeof parsed?.filename === "string") {
|
|
12242
12587
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -12274,7 +12619,7 @@ async function readAccountNames() {
|
|
|
12274
12619
|
}
|
|
12275
12620
|
async function enrich(absolute, entry, accountNames) {
|
|
12276
12621
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
12277
|
-
const meta = await readMeta(
|
|
12622
|
+
const meta = await readMeta(join23(absolute, entry.name), entry.name);
|
|
12278
12623
|
if (meta?.filename) {
|
|
12279
12624
|
entry.displayName = meta.filename;
|
|
12280
12625
|
entry.mimeType = meta.mimeType;
|
|
@@ -12398,8 +12743,8 @@ async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
|
|
|
12398
12743
|
await session.close();
|
|
12399
12744
|
}
|
|
12400
12745
|
}
|
|
12401
|
-
var
|
|
12402
|
-
|
|
12746
|
+
var app20 = new Hono();
|
|
12747
|
+
app20.get("/", requireAdminSession, async (c) => {
|
|
12403
12748
|
const cacheKey = c.var.cacheKey;
|
|
12404
12749
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12405
12750
|
if (!accountId) {
|
|
@@ -12438,7 +12783,7 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
12438
12783
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
12439
12784
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
12440
12785
|
try {
|
|
12441
|
-
const entryPath =
|
|
12786
|
+
const entryPath = join23(absolute, name);
|
|
12442
12787
|
const s = await stat4(entryPath);
|
|
12443
12788
|
entries.push({
|
|
12444
12789
|
name,
|
|
@@ -12468,7 +12813,7 @@ app19.get("/", requireAdminSession, async (c) => {
|
|
|
12468
12813
|
return c.json({ error: message }, 500);
|
|
12469
12814
|
}
|
|
12470
12815
|
});
|
|
12471
|
-
|
|
12816
|
+
app20.get("/download", requireAdminSession, async (c) => {
|
|
12472
12817
|
const cacheKey = c.var.cacheKey;
|
|
12473
12818
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12474
12819
|
if (!accountId) {
|
|
@@ -12532,72 +12877,178 @@ app19.get("/download", requireAdminSession, async (c) => {
|
|
|
12532
12877
|
return c.json({ error: message }, 500);
|
|
12533
12878
|
}
|
|
12534
12879
|
});
|
|
12535
|
-
|
|
12880
|
+
function dataUploadCeiling() {
|
|
12881
|
+
const override = Number(process.env.MAXY_DATA_UPLOAD_MAX_BYTES);
|
|
12882
|
+
return Number.isFinite(override) && override > 0 ? override : MAX_DATA_UPLOAD_BYTES;
|
|
12883
|
+
}
|
|
12884
|
+
app20.post("/upload", requireAdminSession, async (c) => {
|
|
12536
12885
|
const cacheKey = c.var.cacheKey;
|
|
12537
12886
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12538
12887
|
if (!accountId) {
|
|
12539
|
-
console.error(`[data] auth-
|
|
12888
|
+
console.error(`[data-upload] op=auth-reject reason="no account for session"`);
|
|
12540
12889
|
return c.json({ error: "Account not found for session" }, 401);
|
|
12541
12890
|
}
|
|
12542
|
-
|
|
12543
|
-
|
|
12544
|
-
|
|
12545
|
-
|
|
12546
|
-
|
|
12547
|
-
|
|
12548
|
-
|
|
12549
|
-
const
|
|
12550
|
-
|
|
12551
|
-
|
|
12552
|
-
|
|
12553
|
-
|
|
12554
|
-
console.error(`[data] file-upload rejected reason="size" filename="${file.name}" size=${file.size}`);
|
|
12891
|
+
const rawName = c.req.query("filename") ?? "";
|
|
12892
|
+
const safeName = basename7(rawName).replace(/[\0/\\]/g, "_");
|
|
12893
|
+
if (!safeName) return c.json({ error: "filename query param required" }, 400);
|
|
12894
|
+
const uid = `${Date.now()}-${randomUUID10().slice(0, 8)}`;
|
|
12895
|
+
const declaredBytes = c.req.header("content-length") ?? "unknown";
|
|
12896
|
+
const rawRelpath = c.req.query("relpath") ?? "";
|
|
12897
|
+
const relpath = rawRelpath !== "" ? rawRelpath : null;
|
|
12898
|
+
const token = c.req.query("token") ?? "";
|
|
12899
|
+
const finalName = relpath ? basename7(relpath).replace(/[\0/\\]/g, "_") : `${Date.now()}-${safeName}`;
|
|
12900
|
+
const mimeType = (c.req.header("content-type") ?? "").split(";")[0].trim();
|
|
12901
|
+
if (!SUPPORTED_MIME_TYPES.has(mimeType)) {
|
|
12902
|
+
console.error(`[data-upload] op=reject-mime uid=${uid} mime="${mimeType}" token=${token} rel="${relpath ?? ""}"`);
|
|
12555
12903
|
return c.json({
|
|
12556
|
-
error: `
|
|
12904
|
+
error: `Unsupported file type: "${mimeType}". Supported: ${[...SUPPORTED_MIME_TYPES].join(", ")}.`
|
|
12557
12905
|
}, 422);
|
|
12558
12906
|
}
|
|
12559
|
-
|
|
12560
|
-
|
|
12561
|
-
|
|
12562
|
-
|
|
12563
|
-
|
|
12907
|
+
const rawDir = c.req.query("path") ?? "";
|
|
12908
|
+
const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
12909
|
+
if (!base.ok) return c.json({ error: base.error }, base.status);
|
|
12910
|
+
const relDir = relpath ? dirname6(relpath) : ".";
|
|
12911
|
+
const destRel = relDir === "." ? base.relative : join23(base.relative, relDir);
|
|
12912
|
+
if (crossesForeignAccountPartition(destRel, accountId)) {
|
|
12913
|
+
console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
12914
|
+
return c.json({ error: "Not found" }, 404);
|
|
12564
12915
|
}
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
|
|
12568
|
-
|
|
12569
|
-
|
|
12570
|
-
const destDir = dest.absolute;
|
|
12916
|
+
if (!isWithinOwnAccountPartition(destRel, accountId)) {
|
|
12917
|
+
console.error(`[data] write-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
12918
|
+
return c.json({ error: "Path is outside your account folder" }, 403);
|
|
12919
|
+
}
|
|
12920
|
+
const destDir = relDir === "." ? base.absolute : resolve22(base.absolute, relDir);
|
|
12571
12921
|
const destPath = resolve22(destDir, finalName);
|
|
12572
|
-
|
|
12573
|
-
const
|
|
12574
|
-
if (
|
|
12575
|
-
|
|
12576
|
-
const
|
|
12577
|
-
if (
|
|
12578
|
-
|
|
12579
|
-
|
|
12922
|
+
if (relpath) {
|
|
12923
|
+
const firstCreated = await mkdir3(destDir, { recursive: true });
|
|
12924
|
+
if (firstCreated) console.error(`[data-upload] op=mkdir uid=${uid} token=${token} dir="${destRel}"`);
|
|
12925
|
+
} else {
|
|
12926
|
+
const info = await stat4(destDir).catch(() => null);
|
|
12927
|
+
if (!info || !info.isDirectory()) return c.json({ error: "Upload destination is not a directory" }, 400);
|
|
12928
|
+
}
|
|
12929
|
+
const dataRootReal = realpathSync4(DATA_ROOT);
|
|
12930
|
+
const destDirReal = realpathSync4(destDir);
|
|
12931
|
+
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep6)) {
|
|
12932
|
+
console.error(`[data-upload] op=path-traversal-blocked uid=${uid} requested="${destRel}" resolved="${destDirReal}"`);
|
|
12933
|
+
return c.json({ error: "Upload destination escapes DATA_ROOT" }, 403);
|
|
12934
|
+
}
|
|
12935
|
+
const body = c.req.raw.body;
|
|
12936
|
+
if (!body) return c.json({ error: "Empty request body" }, 400);
|
|
12937
|
+
console.error(`[data-upload] op=request uid=${uid} account=${accountId} dir="${destRel}" token=${token} rel="${relpath ?? ""}" declaredBytes=${declaredBytes}`);
|
|
12938
|
+
const ceiling = dataUploadCeiling();
|
|
12939
|
+
const tmpDir = resolve22(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
|
|
12940
|
+
await mkdir3(tmpDir, { recursive: true });
|
|
12941
|
+
const tmpPath = resolve22(tmpDir, `${uid}.part`);
|
|
12942
|
+
const out = createWriteStream2(tmpPath);
|
|
12943
|
+
const t0 = Date.now();
|
|
12944
|
+
let received = 0;
|
|
12945
|
+
let lastLogged = 0;
|
|
12946
|
+
const LOG_EVERY = 64 * 1024 * 1024;
|
|
12947
|
+
let writeError = null;
|
|
12948
|
+
out.on("error", (e) => {
|
|
12949
|
+
writeError = e;
|
|
12950
|
+
});
|
|
12951
|
+
const cleanup = async () => {
|
|
12952
|
+
await new Promise((res) => {
|
|
12953
|
+
if (out.closed) return res();
|
|
12954
|
+
out.once("close", () => res());
|
|
12955
|
+
out.destroy();
|
|
12956
|
+
});
|
|
12957
|
+
await unlink2(tmpPath).catch(() => {
|
|
12958
|
+
});
|
|
12959
|
+
const tempRemoved = !existsSync23(tmpPath);
|
|
12960
|
+
console.error(`[data-upload] op=cleanup uid=${uid} tempRemoved=${tempRemoved}`);
|
|
12961
|
+
};
|
|
12962
|
+
const reader = body.getReader();
|
|
12963
|
+
try {
|
|
12964
|
+
for (; ; ) {
|
|
12965
|
+
if (writeError) throw writeError;
|
|
12966
|
+
const { done, value } = await reader.read();
|
|
12967
|
+
if (done) break;
|
|
12968
|
+
if (!value) continue;
|
|
12969
|
+
received += value.byteLength;
|
|
12970
|
+
if (received > ceiling) {
|
|
12971
|
+
console.error(`[data-upload] op=reject-size uid=${uid} received=${received} ceiling=${ceiling}`);
|
|
12972
|
+
await reader.cancel().catch(() => {
|
|
12973
|
+
});
|
|
12974
|
+
await cleanup();
|
|
12975
|
+
return c.json({
|
|
12976
|
+
error: `File exceeds the ${Math.floor(ceiling / 1024 / 1024)} MB limit.`
|
|
12977
|
+
}, 413);
|
|
12978
|
+
}
|
|
12979
|
+
if (!out.write(value)) {
|
|
12980
|
+
await new Promise((res, rej) => {
|
|
12981
|
+
const onDrain = () => {
|
|
12982
|
+
out.off("error", onErr);
|
|
12983
|
+
res();
|
|
12984
|
+
};
|
|
12985
|
+
const onErr = (e) => {
|
|
12986
|
+
out.off("drain", onDrain);
|
|
12987
|
+
rej(e);
|
|
12988
|
+
};
|
|
12989
|
+
out.once("drain", onDrain);
|
|
12990
|
+
out.once("error", onErr);
|
|
12991
|
+
});
|
|
12992
|
+
}
|
|
12993
|
+
if (received - lastLogged >= LOG_EVERY) {
|
|
12994
|
+
lastLogged = received;
|
|
12995
|
+
console.error(`[data-upload] op=streaming uid=${uid} received=${received}`);
|
|
12996
|
+
}
|
|
12580
12997
|
}
|
|
12581
|
-
|
|
12582
|
-
|
|
12998
|
+
await new Promise((res, rej) => {
|
|
12999
|
+
if (writeError) return rej(writeError);
|
|
13000
|
+
out.once("error", rej);
|
|
13001
|
+
out.end(() => res());
|
|
13002
|
+
});
|
|
13003
|
+
await rename(tmpPath, destPath);
|
|
12583
13004
|
} catch (err) {
|
|
12584
13005
|
const message = err instanceof Error ? err.message : String(err);
|
|
12585
|
-
console.error(`[data
|
|
13006
|
+
console.error(`[data-upload] op=error uid=${uid} err="${message}" token=${token} rel="${relpath ?? ""}"`);
|
|
13007
|
+
await cleanup();
|
|
12586
13008
|
return c.json({ error: message }, 500);
|
|
12587
13009
|
}
|
|
12588
|
-
const relativeDest = `${
|
|
12589
|
-
console.error(`[data
|
|
13010
|
+
const relativeDest = `${destRel}/${finalName}`;
|
|
13011
|
+
console.error(`[data-upload] op=committed uid=${uid} path="${relativeDest}" bytes=${received} token=${token} rel="${relpath ?? ""}" ms=${Date.now() - t0}`);
|
|
12590
13012
|
void indexFile(accountId, relativeDest).catch((err) => {
|
|
12591
|
-
console.error(`[data
|
|
13013
|
+
console.error(`[data-upload] op=index-failed uid=${uid} dest="${relativeDest}" err="${err instanceof Error ? err.message : String(err)}"`);
|
|
12592
13014
|
});
|
|
12593
13015
|
return c.json({
|
|
12594
13016
|
path: relativeDest,
|
|
12595
13017
|
filename: finalName,
|
|
12596
|
-
sizeBytes:
|
|
12597
|
-
mimeType
|
|
13018
|
+
sizeBytes: received,
|
|
13019
|
+
mimeType
|
|
12598
13020
|
});
|
|
12599
13021
|
});
|
|
12600
|
-
|
|
13022
|
+
async function sweepStaleUploadTemps() {
|
|
13023
|
+
const accountsRoot = resolve22(DATA_ROOT, "accounts");
|
|
13024
|
+
let accounts;
|
|
13025
|
+
try {
|
|
13026
|
+
accounts = await readdir3(accountsRoot, { withFileTypes: true });
|
|
13027
|
+
} catch {
|
|
13028
|
+
return 0;
|
|
13029
|
+
}
|
|
13030
|
+
let removed = 0;
|
|
13031
|
+
for (const acc of accounts) {
|
|
13032
|
+
if (!acc.isDirectory()) continue;
|
|
13033
|
+
const tmpDir = resolve22(accountsRoot, acc.name, UPLOAD_TMP_DIR);
|
|
13034
|
+
let entries;
|
|
13035
|
+
try {
|
|
13036
|
+
entries = await readdir3(tmpDir);
|
|
13037
|
+
} catch {
|
|
13038
|
+
continue;
|
|
13039
|
+
}
|
|
13040
|
+
for (const name of entries) {
|
|
13041
|
+
try {
|
|
13042
|
+
await unlink2(resolve22(tmpDir, name));
|
|
13043
|
+
removed++;
|
|
13044
|
+
} catch {
|
|
13045
|
+
}
|
|
13046
|
+
}
|
|
13047
|
+
}
|
|
13048
|
+
if (removed > 0) console.error(`[data-upload] op=sweep removed=${removed}`);
|
|
13049
|
+
return removed;
|
|
13050
|
+
}
|
|
13051
|
+
app20.delete("/", requireAdminSession, async (c) => {
|
|
12601
13052
|
const cacheKey = c.var.cacheKey;
|
|
12602
13053
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12603
13054
|
if (!accountId) {
|
|
@@ -12634,7 +13085,7 @@ app19.delete("/", requireAdminSession, async (c) => {
|
|
|
12634
13085
|
}
|
|
12635
13086
|
const dot = base.lastIndexOf(".");
|
|
12636
13087
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
12637
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
13088
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join23(dirname6(absolute), `${stem}.meta.json`) : null;
|
|
12638
13089
|
await unlink2(absolute);
|
|
12639
13090
|
if (sidecarPath) {
|
|
12640
13091
|
try {
|
|
@@ -12673,7 +13124,7 @@ app19.delete("/", requireAdminSession, async (c) => {
|
|
|
12673
13124
|
return c.json({ error: message }, 500);
|
|
12674
13125
|
}
|
|
12675
13126
|
});
|
|
12676
|
-
|
|
13127
|
+
app20.post("/folder", requireAdminSession, async (c) => {
|
|
12677
13128
|
const cacheKey = c.var.cacheKey;
|
|
12678
13129
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12679
13130
|
if (!accountId) {
|
|
@@ -12708,7 +13159,7 @@ app19.post("/folder", requireAdminSession, async (c) => {
|
|
|
12708
13159
|
console.error(`[data] folder-create path="${newRel}"`);
|
|
12709
13160
|
return c.json({ path: newRel });
|
|
12710
13161
|
});
|
|
12711
|
-
|
|
13162
|
+
app20.post("/rename", requireAdminSession, async (c) => {
|
|
12712
13163
|
const cacheKey = c.var.cacheKey;
|
|
12713
13164
|
const accountId = getAccountIdForSession(cacheKey);
|
|
12714
13165
|
if (!accountId) {
|
|
@@ -12758,7 +13209,7 @@ app19.post("/rename", requireAdminSession, async (c) => {
|
|
|
12758
13209
|
});
|
|
12759
13210
|
return c.json({ path: newRel });
|
|
12760
13211
|
});
|
|
12761
|
-
var files_default =
|
|
13212
|
+
var files_default = app20;
|
|
12762
13213
|
|
|
12763
13214
|
// ../lib/graph-search/src/index.ts
|
|
12764
13215
|
var import_dist = __toESM(require_dist());
|
|
@@ -13523,8 +13974,8 @@ var DEFAULT_LIMIT = 20;
|
|
|
13523
13974
|
var MAX_LIMIT = 2e3;
|
|
13524
13975
|
var MESSAGE_FAMILY_LABELS = ["Message", "UserMessage", "AssistantMessage", "WhatsAppMessage"];
|
|
13525
13976
|
var CONVERSATION_PARENT_LABELS = /* @__PURE__ */ new Set(["AdminConversation", "PublicConversation"]);
|
|
13526
|
-
var
|
|
13527
|
-
|
|
13977
|
+
var app21 = new Hono();
|
|
13978
|
+
app21.get("/", requireAdminSession, async (c) => {
|
|
13528
13979
|
const cacheKey = c.var.cacheKey;
|
|
13529
13980
|
const q = (c.req.query("q") ?? "").trim();
|
|
13530
13981
|
const rawLimit = c.req.query("limit");
|
|
@@ -13660,7 +14111,7 @@ app20.get("/", requireAdminSession, async (c) => {
|
|
|
13660
14111
|
await session.close();
|
|
13661
14112
|
}
|
|
13662
14113
|
});
|
|
13663
|
-
var graph_search_default =
|
|
14114
|
+
var graph_search_default = app21;
|
|
13664
14115
|
|
|
13665
14116
|
// server/routes/admin/graph-subgraph.ts
|
|
13666
14117
|
import neo4j2 from "neo4j-driver";
|
|
@@ -13744,8 +14195,8 @@ var STRIPPED_PROPERTIES = /* @__PURE__ */ new Set([
|
|
|
13744
14195
|
"otpCode",
|
|
13745
14196
|
"cacheKey"
|
|
13746
14197
|
]);
|
|
13747
|
-
var
|
|
13748
|
-
|
|
14198
|
+
var app22 = new Hono();
|
|
14199
|
+
app22.get("/", requireAdminSession, async (c) => {
|
|
13749
14200
|
const cacheKey = c.var.cacheKey;
|
|
13750
14201
|
const accountId = getAccountIdForSession(cacheKey);
|
|
13751
14202
|
if (!accountId) {
|
|
@@ -14328,12 +14779,12 @@ function pruneNode(node, warnedClasses, conversationWarnings) {
|
|
|
14328
14779
|
}
|
|
14329
14780
|
return trashed ? { id: node.id, labels, properties, trashed: true } : { id: node.id, labels, properties };
|
|
14330
14781
|
}
|
|
14331
|
-
var graph_subgraph_default =
|
|
14782
|
+
var graph_subgraph_default = app22;
|
|
14332
14783
|
|
|
14333
14784
|
// server/routes/admin/graph-delete.ts
|
|
14334
14785
|
var ALLOWED_BY = ["graph-page", "graph-drag-trash", "graph-side-panel-trash"];
|
|
14335
|
-
var
|
|
14336
|
-
|
|
14786
|
+
var app23 = new Hono();
|
|
14787
|
+
app23.post("/", requireAdminSession, async (c) => {
|
|
14337
14788
|
const cacheKey = c.var.cacheKey;
|
|
14338
14789
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14339
14790
|
if (!accountId) {
|
|
@@ -14495,11 +14946,11 @@ app22.post("/", requireAdminSession, async (c) => {
|
|
|
14495
14946
|
}
|
|
14496
14947
|
}
|
|
14497
14948
|
});
|
|
14498
|
-
var graph_delete_default =
|
|
14949
|
+
var graph_delete_default = app23;
|
|
14499
14950
|
|
|
14500
14951
|
// server/routes/admin/graph-restore.ts
|
|
14501
|
-
var
|
|
14502
|
-
|
|
14952
|
+
var app24 = new Hono();
|
|
14953
|
+
app24.post("/", requireAdminSession, async (c) => {
|
|
14503
14954
|
const cacheKey = c.var.cacheKey;
|
|
14504
14955
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14505
14956
|
if (!accountId) {
|
|
@@ -14563,11 +15014,11 @@ app23.post("/", requireAdminSession, async (c) => {
|
|
|
14563
15014
|
}
|
|
14564
15015
|
}
|
|
14565
15016
|
});
|
|
14566
|
-
var graph_restore_default =
|
|
15017
|
+
var graph_restore_default = app24;
|
|
14567
15018
|
|
|
14568
15019
|
// server/routes/admin/graph-labels-in-graph.ts
|
|
14569
|
-
var
|
|
14570
|
-
|
|
15020
|
+
var app25 = new Hono();
|
|
15021
|
+
app25.get("/", requireAdminSession, async (c) => {
|
|
14571
15022
|
const cacheKey = c.var.cacheKey;
|
|
14572
15023
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14573
15024
|
if (!accountId) {
|
|
@@ -14633,11 +15084,11 @@ var LABELS_IN_GRAPH_CYPHER = `
|
|
|
14633
15084
|
sum(halfEdges) AS relDegree
|
|
14634
15085
|
RETURN label, nodeCount, relDegree
|
|
14635
15086
|
`;
|
|
14636
|
-
var graph_labels_in_graph_default =
|
|
15087
|
+
var graph_labels_in_graph_default = app25;
|
|
14637
15088
|
|
|
14638
15089
|
// server/routes/admin/graph-default-view.ts
|
|
14639
|
-
var
|
|
14640
|
-
|
|
15090
|
+
var app26 = new Hono();
|
|
15091
|
+
app26.get("/", requireAdminSession, async (c) => {
|
|
14641
15092
|
const cacheKey = c.var.cacheKey;
|
|
14642
15093
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14643
15094
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -14675,7 +15126,7 @@ app25.get("/", requireAdminSession, async (c) => {
|
|
|
14675
15126
|
}
|
|
14676
15127
|
}
|
|
14677
15128
|
});
|
|
14678
|
-
|
|
15129
|
+
app26.put("/", requireAdminSession, async (c) => {
|
|
14679
15130
|
const cacheKey = c.var.cacheKey;
|
|
14680
15131
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14681
15132
|
const userId = getUserIdForSession(cacheKey);
|
|
@@ -14764,20 +15215,20 @@ var WRITE_CYPHER = `
|
|
|
14764
15215
|
p.updatedAt = $updatedAt
|
|
14765
15216
|
RETURN p.labels AS labels
|
|
14766
15217
|
`;
|
|
14767
|
-
var graph_default_view_default =
|
|
15218
|
+
var graph_default_view_default = app26;
|
|
14768
15219
|
|
|
14769
15220
|
// server/routes/admin/sidebar-artefacts.ts
|
|
14770
15221
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
14771
15222
|
import { resolve as resolve23, relative as relative3, isAbsolute, sep as sep7, basename as basename8 } from "path";
|
|
14772
|
-
import { existsSync as
|
|
15223
|
+
import { existsSync as existsSync24 } from "fs";
|
|
14773
15224
|
var LIMIT = 50;
|
|
14774
15225
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
14775
15226
|
function toDataRootRelPath(absPath) {
|
|
14776
15227
|
if (absPath !== DATA_ROOT && !absPath.startsWith(DATA_ROOT + sep7)) return null;
|
|
14777
15228
|
return relative3(DATA_ROOT, absPath);
|
|
14778
15229
|
}
|
|
14779
|
-
var
|
|
14780
|
-
|
|
15230
|
+
var app27 = new Hono();
|
|
15231
|
+
app27.get("/", requireAdminSession, async (c) => {
|
|
14781
15232
|
const cacheKey = c.var.cacheKey;
|
|
14782
15233
|
const accountId = getAccountIdForSession(cacheKey);
|
|
14783
15234
|
if (!accountId) {
|
|
@@ -14876,7 +15327,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
14876
15327
|
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
14877
15328
|
const names = /* @__PURE__ */ new Set();
|
|
14878
15329
|
for (const dir of [overrideDir, bundledDir]) {
|
|
14879
|
-
if (!
|
|
15330
|
+
if (!existsSync24(dir)) continue;
|
|
14880
15331
|
try {
|
|
14881
15332
|
const entries = await readdir4(dir);
|
|
14882
15333
|
for (const entry of entries) {
|
|
@@ -14891,7 +15342,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
14891
15342
|
}
|
|
14892
15343
|
async function readAgentTemplateRow(inp) {
|
|
14893
15344
|
let chosenPath = null;
|
|
14894
|
-
if (
|
|
15345
|
+
if (existsSync24(inp.overridePath)) {
|
|
14895
15346
|
try {
|
|
14896
15347
|
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
14897
15348
|
chosenPath = inp.overridePath;
|
|
@@ -14902,7 +15353,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
14902
15353
|
);
|
|
14903
15354
|
return null;
|
|
14904
15355
|
}
|
|
14905
|
-
} else if (
|
|
15356
|
+
} else if (existsSync24(inp.bundledPath)) {
|
|
14906
15357
|
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
14907
15358
|
console.error(
|
|
14908
15359
|
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
@@ -14941,11 +15392,11 @@ function isWithin(target, root) {
|
|
|
14941
15392
|
const rel = relative3(root, target);
|
|
14942
15393
|
return !rel.startsWith("..") && !isAbsolute(rel);
|
|
14943
15394
|
}
|
|
14944
|
-
var sidebar_artefacts_default =
|
|
15395
|
+
var sidebar_artefacts_default = app27;
|
|
14945
15396
|
|
|
14946
15397
|
// server/routes/admin/session-delete.ts
|
|
14947
|
-
var
|
|
14948
|
-
|
|
15398
|
+
var app28 = new Hono();
|
|
15399
|
+
app28.post("/", requireAdminSession, async (c) => {
|
|
14949
15400
|
let body;
|
|
14950
15401
|
try {
|
|
14951
15402
|
body = await c.req.json();
|
|
@@ -14983,11 +15434,11 @@ app27.post("/", requireAdminSession, async (c) => {
|
|
|
14983
15434
|
console.error(`[session-delete] sessionId=${sessionId} delete-status=${del.status}`);
|
|
14984
15435
|
return c.json({ error: `manager-status-${del.status}` }, 502);
|
|
14985
15436
|
});
|
|
14986
|
-
var session_delete_default =
|
|
15437
|
+
var session_delete_default = app28;
|
|
14987
15438
|
|
|
14988
15439
|
// server/routes/admin/session-stop.ts
|
|
14989
|
-
var
|
|
14990
|
-
|
|
15440
|
+
var app29 = new Hono();
|
|
15441
|
+
app29.post("/", requireAdminSession, async (c) => {
|
|
14991
15442
|
let body;
|
|
14992
15443
|
try {
|
|
14993
15444
|
body = await c.req.json();
|
|
@@ -15012,11 +15463,11 @@ app28.post("/", requireAdminSession, async (c) => {
|
|
|
15012
15463
|
console.error(`[session-stop] sessionId=${sessionId} manager-status=${res.status}`);
|
|
15013
15464
|
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
15014
15465
|
});
|
|
15015
|
-
var session_stop_default =
|
|
15466
|
+
var session_stop_default = app29;
|
|
15016
15467
|
|
|
15017
15468
|
// server/routes/admin/session-archive.ts
|
|
15018
|
-
var
|
|
15019
|
-
|
|
15469
|
+
var app30 = new Hono();
|
|
15470
|
+
app30.post("/", requireAdminSession, async (c) => {
|
|
15020
15471
|
let body;
|
|
15021
15472
|
try {
|
|
15022
15473
|
body = await c.req.json();
|
|
@@ -15064,11 +15515,54 @@ app29.post("/", requireAdminSession, async (c) => {
|
|
|
15064
15515
|
console.error(`[session-archive] sessionId=${sessionId.slice(0, 8)} manager-status=${res.status}`);
|
|
15065
15516
|
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
15066
15517
|
});
|
|
15067
|
-
var session_archive_default =
|
|
15518
|
+
var session_archive_default = app30;
|
|
15519
|
+
|
|
15520
|
+
// server/routes/admin/session-rename.ts
|
|
15521
|
+
var app31 = new Hono();
|
|
15522
|
+
app31.post("/", requireAdminSession, async (c) => {
|
|
15523
|
+
let body;
|
|
15524
|
+
try {
|
|
15525
|
+
body = await c.req.json();
|
|
15526
|
+
} catch {
|
|
15527
|
+
return c.json({ error: "invalid JSON body" }, 400);
|
|
15528
|
+
}
|
|
15529
|
+
const sessionId = typeof body.sessionId === "string" ? body.sessionId : "";
|
|
15530
|
+
if (!SESSION_ID_RE2.test(sessionId)) {
|
|
15531
|
+
return c.json({ error: "sessionId must be a v4 UUID" }, 400);
|
|
15532
|
+
}
|
|
15533
|
+
let res;
|
|
15534
|
+
try {
|
|
15535
|
+
res = await fetch(`${managerBase("session-rename:wrapper")}/${sessionId}/rename`, {
|
|
15536
|
+
method: "POST",
|
|
15537
|
+
headers: { "Content-Type": "application/json" },
|
|
15538
|
+
body: JSON.stringify({ title: body.title })
|
|
15539
|
+
});
|
|
15540
|
+
} catch (err) {
|
|
15541
|
+
console.error(`[session-rename] sessionId=${sessionId.slice(0, 8)} manager-unreachable err=${err instanceof Error ? err.message : String(err)}`);
|
|
15542
|
+
return c.json({ error: "manager-unreachable" }, 502);
|
|
15543
|
+
}
|
|
15544
|
+
if (res.status === 200) {
|
|
15545
|
+
const ok = await res.json().catch(() => ({}));
|
|
15546
|
+
console.log(`[session-rename] sessionId=${sessionId.slice(0, 8)} renamed`);
|
|
15547
|
+
return c.json({ ok: true, sessionId: ok.sessionId ?? sessionId, titleSource: ok.titleSource ?? "user" });
|
|
15548
|
+
}
|
|
15549
|
+
if (res.status === 400) {
|
|
15550
|
+
const b = await res.json().catch(() => ({}));
|
|
15551
|
+
console.error(`[session-rename] sessionId=${sessionId.slice(0, 8)} invalid-title reason=${b.reason ?? "unknown"}`);
|
|
15552
|
+
return c.json({ error: "invalid-title", reason: b.reason ?? "invalid" }, 400);
|
|
15553
|
+
}
|
|
15554
|
+
if (res.status === 404) {
|
|
15555
|
+
console.error(`[session-rename] sessionId=${sessionId.slice(0, 8)} session-not-found`);
|
|
15556
|
+
return c.json({ error: "session-not-found" }, 404);
|
|
15557
|
+
}
|
|
15558
|
+
console.error(`[session-rename] sessionId=${sessionId.slice(0, 8)} manager-status=${res.status}`);
|
|
15559
|
+
return c.json({ error: `manager-status-${res.status}` }, 502);
|
|
15560
|
+
});
|
|
15561
|
+
var session_rename_default = app31;
|
|
15068
15562
|
|
|
15069
15563
|
// server/routes/admin/session-rc-spawn.ts
|
|
15070
|
-
import { randomUUID as
|
|
15071
|
-
function resolveSpawnPlan(host, operatorDomains, body, mintId =
|
|
15564
|
+
import { randomUUID as randomUUID11 } from "crypto";
|
|
15565
|
+
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID11, adminUserId, authenticatedName) {
|
|
15072
15566
|
const operator = isOperatorHost(host, operatorDomains);
|
|
15073
15567
|
const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
|
|
15074
15568
|
const name = typeof body.name === "string" && body.name.length > 0 ? body.name : void 0;
|
|
@@ -15101,8 +15595,8 @@ function shapeWebchatResponse(sessionId, manager) {
|
|
|
15101
15595
|
const landed = redirected ? manager.sessionId : sessionId;
|
|
15102
15596
|
return { sessionId: landed, outcome, target: `/chat?session=${landed}` };
|
|
15103
15597
|
}
|
|
15104
|
-
var
|
|
15105
|
-
|
|
15598
|
+
var app32 = new Hono();
|
|
15599
|
+
app32.post("/", requireAdminSession, async (c) => {
|
|
15106
15600
|
let body;
|
|
15107
15601
|
try {
|
|
15108
15602
|
body = await c.req.json();
|
|
@@ -15114,8 +15608,8 @@ app30.post("/", requireAdminSession, async (c) => {
|
|
|
15114
15608
|
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
15115
15609
|
const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
|
|
15116
15610
|
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
15117
|
-
const plan = resolveSpawnPlan(host, getOperatorDomains(), body,
|
|
15118
|
-
const spawnReqId =
|
|
15611
|
+
const plan = resolveSpawnPlan(host, getOperatorDomains(), body, randomUUID11, adminUserId, authenticatedName);
|
|
15612
|
+
const spawnReqId = randomUUID11();
|
|
15119
15613
|
console.log(
|
|
15120
15614
|
`[chat-spawn] op=request spawnReqId=${spawnReqId} origin=${plan.origin} kind=${plan.kind} sessionId=${plan.kind === "new" ? "new" : plan.sessionId}`
|
|
15121
15615
|
);
|
|
@@ -15157,10 +15651,10 @@ app30.post("/", requireAdminSession, async (c) => {
|
|
|
15157
15651
|
}
|
|
15158
15652
|
return c.json(parsed ?? {});
|
|
15159
15653
|
});
|
|
15160
|
-
var session_rc_spawn_default =
|
|
15654
|
+
var session_rc_spawn_default = app32;
|
|
15161
15655
|
|
|
15162
15656
|
// server/routes/admin/session-reseat.ts
|
|
15163
|
-
import { randomUUID as
|
|
15657
|
+
import { randomUUID as randomUUID12 } from "crypto";
|
|
15164
15658
|
|
|
15165
15659
|
// ../lib/models/src/index.ts
|
|
15166
15660
|
var OPUS_MODEL = "claude-opus-4-8[1m]";
|
|
@@ -15182,7 +15676,7 @@ function isSelectableModel(id) {
|
|
|
15182
15676
|
}
|
|
15183
15677
|
|
|
15184
15678
|
// server/routes/admin/session-reseat.ts
|
|
15185
|
-
function resolveReseatPlan(body, mintId =
|
|
15679
|
+
function resolveReseatPlan(body, mintId = randomUUID12, adminUserId, authenticatedName) {
|
|
15186
15680
|
const sessionId = mintId();
|
|
15187
15681
|
const key = `session:${sessionId}`;
|
|
15188
15682
|
const payload = {
|
|
@@ -15199,9 +15693,9 @@ function resolveReseatPlan(body, mintId = randomUUID11, adminUserId, authenticat
|
|
|
15199
15693
|
if (authenticatedName) payload.authenticatedName = authenticatedName;
|
|
15200
15694
|
return { sessionId, payload };
|
|
15201
15695
|
}
|
|
15202
|
-
var
|
|
15696
|
+
var app33 = new Hono();
|
|
15203
15697
|
var reseatsInFlight = /* @__PURE__ */ new Set();
|
|
15204
|
-
|
|
15698
|
+
app33.post("/", requireAdminSession, async (c) => {
|
|
15205
15699
|
let body;
|
|
15206
15700
|
try {
|
|
15207
15701
|
body = await c.req.json();
|
|
@@ -15221,8 +15715,8 @@ app31.post("/", requireAdminSession, async (c) => {
|
|
|
15221
15715
|
const adminUserId = cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
15222
15716
|
const accountId = cacheKey ? getAccountIdForSession(cacheKey) : void 0;
|
|
15223
15717
|
const authenticatedName = accountId ? await resolveAuthenticatedName(accountId, adminUserId) : void 0;
|
|
15224
|
-
const plan = resolveReseatPlan({ fromSessionId, model },
|
|
15225
|
-
const reseatReqId =
|
|
15718
|
+
const plan = resolveReseatPlan({ fromSessionId, model }, randomUUID12, adminUserId, authenticatedName);
|
|
15719
|
+
const reseatReqId = randomUUID12();
|
|
15226
15720
|
console.log(`[chat-reseat] op=request reseatReqId=${reseatReqId} from=${fromSessionId} to-model=${model} new=${plan.sessionId}`);
|
|
15227
15721
|
let res;
|
|
15228
15722
|
try {
|
|
@@ -15272,7 +15766,7 @@ app31.post("/", requireAdminSession, async (c) => {
|
|
|
15272
15766
|
reseatsInFlight.delete(fromSessionId);
|
|
15273
15767
|
}
|
|
15274
15768
|
});
|
|
15275
|
-
var session_reseat_default =
|
|
15769
|
+
var session_reseat_default = app33;
|
|
15276
15770
|
|
|
15277
15771
|
// server/routes/admin/system-stats.ts
|
|
15278
15772
|
import { readFile as readFile5 } from "fs/promises";
|
|
@@ -15369,8 +15863,8 @@ async function sample() {
|
|
|
15369
15863
|
if (process.platform === "linux") return sampleLinux();
|
|
15370
15864
|
return sampleOsFallback();
|
|
15371
15865
|
}
|
|
15372
|
-
var
|
|
15373
|
-
|
|
15866
|
+
var app34 = new Hono();
|
|
15867
|
+
app34.get("/", async (c) => {
|
|
15374
15868
|
const started = Date.now();
|
|
15375
15869
|
if (!inflight) {
|
|
15376
15870
|
inflight = sample().finally(() => {
|
|
@@ -15393,17 +15887,17 @@ app32.get("/", async (c) => {
|
|
|
15393
15887
|
return c.json({ degraded: true, reason, sampledAtMs: Date.now() });
|
|
15394
15888
|
}
|
|
15395
15889
|
});
|
|
15396
|
-
var system_stats_default =
|
|
15890
|
+
var system_stats_default = app34;
|
|
15397
15891
|
|
|
15398
15892
|
// server/routes/admin/health.ts
|
|
15399
|
-
import { existsSync as
|
|
15400
|
-
import { resolve as resolve24, join as
|
|
15893
|
+
import { existsSync as existsSync25, readFileSync as readFileSync24 } from "fs";
|
|
15894
|
+
import { resolve as resolve24, join as join24 } from "path";
|
|
15401
15895
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
|
|
15402
15896
|
var brandHostname = "maxy";
|
|
15403
|
-
var brandJsonPath =
|
|
15404
|
-
if (
|
|
15897
|
+
var brandJsonPath = join24(PLATFORM_ROOT6, "config", "brand.json");
|
|
15898
|
+
if (existsSync25(brandJsonPath)) {
|
|
15405
15899
|
try {
|
|
15406
|
-
const brand = JSON.parse(
|
|
15900
|
+
const brand = JSON.parse(readFileSync24(brandJsonPath, "utf-8"));
|
|
15407
15901
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
15408
15902
|
} catch {
|
|
15409
15903
|
}
|
|
@@ -15412,8 +15906,8 @@ var VERSION_FILE = resolve24(PLATFORM_ROOT6, `config/.${brandHostname}-version`)
|
|
|
15412
15906
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
15413
15907
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
15414
15908
|
function readVersion() {
|
|
15415
|
-
if (!
|
|
15416
|
-
return
|
|
15909
|
+
if (!existsSync25(VERSION_FILE)) return "unknown";
|
|
15910
|
+
return readFileSync24(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
15417
15911
|
}
|
|
15418
15912
|
async function probeConversationDb() {
|
|
15419
15913
|
let session;
|
|
@@ -15438,8 +15932,8 @@ async function probeConversationDb() {
|
|
|
15438
15932
|
});
|
|
15439
15933
|
}
|
|
15440
15934
|
}
|
|
15441
|
-
var
|
|
15442
|
-
|
|
15935
|
+
var app35 = new Hono();
|
|
15936
|
+
app35.get("/", async (c) => {
|
|
15443
15937
|
const version = readVersion();
|
|
15444
15938
|
const probe = await probeConversationDb();
|
|
15445
15939
|
const uptimeMs = Date.now() - new Date(PROCESS_STARTED_AT).getTime();
|
|
@@ -15461,11 +15955,11 @@ app33.get("/", async (c) => {
|
|
|
15461
15955
|
uptimeMs
|
|
15462
15956
|
});
|
|
15463
15957
|
});
|
|
15464
|
-
var health_default2 =
|
|
15958
|
+
var health_default2 = app35;
|
|
15465
15959
|
|
|
15466
15960
|
// server/routes/admin/linkedin-ingest.ts
|
|
15467
|
-
import { randomUUID as
|
|
15468
|
-
var
|
|
15961
|
+
import { randomUUID as randomUUID13 } from "crypto";
|
|
15962
|
+
var TAG27 = "[linkedin-ingest-route]";
|
|
15469
15963
|
var UUID2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
15470
15964
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
15471
15965
|
var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
|
|
@@ -15563,35 +16057,35 @@ function buildInitialMessage(env) {
|
|
|
15563
16057
|
}
|
|
15564
16058
|
return header;
|
|
15565
16059
|
}
|
|
15566
|
-
var
|
|
15567
|
-
|
|
16060
|
+
var app36 = new Hono();
|
|
16061
|
+
app36.post("/", requireAdminSession, async (c) => {
|
|
15568
16062
|
let body;
|
|
15569
16063
|
try {
|
|
15570
16064
|
body = await c.req.json();
|
|
15571
16065
|
} catch {
|
|
15572
|
-
console.error(
|
|
16066
|
+
console.error(TAG27 + " rejected status=400 reason=schema:body-not-json");
|
|
15573
16067
|
return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
|
|
15574
16068
|
}
|
|
15575
16069
|
const v = validate(body);
|
|
15576
16070
|
if (!v.ok) {
|
|
15577
|
-
console.error(
|
|
16071
|
+
console.error(TAG27 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
|
|
15578
16072
|
return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
|
|
15579
16073
|
}
|
|
15580
16074
|
const envelope = v.envelope;
|
|
15581
16075
|
const cacheKey = c.var.cacheKey ?? "";
|
|
15582
16076
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
15583
16077
|
if (!senderId) {
|
|
15584
|
-
console.error(
|
|
16078
|
+
console.error(TAG27 + " rejected status=500 reason=admin-account-not-resolved");
|
|
15585
16079
|
return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
|
|
15586
16080
|
}
|
|
15587
16081
|
const payloadBytes = JSON.stringify(envelope).length;
|
|
15588
16082
|
console.log(
|
|
15589
|
-
|
|
16083
|
+
TAG27 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
|
|
15590
16084
|
);
|
|
15591
16085
|
const initialMessage = buildInitialMessage(envelope);
|
|
15592
16086
|
const spawnStart = Date.now();
|
|
15593
|
-
const sessionId =
|
|
15594
|
-
console.log(
|
|
16087
|
+
const sessionId = randomUUID13();
|
|
16088
|
+
console.log(TAG27 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
15595
16089
|
const spawned = await managerRcSpawn({
|
|
15596
16090
|
sessionId,
|
|
15597
16091
|
initialMessage,
|
|
@@ -15600,20 +16094,20 @@ app34.post("/", requireAdminSession, async (c) => {
|
|
|
15600
16094
|
});
|
|
15601
16095
|
if ("error" in spawned) {
|
|
15602
16096
|
console.error(
|
|
15603
|
-
|
|
16097
|
+
TAG27 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
|
|
15604
16098
|
);
|
|
15605
16099
|
return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
|
|
15606
16100
|
}
|
|
15607
16101
|
console.log(
|
|
15608
|
-
|
|
16102
|
+
TAG27 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
|
|
15609
16103
|
);
|
|
15610
16104
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
15611
16105
|
});
|
|
15612
|
-
var linkedin_ingest_default =
|
|
16106
|
+
var linkedin_ingest_default = app36;
|
|
15613
16107
|
|
|
15614
16108
|
// server/routes/admin/post-turn-context.ts
|
|
15615
16109
|
import neo4j3 from "neo4j-driver";
|
|
15616
|
-
var
|
|
16110
|
+
var TAG28 = "[post-turn-context]";
|
|
15617
16111
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
15618
16112
|
"embedding",
|
|
15619
16113
|
"passwordHash",
|
|
@@ -15651,11 +16145,11 @@ function pruneProperties(raw) {
|
|
|
15651
16145
|
}
|
|
15652
16146
|
return out;
|
|
15653
16147
|
}
|
|
15654
|
-
var
|
|
15655
|
-
|
|
16148
|
+
var app37 = new Hono();
|
|
16149
|
+
app37.get("/", async (c) => {
|
|
15656
16150
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15657
16151
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
15658
|
-
console.error(`${
|
|
16152
|
+
console.error(`${TAG28} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15659
16153
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
15660
16154
|
}
|
|
15661
16155
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15664,7 +16158,7 @@ app35.get("/", async (c) => {
|
|
|
15664
16158
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15665
16159
|
const offender = tokens.find((t) => !isLoopbackAddr2(t));
|
|
15666
16160
|
if (offender !== void 0) {
|
|
15667
|
-
console.error(`${
|
|
16161
|
+
console.error(`${TAG28} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15668
16162
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
15669
16163
|
}
|
|
15670
16164
|
}
|
|
@@ -15696,7 +16190,7 @@ app35.get("/", async (c) => {
|
|
|
15696
16190
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
15697
16191
|
const total = Date.now() - started;
|
|
15698
16192
|
console.log(
|
|
15699
|
-
`${
|
|
16193
|
+
`${TAG28} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
|
|
15700
16194
|
);
|
|
15701
16195
|
return c.json({
|
|
15702
16196
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -15705,18 +16199,18 @@ app35.get("/", async (c) => {
|
|
|
15705
16199
|
const elapsed = Date.now() - started;
|
|
15706
16200
|
const message = err instanceof Error ? err.message : String(err);
|
|
15707
16201
|
console.error(
|
|
15708
|
-
`${
|
|
16202
|
+
`${TAG28} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
|
|
15709
16203
|
);
|
|
15710
16204
|
return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
|
|
15711
16205
|
} finally {
|
|
15712
16206
|
await session.close();
|
|
15713
16207
|
}
|
|
15714
16208
|
});
|
|
15715
|
-
var post_turn_context_default =
|
|
16209
|
+
var post_turn_context_default = app37;
|
|
15716
16210
|
|
|
15717
16211
|
// server/routes/admin/public-session-context.ts
|
|
15718
16212
|
import neo4j4 from "neo4j-driver";
|
|
15719
|
-
var
|
|
16213
|
+
var TAG29 = "[public-session-context]";
|
|
15720
16214
|
var STRIPPED_PROPERTIES3 = /* @__PURE__ */ new Set([
|
|
15721
16215
|
"embedding",
|
|
15722
16216
|
"passwordHash",
|
|
@@ -15754,11 +16248,11 @@ function pruneProperties2(raw) {
|
|
|
15754
16248
|
}
|
|
15755
16249
|
return out;
|
|
15756
16250
|
}
|
|
15757
|
-
var
|
|
15758
|
-
|
|
16251
|
+
var app38 = new Hono();
|
|
16252
|
+
app38.get("/", async (c) => {
|
|
15759
16253
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15760
16254
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
15761
|
-
console.error(`${
|
|
16255
|
+
console.error(`${TAG29} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15762
16256
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
15763
16257
|
}
|
|
15764
16258
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15767,7 +16261,7 @@ app36.get("/", async (c) => {
|
|
|
15767
16261
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15768
16262
|
const offender = tokens.find((t) => !isLoopbackAddr3(t));
|
|
15769
16263
|
if (offender !== void 0) {
|
|
15770
|
-
console.error(`${
|
|
16264
|
+
console.error(`${TAG29} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15771
16265
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
15772
16266
|
}
|
|
15773
16267
|
}
|
|
@@ -15798,7 +16292,7 @@ app36.get("/", async (c) => {
|
|
|
15798
16292
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
15799
16293
|
const total = Date.now() - started;
|
|
15800
16294
|
console.log(
|
|
15801
|
-
`${
|
|
16295
|
+
`${TAG29} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
|
|
15802
16296
|
);
|
|
15803
16297
|
return c.json({
|
|
15804
16298
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -15807,25 +16301,25 @@ app36.get("/", async (c) => {
|
|
|
15807
16301
|
const elapsed = Date.now() - started;
|
|
15808
16302
|
const message = err instanceof Error ? err.message : String(err);
|
|
15809
16303
|
console.error(
|
|
15810
|
-
`${
|
|
16304
|
+
`${TAG29} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
|
|
15811
16305
|
);
|
|
15812
16306
|
return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
|
|
15813
16307
|
} finally {
|
|
15814
16308
|
await session.close();
|
|
15815
16309
|
}
|
|
15816
16310
|
});
|
|
15817
|
-
var public_session_context_default =
|
|
16311
|
+
var public_session_context_default = app38;
|
|
15818
16312
|
|
|
15819
16313
|
// server/routes/admin/public-session-exit.ts
|
|
15820
|
-
var
|
|
16314
|
+
var TAG30 = "[public-session-exit-route]";
|
|
15821
16315
|
function isLoopbackAddr4(addr) {
|
|
15822
16316
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15823
16317
|
}
|
|
15824
|
-
var
|
|
15825
|
-
|
|
16318
|
+
var app39 = new Hono();
|
|
16319
|
+
app39.post("/", async (c) => {
|
|
15826
16320
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15827
16321
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
15828
|
-
console.error(`${
|
|
16322
|
+
console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15829
16323
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
15830
16324
|
}
|
|
15831
16325
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15834,7 +16328,7 @@ app37.post("/", async (c) => {
|
|
|
15834
16328
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15835
16329
|
const offender = tokens.find((t) => !isLoopbackAddr4(t));
|
|
15836
16330
|
if (offender !== void 0) {
|
|
15837
|
-
console.error(`${
|
|
16331
|
+
console.error(`${TAG30} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15838
16332
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
15839
16333
|
}
|
|
15840
16334
|
}
|
|
@@ -15849,18 +16343,18 @@ app37.post("/", async (c) => {
|
|
|
15849
16343
|
handlePublicSessionExit(sessionId);
|
|
15850
16344
|
return c.json({ ok: true });
|
|
15851
16345
|
});
|
|
15852
|
-
var public_session_exit_default =
|
|
16346
|
+
var public_session_exit_default = app39;
|
|
15853
16347
|
|
|
15854
16348
|
// server/routes/admin/access-session-evict.ts
|
|
15855
|
-
var
|
|
16349
|
+
var TAG31 = "[access-session-evict]";
|
|
15856
16350
|
function isLoopbackAddr5(addr) {
|
|
15857
16351
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15858
16352
|
}
|
|
15859
|
-
var
|
|
15860
|
-
|
|
16353
|
+
var app40 = new Hono();
|
|
16354
|
+
app40.post("/", async (c) => {
|
|
15861
16355
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15862
16356
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
15863
|
-
console.error(`${
|
|
16357
|
+
console.error(`${TAG31} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15864
16358
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
15865
16359
|
}
|
|
15866
16360
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15869,7 +16363,7 @@ app38.post("/", async (c) => {
|
|
|
15869
16363
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15870
16364
|
const offender = tokens.find((t) => !isLoopbackAddr5(t));
|
|
15871
16365
|
if (offender !== void 0) {
|
|
15872
|
-
console.error(`${
|
|
16366
|
+
console.error(`${TAG31} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15873
16367
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
15874
16368
|
}
|
|
15875
16369
|
}
|
|
@@ -15882,22 +16376,22 @@ app38.post("/", async (c) => {
|
|
|
15882
16376
|
const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
|
|
15883
16377
|
if (!grantId) return c.json({ error: "grantId required" }, 400);
|
|
15884
16378
|
const dropped = evictAccessSessionsByGrant(grantId);
|
|
15885
|
-
console.log(`${
|
|
16379
|
+
console.log(`${TAG31} grantId=${grantId} dropped=${dropped}`);
|
|
15886
16380
|
return c.json({ ok: true, dropped });
|
|
15887
16381
|
});
|
|
15888
|
-
var access_session_evict_default =
|
|
16382
|
+
var access_session_evict_default = app40;
|
|
15889
16383
|
|
|
15890
16384
|
// server/routes/admin/enrol-person.ts
|
|
15891
|
-
var
|
|
16385
|
+
var TAG32 = "[enrol]";
|
|
15892
16386
|
function isLoopbackAddr6(addr) {
|
|
15893
16387
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
15894
16388
|
}
|
|
15895
16389
|
var EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
15896
|
-
var
|
|
15897
|
-
|
|
16390
|
+
var app41 = new Hono();
|
|
16391
|
+
app41.post("/", async (c) => {
|
|
15898
16392
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15899
16393
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
15900
|
-
console.error(`${
|
|
16394
|
+
console.error(`${TAG32} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15901
16395
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
15902
16396
|
}
|
|
15903
16397
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15906,7 +16400,7 @@ app39.post("/", async (c) => {
|
|
|
15906
16400
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15907
16401
|
const offender = tokens.find((t) => !isLoopbackAddr6(t));
|
|
15908
16402
|
if (offender !== void 0) {
|
|
15909
|
-
console.error(`${
|
|
16403
|
+
console.error(`${TAG32} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15910
16404
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
15911
16405
|
}
|
|
15912
16406
|
}
|
|
@@ -15931,7 +16425,7 @@ app39.post("/", async (c) => {
|
|
|
15931
16425
|
}
|
|
15932
16426
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
15933
16427
|
if (!accountId) {
|
|
15934
|
-
console.error(`${
|
|
16428
|
+
console.error(`${TAG32} op=person result=no-account-id`);
|
|
15935
16429
|
return c.json({ error: "no-account-id" }, 500);
|
|
15936
16430
|
}
|
|
15937
16431
|
let personId;
|
|
@@ -15939,7 +16433,7 @@ app39.post("/", async (c) => {
|
|
|
15939
16433
|
personId = await enrolPerson({ accountId, phone, email, agentSlug });
|
|
15940
16434
|
} catch (err) {
|
|
15941
16435
|
console.error(
|
|
15942
|
-
`${
|
|
16436
|
+
`${TAG32} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
15943
16437
|
);
|
|
15944
16438
|
return c.json({ error: "enrol-failed" }, 500);
|
|
15945
16439
|
}
|
|
@@ -15949,19 +16443,19 @@ app39.post("/", async (c) => {
|
|
|
15949
16443
|
if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
|
|
15950
16444
|
} catch (err) {
|
|
15951
16445
|
console.error(
|
|
15952
|
-
`${
|
|
16446
|
+
`${TAG32} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
15953
16447
|
);
|
|
15954
16448
|
}
|
|
15955
16449
|
console.log(
|
|
15956
|
-
`${
|
|
16450
|
+
`${TAG32} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
|
|
15957
16451
|
);
|
|
15958
16452
|
return c.json({ personId, grant }, 200);
|
|
15959
16453
|
});
|
|
15960
|
-
var enrol_person_default =
|
|
16454
|
+
var enrol_person_default = app41;
|
|
15961
16455
|
|
|
15962
16456
|
// server/routes/admin/browser.ts
|
|
15963
|
-
var
|
|
15964
|
-
|
|
16457
|
+
var app42 = new Hono();
|
|
16458
|
+
app42.post("/launch", requireAdminSession, async (c) => {
|
|
15965
16459
|
try {
|
|
15966
16460
|
const transport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
|
|
15967
16461
|
console.error(`[admin/browser/launch] op=request transport=${transport}`);
|
|
@@ -15989,50 +16483,51 @@ app40.post("/launch", requireAdminSession, async (c) => {
|
|
|
15989
16483
|
);
|
|
15990
16484
|
}
|
|
15991
16485
|
});
|
|
15992
|
-
var browser_default =
|
|
16486
|
+
var browser_default = app42;
|
|
15993
16487
|
|
|
15994
16488
|
// server/routes/admin/index.ts
|
|
15995
|
-
var
|
|
15996
|
-
|
|
15997
|
-
|
|
15998
|
-
|
|
15999
|
-
|
|
16000
|
-
|
|
16001
|
-
|
|
16002
|
-
|
|
16003
|
-
|
|
16004
|
-
|
|
16005
|
-
|
|
16006
|
-
|
|
16007
|
-
|
|
16008
|
-
|
|
16009
|
-
|
|
16010
|
-
|
|
16011
|
-
|
|
16012
|
-
|
|
16013
|
-
|
|
16014
|
-
|
|
16015
|
-
|
|
16016
|
-
|
|
16017
|
-
|
|
16018
|
-
|
|
16019
|
-
|
|
16020
|
-
|
|
16021
|
-
|
|
16022
|
-
|
|
16023
|
-
|
|
16024
|
-
|
|
16025
|
-
|
|
16026
|
-
|
|
16027
|
-
|
|
16028
|
-
|
|
16489
|
+
var app43 = new Hono();
|
|
16490
|
+
app43.route("/session", session_default);
|
|
16491
|
+
app43.route("/logs", logs_default);
|
|
16492
|
+
app43.route("/claude-info", claude_info_default);
|
|
16493
|
+
app43.route("/attachment", attachment_default);
|
|
16494
|
+
app43.route("/agents", agents_default);
|
|
16495
|
+
app43.route("/sessions", sessions_default);
|
|
16496
|
+
app43.route("/claude-sessions", claude_sessions_default);
|
|
16497
|
+
app43.route("/log-ingest", log_ingest_default);
|
|
16498
|
+
app43.route("/events", events_default);
|
|
16499
|
+
app43.route("/files", files_default);
|
|
16500
|
+
app43.route("/graph-search", graph_search_default);
|
|
16501
|
+
app43.route("/graph-subgraph", graph_subgraph_default);
|
|
16502
|
+
app43.route("/graph-delete", graph_delete_default);
|
|
16503
|
+
app43.route("/graph-restore", graph_restore_default);
|
|
16504
|
+
app43.route("/graph-labels-in-graph", graph_labels_in_graph_default);
|
|
16505
|
+
app43.route("/graph-default-view", graph_default_view_default);
|
|
16506
|
+
app43.route("/sidebar-artefacts", sidebar_artefacts_default);
|
|
16507
|
+
app43.route("/sidebar-sessions", sidebar_sessions_default);
|
|
16508
|
+
app43.route("/session-delete", session_delete_default);
|
|
16509
|
+
app43.route("/session-stop", session_stop_default);
|
|
16510
|
+
app43.route("/session-archive", session_archive_default);
|
|
16511
|
+
app43.route("/session-rename", session_rename_default);
|
|
16512
|
+
app43.route("/browser", browser_default);
|
|
16513
|
+
app43.route("/session-rc-spawn", session_rc_spawn_default);
|
|
16514
|
+
app43.route("/session-reseat", session_reseat_default);
|
|
16515
|
+
app43.route("/system-stats", system_stats_default);
|
|
16516
|
+
app43.route("/health-brand", health_default2);
|
|
16517
|
+
app43.route("/linkedin-ingest", linkedin_ingest_default);
|
|
16518
|
+
app43.route("/post-turn-context", post_turn_context_default);
|
|
16519
|
+
app43.route("/public-session-context", public_session_context_default);
|
|
16520
|
+
app43.route("/public-session-exit", public_session_exit_default);
|
|
16521
|
+
app43.route("/access-session-evict", access_session_evict_default);
|
|
16522
|
+
app43.route("/enrol-person", enrol_person_default);
|
|
16523
|
+
var admin_default = app43;
|
|
16029
16524
|
|
|
16030
16525
|
// server/routes/access/verify-token.ts
|
|
16031
|
-
var
|
|
16526
|
+
var TAG33 = "[access-verify]";
|
|
16032
16527
|
var MINT_TAG = "[access-session-mint]";
|
|
16033
16528
|
var COOKIE_NAME = "__access_session";
|
|
16034
|
-
var
|
|
16035
|
-
|
|
16529
|
+
var app44 = new Hono();
|
|
16530
|
+
app44.post("/", async (c) => {
|
|
16036
16531
|
const ip = c.var.clientIp || "unknown";
|
|
16037
16532
|
let body;
|
|
16038
16533
|
try {
|
|
@@ -16047,39 +16542,39 @@ app42.post("/", async (c) => {
|
|
|
16047
16542
|
}
|
|
16048
16543
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
16049
16544
|
if (rateMsg) {
|
|
16050
|
-
console.error(`${
|
|
16545
|
+
console.error(`${TAG33} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
16051
16546
|
return c.json({ error: rateMsg }, 429);
|
|
16052
16547
|
}
|
|
16053
16548
|
const grant = await findGrantByMagicToken(token);
|
|
16054
16549
|
if (!grant) {
|
|
16055
16550
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
16056
|
-
console.error(`${
|
|
16551
|
+
console.error(`${TAG33} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
16057
16552
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
16058
16553
|
}
|
|
16059
16554
|
if (grant.agentSlug !== agentSlug) {
|
|
16060
16555
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
16061
16556
|
console.error(
|
|
16062
|
-
`${
|
|
16557
|
+
`${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
16063
16558
|
);
|
|
16064
16559
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
16065
16560
|
}
|
|
16066
16561
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
16067
16562
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
16068
16563
|
console.error(
|
|
16069
|
-
`${
|
|
16564
|
+
`${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
16070
16565
|
);
|
|
16071
16566
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
16072
16567
|
}
|
|
16073
16568
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
16074
16569
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
16075
16570
|
console.error(
|
|
16076
|
-
`${
|
|
16571
|
+
`${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
16077
16572
|
);
|
|
16078
16573
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
16079
16574
|
}
|
|
16080
16575
|
if (!grant.sliceToken) {
|
|
16081
16576
|
console.error(
|
|
16082
|
-
`${
|
|
16577
|
+
`${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
16083
16578
|
);
|
|
16084
16579
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
16085
16580
|
}
|
|
@@ -16095,12 +16590,12 @@ app42.post("/", async (c) => {
|
|
|
16095
16590
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
16096
16591
|
} catch (err) {
|
|
16097
16592
|
console.error(
|
|
16098
|
-
`${
|
|
16593
|
+
`${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
16099
16594
|
);
|
|
16100
16595
|
return c.json({ error: "verification-failed" }, 500);
|
|
16101
16596
|
}
|
|
16102
16597
|
clearAccessRateLimit(ip, agentSlug);
|
|
16103
|
-
console.log(`${
|
|
16598
|
+
console.log(`${TAG33} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
16104
16599
|
console.log(
|
|
16105
16600
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
16106
16601
|
);
|
|
@@ -16114,7 +16609,7 @@ app42.post("/", async (c) => {
|
|
|
16114
16609
|
displayName: grant.displayName
|
|
16115
16610
|
});
|
|
16116
16611
|
});
|
|
16117
|
-
var verify_token_default =
|
|
16612
|
+
var verify_token_default = app44;
|
|
16118
16613
|
|
|
16119
16614
|
// app/lib/access-email.ts
|
|
16120
16615
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -16176,10 +16671,10 @@ async function sendMagicLinkEmail(payload) {
|
|
|
16176
16671
|
}
|
|
16177
16672
|
|
|
16178
16673
|
// server/routes/access/request-magic-link.ts
|
|
16179
|
-
var
|
|
16180
|
-
var
|
|
16674
|
+
var TAG34 = "[access-request-link]";
|
|
16675
|
+
var app45 = new Hono();
|
|
16181
16676
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
16182
|
-
|
|
16677
|
+
app45.post("/", async (c) => {
|
|
16183
16678
|
let body;
|
|
16184
16679
|
try {
|
|
16185
16680
|
body = await c.req.json();
|
|
@@ -16193,18 +16688,18 @@ app43.post("/", async (c) => {
|
|
|
16193
16688
|
}
|
|
16194
16689
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
16195
16690
|
if (rateMsg) {
|
|
16196
|
-
console.error(`${
|
|
16691
|
+
console.error(`${TAG34} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
16197
16692
|
return c.json({ error: rateMsg }, 429);
|
|
16198
16693
|
}
|
|
16199
16694
|
recordRequestLinkAttempt(contactValue);
|
|
16200
16695
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
16201
16696
|
if (!accountId) {
|
|
16202
|
-
console.error(`${
|
|
16697
|
+
console.error(`${TAG34} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
16203
16698
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
16204
16699
|
}
|
|
16205
16700
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
16206
16701
|
if (!grant) {
|
|
16207
|
-
console.log(`${
|
|
16702
|
+
console.log(`${TAG34} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
16208
16703
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
16209
16704
|
}
|
|
16210
16705
|
let token;
|
|
@@ -16212,7 +16707,7 @@ app43.post("/", async (c) => {
|
|
|
16212
16707
|
token = await generateNewMagicToken(grant.grantId);
|
|
16213
16708
|
} catch (err) {
|
|
16214
16709
|
console.error(
|
|
16215
|
-
`${
|
|
16710
|
+
`${TAG34} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
16216
16711
|
);
|
|
16217
16712
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
16218
16713
|
}
|
|
@@ -16244,25 +16739,25 @@ app43.post("/", async (c) => {
|
|
|
16244
16739
|
});
|
|
16245
16740
|
if (!sendResult.ok) {
|
|
16246
16741
|
console.error(
|
|
16247
|
-
`${
|
|
16742
|
+
`${TAG34} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
16248
16743
|
);
|
|
16249
16744
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
16250
16745
|
}
|
|
16251
16746
|
console.log(
|
|
16252
|
-
`${
|
|
16747
|
+
`${TAG34} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
16253
16748
|
);
|
|
16254
16749
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
16255
16750
|
});
|
|
16256
|
-
var request_magic_link_default =
|
|
16751
|
+
var request_magic_link_default = app45;
|
|
16257
16752
|
|
|
16258
16753
|
// server/routes/access/index.ts
|
|
16259
|
-
var
|
|
16260
|
-
|
|
16261
|
-
|
|
16262
|
-
var access_default =
|
|
16754
|
+
var app46 = new Hono();
|
|
16755
|
+
app46.route("/verify-token", verify_token_default);
|
|
16756
|
+
app46.route("/request-magic-link", request_magic_link_default);
|
|
16757
|
+
var access_default = app46;
|
|
16263
16758
|
|
|
16264
16759
|
// server/routes/sites.ts
|
|
16265
|
-
import { existsSync as
|
|
16760
|
+
import { existsSync as existsSync26, readFileSync as readFileSync25, realpathSync as realpathSync5, statSync as statSync11 } from "fs";
|
|
16266
16761
|
import { resolve as resolve26 } from "path";
|
|
16267
16762
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
16268
16763
|
var MIME = {
|
|
@@ -16294,8 +16789,8 @@ function getExt(p) {
|
|
|
16294
16789
|
if (idx < p.lastIndexOf("/")) return "";
|
|
16295
16790
|
return p.slice(idx).toLowerCase();
|
|
16296
16791
|
}
|
|
16297
|
-
var
|
|
16298
|
-
|
|
16792
|
+
var app47 = new Hono();
|
|
16793
|
+
app47.get("/:rel{.*}", (c) => {
|
|
16299
16794
|
const reqPath = c.req.path;
|
|
16300
16795
|
const rawRel = c.req.param("rel") ?? "";
|
|
16301
16796
|
const trimmed = rawRel.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
@@ -16328,7 +16823,7 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16328
16823
|
}
|
|
16329
16824
|
let stat7;
|
|
16330
16825
|
try {
|
|
16331
|
-
stat7 =
|
|
16826
|
+
stat7 = existsSync26(filePath) ? statSync11(filePath) : null;
|
|
16332
16827
|
} catch {
|
|
16333
16828
|
stat7 = null;
|
|
16334
16829
|
}
|
|
@@ -16347,7 +16842,7 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16347
16842
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
16348
16843
|
return c.text("Forbidden", 403);
|
|
16349
16844
|
}
|
|
16350
|
-
if (!
|
|
16845
|
+
if (!existsSync26(filePath)) {
|
|
16351
16846
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
16352
16847
|
return c.text("Not found", 404);
|
|
16353
16848
|
}
|
|
@@ -16366,7 +16861,7 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16366
16861
|
}
|
|
16367
16862
|
let body;
|
|
16368
16863
|
try {
|
|
16369
|
-
body =
|
|
16864
|
+
body = readFileSync25(realPath);
|
|
16370
16865
|
} catch (err) {
|
|
16371
16866
|
const code = err?.code;
|
|
16372
16867
|
if (code === "EISDIR") {
|
|
@@ -16398,11 +16893,11 @@ app45.get("/:rel{.*}", (c) => {
|
|
|
16398
16893
|
"X-Content-Type-Options": "nosniff"
|
|
16399
16894
|
});
|
|
16400
16895
|
});
|
|
16401
|
-
var sites_default =
|
|
16896
|
+
var sites_default = app47;
|
|
16402
16897
|
|
|
16403
16898
|
// app/lib/visitor-token.ts
|
|
16404
16899
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
16405
|
-
import { mkdirSync as
|
|
16900
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync26, writeFileSync as writeFileSync11 } from "fs";
|
|
16406
16901
|
import { dirname as dirname7 } from "path";
|
|
16407
16902
|
var TOKEN_PREFIX = "v1.";
|
|
16408
16903
|
var SECRET_BYTES = 32;
|
|
@@ -16411,7 +16906,7 @@ var cachedSecret = null;
|
|
|
16411
16906
|
function getSecret() {
|
|
16412
16907
|
if (cachedSecret) return cachedSecret;
|
|
16413
16908
|
try {
|
|
16414
|
-
const hex2 =
|
|
16909
|
+
const hex2 = readFileSync26(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
16415
16910
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
16416
16911
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
16417
16912
|
return cachedSecret;
|
|
@@ -16420,12 +16915,12 @@ function getSecret() {
|
|
|
16420
16915
|
}
|
|
16421
16916
|
const fresh = randomBytes(SECRET_BYTES).toString("hex");
|
|
16422
16917
|
try {
|
|
16423
|
-
|
|
16424
|
-
|
|
16918
|
+
mkdirSync6(dirname7(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
16919
|
+
writeFileSync11(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
16425
16920
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
16426
16921
|
} catch {
|
|
16427
16922
|
}
|
|
16428
|
-
const hex =
|
|
16923
|
+
const hex = readFileSync26(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
16429
16924
|
cachedSecret = Buffer.from(hex, "hex");
|
|
16430
16925
|
return cachedSecret;
|
|
16431
16926
|
}
|
|
@@ -16478,8 +16973,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
16478
16973
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
16479
16974
|
|
|
16480
16975
|
// app/lib/brand-config.ts
|
|
16481
|
-
import { existsSync as
|
|
16482
|
-
import { join as
|
|
16976
|
+
import { existsSync as existsSync27, readFileSync as readFileSync27 } from "fs";
|
|
16977
|
+
import { join as join25 } from "path";
|
|
16483
16978
|
var cached2 = null;
|
|
16484
16979
|
var cachedAttempted = false;
|
|
16485
16980
|
function readBrandConfig() {
|
|
@@ -16487,10 +16982,10 @@ function readBrandConfig() {
|
|
|
16487
16982
|
cachedAttempted = true;
|
|
16488
16983
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT;
|
|
16489
16984
|
if (!platformRoot2) return null;
|
|
16490
|
-
const brandPath =
|
|
16491
|
-
if (!
|
|
16985
|
+
const brandPath = join25(platformRoot2, "config", "brand.json");
|
|
16986
|
+
if (!existsSync27(brandPath)) return null;
|
|
16492
16987
|
try {
|
|
16493
|
-
cached2 = JSON.parse(
|
|
16988
|
+
cached2 = JSON.parse(readFileSync27(brandPath, "utf-8"));
|
|
16494
16989
|
return cached2;
|
|
16495
16990
|
} catch {
|
|
16496
16991
|
return null;
|
|
@@ -16498,7 +16993,7 @@ function readBrandConfig() {
|
|
|
16498
16993
|
}
|
|
16499
16994
|
|
|
16500
16995
|
// server/routes/visitor-consent.ts
|
|
16501
|
-
var
|
|
16996
|
+
var app48 = new Hono();
|
|
16502
16997
|
var CONSENT_COOKIE_NAME = "mxy_consent";
|
|
16503
16998
|
var CONSENT_COOKIE_MAX_AGE_SECONDS = 60 * 60 * 24 * 365;
|
|
16504
16999
|
var DEFAULT_CONSENT_COPY = {
|
|
@@ -16543,17 +17038,17 @@ function siteSlugFromReferer(referer) {
|
|
|
16543
17038
|
return "";
|
|
16544
17039
|
}
|
|
16545
17040
|
}
|
|
16546
|
-
|
|
17041
|
+
app48.options("/consent", (c) => {
|
|
16547
17042
|
const origin = getOrigin(c);
|
|
16548
17043
|
setCorsHeaders(c, origin);
|
|
16549
17044
|
return c.body(null, 204);
|
|
16550
17045
|
});
|
|
16551
|
-
|
|
17046
|
+
app48.options("/brand-config", (c) => {
|
|
16552
17047
|
const origin = getOrigin(c);
|
|
16553
17048
|
setCorsHeaders(c, origin);
|
|
16554
17049
|
return c.body(null, 204);
|
|
16555
17050
|
});
|
|
16556
|
-
|
|
17051
|
+
app48.post("/consent", async (c) => {
|
|
16557
17052
|
const origin = getOrigin(c);
|
|
16558
17053
|
setCorsHeaders(c, origin);
|
|
16559
17054
|
let raw;
|
|
@@ -16593,7 +17088,7 @@ app46.post("/consent", async (c) => {
|
|
|
16593
17088
|
console.log(`[consent] ${parsed.decision} site=${site} brand=${brandName} tokenBound=${tokenBound}`);
|
|
16594
17089
|
return c.body(null, 204);
|
|
16595
17090
|
});
|
|
16596
|
-
|
|
17091
|
+
app48.get("/brand-config", (c) => {
|
|
16597
17092
|
const origin = getOrigin(c);
|
|
16598
17093
|
setCorsHeaders(c, origin);
|
|
16599
17094
|
const brand = readBrandConfig();
|
|
@@ -16603,7 +17098,7 @@ app46.get("/brand-config", (c) => {
|
|
|
16603
17098
|
c.header("Cache-Control", "public, max-age=300");
|
|
16604
17099
|
return c.json({ consent: { copy, palette } });
|
|
16605
17100
|
});
|
|
16606
|
-
var visitor_consent_default =
|
|
17101
|
+
var visitor_consent_default = app48;
|
|
16607
17102
|
|
|
16608
17103
|
// server/routes/listings.ts
|
|
16609
17104
|
function getCookie(headerValue, name) {
|
|
@@ -16630,8 +17125,8 @@ function appendConsentParams(pageUrl, token) {
|
|
|
16630
17125
|
}
|
|
16631
17126
|
var SAFE_SLUG_RE = /^[a-z0-9](?:[a-z0-9-]{0,118}[a-z0-9])?$/;
|
|
16632
17127
|
var CHAT_SESSION_KEY_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{7,127}$/;
|
|
16633
|
-
var
|
|
16634
|
-
|
|
17128
|
+
var app49 = new Hono();
|
|
17129
|
+
app49.get("/:slug/click", async (c) => {
|
|
16635
17130
|
const slug = c.req.param("slug") ?? "";
|
|
16636
17131
|
const rawSession = c.req.query("session") ?? "";
|
|
16637
17132
|
const sessionKey = CHAT_SESSION_KEY_RE.test(rawSession) ? rawSession : "invalid";
|
|
@@ -16695,10 +17190,10 @@ app47.get("/:slug/click", async (c) => {
|
|
|
16695
17190
|
console.log(`[property-card-click] sessionKey=${sessionKey} listingSlug=${slug} consent=${consentCookie ?? "absent"} ts=${(/* @__PURE__ */ new Date()).toISOString()}`);
|
|
16696
17191
|
return c.redirect(redirectUrl, 302);
|
|
16697
17192
|
});
|
|
16698
|
-
var listings_default =
|
|
17193
|
+
var listings_default = app49;
|
|
16699
17194
|
|
|
16700
17195
|
// server/routes/visitor-event.ts
|
|
16701
|
-
var
|
|
17196
|
+
var app50 = new Hono();
|
|
16702
17197
|
var BOT_UA_RE = /\b(bot|crawl|spider|slurp|headlesschrome|phantomjs|googlebot|bingbot|yandex|baiduspider|ahrefsbot|semrushbot|mj12bot|dotbot|petalbot)\b/i;
|
|
16703
17198
|
var buckets = /* @__PURE__ */ new Map();
|
|
16704
17199
|
var RATE_LIMIT = 60;
|
|
@@ -16765,12 +17260,12 @@ function originAllowed(origin, allowlist) {
|
|
|
16765
17260
|
return false;
|
|
16766
17261
|
}
|
|
16767
17262
|
}
|
|
16768
|
-
|
|
17263
|
+
app50.options("/event", (c) => {
|
|
16769
17264
|
const origin = getOrigin2(c);
|
|
16770
17265
|
setCorsHeaders2(c, origin);
|
|
16771
17266
|
return c.body(null, 204);
|
|
16772
17267
|
});
|
|
16773
|
-
|
|
17268
|
+
app50.post("/event", async (c) => {
|
|
16774
17269
|
const origin = getOrigin2(c);
|
|
16775
17270
|
setCorsHeaders2(c, origin);
|
|
16776
17271
|
const ua = c.req.header("user-agent") ?? "";
|
|
@@ -16975,17 +17470,17 @@ async function writeEvent(opts) {
|
|
|
16975
17470
|
);
|
|
16976
17471
|
}
|
|
16977
17472
|
}
|
|
16978
|
-
var visitor_event_default =
|
|
17473
|
+
var visitor_event_default = app50;
|
|
16979
17474
|
|
|
16980
17475
|
// server/routes/session.ts
|
|
16981
17476
|
import { resolve as resolve27 } from "path";
|
|
16982
|
-
import { existsSync as
|
|
17477
|
+
import { existsSync as existsSync28, writeFileSync as writeFileSync12, mkdirSync as mkdirSync7 } from "fs";
|
|
16983
17478
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16984
17479
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
16985
17480
|
try {
|
|
16986
17481
|
const cacheDir = resolve27(MAXY_DIR, "branding-cache", accountId);
|
|
16987
|
-
|
|
16988
|
-
|
|
17482
|
+
mkdirSync7(cacheDir, { recursive: true });
|
|
17483
|
+
writeFileSync12(resolve27(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
16989
17484
|
} catch (err) {
|
|
16990
17485
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
16991
17486
|
}
|
|
@@ -17021,8 +17516,8 @@ function withVisitorCookie(response, visitorId) {
|
|
|
17021
17516
|
headers
|
|
17022
17517
|
});
|
|
17023
17518
|
}
|
|
17024
|
-
var
|
|
17025
|
-
|
|
17519
|
+
var app51 = new Hono();
|
|
17520
|
+
app51.post("/", async (c) => {
|
|
17026
17521
|
let body;
|
|
17027
17522
|
try {
|
|
17028
17523
|
body = await c.req.json();
|
|
@@ -17074,7 +17569,7 @@ app49.post("/", async (c) => {
|
|
|
17074
17569
|
let agentConfig = null;
|
|
17075
17570
|
if (account) {
|
|
17076
17571
|
const agentDir = resolve27(account.accountDir, "agents", agentSlug);
|
|
17077
|
-
if (!
|
|
17572
|
+
if (!existsSync28(agentDir) || !existsSync28(resolve27(agentDir, "config.json"))) {
|
|
17078
17573
|
return c.json({ error: "Agent not found" }, 404);
|
|
17079
17574
|
}
|
|
17080
17575
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -17233,7 +17728,7 @@ app49.post("/", async (c) => {
|
|
|
17233
17728
|
newVisitorId
|
|
17234
17729
|
);
|
|
17235
17730
|
});
|
|
17236
|
-
var session_default2 =
|
|
17731
|
+
var session_default2 = app51;
|
|
17237
17732
|
|
|
17238
17733
|
// app/lib/graph-health.ts
|
|
17239
17734
|
var import_dist4 = __toESM(require_dist3(), 1);
|
|
@@ -17579,9 +18074,9 @@ async function migrateUploads(opts = {}) {
|
|
|
17579
18074
|
}
|
|
17580
18075
|
|
|
17581
18076
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
17582
|
-
import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as
|
|
17583
|
-
import { existsSync as
|
|
17584
|
-
import { join as
|
|
18077
|
+
import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as writeFile4, unlink as unlink3 } from "fs/promises";
|
|
18078
|
+
import { existsSync as existsSync29 } from "fs";
|
|
18079
|
+
import { join as join26 } from "path";
|
|
17585
18080
|
var ADMIN_ROLE2 = "admin";
|
|
17586
18081
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
17587
18082
|
var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
|
|
@@ -17606,11 +18101,11 @@ async function readRaw(path2) {
|
|
|
17606
18101
|
async function writeRaw(path2, obj) {
|
|
17607
18102
|
const tmp = `${path2}.tmp.${process.pid}.${Date.now()}`;
|
|
17608
18103
|
try {
|
|
17609
|
-
await
|
|
18104
|
+
await writeFile4(tmp, JSON.stringify(obj, null, 2), "utf8");
|
|
17610
18105
|
await rename3(tmp, path2);
|
|
17611
18106
|
} catch (err) {
|
|
17612
18107
|
try {
|
|
17613
|
-
if (
|
|
18108
|
+
if (existsSync29(tmp)) await unlink3(tmp);
|
|
17614
18109
|
} catch {
|
|
17615
18110
|
}
|
|
17616
18111
|
throw err;
|
|
@@ -17626,7 +18121,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17626
18121
|
}
|
|
17627
18122
|
for (const slug of slugs) {
|
|
17628
18123
|
if (!slug.isDirectory()) continue;
|
|
17629
|
-
const slugDir =
|
|
18124
|
+
const slugDir = join26(projectsRoot, slug.name);
|
|
17630
18125
|
let entries;
|
|
17631
18126
|
try {
|
|
17632
18127
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -17635,9 +18130,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17635
18130
|
}
|
|
17636
18131
|
for (const entry of entries) {
|
|
17637
18132
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
17638
|
-
out.push(
|
|
18133
|
+
out.push(join26(slugDir, entry.name));
|
|
17639
18134
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
17640
|
-
const subDir =
|
|
18135
|
+
const subDir = join26(slugDir, entry.name);
|
|
17641
18136
|
let subs;
|
|
17642
18137
|
try {
|
|
17643
18138
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -17645,7 +18140,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
17645
18140
|
continue;
|
|
17646
18141
|
}
|
|
17647
18142
|
for (const s of subs) {
|
|
17648
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
18143
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join26(subDir, s.name));
|
|
17649
18144
|
}
|
|
17650
18145
|
}
|
|
17651
18146
|
}
|
|
@@ -17657,7 +18152,7 @@ function shortId(path2) {
|
|
|
17657
18152
|
return base.slice(0, 8);
|
|
17658
18153
|
}
|
|
17659
18154
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
17660
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
18155
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join26(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
17661
18156
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
17662
18157
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
17663
18158
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -17999,8 +18494,8 @@ var streamSSE = (c, cb, onError) => {
|
|
|
17999
18494
|
|
|
18000
18495
|
// app/lib/whatsapp/gateway/routes.ts
|
|
18001
18496
|
function createWaChannelRoutes(deps) {
|
|
18002
|
-
const
|
|
18003
|
-
|
|
18497
|
+
const app53 = new Hono();
|
|
18498
|
+
app53.get("/wa-channel/inbound", (c) => {
|
|
18004
18499
|
const senderId = c.req.query("senderId");
|
|
18005
18500
|
if (!senderId) return c.json({ error: "senderId required" }, 400);
|
|
18006
18501
|
return streamSSE(c, async (stream2) => {
|
|
@@ -18018,7 +18513,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18018
18513
|
}
|
|
18019
18514
|
});
|
|
18020
18515
|
});
|
|
18021
|
-
|
|
18516
|
+
app53.post("/wa-channel/reply", async (c) => {
|
|
18022
18517
|
const body = await c.req.json().catch(() => null);
|
|
18023
18518
|
const senderId = body?.senderId;
|
|
18024
18519
|
const text = body?.text;
|
|
@@ -18039,7 +18534,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18039
18534
|
console.error(`[whatsapp-native] op=reply-dispatch senderId=${senderId} bytes=${bytes}`);
|
|
18040
18535
|
return c.json({ ok: true });
|
|
18041
18536
|
});
|
|
18042
|
-
|
|
18537
|
+
app53.post("/wa-channel/reply-document", async (c) => {
|
|
18043
18538
|
const body = await c.req.json().catch(() => null);
|
|
18044
18539
|
const senderId = body?.senderId;
|
|
18045
18540
|
const files = body?.files;
|
|
@@ -18078,7 +18573,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18078
18573
|
}
|
|
18079
18574
|
return c.json({ ok: true, results });
|
|
18080
18575
|
});
|
|
18081
|
-
|
|
18576
|
+
app53.post("/wa-channel/ready", async (c) => {
|
|
18082
18577
|
const body = await c.req.json().catch(() => null);
|
|
18083
18578
|
const senderId = body?.senderId;
|
|
18084
18579
|
if (typeof senderId !== "string") {
|
|
@@ -18087,7 +18582,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18087
18582
|
deps.onReady?.(senderId);
|
|
18088
18583
|
return c.json({ ok: true });
|
|
18089
18584
|
});
|
|
18090
|
-
|
|
18585
|
+
app53.post("/wa-channel/received", async (c) => {
|
|
18091
18586
|
const body = await c.req.json().catch(() => null);
|
|
18092
18587
|
const senderId = body?.senderId;
|
|
18093
18588
|
const waMessageId = body?.waMessageId;
|
|
@@ -18097,7 +18592,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18097
18592
|
deps.onReceived?.(senderId, waMessageId);
|
|
18098
18593
|
return c.json({ ok: true });
|
|
18099
18594
|
});
|
|
18100
|
-
|
|
18595
|
+
app53.post("/wa-channel/turn-end", async (c) => {
|
|
18101
18596
|
const body = await c.req.json().catch(() => null);
|
|
18102
18597
|
const senderId = body?.senderId;
|
|
18103
18598
|
const sessionId = body?.sessionId;
|
|
@@ -18128,7 +18623,7 @@ function createWaChannelRoutes(deps) {
|
|
|
18128
18623
|
console.error(`[whatsapp-native] op=turn-end sessionId=${sid} replied=no delivered=fallback bytes=${bytes}`);
|
|
18129
18624
|
return c.json({ ok: true, delivered: "fallback" });
|
|
18130
18625
|
});
|
|
18131
|
-
return
|
|
18626
|
+
return app53;
|
|
18132
18627
|
}
|
|
18133
18628
|
|
|
18134
18629
|
// app/lib/whatsapp/gateway/wa-gateway.ts
|
|
@@ -18381,8 +18876,8 @@ var InboundHub2 = class {
|
|
|
18381
18876
|
|
|
18382
18877
|
// app/lib/webchat/gateway/routes.ts
|
|
18383
18878
|
function createWebchatChannelRoutes(deps) {
|
|
18384
|
-
const
|
|
18385
|
-
|
|
18879
|
+
const app53 = new Hono();
|
|
18880
|
+
app53.get("/webchat-channel/inbound", (c) => {
|
|
18386
18881
|
const key = c.req.query("key");
|
|
18387
18882
|
if (!key) return c.json({ error: "key required" }, 400);
|
|
18388
18883
|
return streamSSE(c, async (stream2) => {
|
|
@@ -18400,7 +18895,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18400
18895
|
}
|
|
18401
18896
|
});
|
|
18402
18897
|
});
|
|
18403
|
-
|
|
18898
|
+
app53.post("/webchat-channel/reply", async (c) => {
|
|
18404
18899
|
const body = await c.req.json().catch(() => null);
|
|
18405
18900
|
const key = body?.key;
|
|
18406
18901
|
const text = body?.text;
|
|
@@ -18410,7 +18905,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18410
18905
|
deps.onReply?.(key, text);
|
|
18411
18906
|
return c.json({ ok: true });
|
|
18412
18907
|
});
|
|
18413
|
-
|
|
18908
|
+
app53.post("/webchat-channel/ready", async (c) => {
|
|
18414
18909
|
const body = await c.req.json().catch(() => null);
|
|
18415
18910
|
const key = body?.key;
|
|
18416
18911
|
if (typeof key !== "string") {
|
|
@@ -18419,7 +18914,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18419
18914
|
deps.onReady?.(key);
|
|
18420
18915
|
return c.json({ ok: true });
|
|
18421
18916
|
});
|
|
18422
|
-
|
|
18917
|
+
app53.post("/webchat-channel/received", async (c) => {
|
|
18423
18918
|
const body = await c.req.json().catch(() => null);
|
|
18424
18919
|
const key = body?.key;
|
|
18425
18920
|
const messageId = body?.messageId;
|
|
@@ -18429,7 +18924,7 @@ function createWebchatChannelRoutes(deps) {
|
|
|
18429
18924
|
deps.onReceived?.(key, messageId);
|
|
18430
18925
|
return c.json({ ok: true });
|
|
18431
18926
|
});
|
|
18432
|
-
return
|
|
18927
|
+
return app53;
|
|
18433
18928
|
}
|
|
18434
18929
|
|
|
18435
18930
|
// app/lib/webchat/gateway/webchat-gateway.ts
|
|
@@ -18742,7 +19237,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
18742
19237
|
|
|
18743
19238
|
// ../lib/entitlement/src/index.ts
|
|
18744
19239
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
18745
|
-
import { existsSync as
|
|
19240
|
+
import { existsSync as existsSync30, readFileSync as readFileSync28, statSync as statSync12 } from "fs";
|
|
18746
19241
|
import { resolve as resolve30 } from "path";
|
|
18747
19242
|
|
|
18748
19243
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -18791,7 +19286,7 @@ function resolveEntitlement(brand, account) {
|
|
|
18791
19286
|
return logResolved(implicitTrust(account), null);
|
|
18792
19287
|
}
|
|
18793
19288
|
const entitlementPath = resolve30(brand.configDir, "entitlement.json");
|
|
18794
|
-
if (!
|
|
19289
|
+
if (!existsSync30(entitlementPath)) {
|
|
18795
19290
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
18796
19291
|
}
|
|
18797
19292
|
const stat7 = statSync12(entitlementPath);
|
|
@@ -18806,7 +19301,7 @@ function resolveEntitlement(brand, account) {
|
|
|
18806
19301
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
18807
19302
|
let pubkeyPem;
|
|
18808
19303
|
try {
|
|
18809
|
-
pubkeyPem =
|
|
19304
|
+
pubkeyPem = readFileSync28(pubkeyPath(brand), "utf-8");
|
|
18810
19305
|
} catch (err) {
|
|
18811
19306
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
18812
19307
|
reason: "pubkey-missing"
|
|
@@ -18820,7 +19315,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
18820
19315
|
}
|
|
18821
19316
|
let envelope;
|
|
18822
19317
|
try {
|
|
18823
|
-
envelope = JSON.parse(
|
|
19318
|
+
envelope = JSON.parse(readFileSync28(entitlementPath, "utf-8"));
|
|
18824
19319
|
} catch {
|
|
18825
19320
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
18826
19321
|
}
|
|
@@ -18981,14 +19476,14 @@ function clientFrom(c) {
|
|
|
18981
19476
|
);
|
|
18982
19477
|
}
|
|
18983
19478
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
18984
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
19479
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join27(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
18985
19480
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
18986
|
-
if (BRAND_JSON_PATH && !
|
|
19481
|
+
if (BRAND_JSON_PATH && !existsSync31(BRAND_JSON_PATH)) {
|
|
18987
19482
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
18988
19483
|
}
|
|
18989
|
-
if (BRAND_JSON_PATH &&
|
|
19484
|
+
if (BRAND_JSON_PATH && existsSync31(BRAND_JSON_PATH)) {
|
|
18990
19485
|
try {
|
|
18991
|
-
const parsed = JSON.parse(
|
|
19486
|
+
const parsed = JSON.parse(readFileSync29(BRAND_JSON_PATH, "utf-8"));
|
|
18992
19487
|
BRAND = { ...BRAND, ...parsed };
|
|
18993
19488
|
} catch (err) {
|
|
18994
19489
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -19007,11 +19502,11 @@ var brandLoginOpts = {
|
|
|
19007
19502
|
bodyFont: BRAND.defaultFonts?.body,
|
|
19008
19503
|
logoContainsName: !!BRAND.logoContainsName
|
|
19009
19504
|
};
|
|
19010
|
-
var ALIAS_DOMAINS_PATH =
|
|
19505
|
+
var ALIAS_DOMAINS_PATH = join27(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
19011
19506
|
function loadAliasDomains() {
|
|
19012
19507
|
try {
|
|
19013
|
-
if (!
|
|
19014
|
-
const parsed = JSON.parse(
|
|
19508
|
+
if (!existsSync31(ALIAS_DOMAINS_PATH)) return null;
|
|
19509
|
+
const parsed = JSON.parse(readFileSync29(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
19015
19510
|
if (!Array.isArray(parsed)) {
|
|
19016
19511
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
19017
19512
|
return null;
|
|
@@ -19035,11 +19530,11 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
|
|
|
19035
19530
|
function isPublicHost(host) {
|
|
19036
19531
|
return host.startsWith("public.") || aliasDomains.has(host);
|
|
19037
19532
|
}
|
|
19038
|
-
var
|
|
19533
|
+
var app52 = new Hono();
|
|
19039
19534
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
19040
19535
|
var waGateway = new WaGateway({
|
|
19041
19536
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
19042
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ??
|
|
19537
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join27(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
19043
19538
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
19044
19539
|
// account + path validation here and funnel through the shared send core.
|
|
19045
19540
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -19055,7 +19550,7 @@ var waGateway = new WaGateway({
|
|
|
19055
19550
|
caption,
|
|
19056
19551
|
accountId,
|
|
19057
19552
|
maxyAccountId,
|
|
19058
|
-
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ??
|
|
19553
|
+
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ?? join27(__dirname, ".."))
|
|
19059
19554
|
});
|
|
19060
19555
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
19061
19556
|
},
|
|
@@ -19085,7 +19580,7 @@ var waGateway = new WaGateway({
|
|
|
19085
19580
|
nativeFileFollowers.set(senderId, ac);
|
|
19086
19581
|
}
|
|
19087
19582
|
});
|
|
19088
|
-
|
|
19583
|
+
app52.route("/", waGateway.routes());
|
|
19089
19584
|
waGateway.startSweeper();
|
|
19090
19585
|
var webchatGateway = new WebchatGateway({
|
|
19091
19586
|
gatewayUrl: webchatGatewayUrl(),
|
|
@@ -19125,15 +19620,15 @@ var webchatGateway = new WebchatGateway({
|
|
|
19125
19620
|
deleteSession: (sessionId) => managerDelete(sessionId),
|
|
19126
19621
|
firePublicSessionEndReview: (input) => firePublicSessionEndReview(input)
|
|
19127
19622
|
});
|
|
19128
|
-
|
|
19623
|
+
app52.route("/", webchatGateway.routes());
|
|
19129
19624
|
webchatGateway.startSweeper();
|
|
19130
19625
|
webchatGateway.startPublicReaper();
|
|
19131
19626
|
var chatRoutes = createChatRoutes({
|
|
19132
19627
|
handleInbound: (input) => webchatGateway.handleInbound(input),
|
|
19133
19628
|
awaitReply: (key, timeoutMs) => webchatGateway.awaitReply(key, timeoutMs)
|
|
19134
19629
|
});
|
|
19135
|
-
|
|
19136
|
-
|
|
19630
|
+
app52.use("*", clientIpMiddleware);
|
|
19631
|
+
app52.use("*", async (c, next) => {
|
|
19137
19632
|
await next();
|
|
19138
19633
|
c.header("X-Content-Type-Options", "nosniff");
|
|
19139
19634
|
c.header("Referrer-Policy", "strict-origin-when-cross-origin");
|
|
@@ -19143,7 +19638,7 @@ app50.use("*", async (c, next) => {
|
|
|
19143
19638
|
);
|
|
19144
19639
|
});
|
|
19145
19640
|
var HTTP_LOG_PATHS = /* @__PURE__ */ new Set(["/vnc-viewer.html", "/vnc-popout.html"]);
|
|
19146
|
-
|
|
19641
|
+
app52.use("*", async (c, next) => {
|
|
19147
19642
|
if (!HTTP_LOG_PATHS.has(c.req.path)) {
|
|
19148
19643
|
await next();
|
|
19149
19644
|
return;
|
|
@@ -19161,7 +19656,7 @@ app50.use("*", async (c, next) => {
|
|
|
19161
19656
|
});
|
|
19162
19657
|
}
|
|
19163
19658
|
});
|
|
19164
|
-
|
|
19659
|
+
app52.use("*", async (c, next) => {
|
|
19165
19660
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19166
19661
|
if (isOperatorHost(host, getOperatorDomains()) || !isPublicHost(host)) {
|
|
19167
19662
|
await next();
|
|
@@ -19192,7 +19687,7 @@ function resolveRemoteAuthOpts() {
|
|
|
19192
19687
|
return brandLoginOpts;
|
|
19193
19688
|
}
|
|
19194
19689
|
var MAX_LOGIN_BODY = 8 * 1024;
|
|
19195
|
-
|
|
19690
|
+
app52.post("/__remote-auth/login", async (c) => {
|
|
19196
19691
|
const client = clientFrom(c);
|
|
19197
19692
|
const clientIp = client.ip || "unknown";
|
|
19198
19693
|
if (!requestIsTlsTerminated(c)) {
|
|
@@ -19237,7 +19732,7 @@ app50.post("/__remote-auth/login", async (c) => {
|
|
|
19237
19732
|
}
|
|
19238
19733
|
});
|
|
19239
19734
|
});
|
|
19240
|
-
|
|
19735
|
+
app52.get("/__remote-auth/logout", (c) => {
|
|
19241
19736
|
const client = clientFrom(c);
|
|
19242
19737
|
const clientIp = client.ip || "unknown";
|
|
19243
19738
|
console.error(`[remote-auth] logout ip=${clientIp}`);
|
|
@@ -19250,7 +19745,7 @@ app50.get("/__remote-auth/logout", (c) => {
|
|
|
19250
19745
|
}
|
|
19251
19746
|
});
|
|
19252
19747
|
});
|
|
19253
|
-
|
|
19748
|
+
app52.post("/__remote-auth/change-password", async (c) => {
|
|
19254
19749
|
const client = clientFrom(c);
|
|
19255
19750
|
const clientIp = client.ip || "unknown";
|
|
19256
19751
|
const rateLimited = checkRateLimit(client);
|
|
@@ -19309,13 +19804,13 @@ app50.post("/__remote-auth/change-password", async (c) => {
|
|
|
19309
19804
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "change", changeError: "Failed to save password", redirect }), 200);
|
|
19310
19805
|
}
|
|
19311
19806
|
});
|
|
19312
|
-
|
|
19807
|
+
app52.get("/__remote-auth/setup", (c) => {
|
|
19313
19808
|
if (isRemoteAuthConfigured()) {
|
|
19314
19809
|
return c.redirect("/");
|
|
19315
19810
|
}
|
|
19316
19811
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup" }), 200);
|
|
19317
19812
|
});
|
|
19318
|
-
|
|
19813
|
+
app52.post("/__remote-auth/set-initial-password", async (c) => {
|
|
19319
19814
|
if (isRemoteAuthConfigured()) {
|
|
19320
19815
|
return c.redirect("/");
|
|
19321
19816
|
}
|
|
@@ -19353,10 +19848,10 @@ app50.post("/__remote-auth/set-initial-password", async (c) => {
|
|
|
19353
19848
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), mode: "setup", setupError: "Failed to save password. Please try again." }), 200);
|
|
19354
19849
|
}
|
|
19355
19850
|
});
|
|
19356
|
-
|
|
19851
|
+
app52.get("/api/remote-auth/status", (c) => {
|
|
19357
19852
|
return c.json({ configured: isRemoteAuthConfigured() });
|
|
19358
19853
|
});
|
|
19359
|
-
|
|
19854
|
+
app52.post("/api/remote-auth/set-password", async (c) => {
|
|
19360
19855
|
let body;
|
|
19361
19856
|
try {
|
|
19362
19857
|
body = await c.req.json();
|
|
@@ -19395,10 +19890,10 @@ app50.post("/api/remote-auth/set-password", async (c) => {
|
|
|
19395
19890
|
return c.json({ error: "Failed to save password" }, 500);
|
|
19396
19891
|
}
|
|
19397
19892
|
});
|
|
19398
|
-
|
|
19893
|
+
app52.route("/api/_client-error", client_error_default);
|
|
19399
19894
|
console.log("[client-error-route] mounted");
|
|
19400
19895
|
var PWA_PUBLIC_PATHS = /* @__PURE__ */ new Set(["/sw.js", ...PWA_SURFACES.map((s) => s.manifestPath)]);
|
|
19401
|
-
|
|
19896
|
+
app52.use("*", async (c, next) => {
|
|
19402
19897
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19403
19898
|
const path2 = c.req.path;
|
|
19404
19899
|
if (path2 === "/favicon.ico" || path2.startsWith("/assets/") || path2.startsWith("/brand/") || PWA_PUBLIC_PATHS.has(path2)) {
|
|
@@ -19438,18 +19933,19 @@ app50.use("*", async (c, next) => {
|
|
|
19438
19933
|
}
|
|
19439
19934
|
return c.html(renderLoginPage({ ...resolveRemoteAuthOpts(), redirect: path2 }), 200);
|
|
19440
19935
|
});
|
|
19441
|
-
|
|
19442
|
-
|
|
19443
|
-
|
|
19444
|
-
|
|
19445
|
-
|
|
19446
|
-
|
|
19447
|
-
|
|
19448
|
-
|
|
19449
|
-
|
|
19450
|
-
|
|
19451
|
-
|
|
19452
|
-
|
|
19936
|
+
app52.route("/api/health", health_default);
|
|
19937
|
+
app52.route("/api/chat", chatRoutes);
|
|
19938
|
+
app52.route("/api/whatsapp", whatsapp_default);
|
|
19939
|
+
app52.route("/api/whatsapp-reader", whatsapp_reader_default);
|
|
19940
|
+
app52.route("/api/public-reader", public_reader_default);
|
|
19941
|
+
app52.route("/api/webchat", createWebchatRoutes({ handleInbound: (input) => webchatGateway.handleInbound(input) }));
|
|
19942
|
+
app52.route("/api/webchat/greeting", webchat_greeting_default);
|
|
19943
|
+
app52.route("/api/telegram", telegram_default);
|
|
19944
|
+
app52.route("/api/quickbooks", quickbooks_default);
|
|
19945
|
+
app52.route("/api/onboarding", onboarding_default);
|
|
19946
|
+
app52.route("/api/admin", admin_default);
|
|
19947
|
+
app52.route("/api/access", access_default);
|
|
19948
|
+
app52.route("/api/session", session_default2);
|
|
19453
19949
|
var SAFE_SLUG_RE2 = /^[a-z][a-z0-9-]{2,49}$/;
|
|
19454
19950
|
var SAFE_FILENAME_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
19455
19951
|
var IMAGE_MIME = {
|
|
@@ -19461,7 +19957,7 @@ var IMAGE_MIME = {
|
|
|
19461
19957
|
".svg": "image/svg+xml",
|
|
19462
19958
|
".ico": "image/x-icon"
|
|
19463
19959
|
};
|
|
19464
|
-
|
|
19960
|
+
app52.get("/agent-assets/:slug/:filename", (c) => {
|
|
19465
19961
|
const slug = c.req.param("slug");
|
|
19466
19962
|
const filename = c.req.param("filename");
|
|
19467
19963
|
if (!SAFE_SLUG_RE2.test(slug)) {
|
|
@@ -19483,20 +19979,20 @@ app50.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
19483
19979
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
19484
19980
|
return c.text("Forbidden", 403);
|
|
19485
19981
|
}
|
|
19486
|
-
if (!
|
|
19982
|
+
if (!existsSync31(filePath)) {
|
|
19487
19983
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
19488
19984
|
return c.text("Not found", 404);
|
|
19489
19985
|
}
|
|
19490
19986
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
19491
19987
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
19492
19988
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
19493
|
-
const body =
|
|
19989
|
+
const body = readFileSync29(filePath);
|
|
19494
19990
|
return c.body(body, 200, {
|
|
19495
19991
|
"Content-Type": contentType,
|
|
19496
19992
|
"Cache-Control": "public, max-age=3600"
|
|
19497
19993
|
});
|
|
19498
19994
|
});
|
|
19499
|
-
|
|
19995
|
+
app52.get("/generated/:filename", (c) => {
|
|
19500
19996
|
const filename = c.req.param("filename");
|
|
19501
19997
|
if (!SAFE_FILENAME_RE.test(filename) || filename.includes("..")) {
|
|
19502
19998
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
@@ -19513,29 +20009,29 @@ app50.get("/generated/:filename", (c) => {
|
|
|
19513
20009
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
19514
20010
|
return c.text("Forbidden", 403);
|
|
19515
20011
|
}
|
|
19516
|
-
if (!
|
|
20012
|
+
if (!existsSync31(filePath)) {
|
|
19517
20013
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
19518
20014
|
return c.text("Not found", 404);
|
|
19519
20015
|
}
|
|
19520
20016
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
19521
20017
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
19522
20018
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
19523
|
-
const body =
|
|
20019
|
+
const body = readFileSync29(filePath);
|
|
19524
20020
|
return c.body(body, 200, {
|
|
19525
20021
|
"Content-Type": contentType,
|
|
19526
20022
|
"Cache-Control": "public, max-age=86400"
|
|
19527
20023
|
});
|
|
19528
20024
|
});
|
|
19529
|
-
|
|
19530
|
-
|
|
19531
|
-
|
|
19532
|
-
|
|
20025
|
+
app52.route("/sites", sites_default);
|
|
20026
|
+
app52.route("/listings", listings_default);
|
|
20027
|
+
app52.route("/v", visitor_event_default);
|
|
20028
|
+
app52.route("/v", visitor_consent_default);
|
|
19533
20029
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
19534
20030
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
19535
20031
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
19536
|
-
if (BRAND_JSON_PATH &&
|
|
20032
|
+
if (BRAND_JSON_PATH && existsSync31(BRAND_JSON_PATH)) {
|
|
19537
20033
|
try {
|
|
19538
|
-
const fullBrand = JSON.parse(
|
|
20034
|
+
const fullBrand = JSON.parse(readFileSync29(BRAND_JSON_PATH, "utf-8"));
|
|
19539
20035
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
19540
20036
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
19541
20037
|
} catch {
|
|
@@ -19552,10 +20048,10 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
19552
20048
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
19553
20049
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
19554
20050
|
var brandIconFsPath = resolve31(process.cwd(), "public", brandIconPath.replace(/^\//, ""));
|
|
19555
|
-
var brandIconExists =
|
|
20051
|
+
var brandIconExists = existsSync31(brandIconFsPath);
|
|
19556
20052
|
var SW_SOURCE = (() => {
|
|
19557
20053
|
try {
|
|
19558
|
-
return
|
|
20054
|
+
return readFileSync29(resolve31(process.cwd(), "public", "sw.js"), "utf-8");
|
|
19559
20055
|
} catch {
|
|
19560
20056
|
return null;
|
|
19561
20057
|
}
|
|
@@ -19563,9 +20059,9 @@ var SW_SOURCE = (() => {
|
|
|
19563
20059
|
function readInstalledVersion() {
|
|
19564
20060
|
try {
|
|
19565
20061
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
19566
|
-
const versionFile =
|
|
19567
|
-
if (!
|
|
19568
|
-
const content =
|
|
20062
|
+
const versionFile = join27(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
20063
|
+
if (!existsSync31(versionFile)) return "unknown";
|
|
20064
|
+
const content = readFileSync29(versionFile, "utf-8").trim();
|
|
19569
20065
|
return content || "unknown";
|
|
19570
20066
|
} catch {
|
|
19571
20067
|
return "unknown";
|
|
@@ -19606,7 +20102,7 @@ var clientErrorReporterScript = `<script>
|
|
|
19606
20102
|
function cachedHtml(file) {
|
|
19607
20103
|
let html = htmlCache.get(file);
|
|
19608
20104
|
if (!html) {
|
|
19609
|
-
html =
|
|
20105
|
+
html = readFileSync29(resolve31(process.cwd(), "public", file), "utf-8");
|
|
19610
20106
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
19611
20107
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
19612
20108
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -19624,13 +20120,13 @@ ${clientErrorReporterScript}
|
|
|
19624
20120
|
}
|
|
19625
20121
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
19626
20122
|
function loadBrandingCache(agentSlug) {
|
|
19627
|
-
const configDir2 =
|
|
20123
|
+
const configDir2 = join27(homedir3(), BRAND.configDir);
|
|
19628
20124
|
try {
|
|
19629
20125
|
const accountId = getDefaultAccountId();
|
|
19630
20126
|
if (!accountId) return null;
|
|
19631
|
-
const cachePath =
|
|
19632
|
-
if (!
|
|
19633
|
-
return JSON.parse(
|
|
20127
|
+
const cachePath = join27(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
20128
|
+
if (!existsSync31(cachePath)) return null;
|
|
20129
|
+
return JSON.parse(readFileSync29(cachePath, "utf-8"));
|
|
19634
20130
|
} catch {
|
|
19635
20131
|
return null;
|
|
19636
20132
|
}
|
|
@@ -19676,7 +20172,7 @@ function escapeHtml(s) {
|
|
|
19676
20172
|
function agentUnavailableHtml() {
|
|
19677
20173
|
return `<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><title>${escapeHtml(BRAND.productName)}</title></head><body style="font-family:system-ui,sans-serif;max-width:32rem;margin:4rem auto;padding:0 1.5rem;color:#222"><h1 style="font-size:1.25rem">Agent unavailable</h1><p>This agent isn't available right now. If you reached this page from a saved link, the agent may have been turned off.</p></body></html>`;
|
|
19678
20174
|
}
|
|
19679
|
-
|
|
20175
|
+
app52.get("/", (c) => {
|
|
19680
20176
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19681
20177
|
const klass = classifyHost(host, getOperatorDomains(), isPublicHost);
|
|
19682
20178
|
if (klass === "operator") {
|
|
@@ -19699,13 +20195,13 @@ app50.get("/", (c) => {
|
|
|
19699
20195
|
console.log(`[host-class] host=${host} class=admin served=index.html`);
|
|
19700
20196
|
return c.html(cachedHtml("index.html"));
|
|
19701
20197
|
});
|
|
19702
|
-
|
|
20198
|
+
app52.get("/public", (c) => {
|
|
19703
20199
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19704
20200
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19705
20201
|
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
19706
20202
|
return c.html(cachedHtml("public.html"));
|
|
19707
20203
|
});
|
|
19708
|
-
|
|
20204
|
+
app52.get("/public-chat", (c) => {
|
|
19709
20205
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19710
20206
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19711
20207
|
if (wantsNextSurface(c)) return c.html(cachedHtml("public-next.html"));
|
|
@@ -19725,12 +20221,12 @@ async function logViewerFetch(c, next) {
|
|
|
19725
20221
|
duration_ms: Date.now() - start
|
|
19726
20222
|
});
|
|
19727
20223
|
}
|
|
19728
|
-
|
|
19729
|
-
|
|
19730
|
-
|
|
20224
|
+
app52.use("/vnc-viewer.html", logViewerFetch);
|
|
20225
|
+
app52.use("/vnc-popout.html", logViewerFetch);
|
|
20226
|
+
app52.get("/vnc-popout.html", (c) => {
|
|
19731
20227
|
let html = htmlCache.get("vnc-popout.html");
|
|
19732
20228
|
if (!html) {
|
|
19733
|
-
html =
|
|
20229
|
+
html = readFileSync29(resolve31(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
19734
20230
|
const name = escapeHtml(BRAND.productName);
|
|
19735
20231
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
19736
20232
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -19740,7 +20236,7 @@ app50.get("/vnc-popout.html", (c) => {
|
|
|
19740
20236
|
}
|
|
19741
20237
|
return c.html(html);
|
|
19742
20238
|
});
|
|
19743
|
-
|
|
20239
|
+
app52.post("/api/vnc/client-event", async (c) => {
|
|
19744
20240
|
let body;
|
|
19745
20241
|
try {
|
|
19746
20242
|
body = await c.req.json();
|
|
@@ -19761,11 +20257,11 @@ app50.post("/api/vnc/client-event", async (c) => {
|
|
|
19761
20257
|
});
|
|
19762
20258
|
return c.json({ ok: true });
|
|
19763
20259
|
});
|
|
19764
|
-
|
|
20260
|
+
app52.get("/g/:slug", (c) => {
|
|
19765
20261
|
return c.html(brandedPublicHtml());
|
|
19766
20262
|
});
|
|
19767
20263
|
for (const pwa of PWA_SURFACES) {
|
|
19768
|
-
|
|
20264
|
+
app52.get(pwa.manifestPath, (c) => {
|
|
19769
20265
|
const manifest = buildManifest(pwa, {
|
|
19770
20266
|
productName: BRAND.productName,
|
|
19771
20267
|
iconPath: brandIconPath,
|
|
@@ -19779,7 +20275,7 @@ for (const pwa of PWA_SURFACES) {
|
|
|
19779
20275
|
return c.body(JSON.stringify(manifest));
|
|
19780
20276
|
});
|
|
19781
20277
|
}
|
|
19782
|
-
|
|
20278
|
+
app52.get("/sw.js", (c) => {
|
|
19783
20279
|
if (SW_SOURCE == null) {
|
|
19784
20280
|
console.error("[pwa] op=sw status=500 reason=sw-source-missing");
|
|
19785
20281
|
return c.text("Service worker unavailable", 500);
|
|
@@ -19788,27 +20284,27 @@ app50.get("/sw.js", (c) => {
|
|
|
19788
20284
|
console.log(`[pwa] op=sw status=200 ct=${SW_CONTENT_TYPE}`);
|
|
19789
20285
|
return c.body(SW_SOURCE);
|
|
19790
20286
|
});
|
|
19791
|
-
|
|
20287
|
+
app52.get("/graph", (c) => {
|
|
19792
20288
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19793
20289
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
19794
20290
|
return c.html(cachedHtml("graph.html"));
|
|
19795
20291
|
});
|
|
19796
|
-
|
|
20292
|
+
app52.get("/chat", (c) => {
|
|
19797
20293
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19798
20294
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19799
20295
|
return c.html(cachedHtml("chat.html"));
|
|
19800
20296
|
});
|
|
19801
|
-
|
|
20297
|
+
app52.get("/data", (c) => {
|
|
19802
20298
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19803
20299
|
if (isPublicHost(host)) return c.text("Not found", 404);
|
|
19804
20300
|
return c.html(cachedHtml("data.html"));
|
|
19805
20301
|
});
|
|
19806
|
-
|
|
20302
|
+
app52.get("/browser", (c) => {
|
|
19807
20303
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19808
20304
|
if (isPublicHost(host) || isOperatorHost(host, getOperatorDomains())) return c.text("Not found", 404);
|
|
19809
20305
|
return c.html(cachedHtml("browser.html"));
|
|
19810
20306
|
});
|
|
19811
|
-
|
|
20307
|
+
app52.get("/:slug", async (c, next) => {
|
|
19812
20308
|
const slug = c.req.param("slug");
|
|
19813
20309
|
if (AGENT_SLUG_PATTERN.test(`/${slug}`)) {
|
|
19814
20310
|
const account = resolveAccount();
|
|
@@ -19824,13 +20320,13 @@ app50.get("/:slug", async (c, next) => {
|
|
|
19824
20320
|
await next();
|
|
19825
20321
|
});
|
|
19826
20322
|
if (brandFaviconPath !== "/favicon.ico") {
|
|
19827
|
-
|
|
20323
|
+
app52.get("/favicon.ico", (c) => {
|
|
19828
20324
|
c.header("Cache-Control", "public, max-age=300");
|
|
19829
20325
|
return c.redirect(brandFaviconPath, 302);
|
|
19830
20326
|
});
|
|
19831
20327
|
}
|
|
19832
|
-
|
|
19833
|
-
|
|
20328
|
+
app52.use("/*", serveStatic({ root: "./public" }));
|
|
20329
|
+
app52.all("*", (c) => {
|
|
19834
20330
|
const host = (c.req.header("host") ?? "").split(":")[0];
|
|
19835
20331
|
const path2 = c.req.path;
|
|
19836
20332
|
if (isPublicHost(host)) {
|
|
@@ -19844,7 +20340,7 @@ app50.all("*", (c) => {
|
|
|
19844
20340
|
});
|
|
19845
20341
|
var port = requirePortEnv("MAXY_UI_INTERNAL_PORT", { tag: "ui-server" });
|
|
19846
20342
|
var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
19847
|
-
var httpServer = serve({ fetch:
|
|
20343
|
+
var httpServer = serve({ fetch: app52.fetch, port, hostname });
|
|
19848
20344
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
19849
20345
|
{
|
|
19850
20346
|
const census = pwaCensus({
|
|
@@ -19898,7 +20394,7 @@ for (const m of SUBAPP_MANIFEST) {
|
|
|
19898
20394
|
}
|
|
19899
20395
|
try {
|
|
19900
20396
|
const registered = [];
|
|
19901
|
-
for (const r of
|
|
20397
|
+
for (const r of app52.routes ?? []) {
|
|
19902
20398
|
if (typeof r.path !== "string" || r.path.includes(":") || r.path.includes("*")) continue;
|
|
19903
20399
|
if (AGENT_SLUG_PATTERN.test(r.path)) {
|
|
19904
20400
|
registered.push({ method: (r.method ?? "ALL").toUpperCase(), path: r.path });
|
|
@@ -19938,11 +20434,11 @@ try {
|
|
|
19938
20434
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
19939
20435
|
async function runAdminUserReconcileTick() {
|
|
19940
20436
|
try {
|
|
19941
|
-
if (!
|
|
20437
|
+
if (!existsSync31(USERS_FILE)) {
|
|
19942
20438
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
19943
20439
|
return;
|
|
19944
20440
|
}
|
|
19945
|
-
const usersRaw =
|
|
20441
|
+
const usersRaw = readFileSync29(USERS_FILE, "utf-8").trim();
|
|
19946
20442
|
if (!usersRaw) {
|
|
19947
20443
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
19948
20444
|
return;
|
|
@@ -19974,6 +20470,7 @@ void migrateUploads().catch((err) => console.error(`[uploads-migrate] failed err
|
|
|
19974
20470
|
console.error(`[file-watcher] start-failed err="${err instanceof Error ? err.message : String(err)}"`);
|
|
19975
20471
|
});
|
|
19976
20472
|
});
|
|
20473
|
+
void sweepStaleUploadTemps().catch((err) => console.error(`[data-upload] op=sweep-failed err="${err instanceof Error ? err.message : String(err)}"`));
|
|
19977
20474
|
void migrateAdminWebchatSidecars().catch((err) => console.error(`[sidecar-backfill] failed err="${err instanceof Error ? err.message : String(err)}"`));
|
|
19978
20475
|
try {
|
|
19979
20476
|
const accounts = enumerateValidAccountIds(getAccountsDirFromEnv());
|
|
@@ -20055,7 +20552,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
20055
20552
|
}
|
|
20056
20553
|
init({
|
|
20057
20554
|
configDir: configDirForWhatsApp,
|
|
20058
|
-
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ??
|
|
20555
|
+
platformRoot: resolve31(process.env.MAXY_PLATFORM_ROOT ?? join27(__dirname, "..")),
|
|
20059
20556
|
accountConfig: bootAccountConfig,
|
|
20060
20557
|
onMessage: async (msg) => {
|
|
20061
20558
|
if (msg.isOwnerMirror) {
|