@rubytech/create-realagent 1.0.816 → 1.0.817
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/plugins/admin/skills/onboarding/SKILL.md +2 -2
- package/payload/platform/plugins/docs/references/cloudflare.md +1 -3
- package/payload/platform/plugins/docs/references/troubleshooting.md +8 -12
- package/payload/server/chunk-P3HTEK33.js +10074 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/{admin-Cxtmv0wo.js → admin-2w0XSMC6.js} +20 -20
- package/payload/server/public/index.html +1 -1
- package/payload/server/server.js +76 -401
package/payload/server/server.js
CHANGED
|
@@ -6,7 +6,6 @@ import {
|
|
|
6
6
|
TELEGRAM_ADMIN_WEBHOOK_SECRET_FILE,
|
|
7
7
|
TELEGRAM_WEBHOOK_SECRET_FILE,
|
|
8
8
|
USERS_FILE,
|
|
9
|
-
actionLogPath,
|
|
10
9
|
autoDeliverPremiumPlugins,
|
|
11
10
|
buildX11Env,
|
|
12
11
|
callOauthLlm,
|
|
@@ -30,7 +29,6 @@ import {
|
|
|
30
29
|
launchAction,
|
|
31
30
|
load,
|
|
32
31
|
logPath,
|
|
33
|
-
reconcileCloudflareSetupFromLog,
|
|
34
32
|
recordFailedAttempt,
|
|
35
33
|
render,
|
|
36
34
|
renderLoginPage,
|
|
@@ -53,7 +51,7 @@ import {
|
|
|
53
51
|
vncLog,
|
|
54
52
|
waitForExit,
|
|
55
53
|
writeChromiumWrapper
|
|
56
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-P3HTEK33.js";
|
|
57
55
|
import {
|
|
58
56
|
agentLogStream,
|
|
59
57
|
clearSessionHistory,
|
|
@@ -620,8 +618,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
620
618
|
};
|
|
621
619
|
|
|
622
620
|
// server/index.ts
|
|
623
|
-
import { readFileSync as
|
|
624
|
-
import { resolve as resolve25, join as
|
|
621
|
+
import { readFileSync as readFileSync18, existsSync as existsSync24, watchFile } from "fs";
|
|
622
|
+
import { resolve as resolve25, join as join10, basename as basename7 } from "path";
|
|
625
623
|
import { homedir as homedir2 } from "os";
|
|
626
624
|
|
|
627
625
|
// app/lib/agent-slug-pattern.ts
|
|
@@ -807,52 +805,6 @@ function defaultRules() {
|
|
|
807
805
|
scope: "session",
|
|
808
806
|
suggestedAction: "The WebFetch SPA preflight has fired more than once in this conversation. Either the agent is ignoring the loud-failure directive (retrying WebFetch after seeing WEBFETCH_CANNOT_READ_JS_SPA), or multiple SPA URLs are being asked about. Read the conversation's stream log for the [tool-use] / [tool-result] sequence around each occurrence \u2014 if the agent dispatched WebFetch on the same URL or substituted Playwright silently, revisit the IDENTITY.md `Tool Failure Discipline` paragraph that names structured-error handling."
|
|
809
807
|
},
|
|
810
|
-
{
|
|
811
|
-
// Task 867 — fires when setup-tunnel.sh emits step=done but no
|
|
812
|
-
// `[persist] role=user … Cloudflare setup completed (actionId: <id>)`
|
|
813
|
-
// line appears within 60s. Covers the three failure modes of the
|
|
814
|
-
// action-relay-queue plumbing: queue-write failed, boot-drain consumer
|
|
815
|
-
// skipped the record, or the agent's hoisted persist threw. The
|
|
816
|
-
// followup pattern is intentionally narrow to the cloudflare-setup
|
|
817
|
-
// relay shape (not a general "any user persist") so a benign user
|
|
818
|
-
// typing in chat does not satisfy the followup. logSource=any so
|
|
819
|
-
// the rule sees both the script tee (in stream logs / server.log)
|
|
820
|
-
// and the [persist] line (server.log).
|
|
821
|
-
id: "cloudflare-setup-relay-not-acknowledged",
|
|
822
|
-
name: "Cloudflare-setup completed but the chat relay never acknowledged",
|
|
823
|
-
type: "absent-followup",
|
|
824
|
-
logSource: "any",
|
|
825
|
-
pattern: "\\[script:setup-tunnel\\] step=done",
|
|
826
|
-
followupPattern: "\\[persist\\] .*role=user.* Cloudflare setup completed \\(actionId:",
|
|
827
|
-
followupWindowMs: 6e4,
|
|
828
|
-
thresholdCount: 0,
|
|
829
|
-
thresholdWindowMinutes: 0,
|
|
830
|
-
suggestedAction: "[Task 867] cloudflare-setup completed but the post-action relay never reached the chat history. Check `[action-relay-queue] phase=enqueued` (queue write), `[action-completion-relay] phase=consumed` (boot-drain ran), and `[persist] role=user \u2026 Cloudflare setup completed` (graph write). One of those is missing; the matching grep recipe is in the Task 867 brief Observability section."
|
|
831
|
-
},
|
|
832
|
-
{
|
|
833
|
-
// Task 879 §C — onboarding turn-completion contract: any assistant
|
|
834
|
-
// turn that narrates a step transition with a non-question-terminated
|
|
835
|
-
// phrase ("Moving to step 9 — operator persona...", "Step 8 done.")
|
|
836
|
-
// must be followed within 30s by either a `render-component` call
|
|
837
|
-
// (the next step's UI surfaces) or `onboarding-complete-step`
|
|
838
|
-
// (deterministic step advance). The trigger pattern matches the
|
|
839
|
-
// `[onboarding-step-narration]` line written by stream-parser at the
|
|
840
|
-
// assistant text block emit site (only for non-question phrases).
|
|
841
|
-
// Operator's symptom in Task 879's evidence: "Moving to step 9..."
|
|
842
|
-
// followed by 4 minutes of silence until the operator nudged with
|
|
843
|
-
// "yeah, so?" — exact failure shape this rule catches.
|
|
844
|
-
id: "assistant-step-advance-deadend",
|
|
845
|
-
name: "Onboarding step-advance narration without follow-up tool call",
|
|
846
|
-
type: "absent-followup",
|
|
847
|
-
logSource: "session",
|
|
848
|
-
pattern: "\\[onboarding-step-narration\\]",
|
|
849
|
-
followupPattern: "\\[render-component\\]|\\[tool-use\\][^\\n]*name=mcp__admin__onboarding-complete-step",
|
|
850
|
-
followupWindowMs: 3e4,
|
|
851
|
-
thresholdCount: 0,
|
|
852
|
-
thresholdWindowMinutes: 0,
|
|
853
|
-
scope: "session",
|
|
854
|
-
suggestedAction: '[Task 879 \xA7C] An onboarding turn narrated a step transition (e.g. "Moving to step N", "Step N done.") but did not render a component or call `onboarding-complete-step` within 30s. The operator is left with a dead-end paragraph and no actionable surface. Check the `platform/plugins/admin/skills/onboarding/SKILL.md` Turn-completion contract section \u2014 the agent must end any step-advance turn with `render-component` or a `?`-terminated question, never bare prose.'
|
|
855
|
-
},
|
|
856
808
|
{
|
|
857
809
|
// Task 538: fires when a [spawn] line appears in a conversation's stream
|
|
858
810
|
// log but no subprocess-lifecycle marker follows within 10s. The three
|
|
@@ -8375,7 +8327,7 @@ app9.post("/", async (c) => {
|
|
|
8375
8327
|
const safe = typeof v === "string" ? truncate(v, 200) : typeof v === "number" || typeof v === "boolean" ? String(v) : JSON.stringify(v).slice(0, 200);
|
|
8376
8328
|
return `${k}=${safe}`;
|
|
8377
8329
|
}).join(" ");
|
|
8378
|
-
const TAGGED_PREFIX_SOURCES = /* @__PURE__ */ new Set([
|
|
8330
|
+
const TAGGED_PREFIX_SOURCES = /* @__PURE__ */ new Set([]);
|
|
8379
8331
|
if (TAGGED_PREFIX_SOURCES.has(source)) {
|
|
8380
8332
|
console.log(
|
|
8381
8333
|
`[${source}] ts=${ts} ip=${ip} version=${version || "unknown"}${extra ? " " + extra : ""}`
|
|
@@ -8597,39 +8549,6 @@ app10.post("/", async (c) => {
|
|
|
8597
8549
|
const payload = await createAdminSession(selected.accountId, selected.config.thinkingView, userId, userName, selected.role, avatar);
|
|
8598
8550
|
return c.json(payload);
|
|
8599
8551
|
});
|
|
8600
|
-
app10.post("/rebind", async (c) => {
|
|
8601
|
-
let body;
|
|
8602
|
-
try {
|
|
8603
|
-
body = await c.req.json();
|
|
8604
|
-
} catch {
|
|
8605
|
-
return c.json({ ok: false, error: "invalid_json" }, 400);
|
|
8606
|
-
}
|
|
8607
|
-
const sessionKey = typeof body.session_key === "string" ? body.session_key : "";
|
|
8608
|
-
const conversationId = typeof body.lastKnownConversationId === "string" ? body.lastKnownConversationId : "";
|
|
8609
|
-
if (!sessionKey || !conversationId) {
|
|
8610
|
-
return c.json({ ok: false, error: "session_key and lastKnownConversationId required" }, 400);
|
|
8611
|
-
}
|
|
8612
|
-
const sk8 = sessionKey.slice(0, 8);
|
|
8613
|
-
const cid8 = conversationId.slice(0, 8);
|
|
8614
|
-
const bridge = await tryCookieBridgeForConversation(c, sessionKey, conversationId);
|
|
8615
|
-
if (!bridge.ok) {
|
|
8616
|
-
console.log(`[admin/session/rebind] sessionKey=${sk8}\u2026 result=bridge-rejected reason=${bridge.reason} conversationId=${cid8}\u2026`);
|
|
8617
|
-
const status = bridge.reason === "conversation-not-found" ? 404 : bridge.reason === "account-mismatch" ? 403 : 401;
|
|
8618
|
-
return c.json({ ok: false, error: bridge.reason }, status);
|
|
8619
|
-
}
|
|
8620
|
-
const existing = getConversationIdForSession(sessionKey);
|
|
8621
|
-
if (existing && existing !== conversationId) {
|
|
8622
|
-
console.log(`[admin/session/rebind] sessionKey=${sk8}\u2026 result=conflict conversationId=${existing.slice(0, 8)}\u2026 requested=${cid8}\u2026`);
|
|
8623
|
-
return c.json({ ok: false, error: "conflict", conversationId: existing }, 409);
|
|
8624
|
-
}
|
|
8625
|
-
const bound = setConversationIdForSession(sessionKey, conversationId);
|
|
8626
|
-
if (!bound) {
|
|
8627
|
-
console.error(`[admin/session/rebind] sessionKey=${sk8}\u2026 result=bind-failed conversationId=${cid8}\u2026 (post-bridge session-store missing \u2014 programmer error)`);
|
|
8628
|
-
return c.json({ ok: false, error: "bind_failed" }, 500);
|
|
8629
|
-
}
|
|
8630
|
-
console.log(`[admin/session/rebind] sessionKey=${sk8}\u2026 result=ok conversationId=${cid8}\u2026`);
|
|
8631
|
-
return c.json({ ok: true, conversationId });
|
|
8632
|
-
});
|
|
8633
8552
|
var session_default2 = app10;
|
|
8634
8553
|
|
|
8635
8554
|
// server/routes/admin/chat.ts
|
|
@@ -9860,13 +9779,14 @@ app17.delete("/:id", requireAdminSession, async (c) => {
|
|
|
9860
9779
|
return c.json({ error: "Failed to delete session" }, 500);
|
|
9861
9780
|
}
|
|
9862
9781
|
});
|
|
9863
|
-
app17.
|
|
9782
|
+
app17.post("/:id/resume", async (c) => {
|
|
9864
9783
|
const conversationId = c.req.param("id");
|
|
9865
9784
|
const sessionKey = c.req.query("session_key") ?? "";
|
|
9866
9785
|
if (!sessionKey) {
|
|
9867
9786
|
console.error(`[session] middleware-reject status=400 code=session-missing reason="session_key required" path=${c.req.path}`);
|
|
9868
9787
|
return c.json({ error: "session_key required", code: "session-missing" }, 400);
|
|
9869
9788
|
}
|
|
9789
|
+
let bridged = false;
|
|
9870
9790
|
let result = validateSession(sessionKey, "admin");
|
|
9871
9791
|
if (!result.ok) {
|
|
9872
9792
|
if (result.reason === "session-not-registered") {
|
|
@@ -9879,6 +9799,7 @@ app17.get("/:id/messages", async (c) => {
|
|
|
9879
9799
|
console.error(`[session] middleware-reject status=401 code=session-not-registered reason="cookie-bridge-rejected:${bridge.reason}" path=${c.req.path} sessionKey=${tail}\u2026`);
|
|
9880
9800
|
return c.json({ error: "Invalid or expired admin session", code: "session-not-registered" }, 401);
|
|
9881
9801
|
}
|
|
9802
|
+
bridged = true;
|
|
9882
9803
|
result = validateSession(sessionKey, "admin");
|
|
9883
9804
|
if (!result.ok) {
|
|
9884
9805
|
const tail = sessionKey.slice(0, 8);
|
|
@@ -9893,34 +9814,12 @@ app17.get("/:id/messages", async (c) => {
|
|
|
9893
9814
|
}
|
|
9894
9815
|
}
|
|
9895
9816
|
const accountId = getAccountIdForSession(sessionKey);
|
|
9896
|
-
if (!accountId) return c.json({ error: "Account not found for session" }, 401);
|
|
9897
|
-
const owned = await verifyConversationOwnership(conversationId, accountId);
|
|
9898
|
-
if (!owned) return c.json({ error: "Conversation not found" }, 404);
|
|
9899
|
-
try {
|
|
9900
|
-
const messages = await getRecentMessages(conversationId, 50);
|
|
9901
|
-
const sanitised = messages.map((m) => ({
|
|
9902
|
-
...m,
|
|
9903
|
-
attachments: m.attachments.map((a) => ({
|
|
9904
|
-
attachmentId: a.attachmentId,
|
|
9905
|
-
filename: a.filename,
|
|
9906
|
-
mimeType: a.mimeType,
|
|
9907
|
-
sizeBytes: a.sizeBytes,
|
|
9908
|
-
ordinal: a.ordinal
|
|
9909
|
-
}))
|
|
9910
|
-
}));
|
|
9911
|
-
return c.json({ messages: sanitised });
|
|
9912
|
-
} catch (err) {
|
|
9913
|
-
console.error(`[sessions-messages] Failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
9914
|
-
return c.json({ error: "Failed to fetch messages" }, 500);
|
|
9915
|
-
}
|
|
9916
|
-
});
|
|
9917
|
-
app17.post("/:id/resume", requireAdminSession, async (c) => {
|
|
9918
|
-
const conversationId = c.req.param("id");
|
|
9919
|
-
const sessionKey = c.var.sessionKey;
|
|
9920
|
-
const accountId = getAccountIdForSession(sessionKey);
|
|
9921
9817
|
const userId = getUserIdForSession(sessionKey);
|
|
9922
|
-
if (!accountId
|
|
9923
|
-
return c.json({ error: "Session missing account
|
|
9818
|
+
if (!accountId) {
|
|
9819
|
+
return c.json({ error: "Session missing account context" }, 400);
|
|
9820
|
+
}
|
|
9821
|
+
if (!userId && !bridged) {
|
|
9822
|
+
return c.json({ error: "Session missing user context" }, 400);
|
|
9924
9823
|
}
|
|
9925
9824
|
const updatedAt = await verifyAndGetConversationUpdatedAt(conversationId, accountId);
|
|
9926
9825
|
if (updatedAt === null) return c.json({ error: "Conversation not found" }, 404);
|
|
@@ -9975,8 +9874,9 @@ app17.post("/:id/resume", requireAdminSession, async (c) => {
|
|
|
9975
9874
|
});
|
|
9976
9875
|
const textRuns = rehydrated.reduce((n, m) => n + (m.events?.filter((e) => e.type === "text").length ?? 0), 0);
|
|
9977
9876
|
const userMessageCount = rehydrated.filter((m) => m.role !== "assistant").length;
|
|
9877
|
+
const reason = bridged ? "post-restart" : "page-refresh";
|
|
9978
9878
|
try {
|
|
9979
|
-
appendFileSync5(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-resume] sessionKey=${sessionKey.slice(0, 8)} conversationId=${conversationId.slice(0, 8)} ${tag} loadedMessages=${messages.length} componentCount=${totalComponents} userAttachmentCount=${totalAttachments}
|
|
9879
|
+
appendFileSync5(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [admin-resume] reason=${reason} sessionKey=${sessionKey.slice(0, 8)} conversationId=${conversationId.slice(0, 8)} ${tag} loadedMessages=${messages.length} componentCount=${totalComponents} userAttachmentCount=${totalAttachments}
|
|
9980
9880
|
`);
|
|
9981
9881
|
if (totalComponents > 0) {
|
|
9982
9882
|
appendFileSync5(streamLogPath, `[${(/* @__PURE__ */ new Date()).toISOString()}] [component-rehydrate] conversationId=${conversationId.slice(0, 8)} count=${totalComponents} valid=${totalValid} invalid=${totalInvalid} textRuns=${textRuns}
|
|
@@ -9989,7 +9889,7 @@ app17.post("/:id/resume", requireAdminSession, async (c) => {
|
|
|
9989
9889
|
} catch {
|
|
9990
9890
|
}
|
|
9991
9891
|
const age = formatAge(updatedAt);
|
|
9992
|
-
console.log(`[admin-resume] ${(/* @__PURE__ */ new Date()).toISOString()} conversationId=${conversationId.slice(0, 8)}\u2026 age=${age} loaded=${messages.length} messages ${tag} components=${totalComponents} attachments=${totalAttachments} sessionKey=${sessionKey.slice(0, 8)}\u2026`);
|
|
9892
|
+
console.log(`[admin-resume] ${(/* @__PURE__ */ new Date()).toISOString()} reason=${reason} conversationId=${conversationId.slice(0, 8)}\u2026 age=${age} loaded=${messages.length} messages ${tag} components=${totalComponents} attachments=${totalAttachments} sessionKey=${sessionKey.slice(0, 8)}\u2026`);
|
|
9993
9893
|
return c.json({ conversationId, messages: rehydrated });
|
|
9994
9894
|
});
|
|
9995
9895
|
app17.post("/:id/label", requireAdminSession, async (c) => {
|
|
@@ -10116,13 +10016,13 @@ async function cdpNavigateNewTab(url, opts = {}) {
|
|
|
10116
10016
|
// server/routes/admin/device-browser.ts
|
|
10117
10017
|
var app19 = new Hono();
|
|
10118
10018
|
app19.post("/navigate", async (c) => {
|
|
10119
|
-
const
|
|
10019
|
+
const TAG19 = "[device-url:click]";
|
|
10120
10020
|
let body;
|
|
10121
10021
|
try {
|
|
10122
10022
|
body = await c.req.json();
|
|
10123
10023
|
} catch (err) {
|
|
10124
10024
|
const detail = err instanceof Error ? err.message : String(err);
|
|
10125
|
-
console.error(`${
|
|
10025
|
+
console.error(`${TAG19} reject reason=body-not-json detail=${detail} browser=fallback navigateResult=error`);
|
|
10126
10026
|
return c.json(
|
|
10127
10027
|
{ ok: false, navigateResult: "error", browser: "fallback", detail: "Request body was not valid JSON" },
|
|
10128
10028
|
400
|
|
@@ -10132,7 +10032,7 @@ app19.post("/navigate", async (c) => {
|
|
|
10132
10032
|
const intent = typeof body.intent === "string" ? body.intent : "";
|
|
10133
10033
|
const hostname2 = typeof body.hostname === "string" ? body.hostname : "";
|
|
10134
10034
|
if (!url) {
|
|
10135
|
-
console.error(`${
|
|
10035
|
+
console.error(`${TAG19} reject reason=missing-url intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`);
|
|
10136
10036
|
return c.json(
|
|
10137
10037
|
{ ok: false, navigateResult: "error", browser: "fallback", detail: "url field is required" },
|
|
10138
10038
|
400
|
|
@@ -10142,7 +10042,7 @@ app19.post("/navigate", async (c) => {
|
|
|
10142
10042
|
try {
|
|
10143
10043
|
parsed = new URL(url);
|
|
10144
10044
|
} catch {
|
|
10145
|
-
console.error(`${
|
|
10045
|
+
console.error(`${TAG19} reject reason=url-malformed intent=${JSON.stringify(intent)} url=${url} browser=fallback navigateResult=error`);
|
|
10146
10046
|
return c.json(
|
|
10147
10047
|
{ ok: false, navigateResult: "error", browser: "fallback", detail: "url is not a valid URL" },
|
|
10148
10048
|
400
|
|
@@ -10150,7 +10050,7 @@ app19.post("/navigate", async (c) => {
|
|
|
10150
10050
|
}
|
|
10151
10051
|
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
10152
10052
|
console.error(
|
|
10153
|
-
`${
|
|
10053
|
+
`${TAG19} reject reason=scheme-not-allowed scheme=${parsed.protocol} intent=${JSON.stringify(intent)} browser=fallback navigateResult=error`
|
|
10154
10054
|
);
|
|
10155
10055
|
return c.json(
|
|
10156
10056
|
{
|
|
@@ -10166,7 +10066,7 @@ app19.post("/navigate", async (c) => {
|
|
|
10166
10066
|
const cdpOk = await ensureCdp(transport);
|
|
10167
10067
|
if (!cdpOk) {
|
|
10168
10068
|
console.error(
|
|
10169
|
-
`${
|
|
10069
|
+
`${TAG19} intent=${JSON.stringify(intent)} browser=fallback navigateResult=cdp-unreachable hostname=${JSON.stringify(hostname2)}`
|
|
10170
10070
|
);
|
|
10171
10071
|
return c.json(
|
|
10172
10072
|
{
|
|
@@ -10182,7 +10082,7 @@ app19.post("/navigate", async (c) => {
|
|
|
10182
10082
|
const browser = outcome.result === "ok" ? "vnc" : "fallback";
|
|
10183
10083
|
const detailStr = outcome.detail ? ` detail=${JSON.stringify(outcome.detail.length > 230 ? outcome.detail.slice(0, 227) + "..." : outcome.detail)}` : "";
|
|
10184
10084
|
console.error(
|
|
10185
|
-
`${
|
|
10085
|
+
`${TAG19} intent=${JSON.stringify(intent)} browser=${browser} navigateResult=${outcome.result} hostname=${JSON.stringify(hostname2)} targetId=${outcome.targetId ?? "none"}${detailStr}`
|
|
10186
10086
|
);
|
|
10187
10087
|
if (outcome.result !== "ok") {
|
|
10188
10088
|
return c.json(
|
|
@@ -10213,18 +10113,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
10213
10113
|
]);
|
|
10214
10114
|
var app20 = new Hono();
|
|
10215
10115
|
app20.post("/", async (c) => {
|
|
10216
|
-
const
|
|
10116
|
+
const TAG19 = "[admin:events]";
|
|
10217
10117
|
let body;
|
|
10218
10118
|
try {
|
|
10219
10119
|
body = await c.req.json();
|
|
10220
10120
|
} catch (err) {
|
|
10221
10121
|
const detail = err instanceof Error ? err.message : String(err);
|
|
10222
|
-
console.error(`${
|
|
10122
|
+
console.error(`${TAG19} reject reason=body-not-json detail=${detail}`);
|
|
10223
10123
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
10224
10124
|
}
|
|
10225
10125
|
const event = typeof body.event === "string" ? body.event : "";
|
|
10226
10126
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
10227
|
-
console.error(`${
|
|
10127
|
+
console.error(`${TAG19} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
10228
10128
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
10229
10129
|
}
|
|
10230
10130
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -10248,7 +10148,7 @@ var events_default = app20;
|
|
|
10248
10148
|
// server/routes/admin/cloudflare.ts
|
|
10249
10149
|
import { homedir } from "os";
|
|
10250
10150
|
import { resolve as resolve18 } from "path";
|
|
10251
|
-
import { readFileSync as
|
|
10151
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
10252
10152
|
|
|
10253
10153
|
// app/lib/dns-label.ts
|
|
10254
10154
|
var VALID_LABEL = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
@@ -10286,131 +10186,14 @@ function addAliasDomain(hostname2) {
|
|
|
10286
10186
|
writeFileSync9(ALIAS_DOMAINS_PATH, JSON.stringify([...existing], null, 2) + "\n", "utf-8");
|
|
10287
10187
|
}
|
|
10288
10188
|
|
|
10289
|
-
// app/lib/action-relay-queue.ts
|
|
10290
|
-
import {
|
|
10291
|
-
existsSync as existsSync20,
|
|
10292
|
-
mkdirSync as mkdirSync9,
|
|
10293
|
-
readdirSync as readdirSync6,
|
|
10294
|
-
readFileSync as readFileSync16,
|
|
10295
|
-
unlinkSync as unlinkSync2,
|
|
10296
|
-
writeFileSync as writeFileSync10
|
|
10297
|
-
} from "fs";
|
|
10298
|
-
import { join as join9 } from "path";
|
|
10299
|
-
var TAG19 = "[action-relay-queue]";
|
|
10300
|
-
var FILE_PREFIX = "action-completion-relay-";
|
|
10301
|
-
var FILE_SUFFIX = ".json";
|
|
10302
|
-
function queueDir(accountDir) {
|
|
10303
|
-
return join9(accountDir, "queue");
|
|
10304
|
-
}
|
|
10305
|
-
function relayFilePath(accountDir, actionId) {
|
|
10306
|
-
return join9(queueDir(accountDir), `${FILE_PREFIX}${actionId}${FILE_SUFFIX}`);
|
|
10307
|
-
}
|
|
10308
|
-
function enqueueActionCompletionRelay(opts) {
|
|
10309
|
-
const dir = queueDir(opts.accountDir);
|
|
10310
|
-
mkdirSync9(dir, { recursive: true });
|
|
10311
|
-
const filePath = relayFilePath(opts.accountDir, opts.actionId);
|
|
10312
|
-
const record = {
|
|
10313
|
-
actionId: opts.actionId,
|
|
10314
|
-
conversationId: opts.conversationId,
|
|
10315
|
-
message: opts.message,
|
|
10316
|
-
queuedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
10317
|
-
};
|
|
10318
|
-
const body = JSON.stringify(record);
|
|
10319
|
-
try {
|
|
10320
|
-
writeFileSync10(filePath, body, { flag: "wx", encoding: "utf-8" });
|
|
10321
|
-
console.log(
|
|
10322
|
-
`${TAG19} phase=enqueued actionId=${opts.actionId} conversationId=${opts.conversationId} path=${filePath} bytes=${Buffer.byteLength(body, "utf-8")}`
|
|
10323
|
-
);
|
|
10324
|
-
return { enqueued: true, path: filePath };
|
|
10325
|
-
} catch (e) {
|
|
10326
|
-
if (e.code === "EEXIST") {
|
|
10327
|
-
console.log(
|
|
10328
|
-
`${TAG19} phase=enqueue-skipped actionId=${opts.actionId} reason=already-queued`
|
|
10329
|
-
);
|
|
10330
|
-
return { enqueued: false, reason: "already-queued", path: filePath };
|
|
10331
|
-
}
|
|
10332
|
-
throw e;
|
|
10333
|
-
}
|
|
10334
|
-
}
|
|
10335
|
-
function consumeActionCompletionRelays(accountDir) {
|
|
10336
|
-
const dir = queueDir(accountDir);
|
|
10337
|
-
if (!existsSync20(dir)) return [];
|
|
10338
|
-
let entries;
|
|
10339
|
-
try {
|
|
10340
|
-
entries = readdirSync6(dir);
|
|
10341
|
-
} catch (e) {
|
|
10342
|
-
console.error(
|
|
10343
|
-
`${TAG19} phase=readdir-failed dir=${dir} error=${e instanceof Error ? e.message : String(e)}`
|
|
10344
|
-
);
|
|
10345
|
-
return [];
|
|
10346
|
-
}
|
|
10347
|
-
const records = [];
|
|
10348
|
-
for (const name of entries) {
|
|
10349
|
-
if (!name.startsWith(FILE_PREFIX) || !name.endsWith(FILE_SUFFIX)) continue;
|
|
10350
|
-
const filePath = join9(dir, name);
|
|
10351
|
-
let raw;
|
|
10352
|
-
try {
|
|
10353
|
-
raw = readFileSync16(filePath, "utf-8");
|
|
10354
|
-
} catch (e) {
|
|
10355
|
-
console.error(
|
|
10356
|
-
`${TAG19} phase=read-failed file=${name} error=${e instanceof Error ? e.message : String(e)}`
|
|
10357
|
-
);
|
|
10358
|
-
continue;
|
|
10359
|
-
}
|
|
10360
|
-
let parsed;
|
|
10361
|
-
try {
|
|
10362
|
-
parsed = JSON.parse(raw);
|
|
10363
|
-
} catch (e) {
|
|
10364
|
-
console.error(
|
|
10365
|
-
`${TAG19} phase=parse-failed file=${name} error=${e instanceof Error ? e.message : String(e)}`
|
|
10366
|
-
);
|
|
10367
|
-
continue;
|
|
10368
|
-
}
|
|
10369
|
-
if (!isActionCompletionRelay(parsed)) {
|
|
10370
|
-
console.error(
|
|
10371
|
-
`${TAG19} phase=shape-invalid file=${name} keys=${parsed && typeof parsed === "object" ? Object.keys(parsed).join(",") : "non-object"}`
|
|
10372
|
-
);
|
|
10373
|
-
continue;
|
|
10374
|
-
}
|
|
10375
|
-
records.push({ rec: parsed, filePath });
|
|
10376
|
-
}
|
|
10377
|
-
records.sort((a, b) => a.rec.queuedAt.localeCompare(b.rec.queuedAt));
|
|
10378
|
-
const out = [];
|
|
10379
|
-
const now = Date.now();
|
|
10380
|
-
for (const { rec, filePath } of records) {
|
|
10381
|
-
const queuedAtMs = Date.parse(rec.queuedAt);
|
|
10382
|
-
const ageMs = Number.isFinite(queuedAtMs) ? now - queuedAtMs : 0;
|
|
10383
|
-
out.push({ ...rec, ageMs, filePath });
|
|
10384
|
-
}
|
|
10385
|
-
return out;
|
|
10386
|
-
}
|
|
10387
|
-
function deleteConsumedRelay(filePath) {
|
|
10388
|
-
try {
|
|
10389
|
-
unlinkSync2(filePath);
|
|
10390
|
-
} catch (e) {
|
|
10391
|
-
const code = e.code;
|
|
10392
|
-
if (code !== "ENOENT") {
|
|
10393
|
-
console.error(
|
|
10394
|
-
`${TAG19} phase=unlink-failed file=${filePath} error=${e instanceof Error ? e.message : String(e)}`
|
|
10395
|
-
);
|
|
10396
|
-
}
|
|
10397
|
-
}
|
|
10398
|
-
}
|
|
10399
|
-
function isActionCompletionRelay(value) {
|
|
10400
|
-
if (!value || typeof value !== "object") return false;
|
|
10401
|
-
const v = value;
|
|
10402
|
-
return typeof v.actionId === "string" && typeof v.conversationId === "string" && typeof v.message === "string" && typeof v.queuedAt === "string";
|
|
10403
|
-
}
|
|
10404
|
-
|
|
10405
10189
|
// server/routes/admin/cloudflare.ts
|
|
10406
|
-
import { existsSync as existsSyncFs, readFileSync as readFileSyncFs } from "fs";
|
|
10407
10190
|
var SETUP_TIMEOUT_MS = 10 * 60 * 1e3;
|
|
10408
10191
|
var DOMAINS_TIMEOUT_MS = 40 * 1e3;
|
|
10409
10192
|
function loadBrandInfo() {
|
|
10410
10193
|
const platformRoot2 = process.env.MAXY_PLATFORM_ROOT ?? resolve18(process.cwd(), "..");
|
|
10411
10194
|
const brandPath = resolve18(platformRoot2, "config", "brand.json");
|
|
10412
10195
|
try {
|
|
10413
|
-
const parsed = JSON.parse(
|
|
10196
|
+
const parsed = JSON.parse(readFileSync16(brandPath, "utf-8"));
|
|
10414
10197
|
const hostname2 = typeof parsed.hostname === "string" && parsed.hostname ? parsed.hostname : "maxy";
|
|
10415
10198
|
const configDir2 = typeof parsed.configDir === "string" && parsed.configDir ? parsed.configDir : ".maxy";
|
|
10416
10199
|
return { hostname: hostname2, configDir: configDir2 };
|
|
@@ -10706,79 +10489,13 @@ actionId: ${actionId}`,
|
|
|
10706
10489
|
};
|
|
10707
10490
|
return ok(success);
|
|
10708
10491
|
});
|
|
10709
|
-
var RELAY_MAX_BODY = 8 * 1024;
|
|
10710
|
-
var RELAY_MAX_MESSAGE = 2048;
|
|
10711
|
-
var ACTION_ID_RE = /^[a-z0-9-]+$/;
|
|
10712
|
-
app21.post("/relay-completion", requireAdminSession, async (c) => {
|
|
10713
|
-
const sessionKey = c.var.sessionKey;
|
|
10714
|
-
let raw;
|
|
10715
|
-
try {
|
|
10716
|
-
raw = await c.req.text();
|
|
10717
|
-
} catch {
|
|
10718
|
-
return c.json({ ok: false, reason: "invalid-body" }, 400);
|
|
10719
|
-
}
|
|
10720
|
-
if (Buffer.byteLength(raw, "utf-8") > RELAY_MAX_BODY) {
|
|
10721
|
-
return c.json({ ok: false, reason: "body-too-large" }, 413);
|
|
10722
|
-
}
|
|
10723
|
-
let body;
|
|
10724
|
-
try {
|
|
10725
|
-
body = JSON.parse(raw);
|
|
10726
|
-
} catch {
|
|
10727
|
-
return c.json({ ok: false, reason: "invalid-json" }, 400);
|
|
10728
|
-
}
|
|
10729
|
-
if (!body || typeof body !== "object") {
|
|
10730
|
-
return c.json({ ok: false, reason: "invalid-body" }, 400);
|
|
10731
|
-
}
|
|
10732
|
-
const { actionId, message } = body;
|
|
10733
|
-
if (typeof actionId !== "string" || !ACTION_ID_RE.test(actionId) || actionId.length > 200) {
|
|
10734
|
-
console.error(`[cloudflare-relay-completion] phase=enqueue-skipped reason=invalid-actionid sessionKey=${sessionKey.slice(-8)}`);
|
|
10735
|
-
return c.json({ ok: false, reason: "invalid-actionid" }, 400);
|
|
10736
|
-
}
|
|
10737
|
-
if (typeof message !== "string" || message.length === 0 || message.length > RELAY_MAX_MESSAGE) {
|
|
10738
|
-
return c.json({ ok: false, reason: "invalid-message" }, 400);
|
|
10739
|
-
}
|
|
10740
|
-
const conversationId = getConversationIdForSession(sessionKey);
|
|
10741
|
-
if (!conversationId) {
|
|
10742
|
-
console.error(`[cloudflare-relay-completion] phase=enqueue-skipped reason=missing-conversation-id sessionKey=${sessionKey.slice(-8)}`);
|
|
10743
|
-
return c.json({ ok: false, reason: "missing-conversation-id" }, 400);
|
|
10744
|
-
}
|
|
10745
|
-
const account = resolveAccount();
|
|
10746
|
-
if (!account) {
|
|
10747
|
-
console.error(`[cloudflare-relay-completion] phase=enqueue-skipped reason=missing-account-dir actionId=${actionId}`);
|
|
10748
|
-
return c.json({ ok: false, reason: "missing-account-dir" }, 500);
|
|
10749
|
-
}
|
|
10750
|
-
const logPath2 = actionLogPath(actionId);
|
|
10751
|
-
let auditOutcome = "log-absent";
|
|
10752
|
-
if (existsSyncFs(logPath2)) {
|
|
10753
|
-
try {
|
|
10754
|
-
const lines = readFileSyncFs(logPath2, "utf-8").split("\n");
|
|
10755
|
-
const reconciled = reconcileCloudflareSetupFromLog(lines);
|
|
10756
|
-
auditOutcome = reconciled ? reconciled.kind : "log-incomplete";
|
|
10757
|
-
} catch (e) {
|
|
10758
|
-
auditOutcome = `read-failed:${e instanceof Error ? e.message : String(e)}`;
|
|
10759
|
-
}
|
|
10760
|
-
}
|
|
10761
|
-
console.log(`[cloudflare-relay-completion] phase=enqueue-attempt actionId=${actionId} auditOutcome=${auditOutcome} conversationId=${conversationId}`);
|
|
10762
|
-
try {
|
|
10763
|
-
enqueueActionCompletionRelay({
|
|
10764
|
-
accountDir: account.accountDir,
|
|
10765
|
-
actionId,
|
|
10766
|
-
conversationId,
|
|
10767
|
-
message
|
|
10768
|
-
});
|
|
10769
|
-
} catch (e) {
|
|
10770
|
-
console.error(`[cloudflare-relay-completion] phase=enqueue-failed actionId=${actionId} error=${e instanceof Error ? e.message : String(e)}`);
|
|
10771
|
-
return c.json({ ok: false, reason: "enqueue-failed" }, 500);
|
|
10772
|
-
}
|
|
10773
|
-
return c.body(null, 204);
|
|
10774
|
-
});
|
|
10775
10492
|
var cloudflare_default = app21;
|
|
10776
10493
|
|
|
10777
10494
|
// server/routes/admin/files.ts
|
|
10778
10495
|
import { createReadStream as createReadStream3 } from "fs";
|
|
10779
10496
|
import { readdir as readdir2, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
|
|
10780
10497
|
import { realpathSync as realpathSync4 } from "fs";
|
|
10781
|
-
import { basename as basename6, dirname as dirname8, join as
|
|
10498
|
+
import { basename as basename6, dirname as dirname8, join as join9, resolve as resolve20, sep as sep2 } from "path";
|
|
10782
10499
|
import { Readable as Readable2 } from "stream";
|
|
10783
10500
|
|
|
10784
10501
|
// app/lib/data-path.ts
|
|
@@ -11136,7 +10853,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
11136
10853
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
11137
10854
|
async function readMeta(absDir, baseName) {
|
|
11138
10855
|
try {
|
|
11139
|
-
const raw = await readFile4(
|
|
10856
|
+
const raw = await readFile4(join9(absDir, `${baseName}.meta.json`), "utf8");
|
|
11140
10857
|
const parsed = JSON.parse(raw);
|
|
11141
10858
|
if (typeof parsed?.filename === "string") {
|
|
11142
10859
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -11174,7 +10891,7 @@ async function readAccountNames() {
|
|
|
11174
10891
|
}
|
|
11175
10892
|
async function enrich(absolute, entry, accountNames) {
|
|
11176
10893
|
if (entry.kind === "directory" && UUID_RE4.test(entry.name)) {
|
|
11177
|
-
const meta = await readMeta(
|
|
10894
|
+
const meta = await readMeta(join9(absolute, entry.name), entry.name);
|
|
11178
10895
|
if (meta?.filename) {
|
|
11179
10896
|
entry.displayName = meta.filename;
|
|
11180
10897
|
entry.mimeType = meta.mimeType;
|
|
@@ -11233,7 +10950,7 @@ app22.get("/", requireAdminSession, async (c) => {
|
|
|
11233
10950
|
continue;
|
|
11234
10951
|
}
|
|
11235
10952
|
try {
|
|
11236
|
-
const entryPath =
|
|
10953
|
+
const entryPath = join9(absolute, name);
|
|
11237
10954
|
const s = await stat4(entryPath);
|
|
11238
10955
|
entries.push({
|
|
11239
10956
|
name,
|
|
@@ -11406,7 +11123,7 @@ app22.delete("/", requireAdminSession, async (c) => {
|
|
|
11406
11123
|
}
|
|
11407
11124
|
const dot = base.lastIndexOf(".");
|
|
11408
11125
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
11409
|
-
const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ?
|
|
11126
|
+
const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join9(dirname8(absolute), `${stem}.meta.json`) : null;
|
|
11410
11127
|
await unlink2(absolute);
|
|
11411
11128
|
if (sidecarPath) {
|
|
11412
11129
|
try {
|
|
@@ -12887,7 +12604,7 @@ var adherence_default = app30;
|
|
|
12887
12604
|
import neo4j3 from "neo4j-driver";
|
|
12888
12605
|
import { readFile as readFile5, readdir as readdir3, stat as stat5 } from "fs/promises";
|
|
12889
12606
|
import { resolve as resolve21, relative as relative2, isAbsolute } from "path";
|
|
12890
|
-
import { existsSync as
|
|
12607
|
+
import { existsSync as existsSync20 } from "fs";
|
|
12891
12608
|
var LIMIT = 50;
|
|
12892
12609
|
var TEXT_MIME_PREFIXES = ["text/", "application/json", "application/markdown"];
|
|
12893
12610
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
@@ -13035,7 +12752,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
13035
12752
|
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
13036
12753
|
const names = /* @__PURE__ */ new Set();
|
|
13037
12754
|
for (const dir of [overrideDir, bundledDir]) {
|
|
13038
|
-
if (!
|
|
12755
|
+
if (!existsSync20(dir)) continue;
|
|
13039
12756
|
try {
|
|
13040
12757
|
const entries = await readdir3(dir);
|
|
13041
12758
|
for (const entry of entries) {
|
|
@@ -13050,7 +12767,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
13050
12767
|
}
|
|
13051
12768
|
async function readAgentTemplateRow(inp) {
|
|
13052
12769
|
let chosenPath = null;
|
|
13053
|
-
if (
|
|
12770
|
+
if (existsSync20(inp.overridePath)) {
|
|
13054
12771
|
try {
|
|
13055
12772
|
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
13056
12773
|
chosenPath = inp.overridePath;
|
|
@@ -13061,7 +12778,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
13061
12778
|
);
|
|
13062
12779
|
return null;
|
|
13063
12780
|
}
|
|
13064
|
-
} else if (
|
|
12781
|
+
} else if (existsSync20(inp.bundledPath)) {
|
|
13065
12782
|
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
13066
12783
|
console.error(
|
|
13067
12784
|
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
@@ -13103,7 +12820,7 @@ var sidebar_artefacts_default = app31;
|
|
|
13103
12820
|
// server/routes/admin/sidebar-artefact-save.ts
|
|
13104
12821
|
import { mkdir as mkdir4, readdir as readdir4, stat as stat6, writeFile as writeFile5 } from "fs/promises";
|
|
13105
12822
|
import { resolve as resolve22 } from "path";
|
|
13106
|
-
import { existsSync as
|
|
12823
|
+
import { existsSync as existsSync21 } from "fs";
|
|
13107
12824
|
var ADMIN_AGENT_FILES2 = /* @__PURE__ */ new Set(["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"]);
|
|
13108
12825
|
var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
13109
12826
|
var app32 = new Hono();
|
|
@@ -13167,7 +12884,7 @@ async function resolveSavePath(id, accountId, accountDir) {
|
|
|
13167
12884
|
}
|
|
13168
12885
|
if (UUID_RE5.test(id)) {
|
|
13169
12886
|
const dir = resolve22(ATTACHMENTS_ROOT, accountId, id);
|
|
13170
|
-
if (!
|
|
12887
|
+
if (!existsSync21(dir)) {
|
|
13171
12888
|
return { kind: "reject", status: 400, reason: "not-found" };
|
|
13172
12889
|
}
|
|
13173
12890
|
try {
|
|
@@ -13191,7 +12908,7 @@ var sidebar_artefact_save_default = app32;
|
|
|
13191
12908
|
|
|
13192
12909
|
// server/routes/admin/sidebar-artefact-content.ts
|
|
13193
12910
|
import { readFile as readFile6, readdir as readdir5 } from "fs/promises";
|
|
13194
|
-
import { existsSync as
|
|
12911
|
+
import { existsSync as existsSync22 } from "fs";
|
|
13195
12912
|
import { resolve as resolve23 } from "path";
|
|
13196
12913
|
var UUID_RE6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
13197
12914
|
var app33 = new Hono();
|
|
@@ -13205,7 +12922,7 @@ app33.get("/", requireAdminSession, async (c) => {
|
|
|
13205
12922
|
return new Response("Not found", { status: 404 });
|
|
13206
12923
|
}
|
|
13207
12924
|
const dir = resolve23(ATTACHMENTS_ROOT, accountId, id);
|
|
13208
|
-
if (!
|
|
12925
|
+
if (!existsSync22(dir)) {
|
|
13209
12926
|
console.error(`[admin/sidebar-artefact-content] not-found id=${id.slice(0, 8)}`);
|
|
13210
12927
|
return new Response("Not found", { status: 404 });
|
|
13211
12928
|
}
|
|
@@ -13267,7 +12984,7 @@ app34.route("/sidebar-artefact-content", sidebar_artefact_content_default);
|
|
|
13267
12984
|
var admin_default = app34;
|
|
13268
12985
|
|
|
13269
12986
|
// server/routes/sites.ts
|
|
13270
|
-
import { existsSync as
|
|
12987
|
+
import { existsSync as existsSync23, readFileSync as readFileSync17, realpathSync as realpathSync5, statSync as statSync8 } from "fs";
|
|
13271
12988
|
import { resolve as resolve24 } from "path";
|
|
13272
12989
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
13273
12990
|
var MIME = {
|
|
@@ -13334,7 +13051,7 @@ app35.get("/:rel{.*}", (c) => {
|
|
|
13334
13051
|
}
|
|
13335
13052
|
let stat7;
|
|
13336
13053
|
try {
|
|
13337
|
-
stat7 =
|
|
13054
|
+
stat7 = existsSync23(filePath) ? statSync8(filePath) : null;
|
|
13338
13055
|
} catch {
|
|
13339
13056
|
stat7 = null;
|
|
13340
13057
|
}
|
|
@@ -13347,7 +13064,7 @@ app35.get("/:rel{.*}", (c) => {
|
|
|
13347
13064
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
13348
13065
|
return c.text("Forbidden", 403);
|
|
13349
13066
|
}
|
|
13350
|
-
if (!
|
|
13067
|
+
if (!existsSync23(filePath)) {
|
|
13351
13068
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
13352
13069
|
return c.text("Not found", 404);
|
|
13353
13070
|
}
|
|
@@ -13366,7 +13083,7 @@ app35.get("/:rel{.*}", (c) => {
|
|
|
13366
13083
|
}
|
|
13367
13084
|
let body;
|
|
13368
13085
|
try {
|
|
13369
|
-
body =
|
|
13086
|
+
body = readFileSync17(realPath);
|
|
13370
13087
|
} catch (err) {
|
|
13371
13088
|
const code = err?.code;
|
|
13372
13089
|
if (code === "EISDIR") {
|
|
@@ -13498,14 +13215,14 @@ function clientFrom(c) {
|
|
|
13498
13215
|
);
|
|
13499
13216
|
}
|
|
13500
13217
|
var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
13501
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT7 ?
|
|
13218
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join10(PLATFORM_ROOT7, "config", "brand.json") : "";
|
|
13502
13219
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
|
|
13503
|
-
if (BRAND_JSON_PATH && !
|
|
13220
|
+
if (BRAND_JSON_PATH && !existsSync24(BRAND_JSON_PATH)) {
|
|
13504
13221
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
13505
13222
|
}
|
|
13506
|
-
if (BRAND_JSON_PATH &&
|
|
13223
|
+
if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
|
|
13507
13224
|
try {
|
|
13508
|
-
const parsed = JSON.parse(
|
|
13225
|
+
const parsed = JSON.parse(readFileSync18(BRAND_JSON_PATH, "utf-8"));
|
|
13509
13226
|
BRAND = { ...BRAND, ...parsed };
|
|
13510
13227
|
} catch (err) {
|
|
13511
13228
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -13524,11 +13241,11 @@ var brandLoginOpts = {
|
|
|
13524
13241
|
bodyFont: BRAND.defaultFonts?.body,
|
|
13525
13242
|
logoContainsName: !!BRAND.logoContainsName
|
|
13526
13243
|
};
|
|
13527
|
-
var ALIAS_DOMAINS_PATH2 =
|
|
13244
|
+
var ALIAS_DOMAINS_PATH2 = join10(homedir2(), BRAND.configDir, "alias-domains.json");
|
|
13528
13245
|
function loadAliasDomains() {
|
|
13529
13246
|
try {
|
|
13530
|
-
if (!
|
|
13531
|
-
const parsed = JSON.parse(
|
|
13247
|
+
if (!existsSync24(ALIAS_DOMAINS_PATH2)) return null;
|
|
13248
|
+
const parsed = JSON.parse(readFileSync18(ALIAS_DOMAINS_PATH2, "utf-8"));
|
|
13532
13249
|
if (!Array.isArray(parsed)) {
|
|
13533
13250
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
13534
13251
|
return null;
|
|
@@ -13874,14 +13591,14 @@ app36.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
13874
13591
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
13875
13592
|
return c.text("Forbidden", 403);
|
|
13876
13593
|
}
|
|
13877
|
-
if (!
|
|
13594
|
+
if (!existsSync24(filePath)) {
|
|
13878
13595
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
13879
13596
|
return c.text("Not found", 404);
|
|
13880
13597
|
}
|
|
13881
13598
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
13882
13599
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
13883
13600
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
13884
|
-
const body =
|
|
13601
|
+
const body = readFileSync18(filePath);
|
|
13885
13602
|
return c.body(body, 200, {
|
|
13886
13603
|
"Content-Type": contentType,
|
|
13887
13604
|
"Cache-Control": "public, max-age=3600"
|
|
@@ -13904,14 +13621,14 @@ app36.get("/generated/:filename", (c) => {
|
|
|
13904
13621
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
13905
13622
|
return c.text("Forbidden", 403);
|
|
13906
13623
|
}
|
|
13907
|
-
if (!
|
|
13624
|
+
if (!existsSync24(filePath)) {
|
|
13908
13625
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
13909
13626
|
return c.text("Not found", 404);
|
|
13910
13627
|
}
|
|
13911
13628
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
13912
13629
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
13913
13630
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
13914
|
-
const body =
|
|
13631
|
+
const body = readFileSync18(filePath);
|
|
13915
13632
|
return c.body(body, 200, {
|
|
13916
13633
|
"Content-Type": contentType,
|
|
13917
13634
|
"Cache-Control": "public, max-age=86400"
|
|
@@ -13921,9 +13638,9 @@ app36.route("/sites", sites_default);
|
|
|
13921
13638
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
13922
13639
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
13923
13640
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
13924
|
-
if (BRAND_JSON_PATH &&
|
|
13641
|
+
if (BRAND_JSON_PATH && existsSync24(BRAND_JSON_PATH)) {
|
|
13925
13642
|
try {
|
|
13926
|
-
const fullBrand = JSON.parse(
|
|
13643
|
+
const fullBrand = JSON.parse(readFileSync18(BRAND_JSON_PATH, "utf-8"));
|
|
13927
13644
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
13928
13645
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
13929
13646
|
} catch {
|
|
@@ -13940,9 +13657,9 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
13940
13657
|
function readInstalledVersion() {
|
|
13941
13658
|
try {
|
|
13942
13659
|
if (!PLATFORM_ROOT7) return "unknown";
|
|
13943
|
-
const versionFile =
|
|
13944
|
-
if (!
|
|
13945
|
-
const content =
|
|
13660
|
+
const versionFile = join10(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
|
|
13661
|
+
if (!existsSync24(versionFile)) return "unknown";
|
|
13662
|
+
const content = readFileSync18(versionFile, "utf-8").trim();
|
|
13946
13663
|
return content || "unknown";
|
|
13947
13664
|
} catch {
|
|
13948
13665
|
return "unknown";
|
|
@@ -13983,7 +13700,7 @@ var clientErrorReporterScript = `<script>
|
|
|
13983
13700
|
function cachedHtml(file) {
|
|
13984
13701
|
let html = htmlCache.get(file);
|
|
13985
13702
|
if (!html) {
|
|
13986
|
-
html =
|
|
13703
|
+
html = readFileSync18(resolve25(process.cwd(), "public", file), "utf-8");
|
|
13987
13704
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
13988
13705
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
13989
13706
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -13999,26 +13716,26 @@ ${clientErrorReporterScript}
|
|
|
13999
13716
|
}
|
|
14000
13717
|
var brandedHtmlCache = /* @__PURE__ */ new Map();
|
|
14001
13718
|
function loadBrandingCache(agentSlug) {
|
|
14002
|
-
const configDir2 =
|
|
13719
|
+
const configDir2 = join10(homedir2(), BRAND.configDir);
|
|
14003
13720
|
try {
|
|
14004
|
-
const accountJsonPath =
|
|
14005
|
-
if (!
|
|
14006
|
-
const account = JSON.parse(
|
|
13721
|
+
const accountJsonPath = join10(configDir2, "account.json");
|
|
13722
|
+
if (!existsSync24(accountJsonPath)) return null;
|
|
13723
|
+
const account = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
|
|
14007
13724
|
const accountId = account.accountId;
|
|
14008
13725
|
if (!accountId) return null;
|
|
14009
|
-
const cachePath =
|
|
14010
|
-
if (!
|
|
14011
|
-
return JSON.parse(
|
|
13726
|
+
const cachePath = join10(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
13727
|
+
if (!existsSync24(cachePath)) return null;
|
|
13728
|
+
return JSON.parse(readFileSync18(cachePath, "utf-8"));
|
|
14012
13729
|
} catch {
|
|
14013
13730
|
return null;
|
|
14014
13731
|
}
|
|
14015
13732
|
}
|
|
14016
13733
|
function resolveDefaultSlug() {
|
|
14017
13734
|
try {
|
|
14018
|
-
const configDir2 =
|
|
14019
|
-
const accountJsonPath =
|
|
14020
|
-
if (!
|
|
14021
|
-
const account = JSON.parse(
|
|
13735
|
+
const configDir2 = join10(homedir2(), BRAND.configDir);
|
|
13736
|
+
const accountJsonPath = join10(configDir2, "account.json");
|
|
13737
|
+
if (!existsSync24(accountJsonPath)) return null;
|
|
13738
|
+
const account = JSON.parse(readFileSync18(accountJsonPath, "utf-8"));
|
|
14022
13739
|
return account.defaultAgent || null;
|
|
14023
13740
|
} catch {
|
|
14024
13741
|
return null;
|
|
@@ -14091,7 +13808,7 @@ app36.use("/vnc-popout.html", logViewerFetch);
|
|
|
14091
13808
|
app36.get("/vnc-popout.html", (c) => {
|
|
14092
13809
|
let html = htmlCache.get("vnc-popout.html");
|
|
14093
13810
|
if (!html) {
|
|
14094
|
-
html =
|
|
13811
|
+
html = readFileSync18(resolve25(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
14095
13812
|
const name = escapeHtml(BRAND.productName);
|
|
14096
13813
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
14097
13814
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -14181,8 +13898,8 @@ try {
|
|
|
14181
13898
|
(async () => {
|
|
14182
13899
|
try {
|
|
14183
13900
|
let userId = "";
|
|
14184
|
-
if (
|
|
14185
|
-
const users = JSON.parse(
|
|
13901
|
+
if (existsSync24(USERS_FILE)) {
|
|
13902
|
+
const users = JSON.parse(readFileSync18(USERS_FILE, "utf-8").trim() || "[]");
|
|
14186
13903
|
userId = users[0]?.userId ?? "";
|
|
14187
13904
|
}
|
|
14188
13905
|
await backfillNullUserIdConversations(userId);
|
|
@@ -14242,48 +13959,6 @@ for (const dir of bootEnabled) {
|
|
|
14242
13959
|
bootDelivered.push(dir);
|
|
14243
13960
|
}
|
|
14244
13961
|
console.error(`[plugins] readiness enabled=${bootEnabled.length} delivered=${bootDelivered.length} dist-missing=[${bootDistMissing.join(",")}] missing=[${bootMissing.join(",")}]`);
|
|
14245
|
-
(async () => {
|
|
14246
|
-
if (!bootAccount) {
|
|
14247
|
-
console.log("[action-completion-relay] phase=consumed-skip reason=no-account");
|
|
14248
|
-
return;
|
|
14249
|
-
}
|
|
14250
|
-
let records;
|
|
14251
|
-
try {
|
|
14252
|
-
records = consumeActionCompletionRelays(bootAccount.accountDir);
|
|
14253
|
-
} catch (err) {
|
|
14254
|
-
console.error(`[action-completion-relay] phase=consume-failed error=${err instanceof Error ? err.message : String(err)}`);
|
|
14255
|
-
return;
|
|
14256
|
-
}
|
|
14257
|
-
if (records.length === 0) {
|
|
14258
|
-
console.log(`[action-completion-relay] phase=consumed-empty accountId=${bootAccount.accountId.slice(0, 8)}\u2026`);
|
|
14259
|
-
return;
|
|
14260
|
-
}
|
|
14261
|
-
console.log(`[action-completion-relay] phase=consume-batch count=${records.length} accountId=${bootAccount.accountId.slice(0, 8)}\u2026`);
|
|
14262
|
-
for (const rec of records) {
|
|
14263
|
-
const sessionKey = `cloudflare-relay-boot:${rec.actionId}`;
|
|
14264
|
-
let outcome = "injected";
|
|
14265
|
-
let dispatchError;
|
|
14266
|
-
try {
|
|
14267
|
-
registerSession(sessionKey, "admin", bootAccount.accountId);
|
|
14268
|
-
setConversationIdForSession(sessionKey, rec.conversationId);
|
|
14269
|
-
for await (const _ev of invokeAgent({ type: "admin" }, rec.message, sessionKey)) {
|
|
14270
|
-
}
|
|
14271
|
-
} catch (err) {
|
|
14272
|
-
outcome = "dispatch-failed";
|
|
14273
|
-
dispatchError = err instanceof Error ? err.message : String(err);
|
|
14274
|
-
} finally {
|
|
14275
|
-
unregisterSession(sessionKey);
|
|
14276
|
-
}
|
|
14277
|
-
if (outcome === "injected") {
|
|
14278
|
-
deleteConsumedRelay(rec.filePath);
|
|
14279
|
-
console.log(`[action-completion-relay] phase=consumed actionId=${rec.actionId} conversationId=${rec.conversationId} ageMs=${rec.ageMs} outcome=injected`);
|
|
14280
|
-
} else {
|
|
14281
|
-
console.error(`[action-completion-relay] phase=consumed actionId=${rec.actionId} conversationId=${rec.conversationId} ageMs=${rec.ageMs} outcome=${outcome} reason=${JSON.stringify(dispatchError ?? "")} fileRetained=${JSON.stringify(rec.filePath)}`);
|
|
14282
|
-
}
|
|
14283
|
-
}
|
|
14284
|
-
})().catch((err) => {
|
|
14285
|
-
console.error(`[action-completion-relay] boot-drain rejected: ${err instanceof Error ? err.message : String(err)}`);
|
|
14286
|
-
});
|
|
14287
13962
|
if (bootAccountConfig?.whatsapp) {
|
|
14288
13963
|
console.error(`[whatsapp:boot] loading whatsapp config from account.json publicAgent=${bootPublicAgent ?? "none"}`);
|
|
14289
13964
|
} else {
|
|
@@ -14291,7 +13966,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
14291
13966
|
}
|
|
14292
13967
|
init({
|
|
14293
13968
|
configDir: configDirForWhatsApp,
|
|
14294
|
-
platformRoot: resolve25(process.env.MAXY_PLATFORM_ROOT ??
|
|
13969
|
+
platformRoot: resolve25(process.env.MAXY_PLATFORM_ROOT ?? join10(__dirname, "..")),
|
|
14295
13970
|
accountConfig: bootAccountConfig,
|
|
14296
13971
|
onMessage: async (msg) => {
|
|
14297
13972
|
try {
|