@rubytech/create-maxy-code 0.1.469 → 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/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 +74 -1
- 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/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/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/server/{chunk-POBXIHOF.js → chunk-JRIBGO45.js} +15 -1
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/server.js +596 -349
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,
|
|
@@ -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
|
|
|
@@ -12788,9 +12788,249 @@ app9.get("/callback", async (c) => {
|
|
|
12788
12788
|
});
|
|
12789
12789
|
var quickbooks_default = app9;
|
|
12790
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
|
+
|
|
12791
13031
|
// server/routes/onboarding.ts
|
|
12792
13032
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync3 } from "child_process";
|
|
12793
|
-
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";
|
|
12794
13034
|
import { createHash as createHash4, randomUUID as randomUUID8 } from "crypto";
|
|
12795
13035
|
|
|
12796
13036
|
// app/lib/claude-spawn-env.ts
|
|
@@ -12799,7 +13039,7 @@ function claudeBin() {
|
|
|
12799
13039
|
}
|
|
12800
13040
|
|
|
12801
13041
|
// server/routes/onboarding.ts
|
|
12802
|
-
import { dirname as dirname9, join as
|
|
13042
|
+
import { dirname as dirname9, join as join26 } from "path";
|
|
12803
13043
|
|
|
12804
13044
|
// app/lib/claude-keychain.ts
|
|
12805
13045
|
import { execFileSync as execFileSync2 } from "child_process";
|
|
@@ -12928,8 +13168,8 @@ function readHostCredsBlob(service) {
|
|
|
12928
13168
|
}
|
|
12929
13169
|
|
|
12930
13170
|
// ../lib/admins-write/src/index.ts
|
|
12931
|
-
import { existsSync as
|
|
12932
|
-
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";
|
|
12933
13173
|
function id8(value) {
|
|
12934
13174
|
return value.slice(0, 8);
|
|
12935
13175
|
}
|
|
@@ -12943,7 +13183,7 @@ function appendUsersAuditLine(audit, fields) {
|
|
|
12943
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()}
|
|
12944
13184
|
`;
|
|
12945
13185
|
try {
|
|
12946
|
-
|
|
13186
|
+
mkdirSync6(dirname8(audit.logFile), { recursive: true, mode: 448 });
|
|
12947
13187
|
appendFileSync2(audit.logFile, line, { mode: 384 });
|
|
12948
13188
|
} catch (err) {
|
|
12949
13189
|
console.error(
|
|
@@ -12961,17 +13201,17 @@ function logLine(input, result) {
|
|
|
12961
13201
|
);
|
|
12962
13202
|
}
|
|
12963
13203
|
function writeFileAtomic(filePath, contents, mode) {
|
|
12964
|
-
|
|
13204
|
+
mkdirSync6(dirname8(filePath), { recursive: true });
|
|
12965
13205
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
12966
|
-
|
|
12967
|
-
|
|
13206
|
+
writeFileSync10(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
13207
|
+
renameSync7(tempPath, filePath);
|
|
12968
13208
|
}
|
|
12969
13209
|
function writeAdminEntry(input) {
|
|
12970
13210
|
const result = { usersJsonResult: "noop", accountJsonResult: "noop" };
|
|
12971
13211
|
try {
|
|
12972
13212
|
let users = [];
|
|
12973
|
-
if (
|
|
12974
|
-
const raw =
|
|
13213
|
+
if (existsSync18(input.usersFile)) {
|
|
13214
|
+
const raw = readFileSync26(input.usersFile, "utf-8").trim();
|
|
12975
13215
|
if (raw) {
|
|
12976
13216
|
const parsed = JSON.parse(raw);
|
|
12977
13217
|
if (!Array.isArray(parsed)) {
|
|
@@ -13002,11 +13242,11 @@ function writeAdminEntry(input) {
|
|
|
13002
13242
|
return result;
|
|
13003
13243
|
}
|
|
13004
13244
|
try {
|
|
13005
|
-
const accountJsonPath =
|
|
13006
|
-
if (!
|
|
13245
|
+
const accountJsonPath = join25(input.accountDir, "account.json");
|
|
13246
|
+
if (!existsSync18(accountJsonPath)) {
|
|
13007
13247
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
13008
13248
|
}
|
|
13009
|
-
const config = JSON.parse(
|
|
13249
|
+
const config = JSON.parse(readFileSync26(accountJsonPath, "utf-8"));
|
|
13010
13250
|
const admins = config.admins ?? [];
|
|
13011
13251
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
13012
13252
|
result.accountJsonResult = "noop";
|
|
@@ -13026,9 +13266,9 @@ function writeAdminEntry(input) {
|
|
|
13026
13266
|
function computeAdminStoreDivergence(input) {
|
|
13027
13267
|
const result = { divergences: 0, accountWithoutUsers: [], usersWithoutAccount: [], errors: [] };
|
|
13028
13268
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
13029
|
-
if (
|
|
13269
|
+
if (existsSync18(input.usersFile)) {
|
|
13030
13270
|
try {
|
|
13031
|
-
const raw =
|
|
13271
|
+
const raw = readFileSync26(input.usersFile, "utf-8").trim();
|
|
13032
13272
|
if (raw) {
|
|
13033
13273
|
const users = JSON.parse(raw);
|
|
13034
13274
|
for (const u of users) {
|
|
@@ -13040,27 +13280,27 @@ function computeAdminStoreDivergence(input) {
|
|
|
13040
13280
|
}
|
|
13041
13281
|
}
|
|
13042
13282
|
const accountUserIds = /* @__PURE__ */ new Set();
|
|
13043
|
-
if (
|
|
13283
|
+
if (existsSync18(input.accountsDir)) {
|
|
13044
13284
|
let entries;
|
|
13045
13285
|
try {
|
|
13046
|
-
entries =
|
|
13286
|
+
entries = readdirSync17(input.accountsDir);
|
|
13047
13287
|
} catch (err) {
|
|
13048
13288
|
result.errors.push({ source: input.accountsDir, detail: err instanceof Error ? err.message : String(err) });
|
|
13049
13289
|
return result;
|
|
13050
13290
|
}
|
|
13051
13291
|
for (const entry of entries) {
|
|
13052
13292
|
if (entry.startsWith(".")) continue;
|
|
13053
|
-
const accountDir =
|
|
13293
|
+
const accountDir = join25(input.accountsDir, entry);
|
|
13054
13294
|
try {
|
|
13055
13295
|
if (!statSync8(accountDir).isDirectory()) continue;
|
|
13056
13296
|
} catch {
|
|
13057
13297
|
continue;
|
|
13058
13298
|
}
|
|
13059
|
-
const accountJsonPath =
|
|
13060
|
-
if (!
|
|
13299
|
+
const accountJsonPath = join25(accountDir, "account.json");
|
|
13300
|
+
if (!existsSync18(accountJsonPath)) continue;
|
|
13061
13301
|
let admins = [];
|
|
13062
13302
|
try {
|
|
13063
|
-
const config = JSON.parse(
|
|
13303
|
+
const config = JSON.parse(readFileSync26(accountJsonPath, "utf-8"));
|
|
13064
13304
|
admins = config.admins ?? [];
|
|
13065
13305
|
} catch (err) {
|
|
13066
13306
|
result.errors.push({ source: accountJsonPath, detail: err instanceof Error ? err.message : String(err) });
|
|
@@ -13108,8 +13348,8 @@ function hashPin2(pin) {
|
|
|
13108
13348
|
return createHash4("sha256").update(pin).digest("hex");
|
|
13109
13349
|
}
|
|
13110
13350
|
function readUsersFile2() {
|
|
13111
|
-
if (!
|
|
13112
|
-
const raw =
|
|
13351
|
+
if (!existsSync19(USERS_FILE)) return null;
|
|
13352
|
+
const raw = readFileSync27(USERS_FILE, "utf-8").trim();
|
|
13113
13353
|
if (!raw) return [];
|
|
13114
13354
|
return JSON.parse(raw);
|
|
13115
13355
|
}
|
|
@@ -13168,7 +13408,7 @@ app10.post("/claude-auth", async (c) => {
|
|
|
13168
13408
|
} catch (err) {
|
|
13169
13409
|
logoutError = err instanceof Error ? err.message : String(err);
|
|
13170
13410
|
}
|
|
13171
|
-
const credentialsPresent =
|
|
13411
|
+
const credentialsPresent = existsSync19(CLAUDE_CREDENTIALS_FILE);
|
|
13172
13412
|
const ranMs = Date.now() - start;
|
|
13173
13413
|
console.log(`[onboarding] op=claude-logout credentialsPresent=${credentialsPresent} ranMs=${ranMs} logoutError=${logoutError ? JSON.stringify(logoutError.slice(0, 120)) : "none"}`);
|
|
13174
13414
|
return c.json({ logged_out: !credentialsPresent });
|
|
@@ -13202,7 +13442,7 @@ app10.post("/claude-auth", async (c) => {
|
|
|
13202
13442
|
return c.json({ launched: cdpReady });
|
|
13203
13443
|
}
|
|
13204
13444
|
ensureLogDir();
|
|
13205
|
-
|
|
13445
|
+
writeFileSync11(logPath("claude-auth"), "");
|
|
13206
13446
|
const claudeAuthLogFd = openSync3(logPath("claude-auth"), "a");
|
|
13207
13447
|
const onClaudeOutput = (chunk) => writeSync(claudeAuthLogFd, chunk);
|
|
13208
13448
|
if (process.platform === "darwin") {
|
|
@@ -13227,14 +13467,14 @@ app10.post("/claude-auth", async (c) => {
|
|
|
13227
13467
|
readBlob: readHostCredsBlob,
|
|
13228
13468
|
writeFile: (blob) => {
|
|
13229
13469
|
const tmp = `${CLAUDE_CREDENTIALS_FILE}.${process.pid}.tmp`;
|
|
13230
|
-
|
|
13231
|
-
|
|
13470
|
+
writeFileSync11(tmp, blob, { mode: 384 });
|
|
13471
|
+
renameSync8(tmp, CLAUDE_CREDENTIALS_FILE);
|
|
13232
13472
|
},
|
|
13233
13473
|
log: (line) => console.log(line)
|
|
13234
13474
|
});
|
|
13235
13475
|
persistKeychainService(
|
|
13236
13476
|
writebackResult,
|
|
13237
|
-
(service) =>
|
|
13477
|
+
(service) => writeFileSync11(join26(dirname9(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
|
|
13238
13478
|
(line) => console.log(line)
|
|
13239
13479
|
);
|
|
13240
13480
|
if (darwinAuthChild === claudeProc2) darwinAuthChild = null;
|
|
@@ -13317,9 +13557,9 @@ app10.post("/set-pin", async (c) => {
|
|
|
13317
13557
|
console.log(`[set-pin] wrote users.json + account.json admins: userId=${userId.slice(0, 8)}\u2026 role=owner`);
|
|
13318
13558
|
if (process.platform === "linux") {
|
|
13319
13559
|
let installOwner = null;
|
|
13320
|
-
if (
|
|
13560
|
+
if (existsSync19(INSTALL_OWNER_FILE)) {
|
|
13321
13561
|
try {
|
|
13322
|
-
const raw =
|
|
13562
|
+
const raw = readFileSync27(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
13323
13563
|
if (raw.length > 0) installOwner = raw;
|
|
13324
13564
|
} catch (err) {
|
|
13325
13565
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -13400,7 +13640,7 @@ app10.delete("/set-pin", requireAdminSession, async (c) => {
|
|
|
13400
13640
|
unlinkSync3(USERS_FILE);
|
|
13401
13641
|
console.log(`[set-pin] cleared users.json (last entry removed): userId=${sessionUserId.slice(0, 8)}\u2026`);
|
|
13402
13642
|
} else {
|
|
13403
|
-
|
|
13643
|
+
writeFileSync11(USERS_FILE, JSON.stringify(remaining), { mode: 384 });
|
|
13404
13644
|
console.log(`[set-pin] removed entry from users.json: userId=${sessionUserId.slice(0, 8)}\u2026 remaining=${remaining.length}`);
|
|
13405
13645
|
}
|
|
13406
13646
|
logUsersAudit(
|
|
@@ -13465,9 +13705,9 @@ app10.put("/set-pin", requireAdminSession, async (c) => {
|
|
|
13465
13705
|
console.log(`[set-pin] changed PIN in place: userId=${sessionUserId.slice(0, 8)}\u2026`);
|
|
13466
13706
|
if (process.platform === "linux") {
|
|
13467
13707
|
let installOwner = null;
|
|
13468
|
-
if (
|
|
13708
|
+
if (existsSync19(INSTALL_OWNER_FILE)) {
|
|
13469
13709
|
try {
|
|
13470
|
-
const raw =
|
|
13710
|
+
const raw = readFileSync27(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
13471
13711
|
if (raw.length > 0) installOwner = raw;
|
|
13472
13712
|
} catch (err) {
|
|
13473
13713
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -13499,9 +13739,9 @@ ${body.newPin}
|
|
|
13499
13739
|
var onboarding_default = app10;
|
|
13500
13740
|
|
|
13501
13741
|
// server/routes/client-error.ts
|
|
13502
|
-
import { appendFileSync as appendFileSync3, existsSync as
|
|
13503
|
-
import { join as
|
|
13504
|
-
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");
|
|
13505
13745
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
13506
13746
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
13507
13747
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -13549,10 +13789,10 @@ function stackHead(stack) {
|
|
|
13549
13789
|
}
|
|
13550
13790
|
function rotateIfNeeded() {
|
|
13551
13791
|
try {
|
|
13552
|
-
if (!
|
|
13792
|
+
if (!existsSync20(CLIENT_ERRORS_LOG)) return;
|
|
13553
13793
|
const stats = statSync9(CLIENT_ERRORS_LOG);
|
|
13554
13794
|
if (stats.size < MAX_LOG_SIZE) return;
|
|
13555
|
-
|
|
13795
|
+
renameSync9(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
|
|
13556
13796
|
} catch (err) {
|
|
13557
13797
|
console.error(`[client-error] log rotation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
13558
13798
|
}
|
|
@@ -13876,18 +14116,18 @@ app13.get("/", requireAdminSession, async (c) => {
|
|
|
13876
14116
|
var accounts_default = app13;
|
|
13877
14117
|
|
|
13878
14118
|
// server/routes/admin/logs.ts
|
|
13879
|
-
import { existsSync as
|
|
14119
|
+
import { existsSync as existsSync22, readdirSync as readdirSync18, readFileSync as readFileSync28, statSync as statSync10 } from "fs";
|
|
13880
14120
|
import { resolve as resolve17, basename as basename7 } from "path";
|
|
13881
14121
|
|
|
13882
14122
|
// app/lib/logs-read-resolve.ts
|
|
13883
|
-
import { existsSync as
|
|
13884
|
-
import { join as
|
|
14123
|
+
import { existsSync as existsSync21 } from "fs";
|
|
14124
|
+
import { join as join28 } from "path";
|
|
13885
14125
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
13886
14126
|
const tried = [filename];
|
|
13887
14127
|
const hits = [];
|
|
13888
14128
|
for (const dir of logDirs) {
|
|
13889
|
-
const fullPath =
|
|
13890
|
-
if (
|
|
14129
|
+
const fullPath = join28(dir, filename);
|
|
14130
|
+
if (existsSync21(fullPath)) {
|
|
13891
14131
|
hits.push({ path: fullPath, dir });
|
|
13892
14132
|
}
|
|
13893
14133
|
}
|
|
@@ -13915,7 +14155,7 @@ app14.get("/", async (c) => {
|
|
|
13915
14155
|
const filePath = resolve17(dir, safe);
|
|
13916
14156
|
searched.push(filePath);
|
|
13917
14157
|
try {
|
|
13918
|
-
const buffer =
|
|
14158
|
+
const buffer = readFileSync28(filePath);
|
|
13919
14159
|
const onDiskBytes = statSync10(filePath).size;
|
|
13920
14160
|
const headers = {
|
|
13921
14161
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -13980,7 +14220,7 @@ app14.get("/", async (c) => {
|
|
|
13980
14220
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
13981
14221
|
try {
|
|
13982
14222
|
const filename = basename7(hit.path);
|
|
13983
|
-
const buffer =
|
|
14223
|
+
const buffer = readFileSync28(hit.path);
|
|
13984
14224
|
const onDiskBytes = statSync10(hit.path).size;
|
|
13985
14225
|
const headers = {
|
|
13986
14226
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -14015,10 +14255,10 @@ app14.get("/", async (c) => {
|
|
|
14015
14255
|
const seen = /* @__PURE__ */ new Set();
|
|
14016
14256
|
const logs = {};
|
|
14017
14257
|
for (const dir of logDirs) {
|
|
14018
|
-
if (!
|
|
14258
|
+
if (!existsSync22(dir)) continue;
|
|
14019
14259
|
let files;
|
|
14020
14260
|
try {
|
|
14021
|
-
files =
|
|
14261
|
+
files = readdirSync18(dir).filter((f) => f.endsWith(".log"));
|
|
14022
14262
|
} catch (err) {
|
|
14023
14263
|
const reason = err instanceof Error ? err.message : String(err);
|
|
14024
14264
|
console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
|
|
@@ -14027,7 +14267,7 @@ app14.get("/", async (c) => {
|
|
|
14027
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 }) => {
|
|
14028
14268
|
seen.add(name);
|
|
14029
14269
|
try {
|
|
14030
|
-
const content =
|
|
14270
|
+
const content = readFileSync28(resolve17(dir, name));
|
|
14031
14271
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
14032
14272
|
logs[name] = tail.trim() || "(empty)";
|
|
14033
14273
|
} catch (err) {
|
|
@@ -14067,7 +14307,7 @@ var claude_info_default = app15;
|
|
|
14067
14307
|
|
|
14068
14308
|
// server/routes/admin/attachment.ts
|
|
14069
14309
|
import { readFile as readFile2, readdir } from "fs/promises";
|
|
14070
|
-
import { existsSync as
|
|
14310
|
+
import { existsSync as existsSync23 } from "fs";
|
|
14071
14311
|
import { resolve as resolve18 } from "path";
|
|
14072
14312
|
var app16 = new Hono();
|
|
14073
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}$/;
|
|
@@ -14090,12 +14330,12 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
14090
14330
|
}
|
|
14091
14331
|
let accountId = pinnedAccountId;
|
|
14092
14332
|
let dir = uploadsDirFor2(accountId, attachmentId);
|
|
14093
|
-
let found =
|
|
14333
|
+
let found = existsSync23(dir);
|
|
14094
14334
|
if (!found) {
|
|
14095
14335
|
for (const candidate of listValidAccounts()) {
|
|
14096
14336
|
if (candidate.accountId === pinnedAccountId) continue;
|
|
14097
14337
|
const candidateDir = uploadsDirFor2(candidate.accountId, attachmentId);
|
|
14098
|
-
if (
|
|
14338
|
+
if (existsSync23(candidateDir)) {
|
|
14099
14339
|
accountId = candidate.accountId;
|
|
14100
14340
|
dir = candidateDir;
|
|
14101
14341
|
found = true;
|
|
@@ -14110,7 +14350,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
|
|
|
14110
14350
|
return new Response("Not found", { status: 404 });
|
|
14111
14351
|
}
|
|
14112
14352
|
const metaPath = resolve18(dir, `${attachmentId}.meta.json`);
|
|
14113
|
-
if (!
|
|
14353
|
+
if (!existsSync23(metaPath)) {
|
|
14114
14354
|
return new Response("Not found", { status: 404 });
|
|
14115
14355
|
}
|
|
14116
14356
|
let meta;
|
|
@@ -14144,23 +14384,23 @@ var attachment_default = app16;
|
|
|
14144
14384
|
|
|
14145
14385
|
// server/routes/admin/agents.ts
|
|
14146
14386
|
import { resolve as resolve19 } from "path";
|
|
14147
|
-
import { readdirSync as
|
|
14387
|
+
import { readdirSync as readdirSync19, readFileSync as readFileSync29, existsSync as existsSync24, rmSync as rmSync3 } from "fs";
|
|
14148
14388
|
var app17 = new Hono();
|
|
14149
14389
|
app17.get("/", (c) => {
|
|
14150
14390
|
const account = resolveAccount();
|
|
14151
14391
|
if (!account) return c.json({ agents: [] });
|
|
14152
14392
|
const agentsDir = resolve19(account.accountDir, "agents");
|
|
14153
|
-
if (!
|
|
14393
|
+
if (!existsSync24(agentsDir)) return c.json({ agents: [] });
|
|
14154
14394
|
const agents = [];
|
|
14155
14395
|
try {
|
|
14156
|
-
const entries =
|
|
14396
|
+
const entries = readdirSync19(agentsDir, { withFileTypes: true });
|
|
14157
14397
|
for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
14158
14398
|
if (!entry.isDirectory()) continue;
|
|
14159
14399
|
if (entry.name === "admin") continue;
|
|
14160
14400
|
const configPath2 = resolve19(agentsDir, entry.name, "config.json");
|
|
14161
|
-
if (!
|
|
14401
|
+
if (!existsSync24(configPath2)) continue;
|
|
14162
14402
|
try {
|
|
14163
|
-
const config = JSON.parse(
|
|
14403
|
+
const config = JSON.parse(readFileSync29(configPath2, "utf-8"));
|
|
14164
14404
|
agents.push({
|
|
14165
14405
|
slug: entry.name,
|
|
14166
14406
|
displayName: config.displayName ?? entry.name,
|
|
@@ -14187,7 +14427,7 @@ app17.delete("/:slug", async (c) => {
|
|
|
14187
14427
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
14188
14428
|
}
|
|
14189
14429
|
const agentDir = resolve19(account.accountDir, "agents", slug);
|
|
14190
|
-
if (!
|
|
14430
|
+
if (!existsSync24(agentDir)) {
|
|
14191
14431
|
return c.json({ error: "Agent not found" }, 404);
|
|
14192
14432
|
}
|
|
14193
14433
|
try {
|
|
@@ -14198,7 +14438,7 @@ app17.delete("/:slug", async (c) => {
|
|
|
14198
14438
|
return c.json({ error: `Graph cleanup failed: ${msg}` }, 500);
|
|
14199
14439
|
}
|
|
14200
14440
|
try {
|
|
14201
|
-
|
|
14441
|
+
rmSync3(agentDir, { recursive: true, force: true });
|
|
14202
14442
|
console.log(`[admin/agents] deleted agent "${slug}"`);
|
|
14203
14443
|
return c.json({ ok: true });
|
|
14204
14444
|
} catch (err) {
|
|
@@ -14217,7 +14457,7 @@ app17.post("/:slug/project", async (c) => {
|
|
|
14217
14457
|
return c.json({ error: "Invalid agent slug" }, 400);
|
|
14218
14458
|
}
|
|
14219
14459
|
const agentDir = resolve19(account.accountDir, "agents", slug);
|
|
14220
|
-
if (!
|
|
14460
|
+
if (!existsSync24(agentDir)) {
|
|
14221
14461
|
return c.json({ error: "Agent not found on disk" }, 404);
|
|
14222
14462
|
}
|
|
14223
14463
|
try {
|
|
@@ -14233,7 +14473,7 @@ var agents_default = app17;
|
|
|
14233
14473
|
// server/routes/admin/sessions.ts
|
|
14234
14474
|
import crypto2 from "crypto";
|
|
14235
14475
|
import { resolve as resolvePath } from "path";
|
|
14236
|
-
import { existsSync as
|
|
14476
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync7, createWriteStream } from "fs";
|
|
14237
14477
|
|
|
14238
14478
|
// ../lib/admin-conversation-purge/src/index.ts
|
|
14239
14479
|
async function purgeAdminConversationJsonls(args) {
|
|
@@ -14380,7 +14620,7 @@ var pickComponentBytes = (..._args) => null;
|
|
|
14380
14620
|
function openResumeStreamLog(accountId, sessionId) {
|
|
14381
14621
|
const dir = resolvePath(ACCOUNTS_DIR, accountId, "resume-logs");
|
|
14382
14622
|
try {
|
|
14383
|
-
|
|
14623
|
+
mkdirSync7(dir, { recursive: true });
|
|
14384
14624
|
} catch {
|
|
14385
14625
|
}
|
|
14386
14626
|
return createWriteStream(resolvePath(dir, `${sessionId}.log`), { flags: "a" });
|
|
@@ -14393,7 +14633,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
|
|
|
14393
14633
|
let reason = null;
|
|
14394
14634
|
if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
|
|
14395
14635
|
else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
|
|
14396
|
-
else if (!
|
|
14636
|
+
else if (!existsSync25(a.storagePath)) reason = "missing-file";
|
|
14397
14637
|
if (reason) {
|
|
14398
14638
|
invalid++;
|
|
14399
14639
|
try {
|
|
@@ -14919,8 +15159,8 @@ app18.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
14919
15159
|
var sessions_default = app18;
|
|
14920
15160
|
|
|
14921
15161
|
// app/lib/claude-agent/spawn-context.ts
|
|
14922
|
-
import { existsSync as
|
|
14923
|
-
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";
|
|
14924
15164
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
14925
15165
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
14926
15166
|
try {
|
|
@@ -14961,14 +15201,14 @@ function frontmatterField(manifest, field2) {
|
|
|
14961
15201
|
function extractPluginToolDescriptions(pluginDir) {
|
|
14962
15202
|
const out = /* @__PURE__ */ new Map();
|
|
14963
15203
|
const candidates = [
|
|
14964
|
-
|
|
14965
|
-
|
|
15204
|
+
join29(pluginDir, "mcp/dist/index.js"),
|
|
15205
|
+
join29(pluginDir, "mcp/src/index.ts")
|
|
14966
15206
|
];
|
|
14967
15207
|
let raw = null;
|
|
14968
15208
|
for (const path3 of candidates) {
|
|
14969
|
-
if (!
|
|
15209
|
+
if (!existsSync26(path3)) continue;
|
|
14970
15210
|
try {
|
|
14971
|
-
raw =
|
|
15211
|
+
raw = readFileSync30(path3, "utf-8");
|
|
14972
15212
|
break;
|
|
14973
15213
|
} catch {
|
|
14974
15214
|
}
|
|
@@ -15018,9 +15258,9 @@ function parseSkillPathsFromFrontmatter(fm) {
|
|
|
15018
15258
|
function listPluginDirs() {
|
|
15019
15259
|
const out = /* @__PURE__ */ new Map();
|
|
15020
15260
|
const platformPlugins = resolve20(PLATFORM_ROOT, "plugins");
|
|
15021
|
-
if (
|
|
15022
|
-
for (const name of
|
|
15023
|
-
const dir =
|
|
15261
|
+
if (existsSync26(platformPlugins)) {
|
|
15262
|
+
for (const name of readdirSync20(platformPlugins)) {
|
|
15263
|
+
const dir = join29(platformPlugins, name);
|
|
15024
15264
|
try {
|
|
15025
15265
|
if (statSync11(dir).isDirectory()) out.set(name, dir);
|
|
15026
15266
|
} catch {
|
|
@@ -15028,13 +15268,13 @@ function listPluginDirs() {
|
|
|
15028
15268
|
}
|
|
15029
15269
|
}
|
|
15030
15270
|
const premiumRoot = resolve20(dirname10(PLATFORM_ROOT), "premium-plugins");
|
|
15031
|
-
if (
|
|
15032
|
-
for (const bundle of
|
|
15033
|
-
const bundlePlugins =
|
|
15034
|
-
if (!
|
|
15271
|
+
if (existsSync26(premiumRoot)) {
|
|
15272
|
+
for (const bundle of readdirSync20(premiumRoot)) {
|
|
15273
|
+
const bundlePlugins = join29(premiumRoot, bundle, "plugins");
|
|
15274
|
+
if (!existsSync26(bundlePlugins)) continue;
|
|
15035
15275
|
try {
|
|
15036
|
-
for (const name of
|
|
15037
|
-
const dir =
|
|
15276
|
+
for (const name of readdirSync20(bundlePlugins)) {
|
|
15277
|
+
const dir = join29(bundlePlugins, name);
|
|
15038
15278
|
try {
|
|
15039
15279
|
if (statSync11(dir).isDirectory()) out.set(name, dir);
|
|
15040
15280
|
} catch {
|
|
@@ -15048,9 +15288,9 @@ function listPluginDirs() {
|
|
|
15048
15288
|
}
|
|
15049
15289
|
function readEnabledPlugins(accountId) {
|
|
15050
15290
|
const accountFile = resolve20(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
15051
|
-
if (!
|
|
15291
|
+
if (!existsSync26(accountFile)) return /* @__PURE__ */ new Set();
|
|
15052
15292
|
try {
|
|
15053
|
-
const parsed = JSON.parse(
|
|
15293
|
+
const parsed = JSON.parse(readFileSync30(accountFile, "utf-8"));
|
|
15054
15294
|
return new Set(
|
|
15055
15295
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
15056
15296
|
);
|
|
@@ -15059,10 +15299,10 @@ function readEnabledPlugins(accountId) {
|
|
|
15059
15299
|
}
|
|
15060
15300
|
}
|
|
15061
15301
|
function readFrontmatter(path3) {
|
|
15062
|
-
if (!
|
|
15302
|
+
if (!existsSync26(path3)) return null;
|
|
15063
15303
|
let raw;
|
|
15064
15304
|
try {
|
|
15065
|
-
raw =
|
|
15305
|
+
raw = readFileSync30(path3, "utf-8");
|
|
15066
15306
|
} catch {
|
|
15067
15307
|
return null;
|
|
15068
15308
|
}
|
|
@@ -15077,7 +15317,7 @@ function computeActivePlugins(accountId) {
|
|
|
15077
15317
|
for (const name of Array.from(enabled).sort()) {
|
|
15078
15318
|
const dir = pluginDirs.get(name);
|
|
15079
15319
|
if (!dir) continue;
|
|
15080
|
-
const fm = readFrontmatter(
|
|
15320
|
+
const fm = readFrontmatter(join29(dir, "PLUGIN.md"));
|
|
15081
15321
|
if (!fm) continue;
|
|
15082
15322
|
const description = frontmatterField(`---
|
|
15083
15323
|
${fm}
|
|
@@ -15094,7 +15334,7 @@ ${fm}
|
|
|
15094
15334
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
15095
15335
|
);
|
|
15096
15336
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
15097
|
-
const hasSource =
|
|
15337
|
+
const hasSource = existsSync26(join29(dir, "mcp/dist/index.js")) || existsSync26(join29(dir, "mcp/src/index.ts"));
|
|
15098
15338
|
if (hasSource) {
|
|
15099
15339
|
console.warn(
|
|
15100
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`
|
|
@@ -15104,7 +15344,7 @@ ${fm}
|
|
|
15104
15344
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
15105
15345
|
const skills = [];
|
|
15106
15346
|
for (const relPath of skillPaths) {
|
|
15107
|
-
const skillPath =
|
|
15347
|
+
const skillPath = join29(dir, relPath);
|
|
15108
15348
|
const skillFm = readFrontmatter(skillPath);
|
|
15109
15349
|
if (!skillFm) continue;
|
|
15110
15350
|
const skillName = frontmatterField(`---
|
|
@@ -15121,10 +15361,10 @@ ${skillFm}
|
|
|
15121
15361
|
}
|
|
15122
15362
|
function computeSpecialistDomains(accountId) {
|
|
15123
15363
|
const specialistsDir = resolve20(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
|
|
15124
|
-
if (!
|
|
15364
|
+
if (!existsSync26(specialistsDir)) return [];
|
|
15125
15365
|
let entries;
|
|
15126
15366
|
try {
|
|
15127
|
-
entries =
|
|
15367
|
+
entries = readdirSync20(specialistsDir);
|
|
15128
15368
|
} catch {
|
|
15129
15369
|
return [];
|
|
15130
15370
|
}
|
|
@@ -15148,7 +15388,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
15148
15388
|
const out = [];
|
|
15149
15389
|
for (const file of entries.sort()) {
|
|
15150
15390
|
if (!file.endsWith(".md")) continue;
|
|
15151
|
-
const fm = readFrontmatter(
|
|
15391
|
+
const fm = readFrontmatter(join29(specialistsDir, file));
|
|
15152
15392
|
if (!fm) continue;
|
|
15153
15393
|
const wrapped = `---
|
|
15154
15394
|
${fm}
|
|
@@ -15167,10 +15407,10 @@ ${fm}
|
|
|
15167
15407
|
}
|
|
15168
15408
|
function computeDormantPlugins(accountId) {
|
|
15169
15409
|
const accountFile = resolve20(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
15170
|
-
if (!
|
|
15410
|
+
if (!existsSync26(accountFile)) return [];
|
|
15171
15411
|
let enabled;
|
|
15172
15412
|
try {
|
|
15173
|
-
const raw =
|
|
15413
|
+
const raw = readFileSync30(accountFile, "utf-8");
|
|
15174
15414
|
const parsed = JSON.parse(raw);
|
|
15175
15415
|
enabled = new Set(
|
|
15176
15416
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -15182,10 +15422,10 @@ function computeDormantPlugins(accountId) {
|
|
|
15182
15422
|
return [];
|
|
15183
15423
|
}
|
|
15184
15424
|
const pluginsDir = resolve20(PLATFORM_ROOT, "plugins");
|
|
15185
|
-
if (!
|
|
15425
|
+
if (!existsSync26(pluginsDir)) return [];
|
|
15186
15426
|
let entries;
|
|
15187
15427
|
try {
|
|
15188
|
-
entries =
|
|
15428
|
+
entries = readdirSync20(pluginsDir);
|
|
15189
15429
|
} catch {
|
|
15190
15430
|
return [];
|
|
15191
15431
|
}
|
|
@@ -15193,10 +15433,10 @@ function computeDormantPlugins(accountId) {
|
|
|
15193
15433
|
for (const name of entries) {
|
|
15194
15434
|
if (enabled.has(name)) continue;
|
|
15195
15435
|
const manifestPath = resolve20(pluginsDir, name, "PLUGIN.md");
|
|
15196
|
-
if (!
|
|
15436
|
+
if (!existsSync26(manifestPath)) continue;
|
|
15197
15437
|
let manifest;
|
|
15198
15438
|
try {
|
|
15199
|
-
manifest =
|
|
15439
|
+
manifest = readFileSync30(manifestPath, "utf-8");
|
|
15200
15440
|
} catch {
|
|
15201
15441
|
continue;
|
|
15202
15442
|
}
|
|
@@ -15210,13 +15450,13 @@ function computeDormantPlugins(accountId) {
|
|
|
15210
15450
|
}
|
|
15211
15451
|
|
|
15212
15452
|
// server/routes/admin/claude-sessions.ts
|
|
15213
|
-
import { existsSync as
|
|
15453
|
+
import { existsSync as existsSync27, readFileSync as readFileSync31 } from "fs";
|
|
15214
15454
|
import { resolve as resolve21 } from "path";
|
|
15215
15455
|
function readTunnelState(brandConfigDir) {
|
|
15216
15456
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
15217
|
-
if (!
|
|
15457
|
+
if (!existsSync27(statePath)) return null;
|
|
15218
15458
|
try {
|
|
15219
|
-
const parsed = JSON.parse(
|
|
15459
|
+
const parsed = JSON.parse(readFileSync31(statePath, "utf-8"));
|
|
15220
15460
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
15221
15461
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
15222
15462
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -15230,7 +15470,7 @@ function resolveTunnelUrl() {
|
|
|
15230
15470
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
|
|
15231
15471
|
let brand;
|
|
15232
15472
|
try {
|
|
15233
|
-
brand = JSON.parse(
|
|
15473
|
+
brand = JSON.parse(readFileSync31(resolve21(platformRoot5, "config", "brand.json"), "utf-8"));
|
|
15234
15474
|
} catch {
|
|
15235
15475
|
return null;
|
|
15236
15476
|
}
|
|
@@ -15241,7 +15481,7 @@ function resolveTunnelUrl() {
|
|
|
15241
15481
|
if (!state) return null;
|
|
15242
15482
|
return `https://${hostname2}.${state.domain}`;
|
|
15243
15483
|
}
|
|
15244
|
-
var
|
|
15484
|
+
var TAG27 = "[claude-session-manager:wrapper]";
|
|
15245
15485
|
async function refuseIfClaudeAuthDead(c, route, sessionId) {
|
|
15246
15486
|
const auth = await ensureAuth();
|
|
15247
15487
|
if (auth.status !== "dead" && auth.status !== "missing") return null;
|
|
@@ -15259,12 +15499,12 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
15259
15499
|
const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
|
|
15260
15500
|
const ownerMs = Date.now() - ownerStart;
|
|
15261
15501
|
const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
|
|
15262
|
-
console.log(`${
|
|
15502
|
+
console.log(`${TAG27} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
|
|
15263
15503
|
const dormantPlugins = computeDormantPlugins(args.senderId);
|
|
15264
15504
|
const activePlugins = computeActivePlugins(args.senderId);
|
|
15265
15505
|
const specialistDomains = computeSpecialistDomains(args.senderId);
|
|
15266
15506
|
const tunnelUrl = resolveTunnelUrl();
|
|
15267
|
-
console.log(`${
|
|
15507
|
+
console.log(`${TAG27} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
|
|
15268
15508
|
const upstreamPayload = JSON.stringify({
|
|
15269
15509
|
senderId: args.senderId,
|
|
15270
15510
|
// Task 205 — pass userId through to the manager so it lands as
|
|
@@ -15291,24 +15531,24 @@ async function performSpawnWithInitialMessage(args) {
|
|
|
15291
15531
|
// unshapely values.
|
|
15292
15532
|
conversationNodeId: args.conversationNodeId
|
|
15293
15533
|
});
|
|
15294
|
-
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"}`);
|
|
15295
15535
|
const forwardStart = Date.now();
|
|
15296
15536
|
const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
|
|
15297
15537
|
method: "POST",
|
|
15298
15538
|
headers: { "content-type": "application/json" },
|
|
15299
15539
|
body: upstreamPayload
|
|
15300
15540
|
}).catch((err) => {
|
|
15301
|
-
console.error(`${
|
|
15541
|
+
console.error(`${TAG27} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
|
|
15302
15542
|
return null;
|
|
15303
15543
|
});
|
|
15304
15544
|
if (!upstream) return {
|
|
15305
15545
|
response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
|
|
15306
15546
|
claudeSessionId: null
|
|
15307
15547
|
};
|
|
15308
|
-
console.log(`${
|
|
15548
|
+
console.log(`${TAG27} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
|
|
15309
15549
|
if (args.initialMessage) {
|
|
15310
15550
|
const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
|
|
15311
|
-
console.log(`${
|
|
15551
|
+
console.log(`${TAG27} initial-message-inlined bytes=${inputBytes}`);
|
|
15312
15552
|
}
|
|
15313
15553
|
const bodyText = await upstream.text().catch(() => "");
|
|
15314
15554
|
let claudeSessionId = null;
|
|
@@ -15343,7 +15583,7 @@ app19.post("/", async (c) => {
|
|
|
15343
15583
|
if (refusal) return refusal;
|
|
15344
15584
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
15345
15585
|
if (!senderId) {
|
|
15346
|
-
console.error(`${
|
|
15586
|
+
console.error(`${TAG27} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
|
|
15347
15587
|
return c.json({ error: "admin-account-not-resolved" }, 500);
|
|
15348
15588
|
}
|
|
15349
15589
|
const userId = getUserIdForSession(cacheKey) ?? void 0;
|
|
@@ -15352,7 +15592,7 @@ app19.post("/", async (c) => {
|
|
|
15352
15592
|
const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
|
|
15353
15593
|
const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
|
|
15354
15594
|
const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
|
|
15355
|
-
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"}`);
|
|
15356
15596
|
const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
|
|
15357
15597
|
const { response, claudeSessionId } = await performSpawnWithInitialMessage({
|
|
15358
15598
|
senderId,
|
|
@@ -15371,13 +15611,13 @@ app19.post("/", async (c) => {
|
|
|
15371
15611
|
claudeSessionId,
|
|
15372
15612
|
senderId
|
|
15373
15613
|
);
|
|
15374
|
-
console.log(`${
|
|
15614
|
+
console.log(`${TAG27} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
|
|
15375
15615
|
return response;
|
|
15376
15616
|
});
|
|
15377
15617
|
var claude_sessions_default = app19;
|
|
15378
15618
|
|
|
15379
15619
|
// server/routes/admin/log-ingest.ts
|
|
15380
|
-
var
|
|
15620
|
+
var TAG28 = "[log-ingest]";
|
|
15381
15621
|
var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
|
|
15382
15622
|
var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
|
|
15383
15623
|
var MAX_LINE_BYTES = 4096;
|
|
@@ -15388,7 +15628,7 @@ function isLoopbackAddr2(addr) {
|
|
|
15388
15628
|
app20.post("/", async (c) => {
|
|
15389
15629
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
15390
15630
|
if (!isLoopbackAddr2(remoteAddr)) {
|
|
15391
|
-
console.error(`${
|
|
15631
|
+
console.error(`${TAG28} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
15392
15632
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
15393
15633
|
}
|
|
15394
15634
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -15397,7 +15637,7 @@ app20.post("/", async (c) => {
|
|
|
15397
15637
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
15398
15638
|
const offender = tokens.find((t) => !isLoopbackAddr2(t));
|
|
15399
15639
|
if (offender !== void 0) {
|
|
15400
|
-
console.error(`${
|
|
15640
|
+
console.error(`${TAG28} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
15401
15641
|
return c.json({ error: "log-ingest-loopback-only" }, 403);
|
|
15402
15642
|
}
|
|
15403
15643
|
}
|
|
@@ -15439,18 +15679,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
|
|
|
15439
15679
|
]);
|
|
15440
15680
|
var app21 = new Hono();
|
|
15441
15681
|
app21.post("/", async (c) => {
|
|
15442
|
-
const
|
|
15682
|
+
const TAG48 = "[admin:events]";
|
|
15443
15683
|
let body;
|
|
15444
15684
|
try {
|
|
15445
15685
|
body = await c.req.json();
|
|
15446
15686
|
} catch (err) {
|
|
15447
15687
|
const detail = err instanceof Error ? err.message : String(err);
|
|
15448
|
-
console.error(`${
|
|
15688
|
+
console.error(`${TAG48} reject reason=body-not-json detail=${detail}`);
|
|
15449
15689
|
return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
|
|
15450
15690
|
}
|
|
15451
15691
|
const event = typeof body.event === "string" ? body.event : "";
|
|
15452
15692
|
if (!ALLOWED_EVENTS.has(event)) {
|
|
15453
|
-
console.error(`${
|
|
15693
|
+
console.error(`${TAG48} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
|
|
15454
15694
|
return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
|
|
15455
15695
|
}
|
|
15456
15696
|
const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
|
|
@@ -15472,11 +15712,11 @@ app21.post("/", async (c) => {
|
|
|
15472
15712
|
var events_default = app21;
|
|
15473
15713
|
|
|
15474
15714
|
// server/routes/admin/files.ts
|
|
15475
|
-
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as
|
|
15715
|
+
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync28 } from "fs";
|
|
15476
15716
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename, rmdir } from "fs/promises";
|
|
15477
15717
|
import { realpathSync as realpathSync6 } from "fs";
|
|
15478
15718
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
15479
|
-
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";
|
|
15480
15720
|
import { Readable as Readable2 } from "stream";
|
|
15481
15721
|
|
|
15482
15722
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -15794,7 +16034,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
15794
16034
|
|
|
15795
16035
|
// app/lib/file-index.ts
|
|
15796
16036
|
import * as fsp from "fs/promises";
|
|
15797
|
-
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";
|
|
15798
16038
|
import { tmpdir as tmpdir2 } from "os";
|
|
15799
16039
|
import { execFile as execFile2 } from "child_process";
|
|
15800
16040
|
import { promisify as promisify2 } from "util";
|
|
@@ -15876,7 +16116,7 @@ async function extractPdf(absolute) {
|
|
|
15876
16116
|
return stdout.trim();
|
|
15877
16117
|
}
|
|
15878
16118
|
async function ocrPdf(absolute) {
|
|
15879
|
-
const outPdf =
|
|
16119
|
+
const outPdf = join30(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
15880
16120
|
try {
|
|
15881
16121
|
await execFileAsync2(
|
|
15882
16122
|
"ocrmypdf",
|
|
@@ -15938,7 +16178,7 @@ async function readDisplayName(absolute) {
|
|
|
15938
16178
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
15939
16179
|
if (base === `${stem}.meta.json`) return null;
|
|
15940
16180
|
try {
|
|
15941
|
-
const raw = await fsp.readFile(
|
|
16181
|
+
const raw = await fsp.readFile(join30(dir, `${stem}.meta.json`), "utf-8");
|
|
15942
16182
|
const meta = JSON.parse(raw);
|
|
15943
16183
|
const dn = meta.displayName ?? meta.filename;
|
|
15944
16184
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -15959,7 +16199,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
15959
16199
|
for (const entry of entries) {
|
|
15960
16200
|
if (entry.isSymbolicLink()) continue;
|
|
15961
16201
|
if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
|
|
15962
|
-
const abs =
|
|
16202
|
+
const abs = join30(root, entry.name);
|
|
15963
16203
|
if (entry.isDirectory()) {
|
|
15964
16204
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
15965
16205
|
if (!sub.clean) clean = false;
|
|
@@ -16315,7 +16555,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
|
16315
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;
|
|
16316
16556
|
async function readMeta(absDir, baseName) {
|
|
16317
16557
|
try {
|
|
16318
|
-
const raw = await readFile4(
|
|
16558
|
+
const raw = await readFile4(join31(absDir, `${baseName}.meta.json`), "utf8");
|
|
16319
16559
|
const parsed = JSON.parse(raw);
|
|
16320
16560
|
if (typeof parsed?.filename === "string") {
|
|
16321
16561
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -16370,7 +16610,7 @@ async function servableFilesIn(dirAbs, uuid) {
|
|
|
16370
16610
|
}
|
|
16371
16611
|
async function enrich(absolute, entry, accountNames) {
|
|
16372
16612
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
16373
|
-
const dirAbs =
|
|
16613
|
+
const dirAbs = join31(absolute, entry.name);
|
|
16374
16614
|
const meta = await readMeta(dirAbs, entry.name);
|
|
16375
16615
|
if (meta?.filename) {
|
|
16376
16616
|
const servable = await servableFilesIn(dirAbs, entry.name);
|
|
@@ -16379,7 +16619,7 @@ async function enrich(absolute, entry, accountNames) {
|
|
|
16379
16619
|
let size = null;
|
|
16380
16620
|
let modifiedAt = entry.modifiedAt;
|
|
16381
16621
|
try {
|
|
16382
|
-
const st = await stat4(
|
|
16622
|
+
const st = await stat4(join31(dirAbs, innerName));
|
|
16383
16623
|
size = st.size;
|
|
16384
16624
|
modifiedAt = st.mtime.toISOString();
|
|
16385
16625
|
} catch {
|
|
@@ -16554,7 +16794,7 @@ app22.get("/", requireAdminSession, async (c) => {
|
|
|
16554
16794
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
16555
16795
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
16556
16796
|
try {
|
|
16557
|
-
const entryPath =
|
|
16797
|
+
const entryPath = join31(absolute, name);
|
|
16558
16798
|
const s = await stat4(entryPath);
|
|
16559
16799
|
entries.push({
|
|
16560
16800
|
name,
|
|
@@ -16617,7 +16857,7 @@ app22.get("/download", requireAdminSession, async (c) => {
|
|
|
16617
16857
|
console.error(`[data] op=scratchpad-no-session sessionId="${sessionId.slice(0, 8)}\u2026"`);
|
|
16618
16858
|
return c.json({ error: "Not found" }, 404);
|
|
16619
16859
|
}
|
|
16620
|
-
const meta = readSidecarMeta(
|
|
16860
|
+
const meta = readSidecarMeta(join31(projectDir, `${sessionId}.meta.json`));
|
|
16621
16861
|
if (!meta.accountId || meta.accountId !== accountId) {
|
|
16622
16862
|
console.error(`[data] account-scope-blocked root="scratchpad" sessionId="${sessionId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
|
|
16623
16863
|
return c.json({ error: "Not found" }, 404);
|
|
@@ -16712,7 +16952,7 @@ async function* walkRegularFiles(dirAbsolute) {
|
|
|
16712
16952
|
const dirents = await readdir3(dirAbsolute, { withFileTypes: true });
|
|
16713
16953
|
for (const d of dirents) {
|
|
16714
16954
|
if (d.isSymbolicLink()) continue;
|
|
16715
|
-
const child =
|
|
16955
|
+
const child = join31(dirAbsolute, d.name);
|
|
16716
16956
|
if (d.isDirectory()) {
|
|
16717
16957
|
yield* walkRegularFiles(child);
|
|
16718
16958
|
continue;
|
|
@@ -16822,7 +17062,7 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
16822
17062
|
const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
16823
17063
|
if (!base.ok) return { ok: false, status: base.status, error: base.error };
|
|
16824
17064
|
const relDir = relpath ? dirname11(relpath) : ".";
|
|
16825
|
-
const destRel = relDir === "." ? base.relative :
|
|
17065
|
+
const destRel = relDir === "." ? base.relative : join31(base.relative, relDir);
|
|
16826
17066
|
if (crossesForeignAccountPartition(destRel, accountId)) {
|
|
16827
17067
|
console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
16828
17068
|
return { ok: false, status: 404, error: "Not found" };
|
|
@@ -16896,7 +17136,7 @@ app22.post("/upload", requireAdminSession, async (c) => {
|
|
|
16896
17136
|
});
|
|
16897
17137
|
await unlink2(tmpPath).catch(() => {
|
|
16898
17138
|
});
|
|
16899
|
-
const tempRemoved = !
|
|
17139
|
+
const tempRemoved = !existsSync28(tmpPath);
|
|
16900
17140
|
console.error(`[data-upload] op=cleanup uid=${uid} tempRemoved=${tempRemoved}`);
|
|
16901
17141
|
};
|
|
16902
17142
|
const reader = body.getReader();
|
|
@@ -16970,7 +17210,7 @@ async function discardChunkUpload(uploadId, state) {
|
|
|
16970
17210
|
});
|
|
16971
17211
|
await unlink2(state.tmpPath).catch(() => {
|
|
16972
17212
|
});
|
|
16973
|
-
const tempRemoved = !
|
|
17213
|
+
const tempRemoved = !existsSync28(state.tmpPath);
|
|
16974
17214
|
console.error(`[data-upload] op=cleanup uid=${uploadId} tempRemoved=${tempRemoved}`);
|
|
16975
17215
|
}
|
|
16976
17216
|
async function writeChunkBody(body, out, alreadyReceived, ceiling) {
|
|
@@ -17199,7 +17439,7 @@ app22.delete("/", requireAdminSession, async (c) => {
|
|
|
17199
17439
|
const dot = base.lastIndexOf(".");
|
|
17200
17440
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
17201
17441
|
const containerDir = dirname11(absolute);
|
|
17202
|
-
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;
|
|
17203
17443
|
const isAttachmentContainer = UUID_RE3.test(stem) && basename9(containerDir) === stem;
|
|
17204
17444
|
await unlink2(absolute);
|
|
17205
17445
|
if (sidecarPath) {
|
|
@@ -17209,7 +17449,7 @@ app22.delete("/", requireAdminSession, async (c) => {
|
|
|
17209
17449
|
}
|
|
17210
17450
|
}
|
|
17211
17451
|
if (isAttachmentContainer) {
|
|
17212
|
-
await unlink2(
|
|
17452
|
+
await unlink2(join31(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
|
|
17213
17453
|
});
|
|
17214
17454
|
await rmdir(containerDir).catch(() => {
|
|
17215
17455
|
});
|
|
@@ -18313,8 +18553,8 @@ function isHiddenByDefault(label) {
|
|
|
18313
18553
|
}
|
|
18314
18554
|
|
|
18315
18555
|
// server/lib/top-level-labels.ts
|
|
18316
|
-
import { readdirSync as
|
|
18317
|
-
import { join as
|
|
18556
|
+
import { readdirSync as readdirSync21, readFileSync as readFileSync32 } from "fs";
|
|
18557
|
+
import { join as join32, resolve as resolve24 } from "path";
|
|
18318
18558
|
var STATIC_TOP_LEVEL_LABELS = Object.freeze(
|
|
18319
18559
|
/* @__PURE__ */ new Set([
|
|
18320
18560
|
// Base-schema infra (schema-base.md has no top-level section).
|
|
@@ -18407,7 +18647,7 @@ function parseTopLevelLabels(content) {
|
|
|
18407
18647
|
}
|
|
18408
18648
|
function resolveReferencesDir() {
|
|
18409
18649
|
if (process.env.MAXY_PLATFORM_ROOT) {
|
|
18410
|
-
return
|
|
18650
|
+
return join32(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
|
|
18411
18651
|
}
|
|
18412
18652
|
return resolve24(import.meta.dirname, "../../../plugins/memory/references");
|
|
18413
18653
|
}
|
|
@@ -18415,9 +18655,9 @@ function parseTableTopLevelLabels(referencesDir) {
|
|
|
18415
18655
|
const labels = /* @__PURE__ */ new Set();
|
|
18416
18656
|
const contributingFiles = [];
|
|
18417
18657
|
try {
|
|
18418
|
-
const fileNames =
|
|
18658
|
+
const fileNames = readdirSync21(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
|
|
18419
18659
|
for (const fileName of fileNames) {
|
|
18420
|
-
const content =
|
|
18660
|
+
const content = readFileSync32(join32(referencesDir, fileName), "utf-8");
|
|
18421
18661
|
const parsed = parseTopLevelLabels(content);
|
|
18422
18662
|
if (parsed.length > 0) contributingFiles.push(fileName);
|
|
18423
18663
|
for (const label of parsed) labels.add(label);
|
|
@@ -19571,7 +19811,7 @@ var graph_default_view_default = app28;
|
|
|
19571
19811
|
// server/routes/admin/sidebar-artefacts.ts
|
|
19572
19812
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
19573
19813
|
import { resolve as resolve25, relative as relative5, isAbsolute as isAbsolute2, sep as sep7, basename as basename10 } from "path";
|
|
19574
|
-
import { existsSync as
|
|
19814
|
+
import { existsSync as existsSync29 } from "fs";
|
|
19575
19815
|
var LIMIT = 50;
|
|
19576
19816
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
19577
19817
|
function toDataRootRelPath(absPath) {
|
|
@@ -19678,7 +19918,7 @@ async function fetchAgentTemplateRows(accountDir) {
|
|
|
19678
19918
|
async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
19679
19919
|
const names = /* @__PURE__ */ new Set();
|
|
19680
19920
|
for (const dir of [overrideDir, bundledDir]) {
|
|
19681
|
-
if (!
|
|
19921
|
+
if (!existsSync29(dir)) continue;
|
|
19682
19922
|
try {
|
|
19683
19923
|
const entries = await readdir4(dir);
|
|
19684
19924
|
for (const entry of entries) {
|
|
@@ -19693,7 +19933,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
|
|
|
19693
19933
|
}
|
|
19694
19934
|
async function readAgentTemplateRow(inp) {
|
|
19695
19935
|
let chosenPath = null;
|
|
19696
|
-
if (
|
|
19936
|
+
if (existsSync29(inp.overridePath)) {
|
|
19697
19937
|
try {
|
|
19698
19938
|
validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
|
|
19699
19939
|
chosenPath = inp.overridePath;
|
|
@@ -19704,7 +19944,7 @@ async function readAgentTemplateRow(inp) {
|
|
|
19704
19944
|
);
|
|
19705
19945
|
return null;
|
|
19706
19946
|
}
|
|
19707
|
-
} else if (
|
|
19947
|
+
} else if (existsSync29(inp.bundledPath)) {
|
|
19708
19948
|
if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
|
|
19709
19949
|
console.error(
|
|
19710
19950
|
`[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
|
|
@@ -20306,14 +20546,14 @@ app37.get("/", async (c) => {
|
|
|
20306
20546
|
var system_stats_default = app37;
|
|
20307
20547
|
|
|
20308
20548
|
// server/routes/admin/health.ts
|
|
20309
|
-
import { existsSync as
|
|
20310
|
-
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";
|
|
20311
20551
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve26(process.cwd(), "..");
|
|
20312
20552
|
var brandHostname = "maxy";
|
|
20313
|
-
var brandJsonPath =
|
|
20314
|
-
if (
|
|
20553
|
+
var brandJsonPath = join33(PLATFORM_ROOT6, "config", "brand.json");
|
|
20554
|
+
if (existsSync30(brandJsonPath)) {
|
|
20315
20555
|
try {
|
|
20316
|
-
const brand = JSON.parse(
|
|
20556
|
+
const brand = JSON.parse(readFileSync33(brandJsonPath, "utf-8"));
|
|
20317
20557
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
20318
20558
|
} catch {
|
|
20319
20559
|
}
|
|
@@ -20322,8 +20562,8 @@ var VERSION_FILE = resolve26(PLATFORM_ROOT6, `config/.${brandHostname}-version`)
|
|
|
20322
20562
|
var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
20323
20563
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
20324
20564
|
function readVersion() {
|
|
20325
|
-
if (!
|
|
20326
|
-
return
|
|
20565
|
+
if (!existsSync30(VERSION_FILE)) return "unknown";
|
|
20566
|
+
return readFileSync33(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
20327
20567
|
}
|
|
20328
20568
|
async function probeConversationDb() {
|
|
20329
20569
|
let session;
|
|
@@ -20502,7 +20742,7 @@ function managerLogFollowUrl(sessionId, opts) {
|
|
|
20502
20742
|
}
|
|
20503
20743
|
|
|
20504
20744
|
// server/routes/admin/linkedin-ingest.ts
|
|
20505
|
-
var
|
|
20745
|
+
var TAG29 = "[linkedin-ingest-route]";
|
|
20506
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}$/;
|
|
20507
20747
|
var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
20508
20748
|
var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
|
|
@@ -20606,29 +20846,29 @@ app39.post("/", requireAdminSession, async (c) => {
|
|
|
20606
20846
|
try {
|
|
20607
20847
|
body = await c.req.json();
|
|
20608
20848
|
} catch {
|
|
20609
|
-
console.error(
|
|
20849
|
+
console.error(TAG29 + " rejected status=400 reason=schema:body-not-json");
|
|
20610
20850
|
return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
|
|
20611
20851
|
}
|
|
20612
20852
|
const v = validate(body);
|
|
20613
20853
|
if (!v.ok) {
|
|
20614
|
-
console.error(
|
|
20854
|
+
console.error(TAG29 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
|
|
20615
20855
|
return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
|
|
20616
20856
|
}
|
|
20617
20857
|
const envelope = v.envelope;
|
|
20618
20858
|
const cacheKey = c.var.cacheKey ?? "";
|
|
20619
20859
|
const senderId = getAccountIdForSession(cacheKey) ?? "";
|
|
20620
20860
|
if (!senderId) {
|
|
20621
|
-
console.error(
|
|
20861
|
+
console.error(TAG29 + " rejected status=500 reason=admin-account-not-resolved");
|
|
20622
20862
|
return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
|
|
20623
20863
|
}
|
|
20624
20864
|
const payloadBytes = JSON.stringify(envelope).length;
|
|
20625
20865
|
console.log(
|
|
20626
|
-
|
|
20866
|
+
TAG29 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
|
|
20627
20867
|
);
|
|
20628
20868
|
const initialMessage = buildInitialMessage(envelope);
|
|
20629
20869
|
const spawnStart = Date.now();
|
|
20630
20870
|
const sessionId = randomUUID13();
|
|
20631
|
-
console.log(
|
|
20871
|
+
console.log(TAG29 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
|
|
20632
20872
|
const spawned = await managerRcSpawn({
|
|
20633
20873
|
sessionId,
|
|
20634
20874
|
initialMessage,
|
|
@@ -20637,12 +20877,12 @@ app39.post("/", requireAdminSession, async (c) => {
|
|
|
20637
20877
|
});
|
|
20638
20878
|
if ("error" in spawned) {
|
|
20639
20879
|
console.error(
|
|
20640
|
-
|
|
20880
|
+
TAG29 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
|
|
20641
20881
|
);
|
|
20642
20882
|
return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
|
|
20643
20883
|
}
|
|
20644
20884
|
console.log(
|
|
20645
|
-
|
|
20885
|
+
TAG29 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
|
|
20646
20886
|
);
|
|
20647
20887
|
return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
|
|
20648
20888
|
});
|
|
@@ -20650,7 +20890,7 @@ var linkedin_ingest_default = app39;
|
|
|
20650
20890
|
|
|
20651
20891
|
// server/routes/admin/post-turn-context.ts
|
|
20652
20892
|
import neo4j3 from "neo4j-driver";
|
|
20653
|
-
var
|
|
20893
|
+
var TAG30 = "[post-turn-context]";
|
|
20654
20894
|
var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
|
|
20655
20895
|
"embedding",
|
|
20656
20896
|
"passwordHash",
|
|
@@ -20692,7 +20932,7 @@ var app40 = new Hono();
|
|
|
20692
20932
|
app40.get("/", async (c) => {
|
|
20693
20933
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
20694
20934
|
if (!isLoopbackAddr3(remoteAddr)) {
|
|
20695
|
-
console.error(`${
|
|
20935
|
+
console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
20696
20936
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
20697
20937
|
}
|
|
20698
20938
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -20701,7 +20941,7 @@ app40.get("/", async (c) => {
|
|
|
20701
20941
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
20702
20942
|
const offender = tokens.find((t) => !isLoopbackAddr3(t));
|
|
20703
20943
|
if (offender !== void 0) {
|
|
20704
|
-
console.error(`${
|
|
20944
|
+
console.error(`${TAG30} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
20705
20945
|
return c.json({ error: "post-turn-context-loopback-only" }, 403);
|
|
20706
20946
|
}
|
|
20707
20947
|
}
|
|
@@ -20733,7 +20973,7 @@ app40.get("/", async (c) => {
|
|
|
20733
20973
|
writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
|
|
20734
20974
|
const total = Date.now() - started;
|
|
20735
20975
|
console.log(
|
|
20736
|
-
`${
|
|
20976
|
+
`${TAG30} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
|
|
20737
20977
|
);
|
|
20738
20978
|
return c.json({
|
|
20739
20979
|
writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
|
|
@@ -20742,7 +20982,7 @@ app40.get("/", async (c) => {
|
|
|
20742
20982
|
const elapsed = Date.now() - started;
|
|
20743
20983
|
const message = err instanceof Error ? err.message : String(err);
|
|
20744
20984
|
console.error(
|
|
20745
|
-
`${
|
|
20985
|
+
`${TAG30} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
|
|
20746
20986
|
);
|
|
20747
20987
|
return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
|
|
20748
20988
|
} finally {
|
|
@@ -20855,7 +21095,7 @@ function formatPreviousContext(writes) {
|
|
|
20855
21095
|
}
|
|
20856
21096
|
|
|
20857
21097
|
// server/routes/admin/public-session-context.ts
|
|
20858
|
-
var
|
|
21098
|
+
var TAG31 = "[public-session-context]";
|
|
20859
21099
|
function isLoopbackAddr4(addr) {
|
|
20860
21100
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
20861
21101
|
}
|
|
@@ -20863,7 +21103,7 @@ var app41 = new Hono();
|
|
|
20863
21103
|
app41.get("/", async (c) => {
|
|
20864
21104
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
20865
21105
|
if (!isLoopbackAddr4(remoteAddr)) {
|
|
20866
|
-
console.error(`${
|
|
21106
|
+
console.error(`${TAG31} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
20867
21107
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
20868
21108
|
}
|
|
20869
21109
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -20872,7 +21112,7 @@ app41.get("/", async (c) => {
|
|
|
20872
21112
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
20873
21113
|
const offender = tokens.find((t) => !isLoopbackAddr4(t));
|
|
20874
21114
|
if (offender !== void 0) {
|
|
20875
|
-
console.error(`${
|
|
21115
|
+
console.error(`${TAG31} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
20876
21116
|
return c.json({ error: "public-session-context-loopback-only" }, 403);
|
|
20877
21117
|
}
|
|
20878
21118
|
}
|
|
@@ -20886,14 +21126,14 @@ app41.get("/", async (c) => {
|
|
|
20886
21126
|
const writes = await fetchSliceWrites(session, sliceToken, accountId);
|
|
20887
21127
|
const total = Date.now() - started;
|
|
20888
21128
|
console.log(
|
|
20889
|
-
`${
|
|
21129
|
+
`${TAG31} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
|
|
20890
21130
|
);
|
|
20891
21131
|
return c.json({ writes });
|
|
20892
21132
|
} catch (err) {
|
|
20893
21133
|
const elapsed = Date.now() - started;
|
|
20894
21134
|
const message = err instanceof Error ? err.message : String(err);
|
|
20895
21135
|
console.error(
|
|
20896
|
-
`${
|
|
21136
|
+
`${TAG31} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
|
|
20897
21137
|
);
|
|
20898
21138
|
return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
|
|
20899
21139
|
} finally {
|
|
@@ -20912,7 +21152,7 @@ function getWebchatGateway() {
|
|
|
20912
21152
|
}
|
|
20913
21153
|
|
|
20914
21154
|
// server/routes/admin/public-session-exit.ts
|
|
20915
|
-
var
|
|
21155
|
+
var TAG32 = "[public-session-exit-route]";
|
|
20916
21156
|
function isLoopbackAddr5(addr) {
|
|
20917
21157
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
20918
21158
|
}
|
|
@@ -20920,7 +21160,7 @@ var app42 = new Hono();
|
|
|
20920
21160
|
app42.post("/", async (c) => {
|
|
20921
21161
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
20922
21162
|
if (!isLoopbackAddr5(remoteAddr)) {
|
|
20923
|
-
console.error(`${
|
|
21163
|
+
console.error(`${TAG32} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
20924
21164
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
20925
21165
|
}
|
|
20926
21166
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -20929,7 +21169,7 @@ app42.post("/", async (c) => {
|
|
|
20929
21169
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
20930
21170
|
const offender = tokens.find((t) => !isLoopbackAddr5(t));
|
|
20931
21171
|
if (offender !== void 0) {
|
|
20932
|
-
console.error(`${
|
|
21172
|
+
console.error(`${TAG32} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
20933
21173
|
return c.json({ error: "public-session-exit-loopback-only" }, 403);
|
|
20934
21174
|
}
|
|
20935
21175
|
}
|
|
@@ -20943,7 +21183,7 @@ app42.post("/", async (c) => {
|
|
|
20943
21183
|
if (!sessionId) return c.json({ error: "sessionId required" }, 400);
|
|
20944
21184
|
const gateway = getWebchatGateway();
|
|
20945
21185
|
if (!gateway) {
|
|
20946
|
-
console.error(`${
|
|
21186
|
+
console.error(`${TAG32} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
|
|
20947
21187
|
return c.json({ error: "webchat-gateway-unset" }, 503);
|
|
20948
21188
|
}
|
|
20949
21189
|
gateway.handlePublicSessionExit(sessionId);
|
|
@@ -20952,7 +21192,7 @@ app42.post("/", async (c) => {
|
|
|
20952
21192
|
var public_session_exit_default = app42;
|
|
20953
21193
|
|
|
20954
21194
|
// server/routes/admin/access-session-evict.ts
|
|
20955
|
-
var
|
|
21195
|
+
var TAG33 = "[access-session-evict]";
|
|
20956
21196
|
function isLoopbackAddr6(addr) {
|
|
20957
21197
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
20958
21198
|
}
|
|
@@ -20960,7 +21200,7 @@ var app43 = new Hono();
|
|
|
20960
21200
|
app43.post("/", async (c) => {
|
|
20961
21201
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
20962
21202
|
if (!isLoopbackAddr6(remoteAddr)) {
|
|
20963
|
-
console.error(`${
|
|
21203
|
+
console.error(`${TAG33} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
20964
21204
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
20965
21205
|
}
|
|
20966
21206
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -20969,7 +21209,7 @@ app43.post("/", async (c) => {
|
|
|
20969
21209
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
20970
21210
|
const offender = tokens.find((t) => !isLoopbackAddr6(t));
|
|
20971
21211
|
if (offender !== void 0) {
|
|
20972
|
-
console.error(`${
|
|
21212
|
+
console.error(`${TAG33} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
20973
21213
|
return c.json({ error: "access-session-evict-loopback-only" }, 403);
|
|
20974
21214
|
}
|
|
20975
21215
|
}
|
|
@@ -20982,13 +21222,13 @@ app43.post("/", async (c) => {
|
|
|
20982
21222
|
const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
|
|
20983
21223
|
if (!grantId) return c.json({ error: "grantId required" }, 400);
|
|
20984
21224
|
const dropped = evictAccessSessionsByGrant(grantId);
|
|
20985
|
-
console.log(`${
|
|
21225
|
+
console.log(`${TAG33} grantId=${grantId} dropped=${dropped}`);
|
|
20986
21226
|
return c.json({ ok: true, dropped });
|
|
20987
21227
|
});
|
|
20988
21228
|
var access_session_evict_default = app43;
|
|
20989
21229
|
|
|
20990
21230
|
// server/routes/admin/enrol-person.ts
|
|
20991
|
-
var
|
|
21231
|
+
var TAG34 = "[enrol]";
|
|
20992
21232
|
function isLoopbackAddr7(addr) {
|
|
20993
21233
|
return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
|
|
20994
21234
|
}
|
|
@@ -20997,7 +21237,7 @@ var app44 = new Hono();
|
|
|
20997
21237
|
app44.post("/", async (c) => {
|
|
20998
21238
|
const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
|
|
20999
21239
|
if (!isLoopbackAddr7(remoteAddr)) {
|
|
21000
|
-
console.error(`${
|
|
21240
|
+
console.error(`${TAG34} reject reason=non-loopback remoteAddr=${remoteAddr}`);
|
|
21001
21241
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
21002
21242
|
}
|
|
21003
21243
|
const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
|
|
@@ -21006,7 +21246,7 @@ app44.post("/", async (c) => {
|
|
|
21006
21246
|
const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
21007
21247
|
const offender = tokens.find((t) => !isLoopbackAddr7(t));
|
|
21008
21248
|
if (offender !== void 0) {
|
|
21009
|
-
console.error(`${
|
|
21249
|
+
console.error(`${TAG34} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
|
|
21010
21250
|
return c.json({ error: "enrol-person-loopback-only" }, 403);
|
|
21011
21251
|
}
|
|
21012
21252
|
}
|
|
@@ -21031,7 +21271,7 @@ app44.post("/", async (c) => {
|
|
|
21031
21271
|
}
|
|
21032
21272
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
21033
21273
|
if (!accountId) {
|
|
21034
|
-
console.error(`${
|
|
21274
|
+
console.error(`${TAG34} op=person result=no-account-id`);
|
|
21035
21275
|
return c.json({ error: "no-account-id" }, 500);
|
|
21036
21276
|
}
|
|
21037
21277
|
let personId;
|
|
@@ -21039,7 +21279,7 @@ app44.post("/", async (c) => {
|
|
|
21039
21279
|
personId = await enrolPerson({ accountId, phone, email, agentSlug });
|
|
21040
21280
|
} catch (err) {
|
|
21041
21281
|
console.error(
|
|
21042
|
-
`${
|
|
21282
|
+
`${TAG34} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
21043
21283
|
);
|
|
21044
21284
|
return c.json({ error: "enrol-failed" }, 500);
|
|
21045
21285
|
}
|
|
@@ -21049,11 +21289,11 @@ app44.post("/", async (c) => {
|
|
|
21049
21289
|
if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
|
|
21050
21290
|
} catch (err) {
|
|
21051
21291
|
console.error(
|
|
21052
|
-
`${
|
|
21292
|
+
`${TAG34} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
21053
21293
|
);
|
|
21054
21294
|
}
|
|
21055
21295
|
console.log(
|
|
21056
|
-
`${
|
|
21296
|
+
`${TAG34} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
|
|
21057
21297
|
);
|
|
21058
21298
|
return c.json({ personId, grant }, 200);
|
|
21059
21299
|
});
|
|
@@ -21099,8 +21339,8 @@ app45.post("/launch", requireAdminSession, async (c) => {
|
|
|
21099
21339
|
var browser_default = app45;
|
|
21100
21340
|
|
|
21101
21341
|
// server/routes/admin/calendar.ts
|
|
21102
|
-
import { existsSync as
|
|
21103
|
-
import { join as
|
|
21342
|
+
import { existsSync as existsSync31 } from "fs";
|
|
21343
|
+
import { join as join35 } from "path";
|
|
21104
21344
|
|
|
21105
21345
|
// server/lib/calendar-ics.ts
|
|
21106
21346
|
var CRLF = "\r\n";
|
|
@@ -21199,8 +21439,8 @@ function countVEvents(ics) {
|
|
|
21199
21439
|
}
|
|
21200
21440
|
|
|
21201
21441
|
// server/lib/calendar-availability.ts
|
|
21202
|
-
import { readFileSync as
|
|
21203
|
-
import { join as
|
|
21442
|
+
import { readFileSync as readFileSync34 } from "fs";
|
|
21443
|
+
import { join as join34 } from "path";
|
|
21204
21444
|
var AVAILABILITY_FILENAME = "calendar-availability.json";
|
|
21205
21445
|
var REQUIRED_KEYS = [
|
|
21206
21446
|
"timezone",
|
|
@@ -21209,10 +21449,10 @@ var REQUIRED_KEYS = [
|
|
|
21209
21449
|
"weekly"
|
|
21210
21450
|
];
|
|
21211
21451
|
function readAvailabilityConfig(accountDir) {
|
|
21212
|
-
const path3 =
|
|
21452
|
+
const path3 = join34(accountDir, AVAILABILITY_FILENAME);
|
|
21213
21453
|
let raw;
|
|
21214
21454
|
try {
|
|
21215
|
-
raw =
|
|
21455
|
+
raw = readFileSync34(path3, "utf-8");
|
|
21216
21456
|
} catch {
|
|
21217
21457
|
throw new Error(`availability not configured: ${path3} not found`);
|
|
21218
21458
|
}
|
|
@@ -21571,7 +21811,7 @@ app46.get("/booking-link", requireAdminSession, (c) => {
|
|
|
21571
21811
|
console.error('[calendar] op=booking-link-fail err="no account configured"');
|
|
21572
21812
|
return c.json({ bookingDomain: null });
|
|
21573
21813
|
}
|
|
21574
|
-
if (!
|
|
21814
|
+
if (!existsSync31(join35(account.accountDir, AVAILABILITY_FILENAME))) {
|
|
21575
21815
|
console.log("[calendar] op=booking-link bookingDomain=none source=availability-config");
|
|
21576
21816
|
return c.json({ bookingDomain: null });
|
|
21577
21817
|
}
|
|
@@ -21607,7 +21847,7 @@ function toNum(v) {
|
|
|
21607
21847
|
}
|
|
21608
21848
|
|
|
21609
21849
|
// server/routes/admin/tasks-list.ts
|
|
21610
|
-
var
|
|
21850
|
+
var TAG35 = "[task-timer]";
|
|
21611
21851
|
var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
|
|
21612
21852
|
var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
|
|
21613
21853
|
var app47 = new Hono();
|
|
@@ -21615,7 +21855,7 @@ app47.get("/", requireAdminSession, async (c) => {
|
|
|
21615
21855
|
const cacheKey = c.var.cacheKey;
|
|
21616
21856
|
const accountId = getAccountIdForSession(cacheKey);
|
|
21617
21857
|
if (!accountId) {
|
|
21618
|
-
console.error(`${
|
|
21858
|
+
console.error(`${TAG35} op=list auth-rejected reason="no account for session"`);
|
|
21619
21859
|
return c.json({ error: "Account not found for session" }, 401);
|
|
21620
21860
|
}
|
|
21621
21861
|
const session = getSession();
|
|
@@ -21653,10 +21893,10 @@ app47.get("/", requireAdminSession, async (c) => {
|
|
|
21653
21893
|
if (COMPLETED.has(status)) completed.push(row);
|
|
21654
21894
|
else if (!HIDDEN_FROM_OPEN.has(status)) open.push(row);
|
|
21655
21895
|
}
|
|
21656
|
-
console.log(`${
|
|
21896
|
+
console.log(`${TAG35} op=list account=${accountId} open=${open.length} completed=${completed.length}`);
|
|
21657
21897
|
return c.json({ open, completed });
|
|
21658
21898
|
} catch (err) {
|
|
21659
|
-
console.error(`${
|
|
21899
|
+
console.error(`${TAG35} op=list error="${err instanceof Error ? err.message : String(err)}"`);
|
|
21660
21900
|
return c.json({ error: "tasks-list-failed" }, 500);
|
|
21661
21901
|
} finally {
|
|
21662
21902
|
await session.close();
|
|
@@ -21666,7 +21906,7 @@ var tasks_list_default = app47;
|
|
|
21666
21906
|
|
|
21667
21907
|
// server/routes/admin/task-timer-start.ts
|
|
21668
21908
|
import { randomUUID as randomUUID14 } from "crypto";
|
|
21669
|
-
var
|
|
21909
|
+
var TAG36 = "[task-timer]";
|
|
21670
21910
|
var app48 = new Hono();
|
|
21671
21911
|
app48.post("/", requireAdminSession, async (c) => {
|
|
21672
21912
|
const cacheKey = c.var.cacheKey;
|
|
@@ -21688,7 +21928,7 @@ app48.post("/", requireAdminSession, async (c) => {
|
|
|
21688
21928
|
{ taskId, accountId }
|
|
21689
21929
|
);
|
|
21690
21930
|
if (target.records.length === 0) {
|
|
21691
|
-
console.error(`${
|
|
21931
|
+
console.error(`${TAG36} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
|
|
21692
21932
|
return c.json({ error: "task-not-found" }, 404);
|
|
21693
21933
|
}
|
|
21694
21934
|
const open = await session.run(
|
|
@@ -21700,7 +21940,7 @@ app48.post("/", requireAdminSession, async (c) => {
|
|
|
21700
21940
|
const priorEntryId = open.records[0]?.get("entryId");
|
|
21701
21941
|
const priorStartedAt = open.records[0]?.get("startedAt");
|
|
21702
21942
|
if (priorEntryId) {
|
|
21703
|
-
console.log(`${
|
|
21943
|
+
console.log(`${TAG36} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
|
|
21704
21944
|
return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
|
|
21705
21945
|
}
|
|
21706
21946
|
const entryId = randomUUID14();
|
|
@@ -21710,10 +21950,10 @@ app48.post("/", requireAdminSession, async (c) => {
|
|
|
21710
21950
|
CREATE (te)-[:LOGGED_AGAINST]->(t)`,
|
|
21711
21951
|
{ taskId, accountId, entryId, now }
|
|
21712
21952
|
);
|
|
21713
|
-
console.log(`${
|
|
21953
|
+
console.log(`${TAG36} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
|
|
21714
21954
|
return c.json({ ok: true, running: true, entryId, startedAt: now });
|
|
21715
21955
|
} catch (err) {
|
|
21716
|
-
console.error(`${
|
|
21956
|
+
console.error(`${TAG36} op=start error="${err instanceof Error ? err.message : String(err)}"`);
|
|
21717
21957
|
return c.json({ error: "task-timer-start-failed" }, 500);
|
|
21718
21958
|
} finally {
|
|
21719
21959
|
await session.close();
|
|
@@ -21723,7 +21963,7 @@ var task_timer_start_default = app48;
|
|
|
21723
21963
|
|
|
21724
21964
|
// server/routes/admin/task-timer-stop.ts
|
|
21725
21965
|
import neo4j5 from "neo4j-driver";
|
|
21726
|
-
var
|
|
21966
|
+
var TAG37 = "[task-timer]";
|
|
21727
21967
|
var app49 = new Hono();
|
|
21728
21968
|
app49.post("/", requireAdminSession, async (c) => {
|
|
21729
21969
|
const cacheKey = c.var.cacheKey;
|
|
@@ -21755,7 +21995,7 @@ app49.post("/", requireAdminSession, async (c) => {
|
|
|
21755
21995
|
{ taskId, accountId }
|
|
21756
21996
|
);
|
|
21757
21997
|
const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
|
|
21758
|
-
console.log(`${
|
|
21998
|
+
console.log(`${TAG37} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
|
|
21759
21999
|
return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
|
|
21760
22000
|
}
|
|
21761
22001
|
const seconds = secondsBetween(startedAt, now);
|
|
@@ -21778,11 +22018,11 @@ app49.post("/", requireAdminSession, async (c) => {
|
|
|
21778
22018
|
const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
|
|
21779
22019
|
const sumAdjustments = toNum(verify.records[0]?.get("sumAdjustments"));
|
|
21780
22020
|
const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
|
|
21781
|
-
console.log(`${
|
|
21782
|
-
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}`);
|
|
21783
22023
|
return c.json({ ok: true, running: false, seconds, secondsLogged });
|
|
21784
22024
|
} catch (err) {
|
|
21785
|
-
console.error(`${
|
|
22025
|
+
console.error(`${TAG37} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
|
|
21786
22026
|
return c.json({ error: "task-timer-stop-failed" }, 500);
|
|
21787
22027
|
} finally {
|
|
21788
22028
|
await session.close();
|
|
@@ -21791,7 +22031,7 @@ app49.post("/", requireAdminSession, async (c) => {
|
|
|
21791
22031
|
var task_timer_stop_default = app49;
|
|
21792
22032
|
|
|
21793
22033
|
// server/routes/admin/task-complete.ts
|
|
21794
|
-
var
|
|
22034
|
+
var TAG38 = "[task-timer]";
|
|
21795
22035
|
var app50 = new Hono();
|
|
21796
22036
|
app50.post("/", requireAdminSession, async (c) => {
|
|
21797
22037
|
const cacheKey = c.var.cacheKey;
|
|
@@ -21818,10 +22058,10 @@ app50.post("/", requireAdminSession, async (c) => {
|
|
|
21818
22058
|
return c.json({ error: "task-not-found" }, 404);
|
|
21819
22059
|
}
|
|
21820
22060
|
const secondsLogged = toNum(result.records[0].get("secondsLogged"));
|
|
21821
|
-
console.log(`${
|
|
22061
|
+
console.log(`${TAG38} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
|
|
21822
22062
|
return c.json({ ok: true, status: "completed", secondsLogged });
|
|
21823
22063
|
} catch (err) {
|
|
21824
|
-
console.error(`${
|
|
22064
|
+
console.error(`${TAG38} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
|
|
21825
22065
|
return c.json({ error: "task-complete-failed" }, 500);
|
|
21826
22066
|
} finally {
|
|
21827
22067
|
await session.close();
|
|
@@ -21832,7 +22072,7 @@ var task_complete_default = app50;
|
|
|
21832
22072
|
// server/routes/admin/task-time-adjust.ts
|
|
21833
22073
|
import { randomUUID as randomUUID15 } from "crypto";
|
|
21834
22074
|
import neo4j6 from "neo4j-driver";
|
|
21835
|
-
var
|
|
22075
|
+
var TAG39 = "[task-time-adjust]";
|
|
21836
22076
|
var app51 = new Hono();
|
|
21837
22077
|
app51.post("/", requireAdminSession, async (c) => {
|
|
21838
22078
|
const cacheKey = c.var.cacheKey;
|
|
@@ -21842,22 +22082,22 @@ app51.post("/", requireAdminSession, async (c) => {
|
|
|
21842
22082
|
try {
|
|
21843
22083
|
body = await c.req.json();
|
|
21844
22084
|
} catch {
|
|
21845
|
-
console.error(`${
|
|
22085
|
+
console.error(`${TAG39} op=reject reason=bad-json`);
|
|
21846
22086
|
return c.json({ error: "invalid-json" }, 400);
|
|
21847
22087
|
}
|
|
21848
22088
|
const taskId = typeof body.taskId === "string" ? body.taskId : "";
|
|
21849
22089
|
if (!taskId) {
|
|
21850
|
-
console.error(`${
|
|
22090
|
+
console.error(`${TAG39} op=reject reason=no-task`);
|
|
21851
22091
|
return c.json({ error: "taskId required" }, 400);
|
|
21852
22092
|
}
|
|
21853
22093
|
const newSeconds = body.newSeconds;
|
|
21854
22094
|
if (typeof newSeconds !== "number" || !Number.isInteger(newSeconds) || newSeconds < 0) {
|
|
21855
|
-
console.error(`${
|
|
22095
|
+
console.error(`${TAG39} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
|
|
21856
22096
|
return c.json({ error: "newSeconds must be a non-negative integer" }, 400);
|
|
21857
22097
|
}
|
|
21858
22098
|
const adjustmentId = randomUUID15();
|
|
21859
22099
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
21860
|
-
console.log(`${
|
|
22100
|
+
console.log(`${TAG39} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
|
|
21861
22101
|
const session = getSession();
|
|
21862
22102
|
try {
|
|
21863
22103
|
const guard = await session.run(
|
|
@@ -21867,12 +22107,12 @@ app51.post("/", requireAdminSession, async (c) => {
|
|
|
21867
22107
|
{ taskId, accountId }
|
|
21868
22108
|
);
|
|
21869
22109
|
if (guard.records.length === 0) {
|
|
21870
|
-
console.error(`${
|
|
22110
|
+
console.error(`${TAG39} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
|
|
21871
22111
|
return c.json({ error: "task-not-found" }, 404);
|
|
21872
22112
|
}
|
|
21873
22113
|
const openCount = toNum(guard.records[0].get("openCount"));
|
|
21874
22114
|
if (openCount > 0) {
|
|
21875
|
-
console.error(`${
|
|
22115
|
+
console.error(`${TAG39} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
|
|
21876
22116
|
return c.json({ error: "task-timer-running" }, 409);
|
|
21877
22117
|
}
|
|
21878
22118
|
const previousSeconds = toNum(guard.records[0].get("previousSeconds"));
|
|
@@ -21898,10 +22138,10 @@ app51.post("/", requireAdminSession, async (c) => {
|
|
|
21898
22138
|
}
|
|
21899
22139
|
);
|
|
21900
22140
|
const secondsLoggedAfter = toNum(write.records[0]?.get("secondsLoggedAfter"));
|
|
21901
|
-
console.log(`${
|
|
22141
|
+
console.log(`${TAG39} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
|
|
21902
22142
|
return c.json({ ok: true, secondsLogged: secondsLoggedAfter });
|
|
21903
22143
|
} catch (err) {
|
|
21904
|
-
console.error(`${
|
|
22144
|
+
console.error(`${TAG39} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
21905
22145
|
return c.json({ error: "task-time-adjust-failed" }, 500);
|
|
21906
22146
|
} finally {
|
|
21907
22147
|
await session.close();
|
|
@@ -21955,7 +22195,7 @@ app52.route("/task-time-adjust", task_time_adjust_default);
|
|
|
21955
22195
|
var admin_default = app52;
|
|
21956
22196
|
|
|
21957
22197
|
// server/routes/access/verify-token.ts
|
|
21958
|
-
var
|
|
22198
|
+
var TAG40 = "[access-verify]";
|
|
21959
22199
|
var MINT_TAG = "[access-session-mint]";
|
|
21960
22200
|
var COOKIE_NAME = "__access_session";
|
|
21961
22201
|
var app53 = new Hono();
|
|
@@ -21974,39 +22214,39 @@ app53.post("/", async (c) => {
|
|
|
21974
22214
|
}
|
|
21975
22215
|
const rateMsg = checkAccessRateLimit(ip, agentSlug);
|
|
21976
22216
|
if (rateMsg) {
|
|
21977
|
-
console.error(`${
|
|
22217
|
+
console.error(`${TAG40} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
|
|
21978
22218
|
return c.json({ error: rateMsg }, 429);
|
|
21979
22219
|
}
|
|
21980
22220
|
const grant = await findGrantByMagicToken(token);
|
|
21981
22221
|
if (!grant) {
|
|
21982
22222
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
21983
|
-
console.error(`${
|
|
22223
|
+
console.error(`${TAG40} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
|
|
21984
22224
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
21985
22225
|
}
|
|
21986
22226
|
if (grant.agentSlug !== agentSlug) {
|
|
21987
22227
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
21988
22228
|
console.error(
|
|
21989
|
-
`${
|
|
22229
|
+
`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
|
|
21990
22230
|
);
|
|
21991
22231
|
return c.json({ error: "invalid-or-expired-link" }, 401);
|
|
21992
22232
|
}
|
|
21993
22233
|
if (grant.status === "expired" || grant.status === "revoked") {
|
|
21994
22234
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
21995
22235
|
console.error(
|
|
21996
|
-
`${
|
|
22236
|
+
`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
|
|
21997
22237
|
);
|
|
21998
22238
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
21999
22239
|
}
|
|
22000
22240
|
if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
|
|
22001
22241
|
recordAccessFailedAttempt(ip, agentSlug);
|
|
22002
22242
|
console.error(
|
|
22003
|
-
`${
|
|
22243
|
+
`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
|
|
22004
22244
|
);
|
|
22005
22245
|
return c.json({ error: "access-no-longer-valid" }, 401);
|
|
22006
22246
|
}
|
|
22007
22247
|
if (!grant.sliceToken) {
|
|
22008
22248
|
console.error(
|
|
22009
|
-
`${
|
|
22249
|
+
`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
|
|
22010
22250
|
);
|
|
22011
22251
|
return c.json({ error: "grant-misconfigured" }, 500);
|
|
22012
22252
|
}
|
|
@@ -22022,12 +22262,12 @@ app53.post("/", async (c) => {
|
|
|
22022
22262
|
await consumeMagicTokenAndActivate(grant.grantId);
|
|
22023
22263
|
} catch (err) {
|
|
22024
22264
|
console.error(
|
|
22025
|
-
`${
|
|
22265
|
+
`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
22026
22266
|
);
|
|
22027
22267
|
return c.json({ error: "verification-failed" }, 500);
|
|
22028
22268
|
}
|
|
22029
22269
|
clearAccessRateLimit(ip, agentSlug);
|
|
22030
|
-
console.log(`${
|
|
22270
|
+
console.log(`${TAG40} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
|
|
22031
22271
|
console.log(
|
|
22032
22272
|
`${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
|
|
22033
22273
|
);
|
|
@@ -22103,7 +22343,7 @@ async function sendMagicLinkEmail(payload) {
|
|
|
22103
22343
|
}
|
|
22104
22344
|
|
|
22105
22345
|
// server/routes/access/request-magic-link.ts
|
|
22106
|
-
var
|
|
22346
|
+
var TAG41 = "[access-request-link]";
|
|
22107
22347
|
var app54 = new Hono();
|
|
22108
22348
|
var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
|
|
22109
22349
|
app54.post("/", async (c) => {
|
|
@@ -22120,18 +22360,18 @@ app54.post("/", async (c) => {
|
|
|
22120
22360
|
}
|
|
22121
22361
|
const rateMsg = checkRequestLinkRateLimit(contactValue);
|
|
22122
22362
|
if (rateMsg) {
|
|
22123
|
-
console.error(`${
|
|
22363
|
+
console.error(`${TAG41} contactValue=${maskContact(contactValue)} result=rate-limited`);
|
|
22124
22364
|
return c.json({ error: rateMsg }, 429);
|
|
22125
22365
|
}
|
|
22126
22366
|
recordRequestLinkAttempt(contactValue);
|
|
22127
22367
|
const accountId = process.env.ACCOUNT_ID ?? "";
|
|
22128
22368
|
if (!accountId) {
|
|
22129
|
-
console.error(`${
|
|
22369
|
+
console.error(`${TAG41} contactValue=${maskContact(contactValue)} result=no-account-id`);
|
|
22130
22370
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
22131
22371
|
}
|
|
22132
22372
|
const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
|
|
22133
22373
|
if (!grant) {
|
|
22134
|
-
console.log(`${
|
|
22374
|
+
console.log(`${TAG41} contactValue=${maskContact(contactValue)} result=notfound`);
|
|
22135
22375
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
22136
22376
|
}
|
|
22137
22377
|
let token;
|
|
@@ -22139,7 +22379,7 @@ app54.post("/", async (c) => {
|
|
|
22139
22379
|
token = await generateNewMagicToken(grant.grantId);
|
|
22140
22380
|
} catch (err) {
|
|
22141
22381
|
console.error(
|
|
22142
|
-
`${
|
|
22382
|
+
`${TAG41} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
|
|
22143
22383
|
);
|
|
22144
22384
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
22145
22385
|
}
|
|
@@ -22171,12 +22411,12 @@ app54.post("/", async (c) => {
|
|
|
22171
22411
|
});
|
|
22172
22412
|
if (!sendResult.ok) {
|
|
22173
22413
|
console.error(
|
|
22174
|
-
`${
|
|
22414
|
+
`${TAG41} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
|
|
22175
22415
|
);
|
|
22176
22416
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
22177
22417
|
}
|
|
22178
22418
|
console.log(
|
|
22179
|
-
`${
|
|
22419
|
+
`${TAG41} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
|
|
22180
22420
|
);
|
|
22181
22421
|
return c.json({ message: VISITOR_MESSAGE }, 200);
|
|
22182
22422
|
});
|
|
@@ -22189,7 +22429,7 @@ app55.route("/request-magic-link", request_magic_link_default);
|
|
|
22189
22429
|
var access_default = app55;
|
|
22190
22430
|
|
|
22191
22431
|
// server/routes/sites.ts
|
|
22192
|
-
import { existsSync as
|
|
22432
|
+
import { existsSync as existsSync32, readFileSync as readFileSync35, realpathSync as realpathSync7, statSync as statSync12 } from "fs";
|
|
22193
22433
|
import { resolve as resolve28 } from "path";
|
|
22194
22434
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
22195
22435
|
var MIME = {
|
|
@@ -22255,7 +22495,7 @@ app56.get("/:rel{.*}", (c) => {
|
|
|
22255
22495
|
}
|
|
22256
22496
|
let stat8;
|
|
22257
22497
|
try {
|
|
22258
|
-
stat8 =
|
|
22498
|
+
stat8 = existsSync32(filePath) ? statSync12(filePath) : null;
|
|
22259
22499
|
} catch {
|
|
22260
22500
|
stat8 = null;
|
|
22261
22501
|
}
|
|
@@ -22274,7 +22514,7 @@ app56.get("/:rel{.*}", (c) => {
|
|
|
22274
22514
|
console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
|
|
22275
22515
|
return c.text("Forbidden", 403);
|
|
22276
22516
|
}
|
|
22277
|
-
if (!
|
|
22517
|
+
if (!existsSync32(filePath)) {
|
|
22278
22518
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
22279
22519
|
return c.text("Not found", 404);
|
|
22280
22520
|
}
|
|
@@ -22293,7 +22533,7 @@ app56.get("/:rel{.*}", (c) => {
|
|
|
22293
22533
|
}
|
|
22294
22534
|
let body;
|
|
22295
22535
|
try {
|
|
22296
|
-
body =
|
|
22536
|
+
body = readFileSync35(realPath);
|
|
22297
22537
|
} catch (err) {
|
|
22298
22538
|
const code = err?.code;
|
|
22299
22539
|
if (code === "EISDIR") {
|
|
@@ -22328,8 +22568,8 @@ app56.get("/:rel{.*}", (c) => {
|
|
|
22328
22568
|
var sites_default = app56;
|
|
22329
22569
|
|
|
22330
22570
|
// app/lib/visitor-token.ts
|
|
22331
|
-
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
22332
|
-
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";
|
|
22333
22573
|
import { dirname as dirname12 } from "path";
|
|
22334
22574
|
var TOKEN_PREFIX = "v1.";
|
|
22335
22575
|
var SECRET_BYTES = 32;
|
|
@@ -22338,21 +22578,21 @@ var cachedSecret = null;
|
|
|
22338
22578
|
function getSecret() {
|
|
22339
22579
|
if (cachedSecret) return cachedSecret;
|
|
22340
22580
|
try {
|
|
22341
|
-
const hex2 =
|
|
22581
|
+
const hex2 = readFileSync36(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
22342
22582
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
22343
22583
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
22344
22584
|
return cachedSecret;
|
|
22345
22585
|
}
|
|
22346
22586
|
} catch {
|
|
22347
22587
|
}
|
|
22348
|
-
const fresh =
|
|
22588
|
+
const fresh = randomBytes2(SECRET_BYTES).toString("hex");
|
|
22349
22589
|
try {
|
|
22350
|
-
|
|
22351
|
-
|
|
22590
|
+
mkdirSync8(dirname12(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
22591
|
+
writeFileSync12(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
22352
22592
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
22353
22593
|
} catch {
|
|
22354
22594
|
}
|
|
22355
|
-
const hex =
|
|
22595
|
+
const hex = readFileSync36(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
22356
22596
|
cachedSecret = Buffer.from(hex, "hex");
|
|
22357
22597
|
return cachedSecret;
|
|
22358
22598
|
}
|
|
@@ -22405,8 +22645,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
22405
22645
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
22406
22646
|
|
|
22407
22647
|
// app/lib/brand-config.ts
|
|
22408
|
-
import { existsSync as
|
|
22409
|
-
import { join as
|
|
22648
|
+
import { existsSync as existsSync33, readFileSync as readFileSync37 } from "fs";
|
|
22649
|
+
import { join as join36 } from "path";
|
|
22410
22650
|
var cached2 = null;
|
|
22411
22651
|
var cachedAttempted = false;
|
|
22412
22652
|
function readBrandConfig() {
|
|
@@ -22414,10 +22654,10 @@ function readBrandConfig() {
|
|
|
22414
22654
|
cachedAttempted = true;
|
|
22415
22655
|
const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
|
|
22416
22656
|
if (!platformRoot5) return null;
|
|
22417
|
-
const brandPath =
|
|
22418
|
-
if (!
|
|
22657
|
+
const brandPath = join36(platformRoot5, "config", "brand.json");
|
|
22658
|
+
if (!existsSync33(brandPath)) return null;
|
|
22419
22659
|
try {
|
|
22420
|
-
cached2 = JSON.parse(
|
|
22660
|
+
cached2 = JSON.parse(readFileSync37(brandPath, "utf-8"));
|
|
22421
22661
|
return cached2;
|
|
22422
22662
|
} catch {
|
|
22423
22663
|
return null;
|
|
@@ -22906,13 +23146,13 @@ var visitor_event_default = app59;
|
|
|
22906
23146
|
|
|
22907
23147
|
// server/routes/session.ts
|
|
22908
23148
|
import { resolve as resolve29 } from "path";
|
|
22909
|
-
import { existsSync as
|
|
23149
|
+
import { existsSync as existsSync34, writeFileSync as writeFileSync13, mkdirSync as mkdirSync9 } from "fs";
|
|
22910
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;
|
|
22911
23151
|
function writeBrandingCache(accountId, agentSlug, branding) {
|
|
22912
23152
|
try {
|
|
22913
23153
|
const cacheDir = resolve29(MAXY_DIR, "branding-cache", accountId);
|
|
22914
|
-
|
|
22915
|
-
|
|
23154
|
+
mkdirSync9(cacheDir, { recursive: true });
|
|
23155
|
+
writeFileSync13(resolve29(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
|
|
22916
23156
|
} catch (err) {
|
|
22917
23157
|
console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
22918
23158
|
}
|
|
@@ -22990,7 +23230,7 @@ app60.post("/", async (c) => {
|
|
|
22990
23230
|
let agentConfig = null;
|
|
22991
23231
|
if (account) {
|
|
22992
23232
|
const agentDir = resolve29(account.accountDir, "agents", agentSlug);
|
|
22993
|
-
if (!
|
|
23233
|
+
if (!existsSync34(agentDir) || !existsSync34(resolve29(agentDir, "config.json"))) {
|
|
22994
23234
|
return c.json({ error: "Agent not found" }, 404);
|
|
22995
23235
|
}
|
|
22996
23236
|
agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
|
|
@@ -23238,7 +23478,7 @@ app61.get("/free-busy", async (c) => {
|
|
|
23238
23478
|
var calendar_public_default = app61;
|
|
23239
23479
|
|
|
23240
23480
|
// app/lib/timeentry-census.ts
|
|
23241
|
-
var
|
|
23481
|
+
var TAG42 = "[timeentry-census]";
|
|
23242
23482
|
function reconcileTimeEntries(rows, now, horizonMs) {
|
|
23243
23483
|
const openEntries = rows.openEntries.length;
|
|
23244
23484
|
let oldestOpenAgeMs = 0;
|
|
@@ -23278,12 +23518,12 @@ async function runTimeEntryCensusOnce(session, now, horizonMs) {
|
|
|
23278
23518
|
sumAdjustments: toNum(r.get("sumAdjustments"))
|
|
23279
23519
|
}));
|
|
23280
23520
|
const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
|
|
23281
|
-
const line = `${
|
|
23521
|
+
const line = `${TAG42} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
|
|
23282
23522
|
if (finding.alarm) console.error(`${line} alarm=true`);
|
|
23283
23523
|
else console.log(line);
|
|
23284
23524
|
return finding;
|
|
23285
23525
|
} catch (err) {
|
|
23286
|
-
console.error(`${
|
|
23526
|
+
console.error(`${TAG42} error="${err instanceof Error ? err.message : String(err)}"`);
|
|
23287
23527
|
return null;
|
|
23288
23528
|
}
|
|
23289
23529
|
}
|
|
@@ -23297,13 +23537,13 @@ function startTimeEntryCensus(openSession, opts = {}) {
|
|
|
23297
23537
|
try {
|
|
23298
23538
|
session = openSession();
|
|
23299
23539
|
} catch (err) {
|
|
23300
|
-
console.error(`${
|
|
23540
|
+
console.error(`${TAG42} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
23301
23541
|
return;
|
|
23302
23542
|
}
|
|
23303
23543
|
try {
|
|
23304
23544
|
await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
|
|
23305
23545
|
} catch (err) {
|
|
23306
|
-
console.error(`${
|
|
23546
|
+
console.error(`${TAG42} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
|
|
23307
23547
|
} finally {
|
|
23308
23548
|
try {
|
|
23309
23549
|
await session.close();
|
|
@@ -23666,8 +23906,8 @@ async function migrateUploads(opts = {}) {
|
|
|
23666
23906
|
|
|
23667
23907
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
23668
23908
|
import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as writeFile4, unlink as unlink3 } from "fs/promises";
|
|
23669
|
-
import { existsSync as
|
|
23670
|
-
import { join as
|
|
23909
|
+
import { existsSync as existsSync35 } from "fs";
|
|
23910
|
+
import { join as join37 } from "path";
|
|
23671
23911
|
var ADMIN_ROLE2 = "admin";
|
|
23672
23912
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
23673
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;
|
|
@@ -23696,7 +23936,7 @@ async function writeRaw(path3, obj) {
|
|
|
23696
23936
|
await rename3(tmp, path3);
|
|
23697
23937
|
} catch (err) {
|
|
23698
23938
|
try {
|
|
23699
|
-
if (
|
|
23939
|
+
if (existsSync35(tmp)) await unlink3(tmp);
|
|
23700
23940
|
} catch {
|
|
23701
23941
|
}
|
|
23702
23942
|
throw err;
|
|
@@ -23712,7 +23952,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
23712
23952
|
}
|
|
23713
23953
|
for (const slug of slugs) {
|
|
23714
23954
|
if (!slug.isDirectory()) continue;
|
|
23715
|
-
const slugDir =
|
|
23955
|
+
const slugDir = join37(projectsRoot, slug.name);
|
|
23716
23956
|
let entries;
|
|
23717
23957
|
try {
|
|
23718
23958
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -23721,9 +23961,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
23721
23961
|
}
|
|
23722
23962
|
for (const entry of entries) {
|
|
23723
23963
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
23724
|
-
out.push(
|
|
23964
|
+
out.push(join37(slugDir, entry.name));
|
|
23725
23965
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
23726
|
-
const subDir =
|
|
23966
|
+
const subDir = join37(slugDir, entry.name);
|
|
23727
23967
|
let subs;
|
|
23728
23968
|
try {
|
|
23729
23969
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -23731,7 +23971,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
23731
23971
|
continue;
|
|
23732
23972
|
}
|
|
23733
23973
|
for (const s of subs) {
|
|
23734
|
-
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));
|
|
23735
23975
|
}
|
|
23736
23976
|
}
|
|
23737
23977
|
}
|
|
@@ -23743,7 +23983,7 @@ function shortId(path3) {
|
|
|
23743
23983
|
return base.slice(0, 8);
|
|
23744
23984
|
}
|
|
23745
23985
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
23746
|
-
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) ?? "";
|
|
23747
23987
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
23748
23988
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
23749
23989
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -25411,14 +25651,14 @@ function makeFileDelivery(opts) {
|
|
|
25411
25651
|
}
|
|
25412
25652
|
|
|
25413
25653
|
// app/lib/webchat/file-delivery.ts
|
|
25414
|
-
var
|
|
25654
|
+
var TAG43 = "[webchat-adaptor]";
|
|
25415
25655
|
function platformRoot2() {
|
|
25416
25656
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
25417
25657
|
}
|
|
25418
25658
|
function makeWebchatSendFile(entry) {
|
|
25419
25659
|
return async (filePath) => {
|
|
25420
25660
|
if (!entry.accountId) {
|
|
25421
|
-
console.error(`${
|
|
25661
|
+
console.error(`${TAG43} file-delivery reject reason=no-account sender=${entry.senderId}`);
|
|
25422
25662
|
return { ok: false, error: "no-account" };
|
|
25423
25663
|
}
|
|
25424
25664
|
const accountDir = resolve32(platformRoot2(), "..", "data/accounts", entry.accountId);
|
|
@@ -25426,14 +25666,14 @@ function makeWebchatSendFile(entry) {
|
|
|
25426
25666
|
const resolved = realpathSync8(filePath);
|
|
25427
25667
|
const accountResolved = realpathSync8(accountDir);
|
|
25428
25668
|
if (!resolved.startsWith(accountResolved + "/")) {
|
|
25429
|
-
console.error(`${
|
|
25669
|
+
console.error(`${TAG43} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
|
|
25430
25670
|
return { ok: false, error: "outside-account" };
|
|
25431
25671
|
}
|
|
25432
25672
|
return { ok: true };
|
|
25433
25673
|
} catch (err) {
|
|
25434
25674
|
const code = err.code;
|
|
25435
25675
|
console.error(
|
|
25436
|
-
`${
|
|
25676
|
+
`${TAG43} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
|
|
25437
25677
|
);
|
|
25438
25678
|
return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
|
|
25439
25679
|
}
|
|
@@ -25442,7 +25682,7 @@ function makeWebchatSendFile(entry) {
|
|
|
25442
25682
|
function makeWebchatFileDelivery(entry) {
|
|
25443
25683
|
return makeFileDelivery({
|
|
25444
25684
|
entry,
|
|
25445
|
-
tag:
|
|
25685
|
+
tag: TAG43,
|
|
25446
25686
|
channel: "webchat",
|
|
25447
25687
|
sendFile: makeWebchatSendFile(entry),
|
|
25448
25688
|
deferUntilVerdict: true
|
|
@@ -25504,7 +25744,7 @@ function buildPublicWebchatSpawnRequest(input) {
|
|
|
25504
25744
|
}
|
|
25505
25745
|
|
|
25506
25746
|
// app/lib/whatsapp/inbound/file-delivery-bridge.ts
|
|
25507
|
-
var
|
|
25747
|
+
var TAG44 = "[whatsapp-adaptor]";
|
|
25508
25748
|
var SEND_USER_FILE2 = "SendUserFile";
|
|
25509
25749
|
var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
|
|
25510
25750
|
function platformRoot3() {
|
|
@@ -25522,7 +25762,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
25522
25762
|
});
|
|
25523
25763
|
if (result.ok) return { ok: true };
|
|
25524
25764
|
console.error(
|
|
25525
|
-
`${
|
|
25765
|
+
`${TAG44} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
|
|
25526
25766
|
);
|
|
25527
25767
|
return { ok: false, error: result.error };
|
|
25528
25768
|
};
|
|
@@ -25530,7 +25770,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
|
|
|
25530
25770
|
function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
25531
25771
|
const shared = makeFileDelivery({
|
|
25532
25772
|
entry,
|
|
25533
|
-
tag:
|
|
25773
|
+
tag: TAG44,
|
|
25534
25774
|
channel: "whatsapp",
|
|
25535
25775
|
sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
|
|
25536
25776
|
});
|
|
@@ -25565,7 +25805,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
|
|
|
25565
25805
|
if (!delivered) {
|
|
25566
25806
|
const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
|
|
25567
25807
|
console.error(
|
|
25568
|
-
`${
|
|
25808
|
+
`${TAG44} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
|
|
25569
25809
|
);
|
|
25570
25810
|
}
|
|
25571
25811
|
}
|
|
@@ -25969,7 +26209,7 @@ function buildTelegramSpawnRequest(input) {
|
|
|
25969
26209
|
import { realpathSync as realpathSync9 } from "fs";
|
|
25970
26210
|
import { readFile as readFile7, stat as stat7 } from "fs/promises";
|
|
25971
26211
|
import { resolve as resolve33, basename as basename11 } from "path";
|
|
25972
|
-
var
|
|
26212
|
+
var TAG45 = "[telegram:outbound]";
|
|
25973
26213
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
25974
26214
|
async function sendTelegramDocument(input) {
|
|
25975
26215
|
const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
|
|
@@ -25985,16 +26225,16 @@ async function sendTelegramDocument(input) {
|
|
|
25985
26225
|
resolvedPath = realpathSync9(filePath);
|
|
25986
26226
|
const accountResolved = realpathSync9(accountDir);
|
|
25987
26227
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
25988
|
-
console.error(`${
|
|
26228
|
+
console.error(`${TAG45} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
|
|
25989
26229
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
25990
26230
|
}
|
|
25991
26231
|
} catch (err) {
|
|
25992
26232
|
const code = err.code;
|
|
25993
26233
|
if (code === "ENOENT") {
|
|
25994
|
-
console.error(`${
|
|
26234
|
+
console.error(`${TAG45} document ENOENT path=${filePath}`);
|
|
25995
26235
|
return { ok: false, status: 404, error: `File not found: ${filePath}` };
|
|
25996
26236
|
}
|
|
25997
|
-
console.error(`${
|
|
26237
|
+
console.error(`${TAG45} document path error: ${String(err)}`);
|
|
25998
26238
|
return { ok: false, status: 500, error: String(err) };
|
|
25999
26239
|
}
|
|
26000
26240
|
const fileStat = await stat7(resolvedPath);
|
|
@@ -26027,13 +26267,13 @@ async function sendTelegramDocument(input) {
|
|
|
26027
26267
|
error = e instanceof Error ? e.message : String(e);
|
|
26028
26268
|
}
|
|
26029
26269
|
console.error(
|
|
26030
|
-
`${
|
|
26270
|
+
`${TAG45} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok}` + (messageId !== void 0 ? ` id=${messageId}` : "")
|
|
26031
26271
|
);
|
|
26032
26272
|
return ok ? { ok: true, messageId } : { ok: false, status: 500, error };
|
|
26033
26273
|
}
|
|
26034
26274
|
|
|
26035
26275
|
// app/lib/telegram/outbound/file-delivery.ts
|
|
26036
|
-
var
|
|
26276
|
+
var TAG46 = "[telegram:outbound]";
|
|
26037
26277
|
function platformRoot4() {
|
|
26038
26278
|
return process.env.MAXY_PLATFORM_ROOT || "";
|
|
26039
26279
|
}
|
|
@@ -26045,11 +26285,11 @@ function makeTelegramSendFile(entry) {
|
|
|
26045
26285
|
botToken = (entry.role === "admin" ? tg?.adminBotToken : tg?.publicBotToken) ?? null;
|
|
26046
26286
|
}
|
|
26047
26287
|
if (!botToken) {
|
|
26048
|
-
console.error(`${
|
|
26288
|
+
console.error(`${TAG46} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
|
|
26049
26289
|
return { ok: false, error: "no-bot-token" };
|
|
26050
26290
|
}
|
|
26051
26291
|
if (entry.replyTarget == null) {
|
|
26052
|
-
console.error(`${
|
|
26292
|
+
console.error(`${TAG46} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
|
|
26053
26293
|
return { ok: false, error: "no-reply-target" };
|
|
26054
26294
|
}
|
|
26055
26295
|
const result = await sendTelegramDocument({
|
|
@@ -26066,7 +26306,7 @@ function makeTelegramSendFile(entry) {
|
|
|
26066
26306
|
function makeTelegramFileDelivery(entry) {
|
|
26067
26307
|
return makeFileDelivery({
|
|
26068
26308
|
entry,
|
|
26069
|
-
tag:
|
|
26309
|
+
tag: TAG46,
|
|
26070
26310
|
channel: "telegram",
|
|
26071
26311
|
sendFile: makeTelegramSendFile(entry)
|
|
26072
26312
|
});
|
|
@@ -26106,17 +26346,17 @@ function startTelegramNativeFileFollower(input) {
|
|
|
26106
26346
|
}
|
|
26107
26347
|
|
|
26108
26348
|
// server/telegram-descriptor.ts
|
|
26109
|
-
import { resolve as resolve34, join as
|
|
26349
|
+
import { resolve as resolve34, join as join38 } from "path";
|
|
26110
26350
|
function telegramGatewayUrl() {
|
|
26111
26351
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
26112
26352
|
}
|
|
26113
26353
|
function telegramServerPath() {
|
|
26114
|
-
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");
|
|
26115
26355
|
}
|
|
26116
26356
|
|
|
26117
26357
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
26118
26358
|
import { randomUUID as randomUUID16 } from "crypto";
|
|
26119
|
-
var
|
|
26359
|
+
var TAG47 = "[public-session-review]";
|
|
26120
26360
|
var CONSUMED_CAP = 500;
|
|
26121
26361
|
var consumed = /* @__PURE__ */ new Set();
|
|
26122
26362
|
function consumeOnce(sessionId) {
|
|
@@ -26143,7 +26383,7 @@ async function fetchJsonl(sessionId) {
|
|
|
26143
26383
|
return await res.text();
|
|
26144
26384
|
} catch (err) {
|
|
26145
26385
|
console.error(
|
|
26146
|
-
`${
|
|
26386
|
+
`${TAG47} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
|
|
26147
26387
|
);
|
|
26148
26388
|
return null;
|
|
26149
26389
|
}
|
|
@@ -26167,7 +26407,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
26167
26407
|
const res = await fetch(url);
|
|
26168
26408
|
if (!res.ok) {
|
|
26169
26409
|
console.error(
|
|
26170
|
-
`${
|
|
26410
|
+
`${TAG47} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
|
|
26171
26411
|
);
|
|
26172
26412
|
return [];
|
|
26173
26413
|
}
|
|
@@ -26175,7 +26415,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
|
|
|
26175
26415
|
return Array.isArray(body.writes) ? body.writes : [];
|
|
26176
26416
|
} catch (err) {
|
|
26177
26417
|
console.error(
|
|
26178
|
-
`${
|
|
26418
|
+
`${TAG47} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
|
|
26179
26419
|
);
|
|
26180
26420
|
return [];
|
|
26181
26421
|
}
|
|
@@ -26204,7 +26444,7 @@ function composeInitialMessage(input) {
|
|
|
26204
26444
|
}
|
|
26205
26445
|
async function dispatchReviewer(input, initialMessage) {
|
|
26206
26446
|
const sessionId = randomUUID16();
|
|
26207
|
-
console.log(`${
|
|
26447
|
+
console.log(`${TAG47} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
|
|
26208
26448
|
const spawned = await managerRcSpawn({
|
|
26209
26449
|
sessionId,
|
|
26210
26450
|
initialMessage,
|
|
@@ -26224,21 +26464,21 @@ async function firePublicSessionEndReview(input) {
|
|
|
26224
26464
|
const dispatchedAt = Date.now();
|
|
26225
26465
|
if (consumed.has(input.sessionId)) {
|
|
26226
26466
|
console.log(
|
|
26227
|
-
`${
|
|
26467
|
+
`${TAG47} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
26228
26468
|
);
|
|
26229
26469
|
return;
|
|
26230
26470
|
}
|
|
26231
26471
|
const jsonl = await fetchJsonl(input.sessionId);
|
|
26232
26472
|
if (!jsonl) {
|
|
26233
26473
|
console.log(
|
|
26234
|
-
`${
|
|
26474
|
+
`${TAG47} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
|
|
26235
26475
|
);
|
|
26236
26476
|
return;
|
|
26237
26477
|
}
|
|
26238
26478
|
const operatorTurns = countOperatorTurns(jsonl);
|
|
26239
26479
|
if (operatorTurns === 0) {
|
|
26240
26480
|
console.log(
|
|
26241
|
-
`${
|
|
26481
|
+
`${TAG47} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
|
|
26242
26482
|
);
|
|
26243
26483
|
return;
|
|
26244
26484
|
}
|
|
@@ -26252,19 +26492,19 @@ async function firePublicSessionEndReview(input) {
|
|
|
26252
26492
|
});
|
|
26253
26493
|
if (!consumeOnce(input.sessionId)) {
|
|
26254
26494
|
console.log(
|
|
26255
|
-
`${
|
|
26495
|
+
`${TAG47} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
|
|
26256
26496
|
);
|
|
26257
26497
|
return;
|
|
26258
26498
|
}
|
|
26259
26499
|
const dispatched = await dispatchReviewer(input, initialMessage);
|
|
26260
26500
|
if (!dispatched.ok) {
|
|
26261
26501
|
console.error(
|
|
26262
|
-
`${
|
|
26502
|
+
`${TAG47} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
|
|
26263
26503
|
);
|
|
26264
26504
|
return;
|
|
26265
26505
|
}
|
|
26266
26506
|
console.log(
|
|
26267
|
-
`${
|
|
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}`
|
|
26268
26508
|
);
|
|
26269
26509
|
}
|
|
26270
26510
|
|
|
@@ -26398,7 +26638,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
26398
26638
|
|
|
26399
26639
|
// ../lib/entitlement/src/index.ts
|
|
26400
26640
|
import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
|
|
26401
|
-
import { existsSync as
|
|
26641
|
+
import { existsSync as existsSync36, readFileSync as readFileSync38, statSync as statSync13 } from "fs";
|
|
26402
26642
|
import { resolve as resolve35 } from "path";
|
|
26403
26643
|
|
|
26404
26644
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -26447,7 +26687,7 @@ function resolveEntitlement(brand, account) {
|
|
|
26447
26687
|
return logResolved(implicitTrust(account), null);
|
|
26448
26688
|
}
|
|
26449
26689
|
const entitlementPath = resolve35(brand.configDir, "entitlement.json");
|
|
26450
|
-
if (!
|
|
26690
|
+
if (!existsSync36(entitlementPath)) {
|
|
26451
26691
|
return logResolved(anonymousFallback("missing"), { reason: "missing" });
|
|
26452
26692
|
}
|
|
26453
26693
|
const stat8 = statSync13(entitlementPath);
|
|
@@ -26462,7 +26702,7 @@ function resolveEntitlement(brand, account) {
|
|
|
26462
26702
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
26463
26703
|
let pubkeyPem;
|
|
26464
26704
|
try {
|
|
26465
|
-
pubkeyPem =
|
|
26705
|
+
pubkeyPem = readFileSync38(pubkeyPath(brand), "utf-8");
|
|
26466
26706
|
} catch (err) {
|
|
26467
26707
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
26468
26708
|
reason: "pubkey-missing"
|
|
@@ -26476,7 +26716,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
26476
26716
|
}
|
|
26477
26717
|
let envelope;
|
|
26478
26718
|
try {
|
|
26479
|
-
envelope = JSON.parse(
|
|
26719
|
+
envelope = JSON.parse(readFileSync38(entitlementPath, "utf-8"));
|
|
26480
26720
|
} catch {
|
|
26481
26721
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
26482
26722
|
}
|
|
@@ -26637,14 +26877,14 @@ function clientFrom(c) {
|
|
|
26637
26877
|
);
|
|
26638
26878
|
}
|
|
26639
26879
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
26640
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
26880
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join39(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
26641
26881
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
26642
|
-
if (BRAND_JSON_PATH && !
|
|
26882
|
+
if (BRAND_JSON_PATH && !existsSync37(BRAND_JSON_PATH)) {
|
|
26643
26883
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
26644
26884
|
}
|
|
26645
|
-
if (BRAND_JSON_PATH &&
|
|
26885
|
+
if (BRAND_JSON_PATH && existsSync37(BRAND_JSON_PATH)) {
|
|
26646
26886
|
try {
|
|
26647
|
-
const parsed = JSON.parse(
|
|
26887
|
+
const parsed = JSON.parse(readFileSync39(BRAND_JSON_PATH, "utf-8"));
|
|
26648
26888
|
BRAND = { ...BRAND, ...parsed };
|
|
26649
26889
|
} catch (err) {
|
|
26650
26890
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -26676,11 +26916,11 @@ var brandLoginOpts = {
|
|
|
26676
26916
|
appleTouchIconPath: brandAppIcon512Path,
|
|
26677
26917
|
themeColor: BRAND.defaultColors?.primary
|
|
26678
26918
|
};
|
|
26679
|
-
var ALIAS_DOMAINS_PATH =
|
|
26919
|
+
var ALIAS_DOMAINS_PATH = join39(homedir4(), BRAND.configDir, "alias-domains.json");
|
|
26680
26920
|
function loadAliasDomains() {
|
|
26681
26921
|
try {
|
|
26682
|
-
if (!
|
|
26683
|
-
const parsed = JSON.parse(
|
|
26922
|
+
if (!existsSync37(ALIAS_DOMAINS_PATH)) return null;
|
|
26923
|
+
const parsed = JSON.parse(readFileSync39(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
26684
26924
|
if (!Array.isArray(parsed)) {
|
|
26685
26925
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
26686
26926
|
return null;
|
|
@@ -26744,7 +26984,7 @@ async function recordPassiveDispatch(input) {
|
|
|
26744
26984
|
var waGateway = new WaGateway({
|
|
26745
26985
|
fetchStandingRules: fetchAccountStandingRules,
|
|
26746
26986
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
26747
|
-
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"),
|
|
26748
26988
|
// Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
|
|
26749
26989
|
// path-validation scope) is the sender's effective SESSION account, resolved
|
|
26750
26990
|
// once at the inbound gate and threaded here via the gateway's per-sender doc
|
|
@@ -26759,7 +26999,7 @@ var waGateway = new WaGateway({
|
|
|
26759
26999
|
caption,
|
|
26760
27000
|
accountId,
|
|
26761
27001
|
maxyAccountId,
|
|
26762
|
-
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ??
|
|
27002
|
+
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, ".."))
|
|
26763
27003
|
});
|
|
26764
27004
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
26765
27005
|
},
|
|
@@ -26856,7 +27096,7 @@ function runDuplicateSenderAudit() {
|
|
|
26856
27096
|
try {
|
|
26857
27097
|
const configDir2 = process.env.CLAUDE_CONFIG_DIR;
|
|
26858
27098
|
if (!configDir2) return;
|
|
26859
|
-
const projectsRoot =
|
|
27099
|
+
const projectsRoot = join39(configDir2, "projects");
|
|
26860
27100
|
const records = [];
|
|
26861
27101
|
for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
|
|
26862
27102
|
if (isSubagent || archived) continue;
|
|
@@ -27370,6 +27610,13 @@ app62.route("/api/webchat", createWebchatRoutes({
|
|
|
27370
27610
|
app62.route("/api/webchat/greeting", webchat_greeting_default);
|
|
27371
27611
|
app62.route("/api/telegram", telegram_default);
|
|
27372
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
|
+
);
|
|
27373
27620
|
app62.route("/api/onboarding", onboarding_default);
|
|
27374
27621
|
app62.route("/api/admin", admin_default);
|
|
27375
27622
|
app62.route("/api/access", access_default);
|
|
@@ -27408,14 +27655,14 @@ app62.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
27408
27655
|
console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
|
|
27409
27656
|
return c.text("Forbidden", 403);
|
|
27410
27657
|
}
|
|
27411
|
-
if (!
|
|
27658
|
+
if (!existsSync37(filePath)) {
|
|
27412
27659
|
console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
|
|
27413
27660
|
return c.text("Not found", 404);
|
|
27414
27661
|
}
|
|
27415
27662
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
27416
27663
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
27417
27664
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
27418
|
-
const body =
|
|
27665
|
+
const body = readFileSync39(filePath);
|
|
27419
27666
|
return c.body(body, 200, {
|
|
27420
27667
|
"Content-Type": contentType,
|
|
27421
27668
|
"Cache-Control": "public, max-age=3600"
|
|
@@ -27438,14 +27685,14 @@ app62.get("/generated/:filename", (c) => {
|
|
|
27438
27685
|
console.error(`[generated] serve file=${filename} status=403`);
|
|
27439
27686
|
return c.text("Forbidden", 403);
|
|
27440
27687
|
}
|
|
27441
|
-
if (!
|
|
27688
|
+
if (!existsSync37(filePath)) {
|
|
27442
27689
|
console.error(`[generated] serve file=${filename} status=404`);
|
|
27443
27690
|
return c.text("Not found", 404);
|
|
27444
27691
|
}
|
|
27445
27692
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
27446
27693
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
27447
27694
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
27448
|
-
const body =
|
|
27695
|
+
const body = readFileSync39(filePath);
|
|
27449
27696
|
return c.body(body, 200, {
|
|
27450
27697
|
"Content-Type": contentType,
|
|
27451
27698
|
"Cache-Control": "public, max-age=86400"
|
|
@@ -27458,9 +27705,9 @@ app62.route("/v", visitor_consent_default);
|
|
|
27458
27705
|
var htmlCache = /* @__PURE__ */ new Map();
|
|
27459
27706
|
var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
27460
27707
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
27461
|
-
if (BRAND_JSON_PATH &&
|
|
27708
|
+
if (BRAND_JSON_PATH && existsSync37(BRAND_JSON_PATH)) {
|
|
27462
27709
|
try {
|
|
27463
|
-
const fullBrand = JSON.parse(
|
|
27710
|
+
const fullBrand = JSON.parse(readFileSync39(BRAND_JSON_PATH, "utf-8"));
|
|
27464
27711
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
27465
27712
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
27466
27713
|
} catch {
|
|
@@ -27487,11 +27734,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
|
27487
27734
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
27488
27735
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
27489
27736
|
var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
|
|
27490
|
-
(p) =>
|
|
27737
|
+
(p) => existsSync37(resolve36(process.cwd(), "public", p.replace(/^\//, "")))
|
|
27491
27738
|
);
|
|
27492
27739
|
var SW_SOURCE = (() => {
|
|
27493
27740
|
try {
|
|
27494
|
-
return
|
|
27741
|
+
return readFileSync39(resolve36(process.cwd(), "public", "sw.js"), "utf-8");
|
|
27495
27742
|
} catch {
|
|
27496
27743
|
return null;
|
|
27497
27744
|
}
|
|
@@ -27499,9 +27746,9 @@ var SW_SOURCE = (() => {
|
|
|
27499
27746
|
function readInstalledVersion() {
|
|
27500
27747
|
try {
|
|
27501
27748
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
27502
|
-
const versionFile =
|
|
27503
|
-
if (!
|
|
27504
|
-
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();
|
|
27505
27752
|
return content || "unknown";
|
|
27506
27753
|
} catch {
|
|
27507
27754
|
return "unknown";
|
|
@@ -27542,7 +27789,7 @@ var clientErrorReporterScript = `<script>
|
|
|
27542
27789
|
function cachedHtml(file) {
|
|
27543
27790
|
let html = htmlCache.get(file);
|
|
27544
27791
|
if (!html) {
|
|
27545
|
-
html =
|
|
27792
|
+
html = readFileSync39(resolve36(process.cwd(), "public", file), "utf-8");
|
|
27546
27793
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
27547
27794
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
27548
27795
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -27559,13 +27806,13 @@ ${clientErrorReporterScript}
|
|
|
27559
27806
|
return html;
|
|
27560
27807
|
}
|
|
27561
27808
|
function loadBrandingCache(agentSlug) {
|
|
27562
|
-
const configDir2 =
|
|
27809
|
+
const configDir2 = join39(homedir4(), BRAND.configDir);
|
|
27563
27810
|
try {
|
|
27564
27811
|
const accountId = getDefaultAccountId();
|
|
27565
27812
|
if (!accountId) return null;
|
|
27566
|
-
const cachePath =
|
|
27567
|
-
if (!
|
|
27568
|
-
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"));
|
|
27569
27816
|
} catch {
|
|
27570
27817
|
return null;
|
|
27571
27818
|
}
|
|
@@ -27660,7 +27907,7 @@ app62.use("/vnc-popout.html", logViewerFetch);
|
|
|
27660
27907
|
app62.get("/vnc-popout.html", (c) => {
|
|
27661
27908
|
let html = htmlCache.get("vnc-popout.html");
|
|
27662
27909
|
if (!html) {
|
|
27663
|
-
html =
|
|
27910
|
+
html = readFileSync39(resolve36(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
27664
27911
|
const name = escapeHtml(BRAND.productName);
|
|
27665
27912
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
27666
27913
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -27792,11 +28039,11 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
|
27792
28039
|
var httpServer = serve({ fetch: app62.fetch, port, hostname });
|
|
27793
28040
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
27794
28041
|
{
|
|
27795
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28042
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27796
28043
|
const reconcileScript = resolve36(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
27797
28044
|
const RECONCILE_INTERVAL_MS = 12e4;
|
|
27798
28045
|
const runReconcile = () => {
|
|
27799
|
-
if (!
|
|
28046
|
+
if (!existsSync37(reconcileScript)) return;
|
|
27800
28047
|
try {
|
|
27801
28048
|
const child = spawn3(process.execPath, [reconcileScript], {
|
|
27802
28049
|
env: { ...process.env, PLATFORM_ROOT: reconcilePlatformRoot },
|
|
@@ -27814,11 +28061,11 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27814
28061
|
loop.unref();
|
|
27815
28062
|
}
|
|
27816
28063
|
{
|
|
27817
|
-
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28064
|
+
const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27818
28065
|
const outlookScript = resolve36(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
|
|
27819
28066
|
const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
|
|
27820
28067
|
const runOutlookComplete = () => {
|
|
27821
|
-
if (!
|
|
28068
|
+
if (!existsSync37(outlookScript)) return;
|
|
27822
28069
|
try {
|
|
27823
28070
|
const child = spawn3(process.execPath, [outlookScript], {
|
|
27824
28071
|
env: { ...process.env, PLATFORM_ROOT: outlookPlatformRoot },
|
|
@@ -27836,19 +28083,19 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27836
28083
|
outlookLoop.unref();
|
|
27837
28084
|
}
|
|
27838
28085
|
{
|
|
27839
|
-
const auditRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28086
|
+
const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27840
28087
|
const strandedAccountsDir = resolve36(auditRoot, "..", "data/accounts");
|
|
27841
28088
|
const STRANDED_AUDIT_INTERVAL_MS = 3e5;
|
|
27842
28089
|
const STRANDED_AGE_MS = 16 * 6e4;
|
|
27843
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;
|
|
27844
28091
|
const runStrandedAudit = () => {
|
|
27845
28092
|
try {
|
|
27846
|
-
if (!
|
|
28093
|
+
if (!existsSync37(strandedAccountsDir)) return;
|
|
27847
28094
|
const now = Date.now();
|
|
27848
|
-
for (const name of
|
|
28095
|
+
for (const name of readdirSync22(strandedAccountsDir)) {
|
|
27849
28096
|
if (!STRANDED_UUID_RE.test(name)) continue;
|
|
27850
28097
|
const pendingPath2 = resolve36(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
|
|
27851
|
-
if (!
|
|
28098
|
+
if (!existsSync37(pendingPath2)) continue;
|
|
27852
28099
|
const ageMs = now - statSync14(pendingPath2).mtimeMs;
|
|
27853
28100
|
if (ageMs > STRANDED_AGE_MS) {
|
|
27854
28101
|
console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs / 1e3)}`);
|
|
@@ -27864,7 +28111,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27864
28111
|
strandedLoop.unref();
|
|
27865
28112
|
}
|
|
27866
28113
|
{
|
|
27867
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28114
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27868
28115
|
const STORAGE_AUDIT_INTERVAL_MS = 3e5;
|
|
27869
28116
|
const runStorageAuditSafe = () => {
|
|
27870
28117
|
runStorageAudit(auditPlatformRoot).catch(
|
|
@@ -27886,7 +28133,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27886
28133
|
pagesAuditLoop.unref();
|
|
27887
28134
|
}
|
|
27888
28135
|
{
|
|
27889
|
-
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28136
|
+
const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27890
28137
|
const publishScript = resolve36(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
|
|
27891
28138
|
const PUBLISH_INTERVAL_MS = 3e5;
|
|
27892
28139
|
const currentAccount = () => {
|
|
@@ -27898,7 +28145,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27898
28145
|
}
|
|
27899
28146
|
};
|
|
27900
28147
|
const spawnPublish = (account) => {
|
|
27901
|
-
if (!
|
|
28148
|
+
if (!existsSync37(publishScript)) return;
|
|
27902
28149
|
try {
|
|
27903
28150
|
const child = spawn3(process.execPath, [publishScript], {
|
|
27904
28151
|
env: {
|
|
@@ -27919,8 +28166,8 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27919
28166
|
const availPath = resolve36(account.accountDir, "calendar-availability.json");
|
|
27920
28167
|
let hasBookingSite = false;
|
|
27921
28168
|
try {
|
|
27922
|
-
if (
|
|
27923
|
-
const cfg = JSON.parse(
|
|
28169
|
+
if (existsSync37(availPath)) {
|
|
28170
|
+
const cfg = JSON.parse(readFileSync39(availPath, "utf-8"));
|
|
27924
28171
|
hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
|
|
27925
28172
|
}
|
|
27926
28173
|
} catch {
|
|
@@ -27928,9 +28175,9 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27928
28175
|
if (!hasBookingSite) return;
|
|
27929
28176
|
const statePath = resolve36(account.accountDir, "state", "booking-availability", "last-publish.json");
|
|
27930
28177
|
let lastSuccessAt = null;
|
|
27931
|
-
if (
|
|
28178
|
+
if (existsSync37(statePath)) {
|
|
27932
28179
|
try {
|
|
27933
|
-
const rec = JSON.parse(
|
|
28180
|
+
const rec = JSON.parse(readFileSync39(statePath, "utf-8"));
|
|
27934
28181
|
lastSuccessAt = rec.lastSuccessAt ?? null;
|
|
27935
28182
|
} catch {
|
|
27936
28183
|
console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
|
|
@@ -27954,12 +28201,12 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
27954
28201
|
}
|
|
27955
28202
|
startTimeEntryCensus(() => getSession());
|
|
27956
28203
|
{
|
|
27957
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
28204
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..");
|
|
27958
28205
|
const auditScript = resolve36(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
27959
28206
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
27960
28207
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
27961
28208
|
const runConnectorAudit = () => {
|
|
27962
|
-
if (!
|
|
28209
|
+
if (!existsSync37(auditScript)) return;
|
|
27963
28210
|
try {
|
|
27964
28211
|
const child = spawn3(process.execPath, [auditScript], {
|
|
27965
28212
|
env: { ...process.env, PLATFORM_ROOT: auditPlatformRoot, LOG_DIR: auditLogDir },
|
|
@@ -28070,11 +28317,11 @@ try {
|
|
|
28070
28317
|
var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
28071
28318
|
async function runAdminUserReconcileTick() {
|
|
28072
28319
|
try {
|
|
28073
|
-
if (!
|
|
28320
|
+
if (!existsSync37(USERS_FILE)) {
|
|
28074
28321
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
28075
28322
|
return;
|
|
28076
28323
|
}
|
|
28077
|
-
const usersRaw =
|
|
28324
|
+
const usersRaw = readFileSync39(USERS_FILE, "utf-8").trim();
|
|
28078
28325
|
if (!usersRaw) {
|
|
28079
28326
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
28080
28327
|
return;
|
|
@@ -28103,8 +28350,8 @@ var adminUserReconcileTimer = setInterval(() => {
|
|
|
28103
28350
|
if (typeof adminUserReconcileTimer.unref === "function") adminUserReconcileTimer.unref();
|
|
28104
28351
|
var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
|
|
28105
28352
|
function countUsersRows() {
|
|
28106
|
-
if (!
|
|
28107
|
-
const raw =
|
|
28353
|
+
if (!existsSync37(USERS_FILE)) return 0;
|
|
28354
|
+
const raw = readFileSync39(USERS_FILE, "utf-8").trim();
|
|
28108
28355
|
if (!raw) return 0;
|
|
28109
28356
|
const users = JSON.parse(raw);
|
|
28110
28357
|
return users.filter((u) => typeof u.userId === "string").length;
|
|
@@ -28224,7 +28471,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
28224
28471
|
}
|
|
28225
28472
|
init({
|
|
28226
28473
|
configDir: configDirForWhatsApp,
|
|
28227
|
-
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ??
|
|
28474
|
+
platformRoot: resolve36(process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, "..")),
|
|
28228
28475
|
accountConfig: bootAccountConfig,
|
|
28229
28476
|
onMessage: async (msg) => {
|
|
28230
28477
|
if (msg.isOwnerMirror) {
|