@rubytech/create-maxy-code 0.1.468 → 0.1.470
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/dist/index.js +40 -0
- package/package.json +1 -1
- package/payload/platform/config/brand.json +1 -0
- package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js +12 -2
- package/payload/platform/lib/storage-broker/dist/__tests__/cf-exec.test.js.map +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts +9 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.d.ts.map +1 -1
- package/payload/platform/lib/storage-broker/dist/cf-exec.js +10 -3
- package/payload/platform/lib/storage-broker/dist/cf-exec.js.map +1 -1
- package/payload/platform/lib/storage-broker/src/__tests__/cf-exec.test.ts +26 -3
- package/payload/platform/lib/storage-broker/src/cf-exec.ts +16 -3
- 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 +106 -1
- package/payload/platform/plugins/docs/references/admin-ui.md +32 -0
- package/payload/platform/plugins/docs/references/google-guide.md +68 -0
- package/payload/platform/plugins/google/.claude-plugin/plugin.json +21 -0
- package/payload/platform/plugins/google/PLUGIN.md +104 -0
- package/payload/platform/plugins/google/lib/mcp-spawn-tee/index.js +193 -0
- package/payload/platform/plugins/google/lib/mcp-spawn-tee/package.json +3 -0
- package/payload/platform/plugins/google/mcp/package.json +20 -0
- package/payload/platform/plugins/google/references/auth.md +43 -24
- package/payload/platform/services/claude-session-manager/dist/account-title-stores.d.ts +17 -4
- package/payload/platform/services/claude-session-manager/dist/account-title-stores.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/account-title-stores.js +50 -13
- package/payload/platform/services/claude-session-manager/dist/account-title-stores.js.map +1 -1
- 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 +12 -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/fs-watcher.d.ts +7 -0
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +8 -0
- package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +8 -8
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/{chunk-FOYHK255.js → chunk-56WJMBQQ.js} +3 -3
- package/payload/server/{chunk-POBXIHOF.js → chunk-JRIBGO45.js} +15 -1
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/server.js +643 -379
- package/payload/server/{src-52M7SECF.js → src-JYPKMWJR.js} +1 -1
package/payload/server/server.js
CHANGED
|
@@ -111,7 +111,7 @@ import {
|
|
|
111
111
|
vncLog,
|
|
112
112
|
walkPremiumBundles,
|
|
113
113
|
writeAdminUserAndPerson
|
|
114
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-JRIBGO45.js";
|
|
115
115
|
import {
|
|
116
116
|
D1_MAX_SQL_STATEMENT_BYTES,
|
|
117
117
|
D1_QUERY_MAX_BODY_BYTES,
|
|
@@ -126,7 +126,7 @@ import {
|
|
|
126
126
|
registerResource,
|
|
127
127
|
resolveOwner,
|
|
128
128
|
tooLargeMessage
|
|
129
|
-
} from "./chunk-
|
|
129
|
+
} from "./chunk-56WJMBQQ.js";
|
|
130
130
|
import {
|
|
131
131
|
__commonJS,
|
|
132
132
|
__toESM
|
|
@@ -1533,10 +1533,10 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1533
1533
|
};
|
|
1534
1534
|
|
|
1535
1535
|
// server/index.ts
|
|
1536
|
-
import { readFileSync as
|
|
1536
|
+
import { readFileSync as readFileSync39, existsSync as existsSync37, watchFile, readdirSync as readdirSync22, statSync as statSync14 } from "fs";
|
|
1537
1537
|
import { spawn as spawn3 } from "child_process";
|
|
1538
1538
|
import { createHash as createHash7 } from "crypto";
|
|
1539
|
-
import { resolve as resolve36, join as
|
|
1539
|
+
import { resolve as resolve36, join as join39, basename as basename12 } from "path";
|
|
1540
1540
|
import { homedir as homedir4 } from "os";
|
|
1541
1541
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1542
1542
|
|
|
@@ -5316,9 +5316,6 @@ function getStatus() {
|
|
|
5316
5316
|
terminalReason: conn.terminalReason
|
|
5317
5317
|
}));
|
|
5318
5318
|
}
|
|
5319
|
-
function getSocket(accountId) {
|
|
5320
|
-
return connections.get(accountId)?.sock ?? null;
|
|
5321
|
-
}
|
|
5322
5319
|
function findConnectionByKey(conns, accountId) {
|
|
5323
5320
|
return conns.find((c) => c.accountId === accountId) ?? conns.find((c) => c.platformAccountId === accountId);
|
|
5324
5321
|
}
|
|
@@ -7085,6 +7082,21 @@ function createScheduleInjectRoutes(deps) {
|
|
|
7085
7082
|
// server/index.ts
|
|
7086
7083
|
var import_dist9 = __toESM(require_dist(), 1);
|
|
7087
7084
|
|
|
7085
|
+
// app/lib/whatsapp/socket-resolution-error.ts
|
|
7086
|
+
function formatPresentKeys(presentKeys) {
|
|
7087
|
+
return presentKeys.join(",") || "none";
|
|
7088
|
+
}
|
|
7089
|
+
function formatSocketResolutionReason(res) {
|
|
7090
|
+
return res.reason === "key-miss" ? `key-miss presentKeys=${formatPresentKeys(res.presentKeys)}` : "disconnected";
|
|
7091
|
+
}
|
|
7092
|
+
function formatSocketResolutionMessage(res, accountId, opts = {}) {
|
|
7093
|
+
if (res.reason === "key-miss") {
|
|
7094
|
+
return `WhatsApp socket key miss: no socket is registered for accountId=${accountId} (present keys: ${formatPresentKeys(res.presentKeys)}). This is an account-keying fault, not a dropped link \u2014 do not advise re-pairing.`;
|
|
7095
|
+
}
|
|
7096
|
+
const clause = opts.disconnectedClause ? `; ${opts.disconnectedClause}` : "";
|
|
7097
|
+
return `WhatsApp account "${accountId}" is registered but its transport is down${clause}.`;
|
|
7098
|
+
}
|
|
7099
|
+
|
|
7088
7100
|
// app/lib/telegram/outbound/send-text.ts
|
|
7089
7101
|
async function sendTelegramText(botToken, chatId, text) {
|
|
7090
7102
|
try {
|
|
@@ -7907,16 +7919,9 @@ async function sendWhatsAppDocument(input) {
|
|
|
7907
7919
|
const jid = normalizeJid2(to);
|
|
7908
7920
|
const res = resolveSocket(accountId);
|
|
7909
7921
|
if (!res.ok) {
|
|
7910
|
-
const reason = res
|
|
7922
|
+
const reason = formatSocketResolutionReason(res);
|
|
7911
7923
|
console.error(`${TAG20} sent document to=${jid} file=${filename} bytes=${fileStat.size} ok=false reason=${reason}`);
|
|
7912
|
-
|
|
7913
|
-
return {
|
|
7914
|
-
ok: false,
|
|
7915
|
-
status: 503,
|
|
7916
|
-
error: `WhatsApp socket key miss: no socket is registered for accountId=${accountId} (present keys: ${res.presentKeys.join(",") || "none"}). This is an account-keying fault, not a dropped link \u2014 do not advise re-pairing.`
|
|
7917
|
-
};
|
|
7918
|
-
}
|
|
7919
|
-
return { ok: false, status: 503, error: `WhatsApp account "${accountId}" is registered but its transport is down.` };
|
|
7924
|
+
return { ok: false, status: 503, error: formatSocketResolutionMessage(res, accountId) };
|
|
7920
7925
|
}
|
|
7921
7926
|
const sock = res.sock;
|
|
7922
7927
|
const buffer = Buffer.from(await readFile(resolvedPath));
|
|
@@ -8448,11 +8453,12 @@ app2.post("/config", async (c) => {
|
|
|
8448
8453
|
}
|
|
8449
8454
|
case "list-groups": {
|
|
8450
8455
|
const groupAccountId = accountId ?? "default";
|
|
8451
|
-
const
|
|
8452
|
-
if (!
|
|
8453
|
-
console.error(`${TAG22} config action=list-groups error="
|
|
8454
|
-
return c.json({ ok: false, error:
|
|
8456
|
+
const groupRes = resolveSocket(groupAccountId);
|
|
8457
|
+
if (!groupRes.ok) {
|
|
8458
|
+
console.error(`${TAG22} config action=list-groups error="${formatSocketResolutionReason(groupRes)}" accountId=${groupAccountId}`);
|
|
8459
|
+
return c.json({ ok: false, error: formatSocketResolutionMessage(groupRes, groupAccountId) });
|
|
8455
8460
|
}
|
|
8461
|
+
const sock = groupRes.sock;
|
|
8456
8462
|
try {
|
|
8457
8463
|
const participating = await sock.groupFetchAllParticipating();
|
|
8458
8464
|
const groups = Object.values(participating).map((g) => ({
|
|
@@ -8761,11 +8767,12 @@ app2.get("/group-info", async (c) => {
|
|
|
8761
8767
|
console.error(`${TAG22} group-info error="not a group JID" jid=${jid} account=${accountId}`);
|
|
8762
8768
|
return c.json({ error: `"${jid}" is not a group JID. Group JIDs end with @g.us.` }, 400);
|
|
8763
8769
|
}
|
|
8764
|
-
const
|
|
8765
|
-
if (!
|
|
8766
|
-
console.error(`${TAG22} group-info error="
|
|
8767
|
-
return c.json({ error:
|
|
8770
|
+
const res = resolveSocket(accountId);
|
|
8771
|
+
if (!res.ok) {
|
|
8772
|
+
console.error(`${TAG22} group-info error="${formatSocketResolutionReason(res)}" account=${accountId}`);
|
|
8773
|
+
return c.json({ error: formatSocketResolutionMessage(res, accountId) }, 400);
|
|
8768
8774
|
}
|
|
8775
|
+
const sock = res.sock;
|
|
8769
8776
|
const meta = await sock.groupMetadata(jid);
|
|
8770
8777
|
const result = {
|
|
8771
8778
|
jid: meta.id,
|
|
@@ -9301,7 +9308,7 @@ app3.post("/r2/object/delete", envelopeBodyLimit("write"), async (c) => {
|
|
|
9301
9308
|
});
|
|
9302
9309
|
var storage_broker_default = app3;
|
|
9303
9310
|
async function runStorageAudit(root) {
|
|
9304
|
-
const { reconcileStorage } = await import("./src-
|
|
9311
|
+
const { reconcileStorage } = await import("./src-JYPKMWJR.js");
|
|
9305
9312
|
const session = getSession();
|
|
9306
9313
|
try {
|
|
9307
9314
|
const cf = await makeHouseCfExec(root);
|
|
@@ -9334,7 +9341,7 @@ async function runStorageAudit(root) {
|
|
|
9334
9341
|
}
|
|
9335
9342
|
}
|
|
9336
9343
|
async function runPagesAudit(root) {
|
|
9337
|
-
const { reconcilePages } = await import("./src-
|
|
9344
|
+
const { reconcilePages } = await import("./src-JYPKMWJR.js");
|
|
9338
9345
|
const session = getSession();
|
|
9339
9346
|
try {
|
|
9340
9347
|
const cf = await makeHousePagesExec(root);
|
|
@@ -12781,9 +12788,249 @@ app9.get("/callback", async (c) => {
|
|
|
12781
12788
|
});
|
|
12782
12789
|
var quickbooks_default = app9;
|
|
12783
12790
|
|
|
12791
|
+
// server/routes/google-oauth.ts
|
|
12792
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
12793
|
+
import { chmodSync, existsSync as existsSync17, mkdirSync as mkdirSync5, readdirSync as readdirSync16, readFileSync as readFileSync25, renameSync as renameSync6, rmSync as rmSync2, writeFileSync as writeFileSync9 } from "fs";
|
|
12794
|
+
import { join as join24 } from "path";
|
|
12795
|
+
var TAG26 = "[google-oauth]";
|
|
12796
|
+
var TOKEN_URL = "https://oauth2.googleapis.com/token";
|
|
12797
|
+
var PRIMARY_CALENDAR_URL = "https://www.googleapis.com/calendar/v3/calendars/primary";
|
|
12798
|
+
var PENDING_LIFETIME_MS = 6e5;
|
|
12799
|
+
function sanitizeAccountKey(key) {
|
|
12800
|
+
const safe = key.replace(/[^A-Za-z0-9._-]/g, "_");
|
|
12801
|
+
return safe === "." || safe === ".." ? `_${safe}` : safe;
|
|
12802
|
+
}
|
|
12803
|
+
function secretsDir(accountsDir, accountId) {
|
|
12804
|
+
return join24(accountsDir, sanitizeAccountKey(accountId), "secrets", "google");
|
|
12805
|
+
}
|
|
12806
|
+
function esc(s) {
|
|
12807
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
12808
|
+
}
|
|
12809
|
+
function refreshTokenBelongsToAccount(accountsDir, accountId, refreshToken) {
|
|
12810
|
+
const dir = join24(secretsDir(accountsDir, accountId), "accounts");
|
|
12811
|
+
if (!existsSync17(dir)) return false;
|
|
12812
|
+
let key;
|
|
12813
|
+
try {
|
|
12814
|
+
key = loadKey(accountsDir, accountId);
|
|
12815
|
+
} catch {
|
|
12816
|
+
return false;
|
|
12817
|
+
}
|
|
12818
|
+
for (const entry of readdirSync16(dir)) {
|
|
12819
|
+
const path3 = join24(dir, entry, "tokens.enc");
|
|
12820
|
+
if (!existsSync17(path3)) continue;
|
|
12821
|
+
try {
|
|
12822
|
+
const blob = JSON.parse(decrypt(key, readFileSync25(path3, "utf-8").trim()));
|
|
12823
|
+
if (blob.refreshToken && blob.refreshToken === refreshToken) return true;
|
|
12824
|
+
} catch {
|
|
12825
|
+
}
|
|
12826
|
+
}
|
|
12827
|
+
return false;
|
|
12828
|
+
}
|
|
12829
|
+
function loadKey(accountsDir, accountId) {
|
|
12830
|
+
const dir = secretsDir(accountsDir, accountId);
|
|
12831
|
+
const keyPath = join24(dir, ".key");
|
|
12832
|
+
mkdirSync5(dir, { recursive: true, mode: 448 });
|
|
12833
|
+
if (existsSync17(keyPath)) return Buffer.from(readFileSync25(keyPath, "utf-8").trim(), "base64");
|
|
12834
|
+
const k = randomBytes(32);
|
|
12835
|
+
writeFileSync9(keyPath, k.toString("base64"), { mode: 384 });
|
|
12836
|
+
chmodSync(keyPath, 384);
|
|
12837
|
+
return k;
|
|
12838
|
+
}
|
|
12839
|
+
function decrypt(key, raw) {
|
|
12840
|
+
const [ivHex, payload] = raw.split(":");
|
|
12841
|
+
const d = createDecipheriv("aes-256-cbc", key, Buffer.from(ivHex, "hex"));
|
|
12842
|
+
return d.update(payload, "hex", "utf8") + d.final("utf8");
|
|
12843
|
+
}
|
|
12844
|
+
function encrypt(key, plain) {
|
|
12845
|
+
const iv = randomBytes(16);
|
|
12846
|
+
const c = createCipheriv("aes-256-cbc", key, iv);
|
|
12847
|
+
return `${iv.toString("hex")}:${c.update(plain, "utf8", "hex") + c.final("hex")}`;
|
|
12848
|
+
}
|
|
12849
|
+
function atomicWrite(path3, contents) {
|
|
12850
|
+
const temp = `${path3}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
12851
|
+
try {
|
|
12852
|
+
writeFileSync9(temp, contents, { mode: 384 });
|
|
12853
|
+
chmodSync(temp, 384);
|
|
12854
|
+
renameSync6(temp, path3);
|
|
12855
|
+
} catch (err) {
|
|
12856
|
+
try {
|
|
12857
|
+
rmSync2(temp, { force: true });
|
|
12858
|
+
} catch {
|
|
12859
|
+
}
|
|
12860
|
+
throw err;
|
|
12861
|
+
}
|
|
12862
|
+
}
|
|
12863
|
+
function readPending(accountsDir, accountId) {
|
|
12864
|
+
const path3 = join24(secretsDir(accountsDir, accountId), "pending-oauth.enc");
|
|
12865
|
+
if (!existsSync17(path3)) return null;
|
|
12866
|
+
const raw = readFileSync25(path3, "utf-8").trim();
|
|
12867
|
+
if (!raw) return null;
|
|
12868
|
+
try {
|
|
12869
|
+
return JSON.parse(decrypt(loadKey(accountsDir, accountId), raw));
|
|
12870
|
+
} catch {
|
|
12871
|
+
return null;
|
|
12872
|
+
}
|
|
12873
|
+
}
|
|
12874
|
+
function clearPending(accountsDir, accountId) {
|
|
12875
|
+
const path3 = join24(secretsDir(accountsDir, accountId), "pending-oauth.enc");
|
|
12876
|
+
if (existsSync17(path3)) rmSync2(path3, { force: true });
|
|
12877
|
+
}
|
|
12878
|
+
function writeTokens(accountsDir, accountId, email, tok) {
|
|
12879
|
+
const key = loadKey(accountsDir, accountId);
|
|
12880
|
+
const dir = join24(secretsDir(accountsDir, accountId), "accounts", sanitizeAccountKey(email));
|
|
12881
|
+
mkdirSync5(dir, { recursive: true, mode: 448 });
|
|
12882
|
+
const now = Date.now();
|
|
12883
|
+
const blob = {
|
|
12884
|
+
accessToken: tok.accessToken,
|
|
12885
|
+
refreshToken: tok.refreshToken,
|
|
12886
|
+
accessTokenExpiry: now + tok.expiresInSeconds * 1e3,
|
|
12887
|
+
lastRefresh: now,
|
|
12888
|
+
email,
|
|
12889
|
+
scopes: tok.scopes
|
|
12890
|
+
};
|
|
12891
|
+
atomicWrite(join24(dir, "tokens.enc"), encrypt(key, JSON.stringify(blob)));
|
|
12892
|
+
}
|
|
12893
|
+
function readHouseGoogleCreds(platformRoot5) {
|
|
12894
|
+
const path3 = join24(platformRoot5, "config", "google-house.env");
|
|
12895
|
+
if (!existsSync17(path3)) return null;
|
|
12896
|
+
const env = {};
|
|
12897
|
+
for (const line of readFileSync25(path3, "utf-8").split(/\r?\n/)) {
|
|
12898
|
+
const m = line.match(/^([A-Z0-9_]+)=(.*)$/);
|
|
12899
|
+
if (m) env[m[1]] = m[2].trim();
|
|
12900
|
+
}
|
|
12901
|
+
if (!env.GOOGLE_CLIENT_ID || !env.GOOGLE_CLIENT_SECRET) return null;
|
|
12902
|
+
return { clientId: env.GOOGLE_CLIENT_ID, clientSecret: env.GOOGLE_CLIENT_SECRET };
|
|
12903
|
+
}
|
|
12904
|
+
function page2(title, body) {
|
|
12905
|
+
return `<!doctype html><meta name="viewport" content="width=device-width,initial-scale=1"><title>${title}</title><div style="font:16px/1.5 system-ui;margin:3rem auto;max-width:30rem;padding:0 1rem"><h1 style="font-size:1.3rem">${title}</h1><p>${body}</p></div>`;
|
|
12906
|
+
}
|
|
12907
|
+
function createGoogleOAuthRoutes(platformRoot5, accountsDir) {
|
|
12908
|
+
const routes = new Hono();
|
|
12909
|
+
routes.get("/oauth/callback", async (c) => {
|
|
12910
|
+
const code = c.req.query("code");
|
|
12911
|
+
const state = c.req.query("state");
|
|
12912
|
+
const accountId = c.req.query("account");
|
|
12913
|
+
if (!code || !state || !accountId) {
|
|
12914
|
+
console.error(`${TAG26} op=callback outcome=error error=missing-params`);
|
|
12915
|
+
return c.html(page2("Missing parameters", "Return to your chat and start again."), 400);
|
|
12916
|
+
}
|
|
12917
|
+
const held = readPending(accountsDir, accountId);
|
|
12918
|
+
const stateMatch = held !== null && held.state === state;
|
|
12919
|
+
console.error(`${TAG26} op=callback reg=${state} account=${accountId} state-match=${stateMatch}`);
|
|
12920
|
+
if (!held || !stateMatch) {
|
|
12921
|
+
return c.html(page2("This link has expired", "Return to your chat and start again."), 400);
|
|
12922
|
+
}
|
|
12923
|
+
const ageMs = Date.now() - held.createdAt;
|
|
12924
|
+
if (ageMs > PENDING_LIFETIME_MS) {
|
|
12925
|
+
console.error(`${TAG26} op=callback reg=${state} outcome=error error=pending-expired ageMs=${ageMs}`);
|
|
12926
|
+
clearPending(accountsDir, accountId);
|
|
12927
|
+
return c.html(page2("This link has expired", "Return to your chat and start again."), 400);
|
|
12928
|
+
}
|
|
12929
|
+
const failed = (title, body, status) => {
|
|
12930
|
+
clearPending(accountsDir, accountId);
|
|
12931
|
+
return c.html(page2(title, body), status);
|
|
12932
|
+
};
|
|
12933
|
+
const creds = readHouseGoogleCreds(platformRoot5);
|
|
12934
|
+
if (!creds) {
|
|
12935
|
+
console.error(`${TAG26} op=token-exchange reg=${state} outcome=error error=house-env-missing`);
|
|
12936
|
+
return failed("Not configured", "This install has no Google credentials yet.", 500);
|
|
12937
|
+
}
|
|
12938
|
+
const publicBase = (process.env.GOOGLE_PUBLIC_BASE ?? "").replace(/\/+$/, "");
|
|
12939
|
+
if (!publicBase) {
|
|
12940
|
+
console.error(`${TAG26} op=callback reg=${state} outcome=error error=public-base-unset`);
|
|
12941
|
+
return failed("Not configured", "This install has no public base configured.", 500);
|
|
12942
|
+
}
|
|
12943
|
+
const redirectUri = `${publicBase}/api/google/oauth/callback?account=${encodeURIComponent(accountId)}`;
|
|
12944
|
+
try {
|
|
12945
|
+
const res = await fetch(TOKEN_URL, {
|
|
12946
|
+
method: "POST",
|
|
12947
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
12948
|
+
body: new URLSearchParams({
|
|
12949
|
+
code,
|
|
12950
|
+
client_id: creds.clientId,
|
|
12951
|
+
client_secret: creds.clientSecret,
|
|
12952
|
+
redirect_uri: redirectUri,
|
|
12953
|
+
grant_type: "authorization_code",
|
|
12954
|
+
code_verifier: held.verifier
|
|
12955
|
+
})
|
|
12956
|
+
});
|
|
12957
|
+
const text = await res.text();
|
|
12958
|
+
if (!res.ok) {
|
|
12959
|
+
console.error(`${TAG26} op=token-exchange reg=${state} outcome=error status=${res.status} body=${text.slice(0, 300)}`);
|
|
12960
|
+
return failed("Could not connect", `Google refused the exchange (${res.status}).`, 502);
|
|
12961
|
+
}
|
|
12962
|
+
console.error(`${TAG26} op=token-exchange reg=${state} outcome=ok`);
|
|
12963
|
+
const tok = JSON.parse(text);
|
|
12964
|
+
const calRes = await fetch(PRIMARY_CALENDAR_URL, {
|
|
12965
|
+
headers: { authorization: `Bearer ${tok.access_token}` }
|
|
12966
|
+
});
|
|
12967
|
+
const calText = await calRes.text();
|
|
12968
|
+
if (!calRes.ok) {
|
|
12969
|
+
console.error(`${TAG26} op=identity reg=${state} outcome=error status=${calRes.status} body=${calText.slice(0, 300)}`);
|
|
12970
|
+
return failed("Could not connect", "Connected, but the calendar identity could not be read.", 502);
|
|
12971
|
+
}
|
|
12972
|
+
const email = JSON.parse(calText).id;
|
|
12973
|
+
console.error(`${TAG26} op=identity reg=${state} email=${email}`);
|
|
12974
|
+
writeTokens(accountsDir, accountId, email, {
|
|
12975
|
+
accessToken: tok.access_token,
|
|
12976
|
+
refreshToken: tok.refresh_token ?? null,
|
|
12977
|
+
expiresInSeconds: tok.expires_in,
|
|
12978
|
+
scopes: tok.scope ? tok.scope.split(" ") : []
|
|
12979
|
+
});
|
|
12980
|
+
console.error(
|
|
12981
|
+
`${TAG26} op=tokens-write reg=${state} account=${accountId} refreshIssued=${tok.refresh_token ? "true" : "false"}`
|
|
12982
|
+
);
|
|
12983
|
+
clearPending(accountsDir, accountId);
|
|
12984
|
+
console.error(`${TAG26} op=pending-clear reg=${state} verified=${readPending(accountsDir, accountId) === null}`);
|
|
12985
|
+
console.error(`${TAG26} op=registered reg=${state} account=${accountId} email=${email}`);
|
|
12986
|
+
return c.html(
|
|
12987
|
+
page2(
|
|
12988
|
+
"Calendar connected",
|
|
12989
|
+
`${esc(email)} is connected to this account. You can close this page and return to your chat.`
|
|
12990
|
+
)
|
|
12991
|
+
);
|
|
12992
|
+
} catch (err) {
|
|
12993
|
+
const msg = err.message;
|
|
12994
|
+
console.error(`${TAG26} op=token-exchange reg=${state} outcome=error error=${msg}`);
|
|
12995
|
+
return failed("Could not connect", "Something went wrong. Return to your chat and try again.", 502);
|
|
12996
|
+
}
|
|
12997
|
+
});
|
|
12998
|
+
routes.post("/oauth/refresh", async (c) => {
|
|
12999
|
+
const body = await c.req.json().catch(() => ({}));
|
|
13000
|
+
const { accountId, refreshToken } = body;
|
|
13001
|
+
if (!accountId || !refreshToken) {
|
|
13002
|
+
return c.json({ error: "accountId and refreshToken are required" }, 400);
|
|
13003
|
+
}
|
|
13004
|
+
if (!refreshTokenBelongsToAccount(accountsDir, accountId, refreshToken)) {
|
|
13005
|
+
console.error(`${TAG26} op=refresh account=${accountId} outcome=denied reason=token-not-held`);
|
|
13006
|
+
return c.json({ error: "refresh token is not held by this account" }, 403);
|
|
13007
|
+
}
|
|
13008
|
+
const creds = readHouseGoogleCreds(platformRoot5);
|
|
13009
|
+
if (!creds) return c.json({ error: "google-house.env is absent or incomplete" }, 500);
|
|
13010
|
+
const res = await fetch(TOKEN_URL, {
|
|
13011
|
+
method: "POST",
|
|
13012
|
+
headers: { "content-type": "application/x-www-form-urlencoded" },
|
|
13013
|
+
body: new URLSearchParams({
|
|
13014
|
+
client_id: creds.clientId,
|
|
13015
|
+
client_secret: creds.clientSecret,
|
|
13016
|
+
refresh_token: refreshToken,
|
|
13017
|
+
grant_type: "refresh_token"
|
|
13018
|
+
})
|
|
13019
|
+
});
|
|
13020
|
+
const text = await res.text();
|
|
13021
|
+
if (!res.ok) {
|
|
13022
|
+
console.error(`${TAG26} op=refresh account=${accountId} outcome=error status=${res.status} body=${text.slice(0, 300)}`);
|
|
13023
|
+
return c.json({ error: text.slice(0, 300) }, 502);
|
|
13024
|
+
}
|
|
13025
|
+
console.error(`${TAG26} op=refresh account=${accountId} outcome=ok`);
|
|
13026
|
+
return c.json(JSON.parse(text));
|
|
13027
|
+
});
|
|
13028
|
+
return routes;
|
|
13029
|
+
}
|
|
13030
|
+
|
|
12784
13031
|
// server/routes/onboarding.ts
|
|
12785
13032
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync3 } from "child_process";
|
|
12786
|
-
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as
|
|
13033
|
+
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeFileSync11, writeSync, existsSync as existsSync19, readFileSync as readFileSync27, unlinkSync as unlinkSync3, renameSync as renameSync8 } from "fs";
|
|
12787
13034
|
import { createHash as createHash4, randomUUID as randomUUID8 } from "crypto";
|
|
12788
13035
|
|
|
12789
13036
|
// app/lib/claude-spawn-env.ts
|
|
@@ -12792,7 +13039,7 @@ function claudeBin() {
|
|
|
12792
13039
|
}
|
|
12793
13040
|
|
|
12794
13041
|
// server/routes/onboarding.ts
|
|
12795
|
-
import { dirname as dirname9, join as
|
|
13042
|
+
import { dirname as dirname9, join as join26 } from "path";
|
|
12796
13043
|
|
|
12797
13044
|
// app/lib/claude-keychain.ts
|
|
12798
13045
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
@@ -12921,8 +13168,8 @@ function readHostCredsBlob(service) {
|
|
|
12921
13168
|
}
|
|
12922
13169
|
|
|
12923
13170
|
// ../lib/admins-write/src/index.ts
|
|
12924
|
-
import { existsSync as
|
|
12925
|
-
import { dirname as dirname8, join as
|
|
13171
|
+
import { existsSync as existsSync18, readFileSync as readFileSync26, writeFileSync as writeFileSync10, renameSync as renameSync7, mkdirSync as mkdirSync6, readdirSync as readdirSync17, statSync as statSync8, appendFileSync as appendFileSync2 } from "fs";
|
|
13172
|
+
import { dirname as dirname8, join as join25 } from "path";
|
|
12926
13173
|
function id8(value) {
|
|
12927
13174
|
return value.slice(0, 8);
|
|
12928
13175
|
}
|
|
@@ -12936,7 +13183,7 @@ function appendUsersAuditLine(audit, fields) {
|
|
|
12936
13183
|
const line = `[users-audit] action=${fields.action} actor=${actor}${targetFields}${sess} field=${fields.field} rowsBefore=${fields.rowsBefore} rowsAfter=${fields.rowsAfter} ts=${(/* @__PURE__ */ new Date()).toISOString()}
|
|
12937
13184
|
`;
|
|
12938
13185
|
try {
|
|
12939
|
-
|
|
13186
|
+
mkdirSync6(dirname8(audit.logFile), { recursive: true, mode: 448 });
|
|
12940
13187
|
appendFileSync2(audit.logFile, line, { mode: 384 });
|
|
12941
13188
|
} catch (err) {
|
|
12942
13189
|
console.error(
|
|
@@ -12954,17 +13201,17 @@ function logLine(input, result) {
|
|
|
12954
13201
|
);
|
|
12955
13202
|
}
|
|
12956
13203
|
function writeFileAtomic(filePath, contents, mode) {
|
|
12957
|
-
|
|
13204
|
+
mkdirSync6(dirname8(filePath), { recursive: true });
|
|
12958
13205
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
12959
|
-
|
|
12960
|
-
|
|
13206
|
+
writeFileSync10(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
13207
|
+
renameSync7(tempPath, filePath);
|
|
12961
13208
|
}
|
|
12962
13209
|
function writeAdminEntry(input) {
|
|
12963
13210
|
const result = { usersJsonResult: "noop", accountJsonResult: "noop" };
|
|
12964
13211
|
try {
|
|
12965
13212
|
let users = [];
|
|
12966
|
-
if (
|
|
12967
|
-
const raw =
|
|
13213
|
+
if (existsSync18(input.usersFile)) {
|
|
13214
|
+
const raw = readFileSync26(input.usersFile, "utf-8").trim();
|
|
12968
13215
|
if (raw) {
|
|
12969
13216
|
const parsed = JSON.parse(raw);
|
|
12970
13217
|
if (!Array.isArray(parsed)) {
|
|
@@ -12995,11 +13242,11 @@ function writeAdminEntry(input) {
|
|
|
12995
13242
|
return result;
|
|
12996
13243
|
}
|
|
12997
13244
|
try {
|
|
12998
|
-
const accountJsonPath =
|
|
12999
|
-
if (!
|
|
13245
|
+
const accountJsonPath = join25(input.accountDir, "account.json");
|
|
13246
|
+
if (!existsSync18(accountJsonPath)) {
|
|
13000
13247
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
13001
13248
|
}
|
|
13002
|
-
const config = JSON.parse(
|
|
13249
|
+
const config = JSON.parse(readFileSync26(accountJsonPath, "utf-8"));
|
|
13003
13250
|
const admins = config.admins ?? [];
|
|
13004
13251
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
13005
13252
|
result.accountJsonResult = "noop";
|
|
@@ -13019,9 +13266,9 @@ function writeAdminEntry(input) {
|
|
|
13019
13266
|
function computeAdminStoreDivergence(input) {
|
|
13020
13267
|
const result = { divergences: 0, accountWithoutUsers: [], usersWithoutAccount: [], errors: [] };
|
|
13021
13268
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
13022
|
-
if (
|
|
13269
|
+
if (existsSync18(input.usersFile)) {
|
|
13023
13270
|
try {
|
|
13024
|
-
const raw =
|
|
13271
|
+
const raw = readFileSync26(input.usersFile, "utf-8").trim();
|
|
13025
13272
|
if (raw) {
|
|
13026
13273
|
const users = JSON.parse(raw);
|
|
13027
13274
|
for (const u of users) {
|
|
@@ -13033,27 +13280,27 @@ function computeAdminStoreDivergence(input) {
|
|
|
13033
13280
|
}
|
|
13034
13281
|
}
|
|
13035
13282
|
const accountUserIds = /* @__PURE__ */ new Set();
|
|
13036
|
-
if (
|
|
13283
|
+
if (existsSync18(input.accountsDir)) {
|
|
13037
13284
|
let entries;
|
|
13038
13285
|
try {
|
|
13039
|
-
entries =
|
|
13286
|
+
entries = readdirSync17(input.accountsDir);
|
|
13040
13287
|
} catch (err) {
|
|
13041
13288
|
result.errors.push({ source: input.accountsDir, detail: err instanceof Error ? err.message : String(err) });
|
|
13042
13289
|
return result;
|
|
13043
13290
|
}
|
|
13044
13291
|
for (const entry of entries) {
|
|
13045
13292
|
if (entry.startsWith(".")) continue;
|
|
13046
|
-
const accountDir =
|
|
13293
|
+
const accountDir = join25(input.accountsDir, entry);
|
|
13047
13294
|
try {
|
|
13048
13295
|
if (!statSync8(accountDir).isDirectory()) continue;
|
|
13049
13296
|
} catch {
|
|
13050
13297
|
continue;
|
|
13051
13298
|
}
|
|
13052
|
-
const accountJsonPath =
|
|
13053
|
-
if (!
|
|
13299
|
+
const accountJsonPath = join25(accountDir, "account.json");
|
|
13300
|
+
if (!existsSync18(accountJsonPath)) continue;
|
|
13054
13301
|
let admins = [];
|
|
13055
13302
|
try {
|
|
13056
|
-
const config = JSON.parse(
|
|
13303
|
+
const config = JSON.parse(readFileSync26(accountJsonPath, "utf-8"));
|
|
13057
13304
|
admins = config.admins ?? [];
|
|
13058
13305
|
} catch (err) {
|
|
13059
13306
|
result.errors.push({ source: accountJsonPath, detail: err instanceof Error ? err.message : String(err) });
|
|
@@ -13101,8 +13348,8 @@ function hashPin2(pin) {
|
|
|
13101
13348
|
return createHash4("sha256").update(pin).digest("hex");
|
|
13102
13349
|
}
|
|
13103
13350
|
function readUsersFile2() {
|
|
13104
|
-
if (!
|
|
13105
|
-
const raw =
|
|
13351
|
+
if (!existsSync19(USERS_FILE)) return null;
|
|
13352
|
+
const raw = readFileSync27(USERS_FILE, "utf-8").trim();
|
|
13106
13353
|
if (!raw) return [];
|
|
13107
13354
|
return JSON.parse(raw);
|
|
13108
13355
|
}
|
|
@@ -13161,7 +13408,7 @@ app10.post("/claude-auth", async (c) => {
|
|
|
13161
13408
|
} catch (err) {
|
|
13162
13409
|
logoutError = err instanceof Error ? err.message : String(err);
|
|
13163
13410
|
}
|
|
13164
|
-
const credentialsPresent =
|
|
13411
|
+
const credentialsPresent = existsSync19(CLAUDE_CREDENTIALS_FILE);
|
|
13165
13412
|
const ranMs = Date.now() - start;
|
|
13166
13413
|
console.log(`[onboarding] op=claude-logout credentialsPresent=${credentialsPresent} ranMs=${ranMs} logoutError=${logoutError ? JSON.stringify(logoutError.slice(0, 120)) : "none"}`);
|
|
13167
13414
|
return c.json({ logged_out: !credentialsPresent });
|
|
@@ -13195,7 +13442,7 @@ app10.post("/claude-auth", async (c) => {
|
|
|
13195
13442
|
return c.json({ launched: cdpReady });
|
|
13196
13443
|
}
|
|
13197
13444
|
ensureLogDir();
|
|
13198
|
-
|
|
13445
|
+
writeFileSync11(logPath("claude-auth"), "");
|
|
13199
13446
|
const claudeAuthLogFd = openSync3(logPath("claude-auth"), "a");
|
|
13200
13447
|
const onClaudeOutput = (chunk) => writeSync(claudeAuthLogFd, chunk);
|
|
13201
13448
|
if (process.platform === "darwin") {
|
|
@@ -13220,14 +13467,14 @@ app10.post("/claude-auth", async (c) => {
|
|
|
13220
13467
|
readBlob: readHostCredsBlob,
|
|
13221
13468
|
writeFile: (blob) => {
|
|
13222
13469
|
const tmp = `${CLAUDE_CREDENTIALS_FILE}.${process.pid}.tmp`;
|
|
13223
|
-
|
|
13224
|
-
|
|
13470
|
+
writeFileSync11(tmp, blob, { mode: 384 });
|
|
13471
|
+
renameSync8(tmp, CLAUDE_CREDENTIALS_FILE);
|
|
13225
13472
|
},
|
|
13226
13473
|
log: (line) => console.log(line)
|
|
13227
13474
|
});
|
|
13228
13475
|
persistKeychainService(
|
|
13229
13476
|
writebackResult,
|
|
13230
|
-
(service) =>
|
|
13477
|
+
(service) => writeFileSync11(join26(dirname9(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
|
|
13231
13478
|
(line) => console.log(line)
|
|
13232
13479
|
);
|
|
13233
13480
|
if (darwinAuthChild === claudeProc2) darwinAuthChild = null;
|
|
@@ -13310,9 +13557,9 @@ app10.post("/set-pin", async (c) => {
|
|
|
13310
13557
|
console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
|
|
13311
13558
|
if (process.platform === "linux") {
|
|
13312
13559
|
let installOwner = null;
|
|
13313
|
-
if (
|
|
13560
|
+
if (existsSync19(INSTALL_OWNER_FILE)) {
|
|
13314
13561
|
try {
|
|
13315
|
-
const raw =
|
|
13562
|
+
const raw = readFileSync27(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
13316
13563
|
if (raw.length > 0) installOwner = raw;
|
|
13317
13564
|
} catch (err) {
|
|
13318
13565
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -13393,7 +13640,7 @@ app10.delete("/set-pin", requireAdminSession, async (c) => {
|
|
|
13393
13640
|
unlinkSync3(USERS_FILE);
|
|
13394
13641
|
console.log(`[set-pin] cleared users.json (last entry removed): userId=${sessionUserId.slice(0, 8)}\u2026`);
|
|
13395
13642
|
} else {
|
|
13396
|
-
|
|
13643
|
+
writeFileSync11(USERS_FILE, JSON.stringify(remaining), { mode: 384 });
|
|
13397
13644
|
console.log(`[set-pin] removed entry from users.json: userId=${sessionUserId.slice(0, 8)}\u2026 remaining=${remaining.length}`);
|
|
13398
13645
|
}
|
|
13399
13646
|
logUsersAudit(
|
|
@@ -13458,9 +13705,9 @@ app10.put("/set-pin", requireAdminSession, async (c) => {
|
|
|
13458
13705
|
console.log(`[set-pin] changed PIN in place: userId=${sessionUserId.slice(0, 8)}\u2026`);
|
|
13459
13706
|
if (process.platform === "linux") {
|
|
13460
13707
|
let installOwner = null;
|
|
13461
|
-
if (
|
|
13708
|
+
if (existsSync19(INSTALL_OWNER_FILE)) {
|
|
13462
13709
|
try {
|
|
13463
|
-
const raw =
|
|
13710
|
+
const raw = readFileSync27(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
13464
13711
|
if (raw.length > 0) installOwner = raw;
|
|
13465
13712
|
} catch (err) {
|
|
13466
13713
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -13492,9 +13739,9 @@ ${body.newPin}
|
|
|
13492
13739
|
var onboarding_default = app10;
|
|
13493
13740
|
|
|
13494
13741
|
// server/routes/client-error.ts
|
|
13495
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
13496
|
-
import { join as
|
|
13497
|
-
var CLIENT_ERRORS_LOG =
|
|
13742
|
+
import { appendFileSync as appendFileSync3, existsSync as existsSync20, renameSync as renameSync9, statSync as statSync9 } from "fs";
|
|
13743
|
+
import { join as join27 } from "path";
|
|
13744
|
+
var CLIENT_ERRORS_LOG = join27(LOG_DIR, "client-errors.log");
|
|
13498
13745
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
13499
13746
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
13500
13747
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -13542,10 +13789,10 @@ function stackHead(stack) {
|
|
|
13542
13789
|
}
|
|
13543
13790
|
function rotateIfNeeded() {
|
|
13544
13791
|
try {
|
|
13545
|
-
if (!
|
|
13792
|
+
if (!existsSync20(CLIENT_ERRORS_LOG)) return;
|
|
13546
13793
|
const stats = statSync9(CLIENT_ERRORS_LOG);
|
|
13547
13794
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
13548
|
-
|
|
13795
|
+
renameSync9(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
13549
13796
|
} catch (err) {
|
|
13550
13797
|
console.error(`[client-error] log rotation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
13551
13798
|
}
|
|
@@ -13869,18 +14116,18 @@ app13.get("/", requireAdminSession, async (c) => {
|
|
|
13869
14116
|
var accounts_default = app13;
|
|
13870
14117
|
|
|
13871
14118
|
// server/routes/admin/logs.ts
|
|
13872
|
-
import { existsSync as
|
|
14119
|
+
import { existsSync as existsSync22, readdirSync as readdirSync18, readFileSync as readFileSync28, statSync as statSync10 } from "fs";
|
|
13873
14120
|
import { resolve as resolve17, basename as basename7 } from "path";
|
|
13874
14121
|
|
|
13875
14122
|
// app/lib/logs-read-resolve.ts
|
|
13876
|
-
import { existsSync as
|
|
13877
|
-
import { join as
|
|
14123
|
+
import { existsSync as existsSync21 } from "fs";
|
|
14124
|
+
import { join as join28 } from "path";
|
|
13878
14125
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
13879
14126
|
const tried = [filename];
|
|
13880
14127
|
const hits = [];
|
|
13881
14128
|
for (const dir of logDirs) {
|
|
13882
|
-
const fullPath =
|
|
13883
|
-
if (
|
|
14129
|
+
const fullPath = join28(dir, filename);
|
|
14130
|
+
if (existsSync21(fullPath)) {
|
|
13884
14131
|
hits.push({ path: fullPath, dir });
|
|
13885
14132
|
}
|
|
13886
14133
|
}
|
|
@@ -13908,7 +14155,7 @@ app14.get("/", async (c) => {
|
|
|
13908
14155
|
const filePath = resolve17(dir, safe);
|
|
13909
14156
|
searched.push(filePath);
|
|
13910
14157
|
try {
|
|
13911
|
-
const buffer =
|
|
14158
|
+
const buffer = readFileSync28(filePath);
|
|
13912
14159
|
const onDiskBytes = statSync10(filePath).size;
|
|
13913
14160
|
const headers = {
|
|
13914
14161
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -13973,7 +14220,7 @@ app14.get("/", async (c) => {
|
|
|
13973
14220
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
13974
14221
|
try {
|
|
13975
14222
|
const filename = basename7(hit.path);
|
|
13976
|
-
const buffer =
|
|
14223
|
+
const buffer = readFileSync28(hit.path);
|
|
13977
14224
|
const onDiskBytes = statSync10(hit.path).size;
|
|
13978
14225
|
const headers = {
|
|
13979
14226
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -14008,10 +14255,10 @@ app14.get("/", async (c) => {
|
|
|
14008
14255
|
const seen = /* @__PURE__ */ new Set();
|
|
14009
14256
|
const logs = {};
|
|
14010
14257
|
for (const dir of logDirs) {
|
|
14011
|
-
if (!
|
|
14258
|
+
if (!existsSync22(dir)) continue;
|
|
14012
14259
|
let files;
|
|
14013
14260
|
try {
|
|
14014
|
-
files =
|
|
14261
|
+
files = readdirSync18(dir).filter((f) => f.endsWith(".log"));
|
|
14015
14262
|
} catch (err) {
|
|
14016
14263
|
const reason = err instanceof Error ? err.message : String(err);
|
|
14017
14264
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
@@ -14020,7 +14267,7 @@ app14.get("/", async (c) => {
|
|
|
14020
14267
|
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync10(resolve17(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
14021
14268
|
seen.add(name);
|
|
14022
14269
|
try {
|
|
14023
|
-
const content =
|
|
14270
|
+
const content = readFileSync28(resolve17(dir, name));
|
|
14024
14271
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
14025
14272
|
logs[name] = tail.trim() || "(empty)";
|
|
14026
14273
|
} catch (err) {
|
|
@@ -14060,7 +14307,7 @@ var claude_info_default = app15;
|
|
|
14060
14307
|
|
|
14061
14308
|
// server/routes/admin/attachment.ts
|
|
14062
14309
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
14063
|
-
import { existsSync as
|
|
14310
|
+
import { existsSync as existsSync23 } from "fs";
|
|
14064
14311
|
import { resolve as resolve18 } from "path";
|
|
14065
14312
|
var app16 = new Hono();
|
|
14066
14313
|
var ATTACHMENT_ID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
|
@@ -14083,12 +14330,12 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
14083
14330
|
}
|
|
14084
14331
|
let accountId = pinnedAccountId;
|
|
14085
14332
|
let dir = uploadsDirFor2(accountId, attachmentId);
|
|
14086
|
-
let found =
|
|
14333
|
+
let found = existsSync23(dir);
|
|
14087
14334
|
if (!found) {
|
|
14088
14335
|
for (const candidate of listValidAccounts()) {
|
|
14089
14336
|
if (candidate.accountId === pinnedAccountId) continue;
|
|
14090
14337
|
const candidateDir = uploadsDirFor2(candidate.accountId, attachmentId);
|
|
14091
|
-
if (
|
|
14338
|
+
if (existsSync23(candidateDir)) {
|
|
14092
14339
|
accountId = candidate.accountId;
|
|
14093
14340
|
dir = candidateDir;
|
|
14094
14341
|
found = true;
|
|
@@ -14103,7 +14350,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
14103
14350
|
return new Response("Not found", { status: 404 });
|
|
14104
14351
|
}
|
|
14105
14352
|
const metaPath = resolve18(dir, `${attachmentId}.meta.json`);
|
|
14106
|
-
if (!
|
|
14353
|
+
if (!existsSync23(metaPath)) {
|
|
14107
14354
|
return new Response("Not found", { status: 404 });
|
|
14108
14355
|
}
|
|
14109
14356
|
let meta;
|
|
@@ -14137,23 +14384,23 @@ var attachment_default = app16;
|
|
|
14137
14384
|
|
|
14138
14385
|
// server/routes/admin/agents.ts
|
|
14139
14386
|
import { resolve as resolve19 } from "path";
|
|
14140
|
-
import { readdirSync as
|
|
14387
|
+
import { readdirSync as readdirSync19, readFileSync as readFileSync29, existsSync as existsSync24, rmSync as rmSync3 } from "fs";
|
|
14141
14388
|
var app17 = new Hono();
|
|
14142
14389
|
app17.get("/", (c) => {
|
|
14143
14390
|
const account = resolveAccount();
|
|
14144
14391
|
if (!account) return c.json({ agents: [] });
|
|
14145
14392
|
const agentsDir = resolve19(account.accountDir, "agents");
|
|
14146
|
-
if (!
|
|
14393
|
+
if (!existsSync24(agentsDir)) return c.json({ agents: [] });
|
|
14147
14394
|
const agents = [];
|
|
14148
14395
|
try {
|
|
14149
|
-
const entries =
|
|
14396
|
+
const entries = readdirSync19(agentsDir, { withFileTypes: true });
|
|
14150
14397
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
14151
14398
|
if (!entry.isDirectory()) continue;
|
|
14152
14399
|
if (entry.name === "admin") continue;
|
|
14153
14400
|
const configPath2 = resolve19(agentsDir, entry.name, "config.json");
|
|
14154
|
-
if (!
|
|
14401
|
+
if (!existsSync24(configPath2)) continue;
|
|
14155
14402
|
try {
|
|
14156
|
-
const config = JSON.parse(
|
|
14403
|
+
const config = JSON.parse(readFileSync29(configPath2, "utf-8"));
|
|
14157
14404
|
agents.push({
|
|
14158
14405
|
slug: entry.name,
|
|
14159
14406
|
displayName: config.displayName ?? entry.name,
|
|
@@ -14180,7 +14427,7 @@ app17.delete("/:slug", async (c) => {
|
|
|
14180
14427
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
14181
14428
|
}
|
|
14182
14429
|
const agentDir = resolve19(account.accountDir, "agents", slug);
|
|
14183
|
-
if (!
|
|
14430
|
+
if (!existsSync24(agentDir)) {
|
|
14184
14431
|
return c.json({ error: "Agent not found" }, 404);
|
|
14185
14432
|
}
|
|
14186
14433
|
try {
|
|
@@ -14191,7 +14438,7 @@ app17.delete("/:slug", async (c) => {
|
|
|
14191
14438
|
return c.json({ error: `Graph cleanup failed: ${msg}` }, 500);
|
|
14192
14439
|
}
|
|
14193
14440
|
try {
|
|
14194
|
-
|
|
14441
|
+
rmSync3(agentDir, { recursive: true, force: true });
|
|
14195
14442
|
console.log(`[admin/agents] deleted agent "${slug}"`);
|
|
14196
14443
|
return c.json({ ok: true });
|
|
14197
14444
|
} catch (err) {
|
|
@@ -14210,7 +14457,7 @@ app17.post("/:slug/project", async (c) => {
|
|
|
14210
14457
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
14211
14458
|
}
|
|
14212
14459
|
const agentDir = resolve19(account.accountDir, "agents", slug);
|
|
14213
|
-
if (!
|
|
14460
|
+
if (!existsSync24(agentDir)) {
|
|
14214
14461
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
14215
14462
|
}
|
|
14216
14463
|
try {
|
|
@@ -14226,7 +14473,7 @@ var agents_default = app17;
|
|
|
14226
14473
|
// server/routes/admin/sessions.ts
|
|
14227
14474
|
import crypto2 from "crypto";
|
|
14228
14475
|
import { resolve as resolvePath } from "path";
|
|
14229
|
-
import { existsSync as
|
|
14476
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync7, createWriteStream } from "fs";
|
|
14230
14477
|
|
|
14231
14478
|
// ../lib/admin-conversation-purge/src/index.ts
|
|
14232
14479
|
async function purgeAdminConversationJsonls(args) {
|
|
@@ -14373,7 +14620,7 @@ var pickComponentBytes = (..._args) => null;
|
|
|
14373
14620
|
function openResumeStreamLog(accountId, sessionId) {
|
|
14374
14621
|
const dir = resolvePath(ACCOUNTS_DIR, accountId, "resume-logs");
|
|
14375
14622
|
try {
|
|
14376
|
-
|
|
14623
|
+
mkdirSync7(dir, { recursive: true });
|
|
14377
14624
|
} catch {
|
|
14378
14625
|
}
|
|
14379
14626
|
return createWriteStream(resolvePath(dir, `${sessionId}.log`), { flags: "a" });
|
|
@@ -14386,7 +14633,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
|
|
|
14386
14633
|
let reason = null;
|
|
14387
14634
|
if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
|
|
14388
14635
|
else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
|
|
14389
|
-
else if (!
|
|
14636
|
+
else if (!existsSync25(a.storagePath)) reason = "missing-file";
|
|
14390
14637
|
if (reason) {
|
|
14391
14638
|
invalid++;
|
|
14392
14639
|
try {
|
|
@@ -14912,8 +15159,8 @@ app18.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
14912
15159
|
var sessions_default = app18;
|
|
14913
15160
|
|
|
14914
15161
|
// app/lib/claude-agent/spawn-context.ts
|
|
14915
|
-
import { existsSync as
|
|
14916
|
-
import { dirname as dirname10, resolve as resolve20, join as
|
|
15162
|
+
import { existsSync as existsSync26, readFileSync as readFileSync30, readdirSync as readdirSync20, statSync as statSync11 } from "fs";
|
|
15163
|
+
import { dirname as dirname10, resolve as resolve20, join as join29 } from "path";
|
|
14917
15164
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
14918
15165
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
14919
15166
|
try {
|
|
@@ -14954,14 +15201,14 @@ function frontmatterField(manifest, field2) {
|
|
|
14954
15201
|
function extractPluginToolDescriptions(pluginDir) {
|
|
14955
15202
|
const out = /* @__PURE__ */ new Map();
|
|
14956
15203
|
const candidates = [
|
|
14957
|
-
|
|
14958
|
-
|
|
15204
|
+
join29(pluginDir, "mcp/dist/index.js"),
|
|
15205
|
+
join29(pluginDir, "mcp/src/index.ts")
|
|
14959
15206
|
];
|
|
14960
15207
|
let raw = null;
|
|
14961
15208
|
for (const path3 of candidates) {
|
|
14962
|
-
if (!
|
|
15209
|
+
if (!existsSync26(path3)) continue;
|
|
14963
15210
|
try {
|
|
14964
|
-
raw =
|
|
15211
|
+
raw = readFileSync30(path3, "utf-8");
|
|
14965
15212
|
break;
|
|
14966
15213
|
} catch {
|
|
14967
15214
|
}
|
|
@@ -15011,9 +15258,9 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
15011
15258
|
function listPluginDirs() {
|
|
15012
15259
|
const out = /* @__PURE__ */ new Map();
|
|
15013
15260
|
const platformPlugins = resolve20(PLATFORM_ROOT, "plugins");
|
|
15014
|
-
if (
|
|
15015
|
-
for (const name of
|
|
15016
|
-
const dir =
|
|
15261
|
+
if (existsSync26(platformPlugins)) {
|
|
15262
|
+
for (const name of readdirSync20(platformPlugins)) {
|
|
15263
|
+
const dir = join29(platformPlugins, name);
|
|
15017
15264
|
try {
|
|
15018
15265
|
if (statSync11(dir).isDirectory()) out.set(name, dir);
|
|
15019
15266
|
} catch {
|
|
@@ -15021,13 +15268,13 @@ function listPluginDirs() {
|
|
|
15021
15268
|
}
|
|
15022
15269
|
}
|
|
15023
15270
|
const premiumRoot = resolve20(dirname10(PLATFORM_ROOT), "premium-plugins");
|
|
15024
|
-
if (
|
|
15025
|
-
for (const bundle of
|
|
15026
|
-
const bundlePlugins =
|
|
15027
|
-
if (!
|
|
15271
|
+
if (existsSync26(premiumRoot)) {
|
|
15272
|
+
for (const bundle of readdirSync20(premiumRoot)) {
|
|
15273
|
+
const bundlePlugins = join29(premiumRoot, bundle, "plugins");
|
|
15274
|
+
if (!existsSync26(bundlePlugins)) continue;
|
|
15028
15275
|
try {
|
|
15029
|
-
for (const name of
|
|
15030
|
-
const dir =
|
|
15276
|
+
for (const name of readdirSync20(bundlePlugins)) {
|
|
15277
|
+
const dir = join29(bundlePlugins, name);
|
|
15031
15278
|
try {
|
|
15032
15279
|
if (statSync11(dir).isDirectory()) out.set(name, dir);
|
|
15033
15280
|
} catch {
|
|
@@ -15041,9 +15288,9 @@ function listPluginDirs() {
|
|
|
15041
15288
|
}
|
|
15042
15289
|
function readEnabledPlugins(accountId) {
|
|
15043
15290
|
const accountFile = resolve20(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
15044
|
-
if (!
|
|
15291
|
+
if (!existsSync26(accountFile)) return /* @__PURE__ */ new Set();
|
|
15045
15292
|
try {
|
|
15046
|
-
const parsed = JSON.parse(
|
|
15293
|
+
const parsed = JSON.parse(readFileSync30(accountFile, "utf-8"));
|
|
15047
15294
|
return new Set(
|
|
15048
15295
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
15049
15296
|
);
|
|
@@ -15052,10 +15299,10 @@ function readEnabledPlugins(accountId) {
|
|
|
15052
15299
|
}
|
|
15053
15300
|
}
|
|
15054
15301
|
function readFrontmatter(path3) {
|
|
15055
|
-
if (!
|
|
15302
|
+
if (!existsSync26(path3)) return null;
|
|
15056
15303
|
let raw;
|
|
15057
15304
|
try {
|
|
15058
|
-
raw =
|
|
15305
|
+
raw = readFileSync30(path3, "utf-8");
|
|
15059
15306
|
} catch {
|
|
15060
15307
|
return null;
|
|
15061
15308
|
}
|
|
@@ -15070,7 +15317,7 @@ function computeActivePlugins(accountId) {
|
|
|
15070
15317
|
for (const name of Array.from(enabled).sort()) {
|
|
15071
15318
|
const dir = pluginDirs.get(name);
|
|
15072
15319
|
if (!dir) continue;
|
|
15073
|
-
const fm = readFrontmatter(
|
|
15320
|
+
const fm = readFrontmatter(join29(dir, "PLUGIN.md"));
|
|
15074
15321
|
if (!fm) continue;
|
|
15075
15322
|
const description = frontmatterField(`---
|
|
15076
15323
|
${fm}
|
|
@@ -15087,7 +15334,7 @@ ${fm}
|
|
|
15087
15334
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
15088
15335
|
);
|
|
15089
15336
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
15090
|
-
const hasSource =
|
|
15337
|
+
const hasSource = existsSync26(join29(dir, "mcp/dist/index.js")) || existsSync26(join29(dir, "mcp/src/index.ts"));
|
|
15091
15338
|
if (hasSource) {
|
|
15092
15339
|
console.warn(
|
|
15093
15340
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -15097,7 +15344,7 @@ ${fm}
|
|
|
15097
15344
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
15098
15345
|
const skills = [];
|
|
15099
15346
|
for (const relPath of skillPaths) {
|
|
15100
|
-
const skillPath =
|
|
15347
|
+
const skillPath = join29(dir, relPath);
|
|
15101
15348
|
const skillFm = readFrontmatter(skillPath);
|
|
15102
15349
|
if (!skillFm) continue;
|
|
15103
15350
|
const skillName = frontmatterField(`---
|
|
@@ -15114,10 +15361,10 @@ ${skillFm}
|
|
|
15114
15361
|
}
|
|
15115
15362
|
function computeSpecialistDomains(accountId) {
|
|
15116
15363
|
const specialistsDir = resolve20(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
15117
|
-
if (!
|
|
15364
|
+
if (!existsSync26(specialistsDir)) return [];
|
|
15118
15365
|
let entries;
|
|
15119
15366
|
try {
|
|
15120
|
-
entries =
|
|
15367
|
+
entries = readdirSync20(specialistsDir);
|
|
15121
15368
|
} catch {
|
|
15122
15369
|
return [];
|
|
15123
15370
|
}
|
|
@@ -15141,7 +15388,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
15141
15388
|
const out = [];
|
|
15142
15389
|
for (const file of entries.sort()) {
|
|
15143
15390
|
if (!file.endsWith(".md")) continue;
|
|
15144
|
-
const fm = readFrontmatter(
|
|
15391
|
+
const fm = readFrontmatter(join29(specialistsDir, file));
|
|
15145
15392
|
if (!fm) continue;
|
|
15146
15393
|
const wrapped = `---
|
|
15147
15394
|
${fm}
|
|
@@ -15160,10 +15407,10 @@ ${fm}
|
|
|
15160
15407
|
}
|
|
15161
15408
|
function computeDormantPlugins(accountId) {
|
|
15162
15409
|
const accountFile = resolve20(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
15163
|
-
if (!
|
|
15410
|
+
if (!existsSync26(accountFile)) return [];
|
|
15164
15411
|
let enabled;
|
|
15165
15412
|
try {
|
|
15166
|
-
const raw =
|
|
15413
|
+
const raw = readFileSync30(accountFile, "utf-8");
|
|
15167
15414
|
const parsed = JSON.parse(raw);
|
|
15168
15415
|
enabled = new Set(
|
|
15169
15416
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -15175,10 +15422,10 @@ function computeDormantPlugins(accountId) {
|
|
|
15175
15422
|
return [];
|
|
15176
15423
|
}
|
|
15177
15424
|
const pluginsDir = resolve20(PLATFORM_ROOT, "plugins");
|
|
15178
|
-
if (!
|
|
15425
|
+
if (!existsSync26(pluginsDir)) return [];
|
|
15179
15426
|
let entries;
|
|
15180
15427
|
try {
|
|
15181
|
-
entries =
|
|
15428
|
+
entries = readdirSync20(pluginsDir);
|
|
15182
15429
|
} catch {
|
|
15183
15430
|
return [];
|
|
15184
15431
|
}
|
|
@@ -15186,10 +15433,10 @@ function computeDormantPlugins(accountId) {
|
|
|
15186
15433
|
for (const name of entries) {
|
|
15187
15434
|
if (enabled.has(name)) continue;
|
|
15188
15435
|
const manifestPath = resolve20(pluginsDir, name, "PLUGIN.md");
|
|
15189
|
-
if (!
|
|
15436
|
+
if (!existsSync26(manifestPath)) continue;
|
|
15190
15437
|
let manifest;
|
|
15191
15438
|
try {
|
|
15192
|
-
manifest =
|
|
15439
|
+
manifest = readFileSync30(manifestPath, "utf-8");
|
|
15193
15440
|
} catch {
|
|
15194
15441
|
continue;
|
|
15195
15442
|
}
|
|
@@ -15203,13 +15450,13 @@ function computeDormantPlugins(accountId) {
|
|
|
15203
15450
|
}
|
|
15204
15451
|
|
|
15205
15452
|
// server/routes/admin/claude-sessions.ts
|
|
15206
|
-
import { existsSync as
|
|
15453
|
+
import { existsSync as existsSync27, readFileSync as readFileSync31 } from "fs";
|
|
15207
15454
|
import { resolve as resolve21 } from "path";
|
|
15208
15455
|
function readTunnelState(brandConfigDir) {
|
|
15209
15456
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
15210
|
-
if (!
|
|
15457
|
+
if (!existsSync27(statePath)) return null;
|
|
15211
15458
|
try {
|
|
15212
|
-
const parsed = JSON.parse(
|
|
15459
|
+
const parsed = JSON.parse(readFileSync31(statePath, "utf-8"));
|
|
15213
15460
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
15214
15461
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
15215
15462
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -15223,7 +15470,7 @@ function resolveTunnelUrl() {
|
|
|
15223
15470
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
|
|
15224
15471
|
let brand;
|
|
15225
15472
|
try {
|
|
15226
|
-
brand = JSON.parse(
|
|
15473
|
+
brand = JSON.parse(readFileSync31(resolve21(platformRoot5, "config", "brand.json"), "utf-8"));
|
|
15227
15474
|
} catch {
|
|
15228
15475
|
return null;
|
|
15229
15476
|
}
|
|
@@ -15234,7 +15481,7 @@ function resolveTunnelUrl() {
|
|
|
15234
15481
|
if (!state) return null;
|
|
15235
15482
|
return `https://${hostname2}.${state.domain}`;
|
|
15236
15483
|
}
|
|
15237
|
-
var
|
|
15484
|
+
var TAG27 = "[claude-session-manager:wrapper]";
|
|
15238
15485
|
async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
15239
15486
|
const auth = await ensureAuth();
|
|
15240
15487
|
if (auth.status !== "dead" && auth.status !== "missing") return null;
|
|
@@ -15252,12 +15499,12 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
15252
15499
|
const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
|
|
15253
15500
|
const ownerMs = Date.now() - ownerStart;
|
|
15254
15501
|
const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
|
|
15255
|
-
console.log(`${
|
|
15502
|
+
console.log(`${TAG27} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
|
|
15256
15503
|
const dormantPlugins = computeDormantPlugins(args.senderId);
|
|
15257
15504
|
const activePlugins = computeActivePlugins(args.senderId);
|
|
15258
15505
|
const specialistDomains = computeSpecialistDomains(args.senderId);
|
|
15259
15506
|
const tunnelUrl = resolveTunnelUrl();
|
|
15260
|
-
console.log(`${
|
|
15507
|
+
console.log(`${TAG27} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
|
|
15261
15508
|
const upstreamPayload = JSON.stringify({
|
|
15262
15509
|
senderId: args.senderId,
|
|
15263
15510
|
// Task 205 — pass userId through to the manager so it lands as
|
|
@@ -15284,24 +15531,24 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
15284
15531
|
// unshapely values.
|
|
15285
15532
|
conversationNodeId: args.conversationNodeId
|
|
15286
15533
|
});
|
|
15287
|
-
console.log(`${
|
|
15534
|
+
console.log(`${TAG27} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
|
|
15288
15535
|
const forwardStart = Date.now();
|
|
15289
15536
|
const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
|
|
15290
15537
|
method: "POST",
|
|
15291
15538
|
headers: { "content-type": "application/json" },
|
|
15292
15539
|
body: upstreamPayload
|
|
15293
15540
|
}).catch((err) => {
|
|
15294
|
-
console.error(`${
|
|
15541
|
+
console.error(`${TAG27} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
|
|
15295
15542
|
return null;
|
|
15296
15543
|
});
|
|
15297
15544
|
if (!upstream) return {
|
|
15298
15545
|
response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
|
|
15299
15546
|
claudeSessionId: null
|
|
15300
15547
|
};
|
|
15301
|
-
console.log(`${
|
|
15548
|
+
console.log(`${TAG27} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
|
|
15302
15549
|
if (args.initialMessage) {
|
|
15303
15550
|
const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
|
|
15304
|
-
console.log(`${
|
|
15551
|
+
console.log(`${TAG27} initial-message-inlined bytes=${inputBytes}`);
|
|
15305
15552
|
}
|
|
15306
15553
|
const bodyText = await upstream.text().catch(() => "");
|
|
15307
15554
|
let claudeSessionId = null;
|
|
@@ -15336,7 +15583,7 @@ app19.post("/", async (c) => {
|
|
|
15336
15583
|
if (refusal) return refusal;
|
|
15337
15584
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
15338
15585
|
if (!senderId) {
|
|
15339
|
-
console.error(`${
|
|
15586
|
+
console.error(`${TAG27} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
|
|
15340
15587
|
return c.json({ error: "admin-account-not-resolved" }, 500);
|
|
15341
15588
|
}
|
|
15342
15589
|
const userId = getUserIdForSession(cacheKey) ?? void 0;
|
|
@@ -15345,7 +15592,7 @@ app19.post("/", async (c) => {
|
|
|
15345
15592
|
const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
|
|
15346
15593
|
const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
|
|
15347
15594
|
const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
|
|
15348
|
-
console.log(`${
|
|
15595
|
+
console.log(`${TAG27} 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"}`);
|
|
15349
15596
|
const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
|
|
15350
15597
|
const { response, claudeSessionId } = await performSpawnWithInitialMessage({
|
|
15351
15598
|
senderId,
|
|
@@ -15364,13 +15611,13 @@ app19.post("/", async (c) => {
|
|
|
15364
15611
|
claudeSessionId,
|
|
15365
15612
|
senderId
|
|
15366
15613
|
);
|
|
15367
|
-
console.log(`${
|
|
15614
|
+
console.log(`${TAG27} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
|
|
15368
15615
|
return response;
|
|
15369
15616
|
});
|
|
15370
15617
|
var claude_sessions_default = app19;
|
|
15371
15618
|
|
|
15372
15619
|
// server/routes/admin/log-ingest.ts
|
|
15373
|
-
var
|
|
15620
|
+
var TAG28 = "[log-ingest]";
|
|
15374
15621
|
var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
|
|
15375
15622
|
var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
|
|
15376
15623
|
var MAX_LINE_BYTES = 4096;
|
|
@@ -15381,7 +15628,7 @@ function isLoopbackAddr2(addr) {
|
|
|
15381
15628
|
app20.post("/", async (c) => {
|
|
15382
15629
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15383
15630
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
15384
|
-
console.error(`${
|
|
15631
|
+
console.error(`${TAG28} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15385
15632
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
15386
15633
|
}
|
|
15387
15634
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15390,7 +15637,7 @@ app20.post("/", async (c) => {
|
|
|
15390
15637
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15391
15638
|
const offender = tokens.find((t) => !isLoopbackAddr2(t));
|
|
15392
15639
|
if (offender !== void 0) {
|
|
15393
|
-
console.error(`${
|
|
15640
|
+
console.error(`${TAG28} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15394
15641
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
15395
15642
|
}
|
|
15396
15643
|
}
|
|
@@ -15432,18 +15679,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
15432
15679
|
]);
|
|
15433
15680
|
var app21 = new Hono();
|
|
15434
15681
|
app21.post("/", async (c) => {
|
|
15435
|
-
const
|
|
15682
|
+
const TAG48 = "[admin:events]";
|
|
15436
15683
|
let body;
|
|
15437
15684
|
try {
|
|
15438
15685
|
body = await c.req.json();
|
|
15439
15686
|
} catch (err) {
|
|
15440
15687
|
const detail = err instanceof Error ? err.message : String(err);
|
|
15441
|
-
console.error(`${
|
|
15688
|
+
console.error(`${TAG48} reject reason=body-not-json detail=${detail}`);
|
|
15442
15689
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
15443
15690
|
}
|
|
15444
15691
|
const event = typeof body.event === "string" ? body.event : "";
|
|
15445
15692
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
15446
|
-
console.error(`${
|
|
15693
|
+
console.error(`${TAG48} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
15447
15694
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
15448
15695
|
}
|
|
15449
15696
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -15465,11 +15712,11 @@ app21.post("/", async (c) => {
|
|
|
15465
15712
|
var events_default = app21;
|
|
15466
15713
|
|
|
15467
15714
|
// server/routes/admin/files.ts
|
|
15468
|
-
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as
|
|
15715
|
+
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync28 } from "fs";
|
|
15469
15716
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename, rmdir } from "fs/promises";
|
|
15470
15717
|
import { realpathSync as realpathSync6 } from "fs";
|
|
15471
15718
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
15472
|
-
import { basename as basename9, dirname as dirname11, join as
|
|
15719
|
+
import { basename as basename9, dirname as dirname11, join as join31, relative as relative4, resolve as resolve23, sep as sep6 } from "path";
|
|
15473
15720
|
import { Readable as Readable2 } from "stream";
|
|
15474
15721
|
|
|
15475
15722
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -15787,7 +16034,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
15787
16034
|
|
|
15788
16035
|
// app/lib/file-index.ts
|
|
15789
16036
|
import * as fsp from "fs/promises";
|
|
15790
|
-
import { resolve as resolve22, relative as relative3, join as
|
|
16037
|
+
import { resolve as resolve22, relative as relative3, join as join30, basename as basename8, extname as extname2, sep as sep5 } from "path";
|
|
15791
16038
|
import { tmpdir as tmpdir2 } from "os";
|
|
15792
16039
|
import { execFile as execFile2 } from "child_process";
|
|
15793
16040
|
import { promisify as promisify2 } from "util";
|
|
@@ -15869,7 +16116,7 @@ async function extractPdf(absolute) {
|
|
|
15869
16116
|
return stdout.trim();
|
|
15870
16117
|
}
|
|
15871
16118
|
async function ocrPdf(absolute) {
|
|
15872
|
-
const outPdf =
|
|
16119
|
+
const outPdf = join30(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
15873
16120
|
try {
|
|
15874
16121
|
await execFileAsync2(
|
|
15875
16122
|
"ocrmypdf",
|
|
@@ -15931,7 +16178,7 @@ async function readDisplayName(absolute) {
|
|
|
15931
16178
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
15932
16179
|
if (base === `${stem}.meta.json`) return null;
|
|
15933
16180
|
try {
|
|
15934
|
-
const raw = await fsp.readFile(
|
|
16181
|
+
const raw = await fsp.readFile(join30(dir, `${stem}.meta.json`), "utf-8");
|
|
15935
16182
|
const meta = JSON.parse(raw);
|
|
15936
16183
|
const dn = meta.displayName ?? meta.filename;
|
|
15937
16184
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -15952,7 +16199,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
15952
16199
|
for (const entry of entries) {
|
|
15953
16200
|
if (entry.isSymbolicLink()) continue;
|
|
15954
16201
|
if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
|
|
15955
|
-
const abs =
|
|
16202
|
+
const abs = join30(root, entry.name);
|
|
15956
16203
|
if (entry.isDirectory()) {
|
|
15957
16204
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
15958
16205
|
if (!sub.clean) clean = false;
|
|
@@ -16308,7 +16555,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
|
16308
16555
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
16309
16556
|
async function readMeta(absDir, baseName) {
|
|
16310
16557
|
try {
|
|
16311
|
-
const raw = await readFile4(
|
|
16558
|
+
const raw = await readFile4(join31(absDir, `${baseName}.meta.json`), "utf8");
|
|
16312
16559
|
const parsed = JSON.parse(raw);
|
|
16313
16560
|
if (typeof parsed?.filename === "string") {
|
|
16314
16561
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -16363,7 +16610,7 @@ async function servableFilesIn(dirAbs, uuid) {
|
|
|
16363
16610
|
}
|
|
16364
16611
|
async function enrich(absolute, entry, accountNames) {
|
|
16365
16612
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
16366
|
-
const dirAbs =
|
|
16613
|
+
const dirAbs = join31(absolute, entry.name);
|
|
16367
16614
|
const meta = await readMeta(dirAbs, entry.name);
|
|
16368
16615
|
if (meta?.filename) {
|
|
16369
16616
|
const servable = await servableFilesIn(dirAbs, entry.name);
|
|
@@ -16372,7 +16619,7 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
16372
16619
|
let size = null;
|
|
16373
16620
|
let modifiedAt = entry.modifiedAt;
|
|
16374
16621
|
try {
|
|
16375
|
-
const st = await stat4(
|
|
16622
|
+
const st = await stat4(join31(dirAbs, innerName));
|
|
16376
16623
|
size = st.size;
|
|
16377
16624
|
modifiedAt = st.mtime.toISOString();
|
|
16378
16625
|
} catch {
|
|
@@ -16547,7 +16794,7 @@ app22.get("/", requireAdminSession, async (c) => {
|
|
|
16547
16794
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
16548
16795
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
16549
16796
|
try {
|
|
16550
|
-
const entryPath =
|
|
16797
|
+
const entryPath = join31(absolute, name);
|
|
16551
16798
|
const s = await stat4(entryPath);
|
|
16552
16799
|
entries.push({
|
|
16553
16800
|
name,
|
|
@@ -16610,7 +16857,7 @@ app22.get("/download", requireAdminSession, async (c) => {
|
|
|
16610
16857
|
console.error(`[data] op=scratchpad-no-session sessionId="${sessionId.slice(0, 8)}\u2026"`);
|
|
16611
16858
|
return c.json({ error: "Not found" }, 404);
|
|
16612
16859
|
}
|
|
16613
|
-
const meta = readSidecarMeta(
|
|
16860
|
+
const meta = readSidecarMeta(join31(projectDir, `${sessionId}.meta.json`));
|
|
16614
16861
|
if (!meta.accountId || meta.accountId !== accountId) {
|
|
16615
16862
|
console.error(`[data] account-scope-blocked root="scratchpad" sessionId="${sessionId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
|
|
16616
16863
|
return c.json({ error: "Not found" }, 404);
|
|
@@ -16705,7 +16952,7 @@ async function* walkRegularFiles(dirAbsolute) {
|
|
|
16705
16952
|
const dirents = await readdir3(dirAbsolute, { withFileTypes: true });
|
|
16706
16953
|
for (const d of dirents) {
|
|
16707
16954
|
if (d.isSymbolicLink()) continue;
|
|
16708
|
-
const child =
|
|
16955
|
+
const child = join31(dirAbsolute, d.name);
|
|
16709
16956
|
if (d.isDirectory()) {
|
|
16710
16957
|
yield* walkRegularFiles(child);
|
|
16711
16958
|
continue;
|
|
@@ -16815,7 +17062,7 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
16815
17062
|
const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
16816
17063
|
if (!base.ok) return { ok: false, status: base.status, error: base.error };
|
|
16817
17064
|
const relDir = relpath ? dirname11(relpath) : ".";
|
|
16818
|
-
const destRel = relDir === "." ? base.relative :
|
|
17065
|
+
const destRel = relDir === "." ? base.relative : join31(base.relative, relDir);
|
|
16819
17066
|
if (crossesForeignAccountPartition(destRel, accountId)) {
|
|
16820
17067
|
console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
16821
17068
|
return { ok: false, status: 404, error: "Not found" };
|
|
@@ -16889,7 +17136,7 @@ app22.post("/upload", requireAdminSession, async (c) => {
|
|
|
16889
17136
|
});
|
|
16890
17137
|
await unlink2(tmpPath).catch(() => {
|
|
16891
17138
|
});
|
|
16892
|
-
const tempRemoved = !
|
|
17139
|
+
const tempRemoved = !existsSync28(tmpPath);
|
|
16893
17140
|
console.error(`[data-upload] op=cleanup uid=${uid} tempRemoved=${tempRemoved}`);
|
|
16894
17141
|
};
|
|
16895
17142
|
const reader = body.getReader();
|
|
@@ -16963,7 +17210,7 @@ async function discardChunkUpload(uploadId, state) {
|
|
|
16963
17210
|
});
|
|
16964
17211
|
await unlink2(state.tmpPath).catch(() => {
|
|
16965
17212
|
});
|
|
16966
|
-
const tempRemoved = !
|
|
17213
|
+
const tempRemoved = !existsSync28(state.tmpPath);
|
|
16967
17214
|
console.error(`[data-upload] op=cleanup uid=${uploadId} tempRemoved=${tempRemoved}`);
|
|
16968
17215
|
}
|
|
16969
17216
|
async function writeChunkBody(body, out, alreadyReceived, ceiling) {
|
|
@@ -17192,7 +17439,7 @@ app22.delete("/", requireAdminSession, async (c) => {
|
|
|
17192
17439
|
const dot = base.lastIndexOf(".");
|
|
17193
17440
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
17194
17441
|
const containerDir = dirname11(absolute);
|
|
17195
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
17442
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join31(containerDir, `${stem}.meta.json`) : null;
|
|
17196
17443
|
const isAttachmentContainer = UUID_RE3.test(stem) && basename9(containerDir) === stem;
|
|
17197
17444
|
await unlink2(absolute);
|
|
17198
17445
|
if (sidecarPath) {
|
|
@@ -17202,7 +17449,7 @@ app22.delete("/", requireAdminSession, async (c) => {
|
|
|
17202
17449
|
}
|
|
17203
17450
|
}
|
|
17204
17451
|
if (isAttachmentContainer) {
|
|
17205
|
-
await unlink2(
|
|
17452
|
+
await unlink2(join31(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
|
|
17206
17453
|
});
|
|
17207
17454
|
await rmdir(containerDir).catch(() => {
|
|
17208
17455
|
});
|
|
@@ -18306,8 +18553,8 @@ function isHiddenByDefault(label) {
|
|
|
18306
18553
|
}
|
|
18307
18554
|
|
|
18308
18555
|
// server/lib/top-level-labels.ts
|
|
18309
|
-
import { readdirSync as
|
|
18310
|
-
import { join as
|
|
18556
|
+
import { readdirSync as readdirSync21, readFileSync as readFileSync32 } from "fs";
|
|
18557
|
+
import { join as join32, resolve as resolve24 } from "path";
|
|
18311
18558
|
var STATIC_TOP_LEVEL_LABELS = Object.freeze(
|
|
18312
18559
|
/* @__PURE__ */ new Set([
|
|
18313
18560
|
// Base-schema infra (schema-base.md has no top-level section).
|
|
@@ -18400,7 +18647,7 @@ function parseTopLevelLabels(content) {
|
|
|
18400
18647
|
}
|
|
18401
18648
|
function resolveReferencesDir() {
|
|
18402
18649
|
if (process.env.MAXY_PLATFORM_ROOT) {
|
|
18403
|
-
return
|
|
18650
|
+
return join32(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
|
|
18404
18651
|
}
|
|
18405
18652
|
return resolve24(import.meta.dirname, "../../../plugins/memory/references");
|
|
18406
18653
|
}
|
|
@@ -18408,9 +18655,9 @@ function parseTableTopLevelLabels(referencesDir) {
|
|
|
18408
18655
|
const labels = /* @__PURE__ */ new Set();
|
|
18409
18656
|
const contributingFiles = [];
|
|
18410
18657
|
try {
|
|
18411
|
-
const fileNames =
|
|
18658
|
+
const fileNames = readdirSync21(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
|
|
18412
18659
|
for (const fileName of fileNames) {
|
|
18413
|
-
const content =
|
|
18660
|
+
const content = readFileSync32(join32(referencesDir, fileName), "utf-8");
|
|
18414
18661
|
const parsed = parseTopLevelLabels(content);
|
|
18415
18662
|
if (parsed.length > 0) contributingFiles.push(fileName);
|
|
18416
18663
|
for (const label of parsed) labels.add(label);
|
|
@@ -19564,7 +19811,7 @@ var graph_default_view_default = app28;
|
|
|
19564
19811
|
// server/routes/admin/sidebar-artefacts.ts
|
|
19565
19812
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
19566
19813
|
import { resolve as resolve25, relative as relative5, isAbsolute as isAbsolute2, sep as sep7, basename as basename10 } from "path";
|
|
19567
|
-
import { existsSync as
|
|
19814
|
+
import { existsSync as existsSync29 } from "fs";
|
|
19568
19815
|
var LIMIT = 50;
|
|
19569
19816
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
19570
19817
|
function toDataRootRelPath(absPath) {
|
|
@@ -19671,7 +19918,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
19671
19918
|
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
19672
19919
|
const names = /* @__PURE__ */ new Set();
|
|
19673
19920
|
for (const dir of [overrideDir, bundledDir]) {
|
|
19674
|
-
if (!
|
|
19921
|
+
if (!existsSync29(dir)) continue;
|
|
19675
19922
|
try {
|
|
19676
19923
|
const entries = await readdir4(dir);
|
|
19677
19924
|
for (const entry of entries) {
|
|
@@ -19686,7 +19933,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
19686
19933
|
}
|
|
19687
19934
|
async function readAgentTemplateRow(inp) {
|
|
19688
19935
|
let chosenPath = null;
|
|
19689
|
-
if (
|
|
19936
|
+
if (existsSync29(inp.overridePath)) {
|
|
19690
19937
|
try {
|
|
19691
19938
|
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
19692
19939
|
chosenPath = inp.overridePath;
|
|
@@ -19697,7 +19944,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
19697
19944
|
);
|
|
19698
19945
|
return null;
|
|
19699
19946
|
}
|
|
19700
|
-
} else if (
|
|
19947
|
+
} else if (existsSync29(inp.bundledPath)) {
|
|
19701
19948
|
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
19702
19949
|
console.error(
|
|
19703
19950
|
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
@@ -20299,14 +20546,14 @@ app37.get("/", async (c) => {
|
|
|
20299
20546
|
var system_stats_default = app37;
|
|
20300
20547
|
|
|
20301
20548
|
// server/routes/admin/health.ts
|
|
20302
|
-
import { existsSync as
|
|
20303
|
-
import { resolve as resolve26, join as
|
|
20549
|
+
import { existsSync as existsSync30, readFileSync as readFileSync33 } from "fs";
|
|
20550
|
+
import { resolve as resolve26, join as join33 } from "path";
|
|
20304
20551
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve26(process.cwd(), "..");
|
|
20305
20552
|
var brandHostname = "maxy";
|
|
20306
|
-
var brandJsonPath =
|
|
20307
|
-
if (
|
|
20553
|
+
var brandJsonPath = join33(PLATFORM_ROOT6, "config", "brand.json");
|
|
20554
|
+
if (existsSync30(brandJsonPath)) {
|
|
20308
20555
|
try {
|
|
20309
|
-
const brand = JSON.parse(
|
|
20556
|
+
const brand = JSON.parse(readFileSync33(brandJsonPath, "utf-8"));
|
|
20310
20557
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
20311
20558
|
} catch {
|
|
20312
20559
|
}
|
|
@@ -20315,8 +20562,8 @@ var VERSION_FILE = resolve26(PLATFORM_ROOT6, `config/.${brandHostname}-version`)
|
|
|
20315
20562
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
20316
20563
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
20317
20564
|
function readVersion() {
|
|
20318
|
-
if (!
|
|
20319
|
-
return
|
|
20565
|
+
if (!existsSync30(VERSION_FILE)) return "unknown";
|
|
20566
|
+
return readFileSync33(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
20320
20567
|
}
|
|
20321
20568
|
async function probeConversationDb() {
|
|
20322
20569
|
let session;
|
|
@@ -20495,7 +20742,7 @@ function managerLogFollowUrl(sessionId, opts) {
|
|
|
20495
20742
|
}
|
|
20496
20743
|
|
|
20497
20744
|
// server/routes/admin/linkedin-ingest.ts
|
|
20498
|
-
var
|
|
20745
|
+
var TAG29 = "[linkedin-ingest-route]";
|
|
20499
20746
|
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}$/;
|
|
20500
20747
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
20501
20748
|
var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
|
|
@@ -20599,29 +20846,29 @@ app39.post("/", requireAdminSession, async (c) => {
|
|
|
20599
20846
|
try {
|
|
20600
20847
|
body = await c.req.json();
|
|
20601
20848
|
} catch {
|
|
20602
|
-
console.error(
|
|
20849
|
+
console.error(TAG29 + " rejected status=400 reason=schema:body-not-json");
|
|
20603
20850
|
return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
|
|
20604
20851
|
}
|
|
20605
20852
|
const v = validate(body);
|
|
20606
20853
|
if (!v.ok) {
|
|
20607
|
-
console.error(
|
|
20854
|
+
console.error(TAG29 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
|
|
20608
20855
|
return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
|
|
20609
20856
|
}
|
|
20610
20857
|
const envelope = v.envelope;
|
|
20611
20858
|
const cacheKey = c.var.cacheKey ?? "";
|
|
20612
20859
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
20613
20860
|
if (!senderId) {
|
|
20614
|
-
console.error(
|
|
20861
|
+
console.error(TAG29 + " rejected status=500 reason=admin-account-not-resolved");
|
|
20615
20862
|
return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
|
|
20616
20863
|
}
|
|
20617
20864
|
const payloadBytes = JSON.stringify(envelope).length;
|
|
20618
20865
|
console.log(
|
|
20619
|
-
|
|
20866
|
+
TAG29 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
|
|
20620
20867
|
);
|
|
20621
20868
|
const initialMessage = buildInitialMessage(envelope);
|
|
20622
20869
|
const spawnStart = Date.now();
|
|
20623
20870
|
const sessionId = randomUUID13();
|
|
20624
|
-
console.log(
|
|
20871
|
+
console.log(TAG29 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
20625
20872
|
const spawned = await managerRcSpawn({
|
|
20626
20873
|
sessionId,
|
|
20627
20874
|
initialMessage,
|
|
@@ -20630,12 +20877,12 @@ app39.post("/", requireAdminSession, async (c) => {
|
|
|
20630
20877
|
});
|
|
20631
20878
|
if ("error" in spawned) {
|
|
20632
20879
|
console.error(
|
|
20633
|
-
|
|
20880
|
+
TAG29 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
|
|
20634
20881
|
);
|
|
20635
20882
|
return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
|
|
20636
20883
|
}
|
|
20637
20884
|
console.log(
|
|
20638
|
-
|
|
20885
|
+
TAG29 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
|
|
20639
20886
|
);
|
|
20640
20887
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
20641
20888
|
});
|
|
@@ -20643,7 +20890,7 @@ var linkedin_ingest_default = app39;
|
|
|
20643
20890
|
|
|
20644
20891
|
// server/routes/admin/post-turn-context.ts
|
|
20645
20892
|
import neo4j3 from "neo4j-driver";
|
|
20646
|
-
var
|
|
20893
|
+
var TAG30 = "[post-turn-context]";
|
|
20647
20894
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
20648
20895
|
"embedding",
|
|
20649
20896
|
"passwordHash",
|
|
@@ -20685,7 +20932,7 @@ var app40 = new Hono();
|
|
|
20685
20932
|
app40.get("/", async (c) => {
|
|
20686
20933
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
20687
20934
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
20688
|
-
console.error(`${
|
|
20935
|
+
console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
20689
20936
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
20690
20937
|
}
|
|
20691
20938
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -20694,7 +20941,7 @@ app40.get("/", async (c) => {
|
|
|
20694
20941
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
20695
20942
|
const offender = tokens.find((t) => !isLoopbackAddr3(t));
|
|
20696
20943
|
if (offender !== void 0) {
|
|
20697
|
-
console.error(`${
|
|
20944
|
+
console.error(`${TAG30} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
20698
20945
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
20699
20946
|
}
|
|
20700
20947
|
}
|
|
@@ -20726,7 +20973,7 @@ app40.get("/", async (c) => {
|
|
|
20726
20973
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
20727
20974
|
const total = Date.now() - started;
|
|
20728
20975
|
console.log(
|
|
20729
|
-
`${
|
|
20976
|
+
`${TAG30} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
|
|
20730
20977
|
);
|
|
20731
20978
|
return c.json({
|
|
20732
20979
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -20735,7 +20982,7 @@ app40.get("/", async (c) => {
|
|
|
20735
20982
|
const elapsed = Date.now() - started;
|
|
20736
20983
|
const message = err instanceof Error ? err.message : String(err);
|
|
20737
20984
|
console.error(
|
|
20738
|
-
`${
|
|
20985
|
+
`${TAG30} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
|
|
20739
20986
|
);
|
|
20740
20987
|
return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
|
|
20741
20988
|
} finally {
|
|
@@ -20848,7 +21095,7 @@ function formatPreviousContext(writes) {
|
|
|
20848
21095
|
}
|
|
20849
21096
|
|
|
20850
21097
|
// server/routes/admin/public-session-context.ts
|
|
20851
|
-
var
|
|
21098
|
+
var TAG31 = "[public-session-context]";
|
|
20852
21099
|
function isLoopbackAddr4(addr) {
|
|
20853
21100
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
20854
21101
|
}
|
|
@@ -20856,7 +21103,7 @@ var app41 = new Hono();
|
|
|
20856
21103
|
app41.get("/", async (c) => {
|
|
20857
21104
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
20858
21105
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
20859
|
-
console.error(`${
|
|
21106
|
+
console.error(`${TAG31} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
20860
21107
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
20861
21108
|
}
|
|
20862
21109
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -20865,7 +21112,7 @@ app41.get("/", async (c) => {
|
|
|
20865
21112
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
20866
21113
|
const offender = tokens.find((t) => !isLoopbackAddr4(t));
|
|
20867
21114
|
if (offender !== void 0) {
|
|
20868
|
-
console.error(`${
|
|
21115
|
+
console.error(`${TAG31} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
20869
21116
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
20870
21117
|
}
|
|
20871
21118
|
}
|
|
@@ -20879,14 +21126,14 @@ app41.get("/", async (c) => {
|
|
|
20879
21126
|
const writes = await fetchSliceWrites(session, sliceToken, accountId);
|
|
20880
21127
|
const total = Date.now() - started;
|
|
20881
21128
|
console.log(
|
|
20882
|
-
`${
|
|
21129
|
+
`${TAG31} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
|
|
20883
21130
|
);
|
|
20884
21131
|
return c.json({ writes });
|
|
20885
21132
|
} catch (err) {
|
|
20886
21133
|
const elapsed = Date.now() - started;
|
|
20887
21134
|
const message = err instanceof Error ? err.message : String(err);
|
|
20888
21135
|
console.error(
|
|
20889
|
-
`${
|
|
21136
|
+
`${TAG31} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
|
|
20890
21137
|
);
|
|
20891
21138
|
return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
|
|
20892
21139
|
} finally {
|
|
@@ -20905,7 +21152,7 @@ function getWebchatGateway() {
|
|
|
20905
21152
|
}
|
|
20906
21153
|
|
|
20907
21154
|
// server/routes/admin/public-session-exit.ts
|
|
20908
|
-
var
|
|
21155
|
+
var TAG32 = "[public-session-exit-route]";
|
|
20909
21156
|
function isLoopbackAddr5(addr) {
|
|
20910
21157
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
20911
21158
|
}
|
|
@@ -20913,7 +21160,7 @@ var app42 = new Hono();
|
|
|
20913
21160
|
app42.post("/", async (c) => {
|
|
20914
21161
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
20915
21162
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
20916
|
-
console.error(`${
|
|
21163
|
+
console.error(`${TAG32} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
20917
21164
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
20918
21165
|
}
|
|
20919
21166
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -20922,7 +21169,7 @@ app42.post("/", async (c) => {
|
|
|
20922
21169
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
20923
21170
|
const offender = tokens.find((t) => !isLoopbackAddr5(t));
|
|
20924
21171
|
if (offender !== void 0) {
|
|
20925
|
-
console.error(`${
|
|
21172
|
+
console.error(`${TAG32} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
20926
21173
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
20927
21174
|
}
|
|
20928
21175
|
}
|
|
@@ -20936,7 +21183,7 @@ app42.post("/", async (c) => {
|
|
|
20936
21183
|
if (!sessionId) return c.json({ error: "sessionId required" }, 400);
|
|
20937
21184
|
const gateway = getWebchatGateway();
|
|
20938
21185
|
if (!gateway) {
|
|
20939
|
-
console.error(`${
|
|
21186
|
+
console.error(`${TAG32} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
|
|
20940
21187
|
return c.json({ error: "webchat-gateway-unset" }, 503);
|
|
20941
21188
|
}
|
|
20942
21189
|
gateway.handlePublicSessionExit(sessionId);
|
|
@@ -20945,7 +21192,7 @@ app42.post("/", async (c) => {
|
|
|
20945
21192
|
var public_session_exit_default = app42;
|
|
20946
21193
|
|
|
20947
21194
|
// server/routes/admin/access-session-evict.ts
|
|
20948
|
-
var
|
|
21195
|
+
var TAG33 = "[access-session-evict]";
|
|
20949
21196
|
function isLoopbackAddr6(addr) {
|
|
20950
21197
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
20951
21198
|
}
|
|
@@ -20953,7 +21200,7 @@ var app43 = new Hono();
|
|
|
20953
21200
|
app43.post("/", async (c) => {
|
|
20954
21201
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
20955
21202
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
20956
|
-
console.error(`${
|
|
21203
|
+
console.error(`${TAG33} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
20957
21204
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
20958
21205
|
}
|
|
20959
21206
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -20962,7 +21209,7 @@ app43.post("/", async (c) => {
|
|
|
20962
21209
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
20963
21210
|
const offender = tokens.find((t) => !isLoopbackAddr6(t));
|
|
20964
21211
|
if (offender !== void 0) {
|
|
20965
|
-
console.error(`${
|
|
21212
|
+
console.error(`${TAG33} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
20966
21213
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
20967
21214
|
}
|
|
20968
21215
|
}
|
|
@@ -20975,13 +21222,13 @@ app43.post("/", async (c) => {
|
|
|
20975
21222
|
const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
|
|
20976
21223
|
if (!grantId) return c.json({ error: "grantId required" }, 400);
|
|
20977
21224
|
const dropped = evictAccessSessionsByGrant(grantId);
|
|
20978
|
-
console.log(`${
|
|
21225
|
+
console.log(`${TAG33} grantId=${grantId} dropped=${dropped}`);
|
|
20979
21226
|
return c.json({ ok: true, dropped });
|
|
20980
21227
|
});
|
|
20981
21228
|
var access_session_evict_default = app43;
|
|
20982
21229
|
|
|
20983
21230
|
// server/routes/admin/enrol-person.ts
|
|
20984
|
-
var
|
|
21231
|
+
var TAG34 = "[enrol]";
|
|
20985
21232
|
function isLoopbackAddr7(addr) {
|
|
20986
21233
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
20987
21234
|
}
|
|
@@ -20990,7 +21237,7 @@ var app44 = new Hono();
|
|
|
20990
21237
|
app44.post("/", async (c) => {
|
|
20991
21238
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
20992
21239
|
if (!isLoopbackAddr7(remoteAddr)) {
|
|
20993
|
-
console.error(`${
|
|
21240
|
+
console.error(`${TAG34} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
20994
21241
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
20995
21242
|
}
|
|
20996
21243
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -20999,7 +21246,7 @@ app44.post("/", async (c) => {
|
|
|
20999
21246
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
21000
21247
|
const offender = tokens.find((t) => !isLoopbackAddr7(t));
|
|
21001
21248
|
if (offender !== void 0) {
|
|
21002
|
-
console.error(`${
|
|
21249
|
+
console.error(`${TAG34} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
21003
21250
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
21004
21251
|
}
|
|
21005
21252
|
}
|
|
@@ -21024,7 +21271,7 @@ app44.post("/", async (c) => {
|
|
|
21024
21271
|
}
|
|
21025
21272
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
21026
21273
|
if (!accountId) {
|
|
21027
|
-
console.error(`${
|
|
21274
|
+
console.error(`${TAG34} op=person result=no-account-id`);
|
|
21028
21275
|
return c.json({ error: "no-account-id" }, 500);
|
|
21029
21276
|
}
|
|
21030
21277
|
let personId;
|
|
@@ -21032,7 +21279,7 @@ app44.post("/", async (c) => {
|
|
|
21032
21279
|
personId = await enrolPerson({ accountId, phone, email, agentSlug });
|
|
21033
21280
|
} catch (err) {
|
|
21034
21281
|
console.error(
|
|
21035
|
-
`${
|
|
21282
|
+
`${TAG34} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
21036
21283
|
);
|
|
21037
21284
|
return c.json({ error: "enrol-failed" }, 500);
|
|
21038
21285
|
}
|
|
@@ -21042,11 +21289,11 @@ app44.post("/", async (c) => {
|
|
|
21042
21289
|
if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
|
|
21043
21290
|
} catch (err) {
|
|
21044
21291
|
console.error(
|
|
21045
|
-
`${
|
|
21292
|
+
`${TAG34} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
21046
21293
|
);
|
|
21047
21294
|
}
|
|
21048
21295
|
console.log(
|
|
21049
|
-
`${
|
|
21296
|
+
`${TAG34} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
|
|
21050
21297
|
);
|
|
21051
21298
|
return c.json({ personId, grant }, 200);
|
|
21052
21299
|
});
|
|
@@ -21092,8 +21339,8 @@ app45.post("/launch", requireAdminSession, async (c) => {
|
|
|
21092
21339
|
var browser_default = app45;
|
|
21093
21340
|
|
|
21094
21341
|
// server/routes/admin/calendar.ts
|
|
21095
|
-
import { existsSync as
|
|
21096
|
-
import { join as
|
|
21342
|
+
import { existsSync as existsSync31 } from "fs";
|
|
21343
|
+
import { join as join35 } from "path";
|
|
21097
21344
|
|
|
21098
21345
|
// server/lib/calendar-ics.ts
|
|
21099
21346
|
var CRLF = "\r\n";
|
|
@@ -21192,8 +21439,8 @@ function countVEvents(ics) {
|
|
|
21192
21439
|
}
|
|
21193
21440
|
|
|
21194
21441
|
// server/lib/calendar-availability.ts
|
|
21195
|
-
import { readFileSync as
|
|
21196
|
-
import { join as
|
|
21442
|
+
import { readFileSync as readFileSync34 } from "fs";
|
|
21443
|
+
import { join as join34 } from "path";
|
|
21197
21444
|
var AVAILABILITY_FILENAME = "calendar-availability.json";
|
|
21198
21445
|
var REQUIRED_KEYS = [
|
|
21199
21446
|
"timezone",
|
|
@@ -21202,10 +21449,10 @@ var REQUIRED_KEYS = [
|
|
|
21202
21449
|
"weekly"
|
|
21203
21450
|
];
|
|
21204
21451
|
function readAvailabilityConfig(accountDir) {
|
|
21205
|
-
const path3 =
|
|
21452
|
+
const path3 = join34(accountDir, AVAILABILITY_FILENAME);
|
|
21206
21453
|
let raw;
|
|
21207
21454
|
try {
|
|
21208
|
-
raw =
|
|
21455
|
+
raw = readFileSync34(path3, "utf-8");
|
|
21209
21456
|
} catch {
|
|
21210
21457
|
throw new Error(`availability not configured: ${path3} not found`);
|
|
21211
21458
|
}
|
|
@@ -21564,7 +21811,7 @@ app46.get("/booking-link", requireAdminSession, (c) => {
|
|
|
21564
21811
|
console.error('[calendar] op=booking-link-fail err="no account configured"');
|
|
21565
21812
|
return c.json({ bookingDomain: null });
|
|
21566
21813
|
}
|
|
21567
|
-
if (!
|
|
21814
|
+
if (!existsSync31(join35(account.accountDir, AVAILABILITY_FILENAME))) {
|
|
21568
21815
|
console.log("[calendar] op=booking-link bookingDomain=none source=availability-config");
|
|
21569
21816
|
return c.json({ bookingDomain: null });
|
|
21570
21817
|
}
|
|
@@ -21600,7 +21847,7 @@ function toNum(v) {
|
|
|
21600
21847
|
}
|
|
21601
21848
|
|
|
21602
21849
|
// server/routes/admin/tasks-list.ts
|
|
21603
|
-
var
|
|
21850
|
+
var TAG35 = "[task-timer]";
|
|
21604
21851
|
var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
|
|
21605
21852
|
var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
|
|
21606
21853
|
var app47 = new Hono();
|
|
@@ -21608,7 +21855,7 @@ app47.get("/", requireAdminSession, async (c) => {
|
|
|
21608
21855
|
const cacheKey = c.var.cacheKey;
|
|
21609
21856
|
const accountId = getAccountIdForSession(cacheKey);
|
|
21610
21857
|
if (!accountId) {
|
|
21611
|
-
console.error(`${
|
|
21858
|
+
console.error(`${TAG35} op=list auth-rejected reason="no account for session"`);
|
|
21612
21859
|
return c.json({ error: "Account not found for session" }, 401);
|
|
21613
21860
|
}
|
|
21614
21861
|
const session = getSession();
|
|
@@ -21646,10 +21893,10 @@ app47.get("/", requireAdminSession, async (c) => {
|
|
|
21646
21893
|
if (COMPLETED.has(status)) completed.push(row);
|
|
21647
21894
|
else if (!HIDDEN_FROM_OPEN.has(status)) open.push(row);
|
|
21648
21895
|
}
|
|
21649
|
-
console.log(`${
|
|
21896
|
+
console.log(`${TAG35} op=list account=${accountId} open=${open.length} completed=${completed.length}`);
|
|
21650
21897
|
return c.json({ open, completed });
|
|
21651
21898
|
} catch (err) {
|
|
21652
|
-
console.error(`${
|
|
21899
|
+
console.error(`${TAG35} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
21653
21900
|
return c.json({ error: "tasks-list-failed" }, 500);
|
|
21654
21901
|
} finally {
|
|
21655
21902
|
await session.close();
|
|
@@ -21659,7 +21906,7 @@ var tasks_list_default = app47;
|
|
|
21659
21906
|
|
|
21660
21907
|
// server/routes/admin/task-timer-start.ts
|
|
21661
21908
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
21662
|
-
var
|
|
21909
|
+
var TAG36 = "[task-timer]";
|
|
21663
21910
|
var app48 = new Hono();
|
|
21664
21911
|
app48.post("/", requireAdminSession, async (c) => {
|
|
21665
21912
|
const cacheKey = c.var.cacheKey;
|
|
@@ -21681,7 +21928,7 @@ app48.post("/", requireAdminSession, async (c) => {
|
|
|
21681
21928
|
{ taskId, accountId }
|
|
21682
21929
|
);
|
|
21683
21930
|
if (target.records.length === 0) {
|
|
21684
|
-
console.error(`${
|
|
21931
|
+
console.error(`${TAG36} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
|
|
21685
21932
|
return c.json({ error: "task-not-found" }, 404);
|
|
21686
21933
|
}
|
|
21687
21934
|
const open = await session.run(
|
|
@@ -21693,7 +21940,7 @@ app48.post("/", requireAdminSession, async (c) => {
|
|
|
21693
21940
|
const priorEntryId = open.records[0]?.get("entryId");
|
|
21694
21941
|
const priorStartedAt = open.records[0]?.get("startedAt");
|
|
21695
21942
|
if (priorEntryId) {
|
|
21696
|
-
console.log(`${
|
|
21943
|
+
console.log(`${TAG36} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
|
|
21697
21944
|
return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
|
|
21698
21945
|
}
|
|
21699
21946
|
const entryId = randomUUID14();
|
|
@@ -21703,10 +21950,10 @@ app48.post("/", requireAdminSession, async (c) => {
|
|
|
21703
21950
|
CREATE (te)-[:LOGGED_AGAINST]->(t)`,
|
|
21704
21951
|
{ taskId, accountId, entryId, now }
|
|
21705
21952
|
);
|
|
21706
|
-
console.log(`${
|
|
21953
|
+
console.log(`${TAG36} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
|
|
21707
21954
|
return c.json({ ok: true, running: true, entryId, startedAt: now });
|
|
21708
21955
|
} catch (err) {
|
|
21709
|
-
console.error(`${
|
|
21956
|
+
console.error(`${TAG36} op=start error="${err instanceof Error ? err.message : String(err)}"`);
|
|
21710
21957
|
return c.json({ error: "task-timer-start-failed" }, 500);
|
|
21711
21958
|
} finally {
|
|
21712
21959
|
await session.close();
|
|
@@ -21716,7 +21963,7 @@ var task_timer_start_default = app48;
|
|
|
21716
21963
|
|
|
21717
21964
|
// server/routes/admin/task-timer-stop.ts
|
|
21718
21965
|
import neo4j5 from "neo4j-driver";
|
|
21719
|
-
var
|
|
21966
|
+
var TAG37 = "[task-timer]";
|
|
21720
21967
|
var app49 = new Hono();
|
|
21721
21968
|
app49.post("/", requireAdminSession, async (c) => {
|
|
21722
21969
|
const cacheKey = c.var.cacheKey;
|
|
@@ -21748,7 +21995,7 @@ app49.post("/", requireAdminSession, async (c) => {
|
|
|
21748
21995
|
{ taskId, accountId }
|
|
21749
21996
|
);
|
|
21750
21997
|
const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
|
|
21751
|
-
console.log(`${
|
|
21998
|
+
console.log(`${TAG37} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
|
|
21752
21999
|
return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
|
|
21753
22000
|
}
|
|
21754
22001
|
const seconds = secondsBetween(startedAt, now);
|
|
@@ -21771,11 +22018,11 @@ app49.post("/", requireAdminSession, async (c) => {
|
|
|
21771
22018
|
const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
|
|
21772
22019
|
const sumAdjustments = toNum(verify.records[0]?.get("sumAdjustments"));
|
|
21773
22020
|
const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
|
|
21774
|
-
console.log(`${
|
|
21775
|
-
console.log(`${
|
|
22021
|
+
console.log(`${TAG37} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
|
|
22022
|
+
console.log(`${TAG37} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
|
|
21776
22023
|
return c.json({ ok: true, running: false, seconds, secondsLogged });
|
|
21777
22024
|
} catch (err) {
|
|
21778
|
-
console.error(`${
|
|
22025
|
+
console.error(`${TAG37} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
|
|
21779
22026
|
return c.json({ error: "task-timer-stop-failed" }, 500);
|
|
21780
22027
|
} finally {
|
|
21781
22028
|
await session.close();
|
|
@@ -21784,7 +22031,7 @@ app49.post("/", requireAdminSession, async (c) => {
|
|
|
21784
22031
|
var task_timer_stop_default = app49;
|
|
21785
22032
|
|
|
21786
22033
|
// server/routes/admin/task-complete.ts
|
|
21787
|
-
var
|
|
22034
|
+
var TAG38 = "[task-timer]";
|
|
21788
22035
|
var app50 = new Hono();
|
|
21789
22036
|
app50.post("/", requireAdminSession, async (c) => {
|
|
21790
22037
|
const cacheKey = c.var.cacheKey;
|
|
@@ -21811,10 +22058,10 @@ app50.post("/", requireAdminSession, async (c) => {
|
|
|
21811
22058
|
return c.json({ error: "task-not-found" }, 404);
|
|
21812
22059
|
}
|
|
21813
22060
|
const secondsLogged = toNum(result.records[0].get("secondsLogged"));
|
|
21814
|
-
console.log(`${
|
|
22061
|
+
console.log(`${TAG38} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
|
|
21815
22062
|
return c.json({ ok: true, status: "completed", secondsLogged });
|
|
21816
22063
|
} catch (err) {
|
|
21817
|
-
console.error(`${
|
|
22064
|
+
console.error(`${TAG38} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
|
|
21818
22065
|
return c.json({ error: "task-complete-failed" }, 500);
|
|
21819
22066
|
} finally {
|
|
21820
22067
|
await session.close();
|
|
@@ -21825,7 +22072,7 @@ var task_complete_default = app50;
|
|
|
21825
22072
|
// server/routes/admin/task-time-adjust.ts
|
|
21826
22073
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
21827
22074
|
import neo4j6 from "neo4j-driver";
|
|
21828
|
-
var
|
|
22075
|
+
var TAG39 = "[task-time-adjust]";
|
|
21829
22076
|
var app51 = new Hono();
|
|
21830
22077
|
app51.post("/", requireAdminSession, async (c) => {
|
|
21831
22078
|
const cacheKey = c.var.cacheKey;
|
|
@@ -21835,22 +22082,22 @@ app51.post("/", requireAdminSession, async (c) => {
|
|
|
21835
22082
|
try {
|
|
21836
22083
|
body = await c.req.json();
|
|
21837
22084
|
} catch {
|
|
21838
|
-
console.error(`${
|
|
22085
|
+
console.error(`${TAG39} op=reject reason=bad-json`);
|
|
21839
22086
|
return c.json({ error: "invalid-json" }, 400);
|
|
21840
22087
|
}
|
|
21841
22088
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
21842
22089
|
if (!taskId) {
|
|
21843
|
-
console.error(`${
|
|
22090
|
+
console.error(`${TAG39} op=reject reason=no-task`);
|
|
21844
22091
|
return c.json({ error: "taskId required" }, 400);
|
|
21845
22092
|
}
|
|
21846
22093
|
const newSeconds = body.newSeconds;
|
|
21847
22094
|
if (typeof newSeconds !== "number" || !Number.isInteger(newSeconds) || newSeconds < 0) {
|
|
21848
|
-
console.error(`${
|
|
22095
|
+
console.error(`${TAG39} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
|
|
21849
22096
|
return c.json({ error: "newSeconds must be a non-negative integer" }, 400);
|
|
21850
22097
|
}
|
|
21851
22098
|
const adjustmentId = randomUUID15();
|
|
21852
22099
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21853
|
-
console.log(`${
|
|
22100
|
+
console.log(`${TAG39} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
|
|
21854
22101
|
const session = getSession();
|
|
21855
22102
|
try {
|
|
21856
22103
|
const guard = await session.run(
|
|
@@ -21860,12 +22107,12 @@ app51.post("/", requireAdminSession, async (c) => {
|
|
|
21860
22107
|
{ taskId, accountId }
|
|
21861
22108
|
);
|
|
21862
22109
|
if (guard.records.length === 0) {
|
|
21863
|
-
console.error(`${
|
|
22110
|
+
console.error(`${TAG39} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
|
|
21864
22111
|
return c.json({ error: "task-not-found" }, 404);
|
|
21865
22112
|
}
|
|
21866
22113
|
const openCount = toNum(guard.records[0].get("openCount"));
|
|
21867
22114
|
if (openCount > 0) {
|
|
21868
|
-
console.error(`${
|
|
22115
|
+
console.error(`${TAG39} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
|
|
21869
22116
|
return c.json({ error: "task-timer-running" }, 409);
|
|
21870
22117
|
}
|
|
21871
22118
|
const previousSeconds = toNum(guard.records[0].get("previousSeconds"));
|
|
@@ -21891,10 +22138,10 @@ app51.post("/", requireAdminSession, async (c) => {
|
|
|
21891
22138
|
}
|
|
21892
22139
|
);
|
|
21893
22140
|
const secondsLoggedAfter = toNum(write.records[0]?.get("secondsLoggedAfter"));
|
|
21894
|
-
console.log(`${
|
|
22141
|
+
console.log(`${TAG39} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
|
|
21895
22142
|
return c.json({ ok: true, secondsLogged: secondsLoggedAfter });
|
|
21896
22143
|
} catch (err) {
|
|
21897
|
-
console.error(`${
|
|
22144
|
+
console.error(`${TAG39} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
21898
22145
|
return c.json({ error: "task-time-adjust-failed" }, 500);
|
|
21899
22146
|
} finally {
|
|
21900
22147
|
await session.close();
|
|
@@ -21948,7 +22195,7 @@ app52.route("/task-time-adjust", task_time_adjust_default);
|
|
|
21948
22195
|
var admin_default = app52;
|
|
21949
22196
|
|
|
21950
22197
|
// server/routes/access/verify-token.ts
|
|
21951
|
-
var
|
|
22198
|
+
var TAG40 = "[access-verify]";
|
|
21952
22199
|
var MINT_TAG = "[access-session-mint]";
|
|
21953
22200
|
var COOKIE_NAME = "__access_session";
|
|
21954
22201
|
var app53 = new Hono();
|
|
@@ -21967,39 +22214,39 @@ app53.post("/", async (c) => {
|
|
|
21967
22214
|
}
|
|
21968
22215
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
21969
22216
|
if (rateMsg) {
|
|
21970
|
-
console.error(`${
|
|
22217
|
+
console.error(`${TAG40} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
21971
22218
|
return c.json({ error: rateMsg }, 429);
|
|
21972
22219
|
}
|
|
21973
22220
|
const grant = await findGrantByMagicToken(token);
|
|
21974
22221
|
if (!grant) {
|
|
21975
22222
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
21976
|
-
console.error(`${
|
|
22223
|
+
console.error(`${TAG40} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
21977
22224
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
21978
22225
|
}
|
|
21979
22226
|
if (grant.agentSlug !== agentSlug) {
|
|
21980
22227
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
21981
22228
|
console.error(
|
|
21982
|
-
`${
|
|
22229
|
+
`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
21983
22230
|
);
|
|
21984
22231
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
21985
22232
|
}
|
|
21986
22233
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
21987
22234
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
21988
22235
|
console.error(
|
|
21989
|
-
`${
|
|
22236
|
+
`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
21990
22237
|
);
|
|
21991
22238
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
21992
22239
|
}
|
|
21993
22240
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
21994
22241
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
21995
22242
|
console.error(
|
|
21996
|
-
`${
|
|
22243
|
+
`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
21997
22244
|
);
|
|
21998
22245
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
21999
22246
|
}
|
|
22000
22247
|
if (!grant.sliceToken) {
|
|
22001
22248
|
console.error(
|
|
22002
|
-
`${
|
|
22249
|
+
`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
22003
22250
|
);
|
|
22004
22251
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
22005
22252
|
}
|
|
@@ -22015,12 +22262,12 @@ app53.post("/", async (c) => {
|
|
|
22015
22262
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
22016
22263
|
} catch (err) {
|
|
22017
22264
|
console.error(
|
|
22018
|
-
`${
|
|
22265
|
+
`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
22019
22266
|
);
|
|
22020
22267
|
return c.json({ error: "verification-failed" }, 500);
|
|
22021
22268
|
}
|
|
22022
22269
|
clearAccessRateLimit(ip, agentSlug);
|
|
22023
|
-
console.log(`${
|
|
22270
|
+
console.log(`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
22024
22271
|
console.log(
|
|
22025
22272
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
22026
22273
|
);
|
|
@@ -22096,7 +22343,7 @@ async function sendMagicLinkEmail(payload) {
|
|
|
22096
22343
|
}
|
|
22097
22344
|
|
|
22098
22345
|
// server/routes/access/request-magic-link.ts
|
|
22099
|
-
var
|
|
22346
|
+
var TAG41 = "[access-request-link]";
|
|
22100
22347
|
var app54 = new Hono();
|
|
22101
22348
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
22102
22349
|
app54.post("/", async (c) => {
|
|
@@ -22113,18 +22360,18 @@ app54.post("/", async (c) => {
|
|
|
22113
22360
|
}
|
|
22114
22361
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
22115
22362
|
if (rateMsg) {
|
|
22116
|
-
console.error(`${
|
|
22363
|
+
console.error(`${TAG41} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
22117
22364
|
return c.json({ error: rateMsg }, 429);
|
|
22118
22365
|
}
|
|
22119
22366
|
recordRequestLinkAttempt(contactValue);
|
|
22120
22367
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
22121
22368
|
if (!accountId) {
|
|
22122
|
-
console.error(`${
|
|
22369
|
+
console.error(`${TAG41} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
22123
22370
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
22124
22371
|
}
|
|
22125
22372
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
22126
22373
|
if (!grant) {
|
|
22127
|
-
console.log(`${
|
|
22374
|
+
console.log(`${TAG41} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
22128
22375
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
22129
22376
|
}
|
|
22130
22377
|
let token;
|
|
@@ -22132,7 +22379,7 @@ app54.post("/", async (c) => {
|
|
|
22132
22379
|
token = await generateNewMagicToken(grant.grantId);
|
|
22133
22380
|
} catch (err) {
|
|
22134
22381
|
console.error(
|
|
22135
|
-
`${
|
|
22382
|
+
`${TAG41} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
22136
22383
|
);
|
|
22137
22384
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
22138
22385
|
}
|
|
@@ -22164,12 +22411,12 @@ app54.post("/", async (c) => {
|
|
|
22164
22411
|
});
|
|
22165
22412
|
if (!sendResult.ok) {
|
|
22166
22413
|
console.error(
|
|
22167
|
-
`${
|
|
22414
|
+
`${TAG41} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
22168
22415
|
);
|
|
22169
22416
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
22170
22417
|
}
|
|
22171
22418
|
console.log(
|
|
22172
|
-
`${
|
|
22419
|
+
`${TAG41} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
22173
22420
|
);
|
|
22174
22421
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
22175
22422
|
});
|
|
@@ -22182,7 +22429,7 @@ app55.route("/request-magic-link", request_magic_link_default);
|
|
|
22182
22429
|
var access_default = app55;
|
|
22183
22430
|
|
|
22184
22431
|
// server/routes/sites.ts
|
|
22185
|
-
import { existsSync as
|
|
22432
|
+
import { existsSync as existsSync32, readFileSync as readFileSync35, realpathSync as realpathSync7, statSync as statSync12 } from "fs";
|
|
22186
22433
|
import { resolve as resolve28 } from "path";
|
|
22187
22434
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
22188
22435
|
var MIME = {
|
|
@@ -22248,7 +22495,7 @@ app56.get("/:rel{.*}", (c) => {
|
|
|
22248
22495
|
}
|
|
22249
22496
|
let stat8;
|
|
22250
22497
|
try {
|
|
22251
|
-
stat8 =
|
|
22498
|
+
stat8 = existsSync32(filePath) ? statSync12(filePath) : null;
|
|
22252
22499
|
} catch {
|
|
22253
22500
|
stat8 = null;
|
|
22254
22501
|
}
|
|
@@ -22267,7 +22514,7 @@ app56.get("/:rel{.*}", (c) => {
|
|
|
22267
22514
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
22268
22515
|
return c.text("Forbidden", 403);
|
|
22269
22516
|
}
|
|
22270
|
-
if (!
|
|
22517
|
+
if (!existsSync32(filePath)) {
|
|
22271
22518
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
22272
22519
|
return c.text("Not found", 404);
|
|
22273
22520
|
}
|
|
@@ -22286,7 +22533,7 @@ app56.get("/:rel{.*}", (c) => {
|
|
|
22286
22533
|
}
|
|
22287
22534
|
let body;
|
|
22288
22535
|
try {
|
|
22289
|
-
body =
|
|
22536
|
+
body = readFileSync35(realPath);
|
|
22290
22537
|
} catch (err) {
|
|
22291
22538
|
const code = err?.code;
|
|
22292
22539
|
if (code === "EISDIR") {
|
|
@@ -22321,8 +22568,8 @@ app56.get("/:rel{.*}", (c) => {
|
|
|
22321
22568
|
var sites_default = app56;
|
|
22322
22569
|
|
|
22323
22570
|
// app/lib/visitor-token.ts
|
|
22324
|
-
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
22325
|
-
import { mkdirSync as
|
|
22571
|
+
import { createHmac, randomBytes as randomBytes2, timingSafeEqual } from "crypto";
|
|
22572
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync36, writeFileSync as writeFileSync12 } from "fs";
|
|
22326
22573
|
import { dirname as dirname12 } from "path";
|
|
22327
22574
|
var TOKEN_PREFIX = "v1.";
|
|
22328
22575
|
var SECRET_BYTES = 32;
|
|
@@ -22331,21 +22578,21 @@ var cachedSecret = null;
|
|
|
22331
22578
|
function getSecret() {
|
|
22332
22579
|
if (cachedSecret) return cachedSecret;
|
|
22333
22580
|
try {
|
|
22334
|
-
const hex2 =
|
|
22581
|
+
const hex2 = readFileSync36(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
22335
22582
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
22336
22583
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
22337
22584
|
return cachedSecret;
|
|
22338
22585
|
}
|
|
22339
22586
|
} catch {
|
|
22340
22587
|
}
|
|
22341
|
-
const fresh =
|
|
22588
|
+
const fresh = randomBytes2(SECRET_BYTES).toString("hex");
|
|
22342
22589
|
try {
|
|
22343
|
-
|
|
22344
|
-
|
|
22590
|
+
mkdirSync8(dirname12(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
22591
|
+
writeFileSync12(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
22345
22592
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
22346
22593
|
} catch {
|
|
22347
22594
|
}
|
|
22348
|
-
const hex =
|
|
22595
|
+
const hex = readFileSync36(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
22349
22596
|
cachedSecret = Buffer.from(hex, "hex");
|
|
22350
22597
|
return cachedSecret;
|
|
22351
22598
|
}
|
|
@@ -22398,8 +22645,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
22398
22645
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
22399
22646
|
|
|
22400
22647
|
// app/lib/brand-config.ts
|
|
22401
|
-
import { existsSync as
|
|
22402
|
-
import { join as
|
|
22648
|
+
import { existsSync as existsSync33, readFileSync as readFileSync37 } from "fs";
|
|
22649
|
+
import { join as join36 } from "path";
|
|
22403
22650
|
var cached2 = null;
|
|
22404
22651
|
var cachedAttempted = false;
|
|
22405
22652
|
function readBrandConfig() {
|
|
@@ -22407,10 +22654,10 @@ function readBrandConfig() {
|
|
|
22407
22654
|
cachedAttempted = true;
|
|
22408
22655
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
|
|
22409
22656
|
if (!platformRoot5) return null;
|
|
22410
|
-
const brandPath =
|
|
22411
|
-
if (!
|
|
22657
|
+
const brandPath = join36(platformRoot5, "config", "brand.json");
|
|
22658
|
+
if (!existsSync33(brandPath)) return null;
|
|
22412
22659
|
try {
|
|
22413
|
-
cached2 = JSON.parse(
|
|
22660
|
+
cached2 = JSON.parse(readFileSync37(brandPath, "utf-8"));
|
|
22414
22661
|
return cached2;
|
|
22415
22662
|
} catch {
|
|
22416
22663
|
return null;
|
|
@@ -22899,13 +23146,13 @@ var visitor_event_default = app59;
|
|
|
22899
23146
|
|
|
22900
23147
|
// server/routes/session.ts
|
|
22901
23148
|
import { resolve as resolve29 } from "path";
|
|
22902
|
-
import { existsSync as
|
|
23149
|
+
import { existsSync as existsSync34, writeFileSync as writeFileSync13, mkdirSync as mkdirSync9 } from "fs";
|
|
22903
23150
|
var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
22904
23151
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
22905
23152
|
try {
|
|
22906
23153
|
const cacheDir = resolve29(MAXY_DIR, "branding-cache", accountId);
|
|
22907
|
-
|
|
22908
|
-
|
|
23154
|
+
mkdirSync9(cacheDir, { recursive: true });
|
|
23155
|
+
writeFileSync13(resolve29(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
22909
23156
|
} catch (err) {
|
|
22910
23157
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
22911
23158
|
}
|
|
@@ -22983,7 +23230,7 @@ app60.post("/", async (c) => {
|
|
|
22983
23230
|
let agentConfig = null;
|
|
22984
23231
|
if (account) {
|
|
22985
23232
|
const agentDir = resolve29(account.accountDir, "agents", agentSlug);
|
|
22986
|
-
if (!
|
|
23233
|
+
if (!existsSync34(agentDir) || !existsSync34(resolve29(agentDir, "config.json"))) {
|
|
22987
23234
|
return c.json({ error: "Agent not found" }, 404);
|
|
22988
23235
|
}
|
|
22989
23236
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -23231,7 +23478,7 @@ app61.get("/free-busy", async (c) => {
|
|
|
23231
23478
|
var calendar_public_default = app61;
|
|
23232
23479
|
|
|
23233
23480
|
// app/lib/timeentry-census.ts
|
|
23234
|
-
var
|
|
23481
|
+
var TAG42 = "[timeentry-census]";
|
|
23235
23482
|
function reconcileTimeEntries(rows, now, horizonMs) {
|
|
23236
23483
|
const openEntries = rows.openEntries.length;
|
|
23237
23484
|
let oldestOpenAgeMs = 0;
|
|
@@ -23271,12 +23518,12 @@ async function runTimeEntryCensusOnce(session, now, horizonMs) {
|
|
|
23271
23518
|
sumAdjustments: toNum(r.get("sumAdjustments"))
|
|
23272
23519
|
}));
|
|
23273
23520
|
const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
|
|
23274
|
-
const line = `${
|
|
23521
|
+
const line = `${TAG42} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
|
|
23275
23522
|
if (finding.alarm) console.error(`${line} alarm=true`);
|
|
23276
23523
|
else console.log(line);
|
|
23277
23524
|
return finding;
|
|
23278
23525
|
} catch (err) {
|
|
23279
|
-
console.error(`${
|
|
23526
|
+
console.error(`${TAG42} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
23280
23527
|
return null;
|
|
23281
23528
|
}
|
|
23282
23529
|
}
|
|
@@ -23290,13 +23537,13 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
23290
23537
|
try {
|
|
23291
23538
|
session = openSession();
|
|
23292
23539
|
} catch (err) {
|
|
23293
|
-
console.error(`${
|
|
23540
|
+
console.error(`${TAG42} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
23294
23541
|
return;
|
|
23295
23542
|
}
|
|
23296
23543
|
try {
|
|
23297
23544
|
await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
|
|
23298
23545
|
} catch (err) {
|
|
23299
|
-
console.error(`${
|
|
23546
|
+
console.error(`${TAG42} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
23300
23547
|
} finally {
|
|
23301
23548
|
try {
|
|
23302
23549
|
await session.close();
|
|
@@ -23659,8 +23906,8 @@ async function migrateUploads(opts = {}) {
|
|
|
23659
23906
|
|
|
23660
23907
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
23661
23908
|
import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as writeFile4, unlink as unlink3 } from "fs/promises";
|
|
23662
|
-
import { existsSync as
|
|
23663
|
-
import { join as
|
|
23909
|
+
import { existsSync as existsSync35 } from "fs";
|
|
23910
|
+
import { join as join37 } from "path";
|
|
23664
23911
|
var ADMIN_ROLE2 = "admin";
|
|
23665
23912
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
23666
23913
|
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;
|
|
@@ -23689,7 +23936,7 @@ async function writeRaw(path3, obj) {
|
|
|
23689
23936
|
await rename3(tmp, path3);
|
|
23690
23937
|
} catch (err) {
|
|
23691
23938
|
try {
|
|
23692
|
-
if (
|
|
23939
|
+
if (existsSync35(tmp)) await unlink3(tmp);
|
|
23693
23940
|
} catch {
|
|
23694
23941
|
}
|
|
23695
23942
|
throw err;
|
|
@@ -23705,7 +23952,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
23705
23952
|
}
|
|
23706
23953
|
for (const slug of slugs) {
|
|
23707
23954
|
if (!slug.isDirectory()) continue;
|
|
23708
|
-
const slugDir =
|
|
23955
|
+
const slugDir = join37(projectsRoot, slug.name);
|
|
23709
23956
|
let entries;
|
|
23710
23957
|
try {
|
|
23711
23958
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -23714,9 +23961,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
23714
23961
|
}
|
|
23715
23962
|
for (const entry of entries) {
|
|
23716
23963
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
23717
|
-
out.push(
|
|
23964
|
+
out.push(join37(slugDir, entry.name));
|
|
23718
23965
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
23719
|
-
const subDir =
|
|
23966
|
+
const subDir = join37(slugDir, entry.name);
|
|
23720
23967
|
let subs;
|
|
23721
23968
|
try {
|
|
23722
23969
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -23724,7 +23971,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
23724
23971
|
continue;
|
|
23725
23972
|
}
|
|
23726
23973
|
for (const s of subs) {
|
|
23727
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
23974
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join37(subDir, s.name));
|
|
23728
23975
|
}
|
|
23729
23976
|
}
|
|
23730
23977
|
}
|
|
@@ -23736,7 +23983,7 @@ function shortId(path3) {
|
|
|
23736
23983
|
return base.slice(0, 8);
|
|
23737
23984
|
}
|
|
23738
23985
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
23739
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
23986
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join37(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
23740
23987
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
23741
23988
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
23742
23989
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -25404,14 +25651,14 @@ function makeFileDelivery(opts) {
|
|
|
25404
25651
|
}
|
|
25405
25652
|
|
|
25406
25653
|
// app/lib/webchat/file-delivery.ts
|
|
25407
|
-
var
|
|
25654
|
+
var TAG43 = "[webchat-adaptor]";
|
|
25408
25655
|
function platformRoot2() {
|
|
25409
25656
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
25410
25657
|
}
|
|
25411
25658
|
function makeWebchatSendFile(entry) {
|
|
25412
25659
|
return async (filePath) => {
|
|
25413
25660
|
if (!entry.accountId) {
|
|
25414
|
-
console.error(`${
|
|
25661
|
+
console.error(`${TAG43} file-delivery reject reason=no-account sender=${entry.senderId}`);
|
|
25415
25662
|
return { ok: false, error: "no-account" };
|
|
25416
25663
|
}
|
|
25417
25664
|
const accountDir = resolve32(platformRoot2(), "..", "data/accounts", entry.accountId);
|
|
@@ -25419,14 +25666,14 @@ function makeWebchatSendFile(entry) {
|
|
|
25419
25666
|
const resolved = realpathSync8(filePath);
|
|
25420
25667
|
const accountResolved = realpathSync8(accountDir);
|
|
25421
25668
|
if (!resolved.startsWith(accountResolved + "/")) {
|
|
25422
|
-
console.error(`${
|
|
25669
|
+
console.error(`${TAG43} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
|
|
25423
25670
|
return { ok: false, error: "outside-account" };
|
|
25424
25671
|
}
|
|
25425
25672
|
return { ok: true };
|
|
25426
25673
|
} catch (err) {
|
|
25427
25674
|
const code = err.code;
|
|
25428
25675
|
console.error(
|
|
25429
|
-
`${
|
|
25676
|
+
`${TAG43} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
|
|
25430
25677
|
);
|
|
25431
25678
|
return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
|
|
25432
25679
|
}
|
|
@@ -25435,7 +25682,7 @@ function makeWebchatSendFile(entry) {
|
|
|
25435
25682
|
function makeWebchatFileDelivery(entry) {
|
|
25436
25683
|
return makeFileDelivery({
|
|
25437
25684
|
entry,
|
|
25438
|
-
tag:
|
|
25685
|
+
tag: TAG43,
|
|
25439
25686
|
channel: "webchat",
|
|
25440
25687
|
sendFile: makeWebchatSendFile(entry),
|
|
25441
25688
|
deferUntilVerdict: true
|
|
@@ -25497,7 +25744,7 @@ function buildPublicWebchatSpawnRequest(input) {
|
|
|
25497
25744
|
}
|
|
25498
25745
|
|
|
25499
25746
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
25500
|
-
var
|
|
25747
|
+
var TAG44 = "[whatsapp-adaptor]";
|
|
25501
25748
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
25502
25749
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
25503
25750
|
function platformRoot3() {
|
|
@@ -25515,7 +25762,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
25515
25762
|
});
|
|
25516
25763
|
if (result.ok) return { ok: true };
|
|
25517
25764
|
console.error(
|
|
25518
|
-
`${
|
|
25765
|
+
`${TAG44} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
25519
25766
|
);
|
|
25520
25767
|
return { ok: false, error: result.error };
|
|
25521
25768
|
};
|
|
@@ -25523,7 +25770,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
25523
25770
|
function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
25524
25771
|
const shared = makeFileDelivery({
|
|
25525
25772
|
entry,
|
|
25526
|
-
tag:
|
|
25773
|
+
tag: TAG44,
|
|
25527
25774
|
channel: "whatsapp",
|
|
25528
25775
|
sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
|
|
25529
25776
|
});
|
|
@@ -25558,7 +25805,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
|
25558
25805
|
if (!delivered) {
|
|
25559
25806
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
25560
25807
|
console.error(
|
|
25561
|
-
`${
|
|
25808
|
+
`${TAG44} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
25562
25809
|
);
|
|
25563
25810
|
}
|
|
25564
25811
|
}
|
|
@@ -25590,20 +25837,29 @@ function startNativeFileFollower(input) {
|
|
|
25590
25837
|
};
|
|
25591
25838
|
const sid = input.senderId.slice(0, 8);
|
|
25592
25839
|
let lastComposingAt = Number.NEGATIVE_INFINITY;
|
|
25840
|
+
const presenceSock = (state) => {
|
|
25841
|
+
const res = resolveSocket(input.accountId);
|
|
25842
|
+
if (!res.ok) {
|
|
25843
|
+
console.error(
|
|
25844
|
+
`[whatsapp-adaptor] op=presence state=${state} sender=${sid} ok=false reason=${formatSocketResolutionReason(res)}`
|
|
25845
|
+
);
|
|
25846
|
+
return null;
|
|
25847
|
+
}
|
|
25848
|
+
console.error(`[whatsapp-adaptor] op=presence state=${state} sender=${sid}`);
|
|
25849
|
+
return res.sock;
|
|
25850
|
+
};
|
|
25593
25851
|
const onActivity = () => {
|
|
25594
25852
|
const now = Date.now();
|
|
25595
25853
|
if (now - lastComposingAt < COMPOSING_REFRESH_MS) return;
|
|
25596
25854
|
lastComposingAt = now;
|
|
25597
|
-
const sock =
|
|
25855
|
+
const sock = presenceSock("composing");
|
|
25598
25856
|
if (!sock) return;
|
|
25599
|
-
console.error(`[whatsapp-adaptor] op=presence state=composing sender=${sid}`);
|
|
25600
25857
|
void sendComposing(sock, input.senderId);
|
|
25601
25858
|
};
|
|
25602
25859
|
const onTurnComplete = () => {
|
|
25603
25860
|
lastComposingAt = Number.NEGATIVE_INFINITY;
|
|
25604
|
-
const sock =
|
|
25861
|
+
const sock = presenceSock("paused");
|
|
25605
25862
|
if (!sock) return;
|
|
25606
|
-
console.error(`[whatsapp-adaptor] op=presence state=paused sender=${sid}`);
|
|
25607
25863
|
void sendPaused(sock, input.senderId);
|
|
25608
25864
|
};
|
|
25609
25865
|
return startFollower({
|
|
@@ -25953,7 +26209,7 @@ function buildTelegramSpawnRequest(input) {
|
|
|
25953
26209
|
import { realpathSync as realpathSync9 } from "fs";
|
|
25954
26210
|
import { readFile as readFile7, stat as stat7 } from "fs/promises";
|
|
25955
26211
|
import { resolve as resolve33, basename as basename11 } from "path";
|
|
25956
|
-
var
|
|
26212
|
+
var TAG45 = "[telegram:outbound]";
|
|
25957
26213
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
25958
26214
|
async function sendTelegramDocument(input) {
|
|
25959
26215
|
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
|
|
@@ -25969,16 +26225,16 @@ async function sendTelegramDocument(input) {
|
|
|
25969
26225
|
resolvedPath = realpathSync9(filePath);
|
|
25970
26226
|
const accountResolved = realpathSync9(accountDir);
|
|
25971
26227
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
25972
|
-
console.error(`${
|
|
26228
|
+
console.error(`${TAG45} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
25973
26229
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
25974
26230
|
}
|
|
25975
26231
|
} catch (err) {
|
|
25976
26232
|
const code = err.code;
|
|
25977
26233
|
if (code === "ENOENT") {
|
|
25978
|
-
console.error(`${
|
|
26234
|
+
console.error(`${TAG45} document ENOENT path=${filePath}`);
|
|
25979
26235
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
25980
26236
|
}
|
|
25981
|
-
console.error(`${
|
|
26237
|
+
console.error(`${TAG45} document path error: ${String(err)}`);
|
|
25982
26238
|
return { ok: false, status: 500, error: String(err) };
|
|
25983
26239
|
}
|
|
25984
26240
|
const fileStat = await stat7(resolvedPath);
|
|
@@ -26011,13 +26267,13 @@ async function sendTelegramDocument(input) {
|
|
|
26011
26267
|
error = e instanceof Error ? e.message : String(e);
|
|
26012
26268
|
}
|
|
26013
26269
|
console.error(
|
|
26014
|
-
`${
|
|
26270
|
+
`${TAG45} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
26015
26271
|
);
|
|
26016
26272
|
return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
26017
26273
|
}
|
|
26018
26274
|
|
|
26019
26275
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
26020
|
-
var
|
|
26276
|
+
var TAG46 = "[telegram:outbound]";
|
|
26021
26277
|
function platformRoot4() {
|
|
26022
26278
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
26023
26279
|
}
|
|
@@ -26029,11 +26285,11 @@ function makeTelegramSendFile(entry) {
|
|
|
26029
26285
|
botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
|
|
26030
26286
|
}
|
|
26031
26287
|
if (!botToken) {
|
|
26032
|
-
console.error(`${
|
|
26288
|
+
console.error(`${TAG46} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
|
|
26033
26289
|
return { ok: false, error: "no-bot-token" };
|
|
26034
26290
|
}
|
|
26035
26291
|
if (entry.replyTarget == null) {
|
|
26036
|
-
console.error(`${
|
|
26292
|
+
console.error(`${TAG46} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
26037
26293
|
return { ok: false, error: "no-reply-target" };
|
|
26038
26294
|
}
|
|
26039
26295
|
const result = await sendTelegramDocument({
|
|
@@ -26050,7 +26306,7 @@ function makeTelegramSendFile(entry) {
|
|
|
26050
26306
|
function makeTelegramFileDelivery(entry) {
|
|
26051
26307
|
return makeFileDelivery({
|
|
26052
26308
|
entry,
|
|
26053
|
-
tag:
|
|
26309
|
+
tag: TAG46,
|
|
26054
26310
|
channel: "telegram",
|
|
26055
26311
|
sendFile: makeTelegramSendFile(entry)
|
|
26056
26312
|
});
|
|
@@ -26090,17 +26346,17 @@ function startTelegramNativeFileFollower(input) {
|
|
|
26090
26346
|
}
|
|
26091
26347
|
|
|
26092
26348
|
// server/telegram-descriptor.ts
|
|
26093
|
-
import { resolve as resolve34, join as
|
|
26349
|
+
import { resolve as resolve34, join as join38 } from "path";
|
|
26094
26350
|
function telegramGatewayUrl() {
|
|
26095
26351
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
26096
26352
|
}
|
|
26097
26353
|
function telegramServerPath() {
|
|
26098
|
-
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve34(process.env.MAXY_PLATFORM_ROOT ??
|
|
26354
|
+
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve34(process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, ".."), "services/telegram-channel/dist/server.js");
|
|
26099
26355
|
}
|
|
26100
26356
|
|
|
26101
26357
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
26102
26358
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
26103
|
-
var
|
|
26359
|
+
var TAG47 = "[public-session-review]";
|
|
26104
26360
|
var CONSUMED_CAP = 500;
|
|
26105
26361
|
var consumed = /* @__PURE__ */ new Set();
|
|
26106
26362
|
function consumeOnce(sessionId) {
|
|
@@ -26127,7 +26383,7 @@ async function fetchJsonl(sessionId) {
|
|
|
26127
26383
|
return await res.text();
|
|
26128
26384
|
} catch (err) {
|
|
26129
26385
|
console.error(
|
|
26130
|
-
`${
|
|
26386
|
+
`${TAG47} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
26131
26387
|
);
|
|
26132
26388
|
return null;
|
|
26133
26389
|
}
|
|
@@ -26151,7 +26407,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
26151
26407
|
const res = await fetch(url);
|
|
26152
26408
|
if (!res.ok) {
|
|
26153
26409
|
console.error(
|
|
26154
|
-
`${
|
|
26410
|
+
`${TAG47} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
26155
26411
|
);
|
|
26156
26412
|
return [];
|
|
26157
26413
|
}
|
|
@@ -26159,7 +26415,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
26159
26415
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
26160
26416
|
} catch (err) {
|
|
26161
26417
|
console.error(
|
|
26162
|
-
`${
|
|
26418
|
+
`${TAG47} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
26163
26419
|
);
|
|
26164
26420
|
return [];
|
|
26165
26421
|
}
|
|
@@ -26188,7 +26444,7 @@ function composeInitialMessage(input) {
|
|
|
26188
26444
|
}
|
|
26189
26445
|
async function dispatchReviewer(input, initialMessage) {
|
|
26190
26446
|
const sessionId = randomUUID16();
|
|
26191
|
-
console.log(`${
|
|
26447
|
+
console.log(`${TAG47} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
26192
26448
|
const spawned = await managerRcSpawn({
|
|
26193
26449
|
sessionId,
|
|
26194
26450
|
initialMessage,
|
|
@@ -26208,21 +26464,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
26208
26464
|
const dispatchedAt = Date.now();
|
|
26209
26465
|
if (consumed.has(input.sessionId)) {
|
|
26210
26466
|
console.log(
|
|
26211
|
-
`${
|
|
26467
|
+
`${TAG47} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
26212
26468
|
);
|
|
26213
26469
|
return;
|
|
26214
26470
|
}
|
|
26215
26471
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
26216
26472
|
if (!jsonl) {
|
|
26217
26473
|
console.log(
|
|
26218
|
-
`${
|
|
26474
|
+
`${TAG47} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
26219
26475
|
);
|
|
26220
26476
|
return;
|
|
26221
26477
|
}
|
|
26222
26478
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
26223
26479
|
if (operatorTurns === 0) {
|
|
26224
26480
|
console.log(
|
|
26225
|
-
`${
|
|
26481
|
+
`${TAG47} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
26226
26482
|
);
|
|
26227
26483
|
return;
|
|
26228
26484
|
}
|
|
@@ -26236,19 +26492,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
26236
26492
|
});
|
|
26237
26493
|
if (!consumeOnce(input.sessionId)) {
|
|
26238
26494
|
console.log(
|
|
26239
|
-
`${
|
|
26495
|
+
`${TAG47} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
26240
26496
|
);
|
|
26241
26497
|
return;
|
|
26242
26498
|
}
|
|
26243
26499
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
26244
26500
|
if (!dispatched.ok) {
|
|
26245
26501
|
console.error(
|
|
26246
|
-
`${
|
|
26502
|
+
`${TAG47} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
26247
26503
|
);
|
|
26248
26504
|
return;
|
|
26249
26505
|
}
|
|
26250
26506
|
console.log(
|
|
26251
|
-
`${
|
|
26507
|
+
`${TAG47} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
|
|
26252
26508
|
);
|
|
26253
26509
|
}
|
|
26254
26510
|
|
|
@@ -26382,7 +26638,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
26382
26638
|
|
|
26383
26639
|
// ../lib/entitlement/src/index.ts
|
|
26384
26640
|
import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
|
|
26385
|
-
import { existsSync as
|
|
26641
|
+
import { existsSync as existsSync36, readFileSync as readFileSync38, statSync as statSync13 } from "fs";
|
|
26386
26642
|
import { resolve as resolve35 } from "path";
|
|
26387
26643
|
|
|
26388
26644
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -26431,7 +26687,7 @@ function resolveEntitlement(brand, account) {
|
|
|
26431
26687
|
return logResolved(implicitTrust(account), null);
|
|
26432
26688
|
}
|
|
26433
26689
|
const entitlementPath = resolve35(brand.configDir, "entitlement.json");
|
|
26434
|
-
if (!
|
|
26690
|
+
if (!existsSync36(entitlementPath)) {
|
|
26435
26691
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
26436
26692
|
}
|
|
26437
26693
|
const stat8 = statSync13(entitlementPath);
|
|
@@ -26446,7 +26702,7 @@ function resolveEntitlement(brand, account) {
|
|
|
26446
26702
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
26447
26703
|
let pubkeyPem;
|
|
26448
26704
|
try {
|
|
26449
|
-
pubkeyPem =
|
|
26705
|
+
pubkeyPem = readFileSync38(pubkeyPath(brand), "utf-8");
|
|
26450
26706
|
} catch (err) {
|
|
26451
26707
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
26452
26708
|
reason: "pubkey-missing"
|
|
@@ -26460,7 +26716,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
26460
26716
|
}
|
|
26461
26717
|
let envelope;
|
|
26462
26718
|
try {
|
|
26463
|
-
envelope = JSON.parse(
|
|
26719
|
+
envelope = JSON.parse(readFileSync38(entitlementPath, "utf-8"));
|
|
26464
26720
|
} catch {
|
|
26465
26721
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
26466
26722
|
}
|
|
@@ -26621,14 +26877,14 @@ function clientFrom(c) {
|
|
|
26621
26877
|
);
|
|
26622
26878
|
}
|
|
26623
26879
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
26624
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
26880
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join39(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
26625
26881
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
26626
|
-
if (BRAND_JSON_PATH && !
|
|
26882
|
+
if (BRAND_JSON_PATH && !existsSync37(BRAND_JSON_PATH)) {
|
|
26627
26883
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
26628
26884
|
}
|
|
26629
|
-
if (BRAND_JSON_PATH &&
|
|
26885
|
+
if (BRAND_JSON_PATH && existsSync37(BRAND_JSON_PATH)) {
|
|
26630
26886
|
try {
|
|
26631
|
-
const parsed = JSON.parse(
|
|
26887
|
+
const parsed = JSON.parse(readFileSync39(BRAND_JSON_PATH, "utf-8"));
|
|
26632
26888
|
BRAND = { ...BRAND, ...parsed };
|
|
26633
26889
|
} catch (err) {
|
|
26634
26890
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -26660,11 +26916,11 @@ var brandLoginOpts = {
|
|
|
26660
26916
|
appleTouchIconPath: brandAppIcon512Path,
|
|
26661
26917
|
themeColor: BRAND.defaultColors?.primary
|
|
26662
26918
|
};
|
|
26663
|
-
var ALIAS_DOMAINS_PATH =
|
|
26919
|
+
var ALIAS_DOMAINS_PATH = join39(homedir4(), BRAND.configDir, "alias-domains.json");
|
|
26664
26920
|
function loadAliasDomains() {
|
|
26665
26921
|
try {
|
|
26666
|
-
if (!
|
|
26667
|
-
const parsed = JSON.parse(
|
|
26922
|
+
if (!existsSync37(ALIAS_DOMAINS_PATH)) return null;
|
|
26923
|
+
const parsed = JSON.parse(readFileSync39(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
26668
26924
|
if (!Array.isArray(parsed)) {
|
|
26669
26925
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
26670
26926
|
return null;
|
|
@@ -26728,7 +26984,7 @@ async function recordPassiveDispatch(input) {
|
|
|
26728
26984
|
var waGateway = new WaGateway({
|
|
26729
26985
|
fetchStandingRules: fetchAccountStandingRules,
|
|
26730
26986
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
26731
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve36(process.env.MAXY_PLATFORM_ROOT ??
|
|
26987
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve36(process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
26732
26988
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
26733
26989
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
26734
26990
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -26743,7 +26999,7 @@ var waGateway = new WaGateway({
|
|
|
26743
26999
|
caption,
|
|
26744
27000
|
accountId,
|
|
26745
27001
|
maxyAccountId,
|
|
26746
|
-
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ??
|
|
27002
|
+
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, ".."))
|
|
26747
27003
|
});
|
|
26748
27004
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
26749
27005
|
},
|
|
@@ -26840,7 +27096,7 @@ function runDuplicateSenderAudit() {
|
|
|
26840
27096
|
try {
|
|
26841
27097
|
const configDir2 = process.env.CLAUDE_CONFIG_DIR;
|
|
26842
27098
|
if (!configDir2) return;
|
|
26843
|
-
const projectsRoot =
|
|
27099
|
+
const projectsRoot = join39(configDir2, "projects");
|
|
26844
27100
|
const records = [];
|
|
26845
27101
|
for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
|
|
26846
27102
|
if (isSubagent || archived) continue;
|
|
@@ -27000,10 +27256,11 @@ var scheduleInjectRoutes = createScheduleInjectRoutes({
|
|
|
27000
27256
|
const res = resolveSocket(accountId);
|
|
27001
27257
|
if (!res.ok) {
|
|
27002
27258
|
if (res.reason === "key-miss") {
|
|
27003
|
-
console.error(`[whatsapp-native] op=socket-key-miss accountId=${accountId} presentKeys=${res.presentKeys
|
|
27004
|
-
throw new Error(`WhatsApp socket key miss: no socket is registered for accountId=${accountId} (present keys: ${res.presentKeys.join(",") || "none"}). This is an account-keying fault, not a dropped link \u2014 do not advise re-pairing.`);
|
|
27259
|
+
console.error(`[whatsapp-native] op=socket-key-miss accountId=${accountId} presentKeys=${formatPresentKeys(res.presentKeys)}`);
|
|
27005
27260
|
}
|
|
27006
|
-
throw new Error(
|
|
27261
|
+
throw new Error(
|
|
27262
|
+
formatSocketResolutionMessage(res, accountId, { disconnectedClause: "cannot deliver scheduled reply" })
|
|
27263
|
+
);
|
|
27007
27264
|
}
|
|
27008
27265
|
await sendTextMessage(res.sock, toWhatsappJid(destination), text, { accountId: res.accountId });
|
|
27009
27266
|
},
|
|
@@ -27353,6 +27610,13 @@ app62.route("/api/webchat", createWebchatRoutes({
|
|
|
27353
27610
|
app62.route("/api/webchat/greeting", webchat_greeting_default);
|
|
27354
27611
|
app62.route("/api/telegram", telegram_default);
|
|
27355
27612
|
app62.route("/api/quickbooks", quickbooks_default);
|
|
27613
|
+
app62.route(
|
|
27614
|
+
"/api/google",
|
|
27615
|
+
createGoogleOAuthRoutes(
|
|
27616
|
+
resolve36(process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..")),
|
|
27617
|
+
resolve36(process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, ".."), "..", "data/accounts")
|
|
27618
|
+
)
|
|
27619
|
+
);
|
|
27356
27620
|
app62.route("/api/onboarding", onboarding_default);
|
|
27357
27621
|
app62.route("/api/admin", admin_default);
|
|
27358
27622
|
app62.route("/api/access", access_default);
|
|
@@ -27391,14 +27655,14 @@ app62.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
27391
27655
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
27392
27656
|
return c.text("Forbidden", 403);
|
|
27393
27657
|
}
|
|
27394
|
-
if (!
|
|
27658
|
+
if (!existsSync37(filePath)) {
|
|
27395
27659
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
27396
27660
|
return c.text("Not found", 404);
|
|
27397
27661
|
}
|
|
27398
27662
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
27399
27663
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
27400
27664
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
27401
|
-
const body =
|
|
27665
|
+
const body = readFileSync39(filePath);
|
|
27402
27666
|
return c.body(body, 200, {
|
|
27403
27667
|
"Content-Type": contentType,
|
|
27404
27668
|
"Cache-Control": "public, max-age=3600"
|
|
@@ -27421,14 +27685,14 @@ app62.get("/generated/:filename", (c) => {
|
|
|
27421
27685
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
27422
27686
|
return c.text("Forbidden", 403);
|
|
27423
27687
|
}
|
|
27424
|
-
if (!
|
|
27688
|
+
if (!existsSync37(filePath)) {
|
|
27425
27689
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
27426
27690
|
return c.text("Not found", 404);
|
|
27427
27691
|
}
|
|
27428
27692
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
27429
27693
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
27430
27694
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
27431
|
-
const body =
|
|
27695
|
+
const body = readFileSync39(filePath);
|
|
27432
27696
|
return c.body(body, 200, {
|
|
27433
27697
|
"Content-Type": contentType,
|
|
27434
27698
|
"Cache-Control": "public, max-age=86400"
|
|
@@ -27441,9 +27705,9 @@ app62.route("/v", visitor_consent_default);
|
|
|
27441
27705
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
27442
27706
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
27443
27707
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
27444
|
-
if (BRAND_JSON_PATH &&
|
|
27708
|
+
if (BRAND_JSON_PATH && existsSync37(BRAND_JSON_PATH)) {
|
|
27445
27709
|
try {
|
|
27446
|
-
const fullBrand = JSON.parse(
|
|
27710
|
+
const fullBrand = JSON.parse(readFileSync39(BRAND_JSON_PATH, "utf-8"));
|
|
27447
27711
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
27448
27712
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
27449
27713
|
} catch {
|
|
@@ -27470,11 +27734,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
27470
27734
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
27471
27735
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
27472
27736
|
var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
|
|
27473
|
-
(p) =>
|
|
27737
|
+
(p) => existsSync37(resolve36(process.cwd(), "public", p.replace(/^\//, "")))
|
|
27474
27738
|
);
|
|
27475
27739
|
var SW_SOURCE = (() => {
|
|
27476
27740
|
try {
|
|
27477
|
-
return
|
|
27741
|
+
return readFileSync39(resolve36(process.cwd(), "public", "sw.js"), "utf-8");
|
|
27478
27742
|
} catch {
|
|
27479
27743
|
return null;
|
|
27480
27744
|
}
|
|
@@ -27482,9 +27746,9 @@ var SW_SOURCE = (() => {
|
|
|
27482
27746
|
function readInstalledVersion() {
|
|
27483
27747
|
try {
|
|
27484
27748
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
27485
|
-
const versionFile =
|
|
27486
|
-
if (!
|
|
27487
|
-
const content =
|
|
27749
|
+
const versionFile = join39(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
27750
|
+
if (!existsSync37(versionFile)) return "unknown";
|
|
27751
|
+
const content = readFileSync39(versionFile, "utf-8").trim();
|
|
27488
27752
|
return content || "unknown";
|
|
27489
27753
|
} catch {
|
|
27490
27754
|
return "unknown";
|
|
@@ -27525,7 +27789,7 @@ var clientErrorReporterScript = `<script>
|
|
|
27525
27789
|
function cachedHtml(file) {
|
|
27526
27790
|
let html = htmlCache.get(file);
|
|
27527
27791
|
if (!html) {
|
|
27528
|
-
html =
|
|
27792
|
+
html = readFileSync39(resolve36(process.cwd(), "public", file), "utf-8");
|
|
27529
27793
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
27530
27794
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
27531
27795
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -27542,13 +27806,13 @@ ${clientErrorReporterScript}
|
|
|
27542
27806
|
return html;
|
|
27543
27807
|
}
|
|
27544
27808
|
function loadBrandingCache(agentSlug) {
|
|
27545
|
-
const configDir2 =
|
|
27809
|
+
const configDir2 = join39(homedir4(), BRAND.configDir);
|
|
27546
27810
|
try {
|
|
27547
27811
|
const accountId = getDefaultAccountId();
|
|
27548
27812
|
if (!accountId) return null;
|
|
27549
|
-
const cachePath =
|
|
27550
|
-
if (!
|
|
27551
|
-
return JSON.parse(
|
|
27813
|
+
const cachePath = join39(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
27814
|
+
if (!existsSync37(cachePath)) return null;
|
|
27815
|
+
return JSON.parse(readFileSync39(cachePath, "utf-8"));
|
|
27552
27816
|
} catch {
|
|
27553
27817
|
return null;
|
|
27554
27818
|
}
|
|
@@ -27643,7 +27907,7 @@ app62.use("/vnc-popout.html", logViewerFetch);
|
|
|
27643
27907
|
app62.get("/vnc-popout.html", (c) => {
|
|
27644
27908
|
let html = htmlCache.get("vnc-popout.html");
|
|
27645
27909
|
if (!html) {
|
|
27646
|
-
html =
|
|
27910
|
+
html = readFileSync39(resolve36(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
27647
27911
|
const name = escapeHtml(BRAND.productName);
|
|
27648
27912
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
27649
27913
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -27775,11 +28039,11 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
|
27775
28039
|
var httpServer = serve({ fetch: app62.fetch, port, hostname });
|
|
27776
28040
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
27777
28041
|
{
|
|
27778
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28042
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27779
28043
|
const reconcileScript = resolve36(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
27780
28044
|
const RECONCILE_INTERVAL_MS = 12e4;
|
|
27781
28045
|
const runReconcile = () => {
|
|
27782
|
-
if (!
|
|
28046
|
+
if (!existsSync37(reconcileScript)) return;
|
|
27783
28047
|
try {
|
|
27784
28048
|
const child = spawn3(process.execPath, [reconcileScript], {
|
|
27785
28049
|
env: { ...process.env, PLATFORM_ROOT: reconcilePlatformRoot },
|
|
@@ -27797,11 +28061,11 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27797
28061
|
loop.unref();
|
|
27798
28062
|
}
|
|
27799
28063
|
{
|
|
27800
|
-
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28064
|
+
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27801
28065
|
const outlookScript = resolve36(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
27802
28066
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
27803
28067
|
const runOutlookComplete = () => {
|
|
27804
|
-
if (!
|
|
28068
|
+
if (!existsSync37(outlookScript)) return;
|
|
27805
28069
|
try {
|
|
27806
28070
|
const child = spawn3(process.execPath, [outlookScript], {
|
|
27807
28071
|
env: { ...process.env, PLATFORM_ROOT: outlookPlatformRoot },
|
|
@@ -27819,19 +28083,19 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27819
28083
|
outlookLoop.unref();
|
|
27820
28084
|
}
|
|
27821
28085
|
{
|
|
27822
|
-
const auditRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28086
|
+
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27823
28087
|
const strandedAccountsDir = resolve36(auditRoot, "..", "data/accounts");
|
|
27824
28088
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
27825
28089
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
27826
28090
|
const STRANDED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
27827
28091
|
const runStrandedAudit = () => {
|
|
27828
28092
|
try {
|
|
27829
|
-
if (!
|
|
28093
|
+
if (!existsSync37(strandedAccountsDir)) return;
|
|
27830
28094
|
const now = Date.now();
|
|
27831
|
-
for (const name of
|
|
28095
|
+
for (const name of readdirSync22(strandedAccountsDir)) {
|
|
27832
28096
|
if (!STRANDED_UUID_RE.test(name)) continue;
|
|
27833
28097
|
const pendingPath2 = resolve36(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
|
|
27834
|
-
if (!
|
|
28098
|
+
if (!existsSync37(pendingPath2)) continue;
|
|
27835
28099
|
const ageMs = now - statSync14(pendingPath2).mtimeMs;
|
|
27836
28100
|
if (ageMs > STRANDED_AGE_MS) {
|
|
27837
28101
|
console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs / 1e3)}`);
|
|
@@ -27847,7 +28111,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27847
28111
|
strandedLoop.unref();
|
|
27848
28112
|
}
|
|
27849
28113
|
{
|
|
27850
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28114
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27851
28115
|
const STORAGE_AUDIT_INTERVAL_MS = 3e5;
|
|
27852
28116
|
const runStorageAuditSafe = () => {
|
|
27853
28117
|
runStorageAudit(auditPlatformRoot).catch(
|
|
@@ -27869,7 +28133,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27869
28133
|
pagesAuditLoop.unref();
|
|
27870
28134
|
}
|
|
27871
28135
|
{
|
|
27872
|
-
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28136
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27873
28137
|
const publishScript = resolve36(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
27874
28138
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
27875
28139
|
const currentAccount = () => {
|
|
@@ -27881,7 +28145,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27881
28145
|
}
|
|
27882
28146
|
};
|
|
27883
28147
|
const spawnPublish = (account) => {
|
|
27884
|
-
if (!
|
|
28148
|
+
if (!existsSync37(publishScript)) return;
|
|
27885
28149
|
try {
|
|
27886
28150
|
const child = spawn3(process.execPath, [publishScript], {
|
|
27887
28151
|
env: {
|
|
@@ -27902,8 +28166,8 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27902
28166
|
const availPath = resolve36(account.accountDir, "calendar-availability.json");
|
|
27903
28167
|
let hasBookingSite = false;
|
|
27904
28168
|
try {
|
|
27905
|
-
if (
|
|
27906
|
-
const cfg = JSON.parse(
|
|
28169
|
+
if (existsSync37(availPath)) {
|
|
28170
|
+
const cfg = JSON.parse(readFileSync39(availPath, "utf-8"));
|
|
27907
28171
|
hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
27908
28172
|
}
|
|
27909
28173
|
} catch {
|
|
@@ -27911,9 +28175,9 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27911
28175
|
if (!hasBookingSite) return;
|
|
27912
28176
|
const statePath = resolve36(account.accountDir, "state", "booking-availability", "last-publish.json");
|
|
27913
28177
|
let lastSuccessAt = null;
|
|
27914
|
-
if (
|
|
28178
|
+
if (existsSync37(statePath)) {
|
|
27915
28179
|
try {
|
|
27916
|
-
const rec = JSON.parse(
|
|
28180
|
+
const rec = JSON.parse(readFileSync39(statePath, "utf-8"));
|
|
27917
28181
|
lastSuccessAt = rec.lastSuccessAt ?? null;
|
|
27918
28182
|
} catch {
|
|
27919
28183
|
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
|
|
@@ -27937,12 +28201,12 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27937
28201
|
}
|
|
27938
28202
|
startTimeEntryCensus(() => getSession());
|
|
27939
28203
|
{
|
|
27940
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28204
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27941
28205
|
const auditScript = resolve36(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
27942
28206
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
27943
28207
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
27944
28208
|
const runConnectorAudit = () => {
|
|
27945
|
-
if (!
|
|
28209
|
+
if (!existsSync37(auditScript)) return;
|
|
27946
28210
|
try {
|
|
27947
28211
|
const child = spawn3(process.execPath, [auditScript], {
|
|
27948
28212
|
env: { ...process.env, PLATFORM_ROOT: auditPlatformRoot, LOG_DIR: auditLogDir },
|
|
@@ -28053,11 +28317,11 @@ try {
|
|
|
28053
28317
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
28054
28318
|
async function runAdminUserReconcileTick() {
|
|
28055
28319
|
try {
|
|
28056
|
-
if (!
|
|
28320
|
+
if (!existsSync37(USERS_FILE)) {
|
|
28057
28321
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
28058
28322
|
return;
|
|
28059
28323
|
}
|
|
28060
|
-
const usersRaw =
|
|
28324
|
+
const usersRaw = readFileSync39(USERS_FILE, "utf-8").trim();
|
|
28061
28325
|
if (!usersRaw) {
|
|
28062
28326
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
28063
28327
|
return;
|
|
@@ -28086,8 +28350,8 @@ var adminUserReconcileTimer = setInterval(() => {
|
|
|
28086
28350
|
if (typeof adminUserReconcileTimer.unref === "function") adminUserReconcileTimer.unref();
|
|
28087
28351
|
var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
28088
28352
|
function countUsersRows() {
|
|
28089
|
-
if (!
|
|
28090
|
-
const raw =
|
|
28353
|
+
if (!existsSync37(USERS_FILE)) return 0;
|
|
28354
|
+
const raw = readFileSync39(USERS_FILE, "utf-8").trim();
|
|
28091
28355
|
if (!raw) return 0;
|
|
28092
28356
|
const users = JSON.parse(raw);
|
|
28093
28357
|
return users.filter((u) => typeof u.userId === "string").length;
|
|
@@ -28207,7 +28471,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
28207
28471
|
}
|
|
28208
28472
|
init({
|
|
28209
28473
|
configDir: configDirForWhatsApp,
|
|
28210
|
-
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ??
|
|
28474
|
+
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..")),
|
|
28211
28475
|
accountConfig: bootAccountConfig,
|
|
28212
28476
|
onMessage: async (msg) => {
|
|
28213
28477
|
if (msg.isOwnerMirror) {
|