@rubytech/create-maxy-code 0.1.330 → 0.1.331
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 +19 -2
- package/package.json +1 -1
- package/payload/platform/config/brand.json +1 -0
- package/payload/platform/lib/account-enumeration/dist/index.d.ts +33 -0
- package/payload/platform/lib/account-enumeration/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/account-enumeration/dist/index.js +76 -0
- package/payload/platform/lib/account-enumeration/dist/index.js.map +1 -1
- package/payload/platform/lib/account-enumeration/src/index.ts +78 -0
- package/payload/platform/plugins/admin/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/admin/PLUGIN.md +13 -1
- package/payload/platform/plugins/admin/mcp/dist/index.js +102 -0
- package/payload/platform/plugins/admin/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.d.ts +2 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.js +57 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/__tests__/account-lifecycle.test.js.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts +34 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.d.ts.map +1 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js +78 -0
- package/payload/platform/plugins/admin/mcp/dist/tools/account-lifecycle.js.map +1 -0
- package/payload/platform/plugins/admin/skills/plainly/SKILL.md +7 -0
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -2
- package/payload/platform/plugins/contacts/mcp/dist/index.js +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.d.ts +2 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.d.ts.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.js +71 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/__tests__/contact-lookup.test.js.map +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts +1 -0
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.d.ts.map +1 -1
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js +10 -3
- package/payload/platform/plugins/contacts/mcp/dist/tools/contact-lookup.js.map +1 -1
- package/payload/platform/plugins/contacts/mcp/package.json +4 -2
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/memory/.claude-plugin/plugin.json +1 -1
- package/payload/platform/plugins/memory/PLUGIN.md +1 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js +3 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.js +39 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-lookup-by-name.test.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.js +13 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/memory-lookup-by-name.js.map +1 -1
- package/payload/platform/scripts/__tests__/provision-role-stamp.test.sh +40 -0
- package/payload/platform/scripts/__tests__/sweep-durability.test.sh +103 -0
- package/payload/platform/scripts/lib/provision-account-dir.sh +319 -0
- package/payload/platform/scripts/lib/resolve-account-dir.sh +79 -132
- package/payload/platform/scripts/setup-account.sh +28 -361
- 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 +4 -0
- package/payload/platform/services/claude-session-manager/dist/canonical-tool-names.generated.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.d.ts +18 -0
- package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/config.js +63 -7
- package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js +30 -2
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/index.js +16 -1
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +7 -0
- package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +5 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +8 -0
- package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.d.ts +6 -0
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.js +17 -5
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/instructions.js +25 -1
- package/payload/platform/services/webchat-channel/dist/instructions.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.d.ts +17 -0
- package/payload/platform/services/webchat-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/notification.js +14 -0
- package/payload/platform/services/webchat-channel/dist/notification.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.d.ts.map +1 -1
- package/payload/platform/services/webchat-channel/dist/server.js +66 -2
- package/payload/platform/services/webchat-channel/dist/server.js.map +1 -1
- package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts +28 -0
- package/payload/platform/services/webchat-channel/dist/turn-follow.d.ts.map +1 -0
- package/payload/platform/services/webchat-channel/dist/turn-follow.js +188 -0
- package/payload/platform/services/webchat-channel/dist/turn-follow.js.map +1 -0
- package/payload/platform/services/whatsapp-channel/dist/notification.d.ts.map +1 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js +24 -1
- package/payload/platform/services/whatsapp-channel/dist/notification.js.map +1 -1
- package/payload/platform/templates/account.json +2 -0
- package/payload/server/public/assets/AdminLoginScreens-DexSvtjD.js +1 -0
- package/payload/server/public/assets/AdminShell-Bf9tndNg.js +1 -0
- package/payload/server/public/assets/{Checkbox-1flpB9H0.js → Checkbox-D58GsKoQ.js} +1 -1
- package/payload/server/public/assets/{OperatorConversations-DrPqB9Ym.css → OperatorConversations-CDdp2nVn.css} +1 -1
- package/payload/server/public/assets/OperatorConversations-RmqANYz8.js +9 -0
- package/payload/server/public/assets/{admin-BWJTvagN.js → admin-CH5Vkkt4.js} +1 -1
- package/payload/server/public/assets/{browser-XM5e-fn1.js → browser-BwDtzSlr.js} +1 -1
- package/payload/server/public/assets/chat-3GY0LmYH.js +1 -0
- package/payload/server/public/assets/data-CttrzhfL.js +1 -0
- package/payload/server/public/assets/{graph-CIIz9Dmh.js → graph-CZSdF2jv.js} +3 -3
- package/payload/server/public/assets/{graph-labels-BRKvhE0e.js → graph-labels-Bi0fu8Ns.js} +1 -1
- package/payload/server/public/assets/operator-BEivxmRy.js +1 -0
- package/payload/server/public/assets/page-DUvT07SB.js +30 -0
- package/payload/server/public/assets/{public-BPlZnopr.js → public-B3eIlVbd.js} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/chat.html +5 -5
- package/payload/server/public/data.html +4 -4
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +6 -6
- package/payload/server/public/operator.html +7 -7
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +314 -222
- package/payload/server/public/assets/AdminLoginScreens-BnuaXvxN.js +0 -1
- package/payload/server/public/assets/AdminShell-Br0DJQNu.js +0 -1
- package/payload/server/public/assets/OperatorConversations-C8sITz2_.js +0 -9
- package/payload/server/public/assets/chat-COFMxaoC.js +0 -1
- package/payload/server/public/assets/data-BHtJozT2.js +0 -1
- package/payload/server/public/assets/operator-9hbxrXKm.js +0 -1
- package/payload/server/public/assets/page-CXkBfOhG.js +0 -30
package/payload/server/server.js
CHANGED
|
@@ -1293,8 +1293,8 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1293
1293
|
};
|
|
1294
1294
|
|
|
1295
1295
|
// server/index.ts
|
|
1296
|
-
import { readFileSync as
|
|
1297
|
-
import { resolve as resolve33, join as
|
|
1296
|
+
import { readFileSync as readFileSync32, existsSync as existsSync31, watchFile } from "fs";
|
|
1297
|
+
import { resolve as resolve33, join as join29, basename as basename10 } from "path";
|
|
1298
1298
|
import { homedir as homedir3 } from "os";
|
|
1299
1299
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1300
1300
|
|
|
@@ -1650,7 +1650,7 @@ async function ensureAuth() {
|
|
|
1650
1650
|
}
|
|
1651
1651
|
|
|
1652
1652
|
// server/routes/health.ts
|
|
1653
|
-
import { existsSync as existsSync3, readFileSync as
|
|
1653
|
+
import { existsSync as existsSync3, readFileSync as readFileSync7 } from "fs";
|
|
1654
1654
|
import { createConnection as createConnection2 } from "net";
|
|
1655
1655
|
|
|
1656
1656
|
// app/lib/network.ts
|
|
@@ -3297,6 +3297,23 @@ function enumerateValidAccountIds(accountsDir) {
|
|
|
3297
3297
|
cache.set(accountsDir, valid);
|
|
3298
3298
|
return valid;
|
|
3299
3299
|
}
|
|
3300
|
+
function resolveHouseOrSoleAccountId(accountsDir) {
|
|
3301
|
+
const valid = enumerateValidAccountIds(accountsDir);
|
|
3302
|
+
const houses = [];
|
|
3303
|
+
for (const id of valid) {
|
|
3304
|
+
const configPath2 = resolve3(accountsDir, id, "account.json");
|
|
3305
|
+
try {
|
|
3306
|
+
const cfg = JSON.parse(readFileSync4(configPath2, "utf-8"));
|
|
3307
|
+
if (cfg.role === "house") houses.push(id);
|
|
3308
|
+
} catch {
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
if (houses.length === 1) return houses[0];
|
|
3312
|
+
if (houses.length === 0 && valid.length === 1) return valid[0];
|
|
3313
|
+
throw new Error(
|
|
3314
|
+
`[account-registry] resolveHouseOrSoleAccountId: houses=${houses.length} total=${valid.length} under ${accountsDir} \u2014 expected exactly one role:"house" (or a single unlabelled account). Loud-fail rather than picking one silently.`
|
|
3315
|
+
);
|
|
3316
|
+
}
|
|
3300
3317
|
function getAccountsDirFromEnv() {
|
|
3301
3318
|
const root = process.env.MAXY_PLATFORM_ROOT;
|
|
3302
3319
|
if (!root) {
|
|
@@ -3324,26 +3341,39 @@ var cached = null;
|
|
|
3324
3341
|
var cachedAccountsDir = null;
|
|
3325
3342
|
function resolvePlatformAccountId(accountsDir = ACCOUNTS_DIR) {
|
|
3326
3343
|
if (cached !== null && cachedAccountsDir === accountsDir) return cached;
|
|
3327
|
-
const
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3344
|
+
const resolved = resolveHouseOrSoleAccountId(accountsDir);
|
|
3345
|
+
cached = resolved;
|
|
3346
|
+
cachedAccountsDir = accountsDir;
|
|
3347
|
+
return cached;
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3350
|
+
// app/lib/managed-service.ts
|
|
3351
|
+
import { join as join3 } from "path";
|
|
3352
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
3353
|
+
function isHouseManagedService(accountsDir = ACCOUNTS_DIR) {
|
|
3354
|
+
let houseId;
|
|
3355
|
+
try {
|
|
3356
|
+
houseId = resolvePlatformAccountId(accountsDir);
|
|
3357
|
+
} catch {
|
|
3358
|
+
return false;
|
|
3332
3359
|
}
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3360
|
+
try {
|
|
3361
|
+
const cfg = JSON.parse(
|
|
3362
|
+
readFileSync5(join3(accountsDir, houseId, "account.json"), "utf-8")
|
|
3336
3363
|
);
|
|
3364
|
+
return cfg.managedService === true;
|
|
3365
|
+
} catch {
|
|
3366
|
+
return false;
|
|
3337
3367
|
}
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
return
|
|
3368
|
+
}
|
|
3369
|
+
function isCustomerTurnSuppressed(role, managedService) {
|
|
3370
|
+
return managedService === true && role !== "admin";
|
|
3341
3371
|
}
|
|
3342
3372
|
|
|
3343
3373
|
// app/lib/whatsapp/inbound/media.ts
|
|
3344
3374
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
3345
3375
|
import { writeFile, mkdir } from "fs/promises";
|
|
3346
|
-
import { join as
|
|
3376
|
+
import { join as join4 } from "path";
|
|
3347
3377
|
import {
|
|
3348
3378
|
downloadMediaMessage,
|
|
3349
3379
|
downloadContentFromMessage,
|
|
@@ -3429,7 +3459,7 @@ async function downloadInboundMedia(msg, sock, opts) {
|
|
|
3429
3459
|
await mkdir(MEDIA_DIR, { recursive: true });
|
|
3430
3460
|
const ext = mimeToExt(mimetype ?? "application/octet-stream");
|
|
3431
3461
|
const filename = `${randomUUID3()}.${ext}`;
|
|
3432
|
-
const filePath =
|
|
3462
|
+
const filePath = join4(MEDIA_DIR, filename);
|
|
3433
3463
|
await writeFile(filePath, buffer);
|
|
3434
3464
|
const sizeKB = (buffer.length / 1024).toFixed(0);
|
|
3435
3465
|
console.error(`${TAG9} media downloaded type=${mimetype ?? "unknown"} size=${sizeKB}KB path=${filePath}`);
|
|
@@ -4471,6 +4501,12 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4471
4501
|
`${TAG13} inbound account=${conn.accountId} from=${senderPhone} group=${isGroup} access=${accessResult.allowed ? "allowed" : "blocked"}(${accessResult.reason}) agent=${accessResult.agentType}` + (extracted.mediaType ? ` media=${extracted.mediaType}` : "") + (mediaResult ? ` mediaPath=${mediaResult.path}` : "") + (extracted.quotedMessage ? ` replyTo=${extracted.quotedMessage.id}` : "")
|
|
4472
4502
|
);
|
|
4473
4503
|
if (!accessResult.allowed) return;
|
|
4504
|
+
if (isCustomerTurnSuppressed(accessResult.agentType, isHouseManagedService())) {
|
|
4505
|
+
console.error(
|
|
4506
|
+
`[channel-house] op=inbound from=${senderPhone} accountId=${conn.platformAccountId} autoReply=suppressed`
|
|
4507
|
+
);
|
|
4508
|
+
return;
|
|
4509
|
+
}
|
|
4474
4510
|
const sendReceipts = whatsAppConfig.accounts?.[conn.accountId]?.sendReadReceipts ?? whatsAppConfig.sendReadReceipts ?? true;
|
|
4475
4511
|
if (sendReceipts && msg.key.id) {
|
|
4476
4512
|
sendReadReceipt(conn.sock, remoteJid, [msg.key.id], isGroup ? senderJid : void 0);
|
|
@@ -4541,7 +4577,7 @@ async function handleInboundMessage(conn, msg) {
|
|
|
4541
4577
|
// app/lib/vnc.ts
|
|
4542
4578
|
import { spawnSync, execFileSync } from "child_process";
|
|
4543
4579
|
import { createConnection } from "net";
|
|
4544
|
-
import { mkdirSync, readFileSync as
|
|
4580
|
+
import { mkdirSync, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
|
|
4545
4581
|
import { resolve as resolve4 } from "path";
|
|
4546
4582
|
var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve4(process.cwd(), "..");
|
|
4547
4583
|
var VNC_SCRIPT = resolve4(PLATFORM_ROOT3, "scripts/vnc.sh");
|
|
@@ -4599,7 +4635,7 @@ function discoverNativeDisplay() {
|
|
|
4599
4635
|
const leaderPid = leaderResult.stdout?.trim();
|
|
4600
4636
|
if (leaderPid) {
|
|
4601
4637
|
try {
|
|
4602
|
-
const environ =
|
|
4638
|
+
const environ = readFileSync6(`/proc/${leaderPid}/environ`, "utf8");
|
|
4603
4639
|
const match = environ.split("\0").find((e) => e.startsWith("WAYLAND_DISPLAY="));
|
|
4604
4640
|
if (match) waylandDisplay = match.split("=")[1];
|
|
4605
4641
|
} catch {
|
|
@@ -4859,7 +4895,7 @@ app.get("/", async (c) => {
|
|
|
4859
4895
|
let pinConfigured = false;
|
|
4860
4896
|
try {
|
|
4861
4897
|
if (existsSync3(USERS_FILE)) {
|
|
4862
|
-
const raw =
|
|
4898
|
+
const raw = readFileSync7(USERS_FILE, "utf-8").trim();
|
|
4863
4899
|
if (raw) {
|
|
4864
4900
|
const users = JSON.parse(raw);
|
|
4865
4901
|
pinConfigured = Array.isArray(users) && users.length > 0;
|
|
@@ -5117,7 +5153,7 @@ async function storeComponentArtefact(accountId, attachmentId, mimeType, content
|
|
|
5117
5153
|
// app/lib/stt/voice-note.ts
|
|
5118
5154
|
import { writeFile as writeFile3, mkdtemp, rm } from "fs/promises";
|
|
5119
5155
|
import { tmpdir } from "os";
|
|
5120
|
-
import { join as
|
|
5156
|
+
import { join as join5 } from "path";
|
|
5121
5157
|
var TAG14 = "[voice]";
|
|
5122
5158
|
var AUDIO_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
5123
5159
|
"audio/ogg",
|
|
@@ -5161,9 +5197,9 @@ async function transcribeVoiceNote(file, source) {
|
|
|
5161
5197
|
let tempDir;
|
|
5162
5198
|
let tempPath;
|
|
5163
5199
|
try {
|
|
5164
|
-
tempDir = await mkdtemp(
|
|
5200
|
+
tempDir = await mkdtemp(join5(tmpdir(), "voice-"));
|
|
5165
5201
|
const ext = audioExtension(mimeType);
|
|
5166
|
-
tempPath =
|
|
5202
|
+
tempPath = join5(tempDir, `recording${ext}`);
|
|
5167
5203
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
5168
5204
|
await writeFile3(tempPath, buffer);
|
|
5169
5205
|
} catch (err) {
|
|
@@ -5483,15 +5519,15 @@ ${result.result.text}` : result.result.text;
|
|
|
5483
5519
|
}
|
|
5484
5520
|
|
|
5485
5521
|
// server/routes/whatsapp.ts
|
|
5486
|
-
import { join as
|
|
5487
|
-
import { readdirSync as readdirSync3, readFileSync as
|
|
5522
|
+
import { join as join8, resolve as resolve9 } from "path";
|
|
5523
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync9, existsSync as existsSync5 } from "fs";
|
|
5488
5524
|
|
|
5489
5525
|
// app/lib/whatsapp/login.ts
|
|
5490
5526
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
5491
5527
|
|
|
5492
5528
|
// app/lib/whatsapp/config-persist.ts
|
|
5493
|
-
import { readFileSync as
|
|
5494
|
-
import { resolve as resolve7, join as
|
|
5529
|
+
import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, existsSync as existsSync4 } from "fs";
|
|
5530
|
+
import { resolve as resolve7, join as join6 } from "path";
|
|
5495
5531
|
var TAG15 = "[whatsapp:config]";
|
|
5496
5532
|
function configPath(accountDir) {
|
|
5497
5533
|
return resolve7(accountDir, "account.json");
|
|
@@ -5499,7 +5535,7 @@ function configPath(accountDir) {
|
|
|
5499
5535
|
function readConfig(accountDir) {
|
|
5500
5536
|
const path2 = configPath(accountDir);
|
|
5501
5537
|
if (!existsSync4(path2)) throw new Error(`account.json not found at ${path2}`);
|
|
5502
|
-
return JSON.parse(
|
|
5538
|
+
return JSON.parse(readFileSync8(path2, "utf-8"));
|
|
5503
5539
|
}
|
|
5504
5540
|
function writeConfig(accountDir, config) {
|
|
5505
5541
|
const path2 = configPath(accountDir);
|
|
@@ -5643,7 +5679,7 @@ function setPublicAgent(accountDir, slug) {
|
|
|
5643
5679
|
if (!trimmed) {
|
|
5644
5680
|
return { ok: false, error: "Agent slug cannot be empty." };
|
|
5645
5681
|
}
|
|
5646
|
-
const agentConfigPath =
|
|
5682
|
+
const agentConfigPath = join6(accountDir, "agents", trimmed, "config.json");
|
|
5647
5683
|
if (!existsSync4(agentConfigPath)) {
|
|
5648
5684
|
return { ok: false, error: `Agent "${trimmed}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.` };
|
|
5649
5685
|
}
|
|
@@ -6217,11 +6253,11 @@ function serializeWhatsAppSchema() {
|
|
|
6217
6253
|
|
|
6218
6254
|
// app/lib/whatsapp/status-reconcile.ts
|
|
6219
6255
|
import { readdirSync as readdirSync2 } from "fs";
|
|
6220
|
-
import { join as
|
|
6256
|
+
import { join as join7 } from "path";
|
|
6221
6257
|
var TAG18 = "[whatsapp:reconcile]";
|
|
6222
6258
|
function listCredsAccountIds(credsRoot) {
|
|
6223
6259
|
try {
|
|
6224
|
-
return readdirSync2(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(
|
|
6260
|
+
return readdirSync2(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(join7(credsRoot, e.name))).map((e) => e.name);
|
|
6225
6261
|
} catch {
|
|
6226
6262
|
return [];
|
|
6227
6263
|
}
|
|
@@ -6236,7 +6272,7 @@ function reconcileCredsOnDisk(opts) {
|
|
|
6236
6272
|
const entries = [];
|
|
6237
6273
|
for (const accountId of listCredsAccountIds(credsRoot)) {
|
|
6238
6274
|
if (liveAccountIds.has(accountId)) continue;
|
|
6239
|
-
const authDir =
|
|
6275
|
+
const authDir = join7(credsRoot, accountId);
|
|
6240
6276
|
const selfPhone = readSelfId(authDir).e164 ?? void 0;
|
|
6241
6277
|
const configured = accountDir ? isAccountConfigured(accountDir, accountId) : false;
|
|
6242
6278
|
console.error(
|
|
@@ -6263,7 +6299,7 @@ app2.get("/status", (c) => {
|
|
|
6263
6299
|
try {
|
|
6264
6300
|
const live = getStatus();
|
|
6265
6301
|
const liveIds = new Set(live.map((a) => a.accountId));
|
|
6266
|
-
const credsRoot =
|
|
6302
|
+
const credsRoot = join8(MAXY_DIR, "credentials", "whatsapp");
|
|
6267
6303
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
6268
6304
|
const reconciled = reconcileCredsOnDisk({ credsRoot, accountDir, liveAccountIds: liveIds });
|
|
6269
6305
|
const accounts = [...live, ...reconciled];
|
|
@@ -6284,7 +6320,7 @@ app2.post("/login/start", async (c) => {
|
|
|
6284
6320
|
if (!phone) {
|
|
6285
6321
|
return c.json({ error: 'Missing required field "phone" (E.164, e.g. +441234567890).' }, 400);
|
|
6286
6322
|
}
|
|
6287
|
-
const authDir =
|
|
6323
|
+
const authDir = join8(MAXY_DIR, "credentials", "whatsapp", accountId);
|
|
6288
6324
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
6289
6325
|
const result = await startLogin({ accountId, authDir, phone, accountDir, force });
|
|
6290
6326
|
console.error(`${TAG19} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
|
|
@@ -6392,7 +6428,7 @@ app2.post("/config", async (c) => {
|
|
|
6392
6428
|
const configPath2 = resolve9(agentsDir, entry.name, "config.json");
|
|
6393
6429
|
if (!existsSync5(configPath2)) continue;
|
|
6394
6430
|
try {
|
|
6395
|
-
const config = JSON.parse(
|
|
6431
|
+
const config = JSON.parse(readFileSync9(configPath2, "utf-8"));
|
|
6396
6432
|
agents.push({ slug: entry.name, displayName: config.displayName ?? entry.name });
|
|
6397
6433
|
} catch {
|
|
6398
6434
|
console.error(`${TAG19} config action=list-public-agents error="failed to parse config.json for agent ${entry.name}" \u2014 skipping`);
|
|
@@ -6661,12 +6697,12 @@ app2.get("/group-info", async (c) => {
|
|
|
6661
6697
|
var whatsapp_default = app2;
|
|
6662
6698
|
|
|
6663
6699
|
// server/routes/whatsapp-reader.ts
|
|
6664
|
-
import { readFileSync as
|
|
6665
|
-
import { basename as basename2, dirname, isAbsolute, join as
|
|
6700
|
+
import { readFileSync as readFileSync13, watch, statSync as statSync4, openSync, readSync, closeSync, existsSync as existsSync7, readdirSync as readdirSync7 } from "fs";
|
|
6701
|
+
import { basename as basename2, dirname, isAbsolute, join as join12, relative as relative2, resolve as resolve11, sep as sep3 } from "path";
|
|
6666
6702
|
|
|
6667
6703
|
// server/routes/admin/sidebar-sessions.ts
|
|
6668
|
-
import { readdirSync as readdirSync4, readFileSync as
|
|
6669
|
-
import { join as
|
|
6704
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync10, statSync as statSync2 } from "fs";
|
|
6705
|
+
import { join as join9, resolve as resolve10 } from "path";
|
|
6670
6706
|
|
|
6671
6707
|
// app/lib/whatsapp-reader/select-sessions.ts
|
|
6672
6708
|
function isReaderChannelSession(role, channel) {
|
|
@@ -6725,7 +6761,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6725
6761
|
throw err;
|
|
6726
6762
|
}
|
|
6727
6763
|
for (const slug of slugs) {
|
|
6728
|
-
const slugDir =
|
|
6764
|
+
const slugDir = join9(projectsRoot, slug);
|
|
6729
6765
|
let entries;
|
|
6730
6766
|
try {
|
|
6731
6767
|
entries = readdirSync4(slugDir, { withFileTypes: true });
|
|
@@ -6736,9 +6772,9 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6736
6772
|
}
|
|
6737
6773
|
for (const entry of entries) {
|
|
6738
6774
|
if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
|
|
6739
|
-
out.push({ path:
|
|
6775
|
+
out.push({ path: join9(slugDir, entry.name), isSubagent: false, archived: false });
|
|
6740
6776
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
6741
|
-
const subDir =
|
|
6777
|
+
const subDir = join9(slugDir, entry.name);
|
|
6742
6778
|
let subEntries;
|
|
6743
6779
|
try {
|
|
6744
6780
|
subEntries = readdirSync4(subDir, { withFileTypes: true });
|
|
@@ -6749,11 +6785,11 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6749
6785
|
}
|
|
6750
6786
|
for (const sub of subEntries) {
|
|
6751
6787
|
if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
|
|
6752
|
-
out.push({ path:
|
|
6788
|
+
out.push({ path: join9(subDir, sub.name), isSubagent: true, archived: false });
|
|
6753
6789
|
}
|
|
6754
6790
|
}
|
|
6755
6791
|
} else if (entry.isDirectory() && entry.name === "archive") {
|
|
6756
|
-
const archiveDir =
|
|
6792
|
+
const archiveDir = join9(slugDir, entry.name);
|
|
6757
6793
|
let archiveEntries;
|
|
6758
6794
|
try {
|
|
6759
6795
|
archiveEntries = readdirSync4(archiveDir, { withFileTypes: true });
|
|
@@ -6764,7 +6800,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6764
6800
|
}
|
|
6765
6801
|
for (const arc of archiveEntries) {
|
|
6766
6802
|
if (arc.isFile() && SESSION_ID_RE.test(arc.name)) {
|
|
6767
|
-
out.push({ path:
|
|
6803
|
+
out.push({ path: join9(archiveDir, arc.name), isSubagent: false, archived: true });
|
|
6768
6804
|
}
|
|
6769
6805
|
}
|
|
6770
6806
|
}
|
|
@@ -6797,10 +6833,10 @@ async function fetchLiveSessions() {
|
|
|
6797
6833
|
function loadUserTitles(accountDir) {
|
|
6798
6834
|
const out = /* @__PURE__ */ new Map();
|
|
6799
6835
|
if (!accountDir) return out;
|
|
6800
|
-
const path2 =
|
|
6836
|
+
const path2 = join9(accountDir, "session-titles.json");
|
|
6801
6837
|
let raw;
|
|
6802
6838
|
try {
|
|
6803
|
-
raw =
|
|
6839
|
+
raw = readFileSync10(path2, "utf8");
|
|
6804
6840
|
} catch {
|
|
6805
6841
|
return out;
|
|
6806
6842
|
}
|
|
@@ -6823,10 +6859,10 @@ function loadUserTitles(accountDir) {
|
|
|
6823
6859
|
return out;
|
|
6824
6860
|
}
|
|
6825
6861
|
function readSidecarMeta(metaPath) {
|
|
6826
|
-
const empty = { bridgeIds: [], role: null, channel: null, senderId: null, startedAt: null, personId: null, adminUserId: null, visitorId: null, agentSlug: null };
|
|
6862
|
+
const empty = { bridgeIds: [], role: null, channel: null, senderId: null, startedAt: null, personId: null, adminUserId: null, visitorId: null, agentSlug: null, accountId: null };
|
|
6827
6863
|
let raw;
|
|
6828
6864
|
try {
|
|
6829
|
-
raw =
|
|
6865
|
+
raw = readFileSync10(metaPath, "utf8");
|
|
6830
6866
|
} catch {
|
|
6831
6867
|
return empty;
|
|
6832
6868
|
}
|
|
@@ -6848,7 +6884,8 @@ function readSidecarMeta(metaPath) {
|
|
|
6848
6884
|
personId: typeof r.personId === "string" ? r.personId : null,
|
|
6849
6885
|
adminUserId: typeof r.adminUserId === "string" ? r.adminUserId : null,
|
|
6850
6886
|
visitorId: typeof r.visitorId === "string" ? r.visitorId : null,
|
|
6851
|
-
agentSlug: typeof r.agentSlug === "string" ? r.agentSlug : null
|
|
6887
|
+
agentSlug: typeof r.agentSlug === "string" ? r.agentSlug : null,
|
|
6888
|
+
accountId: typeof r.accountId === "string" ? r.accountId : null
|
|
6852
6889
|
};
|
|
6853
6890
|
}
|
|
6854
6891
|
function startsWithCliMarker(s) {
|
|
@@ -6915,12 +6952,33 @@ function resolveTitle(body, sessionId, userTitles) {
|
|
|
6915
6952
|
}
|
|
6916
6953
|
app3.get("/", requireAdminSession, async (c) => {
|
|
6917
6954
|
const accountId = process.env.ACCOUNT_ID ?? null;
|
|
6955
|
+
const switcherUserId = (() => {
|
|
6956
|
+
const cacheKey = c.get("cacheKey");
|
|
6957
|
+
return cacheKey ? getUserIdForSession(cacheKey) : void 0;
|
|
6958
|
+
})();
|
|
6959
|
+
const accounts = [];
|
|
6960
|
+
if (switcherUserId) {
|
|
6961
|
+
for (const a of resolveUserAccounts(switcherUserId)) {
|
|
6962
|
+
let businessName = null;
|
|
6963
|
+
try {
|
|
6964
|
+
const branding = await fetchBranding(a.accountId);
|
|
6965
|
+
businessName = branding?.name || null;
|
|
6966
|
+
} catch {
|
|
6967
|
+
}
|
|
6968
|
+
accounts.push({
|
|
6969
|
+
accountId: a.accountId,
|
|
6970
|
+
role: a.config.role ?? "",
|
|
6971
|
+
businessName,
|
|
6972
|
+
isHouse: a.config.role === "house"
|
|
6973
|
+
});
|
|
6974
|
+
}
|
|
6975
|
+
}
|
|
6918
6976
|
const configDir2 = claudeConfigDir();
|
|
6919
6977
|
if (!configDir2) {
|
|
6920
6978
|
console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
|
|
6921
|
-
return c.json({ sessions: [], accountId });
|
|
6979
|
+
return c.json({ sessions: [], accountId, accounts });
|
|
6922
6980
|
}
|
|
6923
|
-
const projectsRoot =
|
|
6981
|
+
const projectsRoot = join9(configDir2, "projects");
|
|
6924
6982
|
const jsonls = enumerateJsonls(projectsRoot);
|
|
6925
6983
|
const liveSessions = await fetchLiveSessions();
|
|
6926
6984
|
const accountDir = accountId ? resolve10(ACCOUNTS_DIR, accountId) : null;
|
|
@@ -6947,7 +7005,7 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
6947
7005
|
let body;
|
|
6948
7006
|
let mtimeMs;
|
|
6949
7007
|
try {
|
|
6950
|
-
body =
|
|
7008
|
+
body = readFileSync10(path2, "utf8");
|
|
6951
7009
|
mtimeMs = statSync2(path2).mtimeMs;
|
|
6952
7010
|
} catch {
|
|
6953
7011
|
continue;
|
|
@@ -6956,8 +7014,8 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
6956
7014
|
const pid = live ? liveSessions.get(sessionId) ?? null : null;
|
|
6957
7015
|
const resolved = resolveTitle(body, sessionId, userTitles);
|
|
6958
7016
|
titleSourceCounts[resolved.source] += 1;
|
|
6959
|
-
const metaPath =
|
|
6960
|
-
const { bridgeIds, role, channel: sidecarChannel, personId, adminUserId } = readSidecarMeta(metaPath);
|
|
7017
|
+
const metaPath = join9(projectDir, `${sessionId}.meta.json`);
|
|
7018
|
+
const { bridgeIds, role, channel: sidecarChannel, personId, adminUserId, accountId: rowAccountId } = readSidecarMeta(metaPath);
|
|
6961
7019
|
if (isReaderChannelSession(role, sidecarChannel)) {
|
|
6962
7020
|
excludedChannelCount += 1;
|
|
6963
7021
|
continue;
|
|
@@ -6979,7 +7037,8 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
6979
7037
|
archived,
|
|
6980
7038
|
channel: resolved.channel,
|
|
6981
7039
|
personName: null,
|
|
6982
|
-
model: lastAssistantModel(body)
|
|
7040
|
+
model: lastAssistantModel(body),
|
|
7041
|
+
accountId: rowAccountId
|
|
6983
7042
|
});
|
|
6984
7043
|
if (live) liveCount += 1;
|
|
6985
7044
|
if (isSubagent) subagentCount += 1;
|
|
@@ -7015,20 +7074,20 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
7015
7074
|
console.log(
|
|
7016
7075
|
`[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} excludedChannel=${excludedChannelCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
|
|
7017
7076
|
);
|
|
7018
|
-
return c.json({ sessions: rows, accountId });
|
|
7077
|
+
return c.json({ sessions: rows, accountId, accounts });
|
|
7019
7078
|
});
|
|
7020
7079
|
var sidebar_sessions_default = app3;
|
|
7021
7080
|
|
|
7022
7081
|
// app/lib/admin-identity/pin-validator.ts
|
|
7023
7082
|
import { createHash } from "crypto";
|
|
7024
|
-
import { existsSync as existsSync6, readFileSync as
|
|
7025
|
-
import { join as
|
|
7083
|
+
import { existsSync as existsSync6, readFileSync as readFileSync11, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
|
|
7084
|
+
import { join as join10 } from "path";
|
|
7026
7085
|
function hashPin(pin) {
|
|
7027
7086
|
return createHash("sha256").update(pin).digest("hex");
|
|
7028
7087
|
}
|
|
7029
7088
|
function readUsersFile(usersFilePath) {
|
|
7030
7089
|
if (!existsSync6(usersFilePath)) return null;
|
|
7031
|
-
const raw =
|
|
7090
|
+
const raw = readFileSync11(usersFilePath, "utf-8").trim();
|
|
7032
7091
|
if (!raw) return [];
|
|
7033
7092
|
return JSON.parse(raw);
|
|
7034
7093
|
}
|
|
@@ -7056,16 +7115,16 @@ function scanForOrphanedAccountAdmins(users, accountsDir) {
|
|
|
7056
7115
|
}
|
|
7057
7116
|
for (const entry of entries) {
|
|
7058
7117
|
if (entry.startsWith(".")) continue;
|
|
7059
|
-
const accountDir =
|
|
7118
|
+
const accountDir = join10(accountsDir, entry);
|
|
7060
7119
|
try {
|
|
7061
7120
|
if (!statSync3(accountDir).isDirectory()) continue;
|
|
7062
7121
|
} catch {
|
|
7063
7122
|
continue;
|
|
7064
7123
|
}
|
|
7065
|
-
const accountJsonPath =
|
|
7124
|
+
const accountJsonPath = join10(accountDir, "account.json");
|
|
7066
7125
|
if (!existsSync6(accountJsonPath)) continue;
|
|
7067
7126
|
try {
|
|
7068
|
-
const config = JSON.parse(
|
|
7127
|
+
const config = JSON.parse(readFileSync11(accountJsonPath, "utf-8"));
|
|
7069
7128
|
const admins = config.admins ?? [];
|
|
7070
7129
|
for (const a of admins) {
|
|
7071
7130
|
if (typeof a.userId === "string" && !known.has(a.userId)) orphans.push(a.userId);
|
|
@@ -7321,8 +7380,8 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
7321
7380
|
}
|
|
7322
7381
|
|
|
7323
7382
|
// app/lib/whatsapp-reader/enrich-attachments.ts
|
|
7324
|
-
import { readFileSync as
|
|
7325
|
-
import { join as
|
|
7383
|
+
import { readFileSync as readFileSync12, readdirSync as readdirSync6 } from "fs";
|
|
7384
|
+
import { join as join11 } from "path";
|
|
7326
7385
|
var ADMIN_UPLOAD_PATH = /\/uploads\/(?!public\/)([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\//gi;
|
|
7327
7386
|
function adminAttachmentIds(text) {
|
|
7328
7387
|
const ids = [];
|
|
@@ -7335,7 +7394,7 @@ function adminAttachmentIds(text) {
|
|
|
7335
7394
|
function adminAttachmentsFromText(text, uploadsBase) {
|
|
7336
7395
|
const out = [];
|
|
7337
7396
|
for (const id of adminAttachmentIds(text)) {
|
|
7338
|
-
const meta = readAttachmentMeta(
|
|
7397
|
+
const meta = readAttachmentMeta(join11(uploadsBase, id));
|
|
7339
7398
|
if (meta) out.push(meta);
|
|
7340
7399
|
}
|
|
7341
7400
|
return out;
|
|
@@ -7343,7 +7402,7 @@ function adminAttachmentsFromText(text, uploadsBase) {
|
|
|
7343
7402
|
function readSidecar(dir, attachmentId) {
|
|
7344
7403
|
let parsed;
|
|
7345
7404
|
try {
|
|
7346
|
-
parsed = JSON.parse(
|
|
7405
|
+
parsed = JSON.parse(readFileSync12(join11(dir, `${attachmentId}.meta.json`), "utf8"));
|
|
7347
7406
|
} catch {
|
|
7348
7407
|
return null;
|
|
7349
7408
|
}
|
|
@@ -7372,7 +7431,7 @@ function listSessionAttachmentsInDir(dir) {
|
|
|
7372
7431
|
}
|
|
7373
7432
|
const sidecars = [];
|
|
7374
7433
|
for (const name of entries) {
|
|
7375
|
-
const sidecar = readSidecar(
|
|
7434
|
+
const sidecar = readSidecar(join11(dir, name), name);
|
|
7376
7435
|
if (sidecar) sidecars.push(sidecar);
|
|
7377
7436
|
}
|
|
7378
7437
|
sidecars.sort((a, b) => a.storedAt.localeCompare(b.storedAt));
|
|
@@ -7407,17 +7466,17 @@ var app4 = new Hono();
|
|
|
7407
7466
|
app4.get("/conversations", requireAdminSession, async (c) => {
|
|
7408
7467
|
const cfg = claudeConfigDir();
|
|
7409
7468
|
if (!cfg) return c.json({ conversations: [] });
|
|
7410
|
-
const projectsRoot =
|
|
7469
|
+
const projectsRoot = join12(cfg, "projects");
|
|
7411
7470
|
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
7412
7471
|
const rows = [];
|
|
7413
7472
|
for (const { path: path2 } of enumerateJsonls(projectsRoot)) {
|
|
7414
7473
|
const sessionId = basename2(path2).replace(/\.jsonl$/, "");
|
|
7415
7474
|
const projectDir = dirname(path2);
|
|
7416
|
-
const meta = readSidecarMeta(
|
|
7475
|
+
const meta = readSidecarMeta(join12(projectDir, `${sessionId}.meta.json`));
|
|
7417
7476
|
if (!isReaderChannelSession(meta.role, meta.channel)) continue;
|
|
7418
7477
|
let body = "";
|
|
7419
7478
|
try {
|
|
7420
|
-
body =
|
|
7479
|
+
body = readFileSync13(path2, "utf8");
|
|
7421
7480
|
} catch {
|
|
7422
7481
|
}
|
|
7423
7482
|
const { title } = resolveTitle(body, sessionId, userTitles);
|
|
@@ -7521,11 +7580,11 @@ app4.get("/stream", requireAdminSession, (c) => {
|
|
|
7521
7580
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
7522
7581
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
7523
7582
|
const cfg = claudeConfigDir();
|
|
7524
|
-
const projectsRoot = cfg ? resolve11(
|
|
7583
|
+
const projectsRoot = cfg ? resolve11(join12(cfg, "projects")) : null;
|
|
7525
7584
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
7526
7585
|
return c.json({ error: "bad session reference" }, 400);
|
|
7527
7586
|
}
|
|
7528
|
-
const jsonlPath = resolve11(
|
|
7587
|
+
const jsonlPath = resolve11(join12(projectDir, `${sessionId}.jsonl`));
|
|
7529
7588
|
if (!jsonlPath.startsWith(projectsRoot + sep3)) {
|
|
7530
7589
|
return c.json({ error: "bad session reference" }, 400);
|
|
7531
7590
|
}
|
|
@@ -7638,7 +7697,7 @@ app4.get("/directives", requireAdminSession, (c) => {
|
|
|
7638
7697
|
const pid = Number(pidPart);
|
|
7639
7698
|
let len = 0;
|
|
7640
7699
|
try {
|
|
7641
|
-
len = statSync4(
|
|
7700
|
+
len = statSync4(join12(dir, name)).size;
|
|
7642
7701
|
} catch {
|
|
7643
7702
|
}
|
|
7644
7703
|
return { name, secs, pid, ts: Number.isFinite(secs) ? new Date(secs * 1e3).toISOString() : null, len };
|
|
@@ -7653,11 +7712,11 @@ app4.get("/directive", requireAdminSession, (c) => {
|
|
|
7653
7712
|
}
|
|
7654
7713
|
const dir = directiveStoreDir(sessionId);
|
|
7655
7714
|
if (!dir) return c.json({ error: "no account" }, 404);
|
|
7656
|
-
const path2 = resolve11(
|
|
7715
|
+
const path2 = resolve11(join12(dir, name));
|
|
7657
7716
|
if (!path2.startsWith(dir + sep3)) return c.json({ error: "bad reference" }, 400);
|
|
7658
7717
|
let body;
|
|
7659
7718
|
try {
|
|
7660
|
-
body =
|
|
7719
|
+
body = readFileSync13(path2, "utf8");
|
|
7661
7720
|
} catch {
|
|
7662
7721
|
return c.json({ error: "not found" }, 404);
|
|
7663
7722
|
}
|
|
@@ -7666,8 +7725,8 @@ app4.get("/directive", requireAdminSession, (c) => {
|
|
|
7666
7725
|
var whatsapp_reader_default = app4;
|
|
7667
7726
|
|
|
7668
7727
|
// server/routes/public-reader.ts
|
|
7669
|
-
import { statSync as statSync5, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2, readFileSync as
|
|
7670
|
-
import { basename as basename3, dirname as dirname2, join as
|
|
7728
|
+
import { statSync as statSync5, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2, readFileSync as readFileSync14, readdirSync as readdirSync8 } from "fs";
|
|
7729
|
+
import { basename as basename3, dirname as dirname2, join as join13, resolve as resolve12, sep as sep4 } from "path";
|
|
7671
7730
|
|
|
7672
7731
|
// app/lib/whatsapp-reader/delivered-kinds.ts
|
|
7673
7732
|
var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -7741,10 +7800,10 @@ function enumeratePublicRows() {
|
|
|
7741
7800
|
const cfg = claudeConfigDir();
|
|
7742
7801
|
if (!cfg) return [];
|
|
7743
7802
|
const rows = [];
|
|
7744
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
7803
|
+
for (const { path: path2 } of enumerateJsonls(join13(cfg, "projects"))) {
|
|
7745
7804
|
const sessionId = basename3(path2).replace(/\.jsonl$/, "");
|
|
7746
7805
|
const projectDir = dirname2(path2);
|
|
7747
|
-
const meta = readSidecarMeta(
|
|
7806
|
+
const meta = readSidecarMeta(join13(projectDir, `${sessionId}.meta.json`));
|
|
7748
7807
|
rows.push({
|
|
7749
7808
|
sessionId,
|
|
7750
7809
|
projectDir,
|
|
@@ -7820,15 +7879,15 @@ app5.get("/stream", (c) => {
|
|
|
7820
7879
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
7821
7880
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
7822
7881
|
const cfg = claudeConfigDir();
|
|
7823
|
-
const projectsRoot = cfg ? resolve12(
|
|
7882
|
+
const projectsRoot = cfg ? resolve12(join13(cfg, "projects")) : null;
|
|
7824
7883
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
7825
7884
|
return c.json({ error: "bad session reference" }, 400);
|
|
7826
7885
|
}
|
|
7827
|
-
const jsonlPath = resolve12(
|
|
7886
|
+
const jsonlPath = resolve12(join13(projectDir, `${sessionId}.jsonl`));
|
|
7828
7887
|
if (!jsonlPath.startsWith(projectsRoot + sep4)) {
|
|
7829
7888
|
return c.json({ error: "bad session reference" }, 400);
|
|
7830
7889
|
}
|
|
7831
|
-
const meta = readSidecarMeta(
|
|
7890
|
+
const meta = readSidecarMeta(join13(projectDir, `${sessionId}.meta.json`));
|
|
7832
7891
|
const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
|
|
7833
7892
|
const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
|
|
7834
7893
|
if (!(isPublicWebchat && owns)) {
|
|
@@ -7943,7 +8002,7 @@ app5.get("/attachment/:attachmentId", (c) => {
|
|
|
7943
8002
|
try {
|
|
7944
8003
|
dataFile = readdirSync8(dir).find((f) => !f.endsWith(".meta.json"));
|
|
7945
8004
|
if (!dataFile) throw new Error("no data file");
|
|
7946
|
-
buffer =
|
|
8005
|
+
buffer = readFileSync14(resolve12(dir, dataFile));
|
|
7947
8006
|
} catch {
|
|
7948
8007
|
console.error(`${ATT_TAG} op=denied session=${ses} att=${at} reason=not-found`);
|
|
7949
8008
|
return new Response("Not found", { status: 404 });
|
|
@@ -7962,20 +8021,20 @@ var public_reader_default = app5;
|
|
|
7962
8021
|
|
|
7963
8022
|
// server/routes/webchat.ts
|
|
7964
8023
|
import { basename as basename4, dirname as dirname3 } from "path";
|
|
7965
|
-
import { join as
|
|
7966
|
-
import { existsSync as existsSync9, readdirSync as readdirSync10, readFileSync as
|
|
8024
|
+
import { join as join16 } from "path";
|
|
8025
|
+
import { existsSync as existsSync9, readdirSync as readdirSync10, readFileSync as readFileSync17, renameSync as renameSync3, statSync as statSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
7967
8026
|
|
|
7968
8027
|
// server/canonical-webchat-override.ts
|
|
7969
|
-
import { readFileSync as
|
|
7970
|
-
import { join as
|
|
8028
|
+
import { readFileSync as readFileSync15, writeFileSync as writeFileSync5, renameSync } from "fs";
|
|
8029
|
+
import { join as join14 } from "path";
|
|
7971
8030
|
var FILE = "canonical-webchat-session.json";
|
|
7972
8031
|
var UUID = /^[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}$/;
|
|
7973
8032
|
function canonicalOverridePath(accountDir) {
|
|
7974
|
-
return
|
|
8033
|
+
return join14(accountDir, FILE);
|
|
7975
8034
|
}
|
|
7976
8035
|
function readRaw(accountDir) {
|
|
7977
8036
|
try {
|
|
7978
|
-
return JSON.parse(
|
|
8037
|
+
return JSON.parse(readFileSync15(canonicalOverridePath(accountDir), "utf8"));
|
|
7979
8038
|
} catch {
|
|
7980
8039
|
return null;
|
|
7981
8040
|
}
|
|
@@ -8062,8 +8121,8 @@ function isNewSessionEffortLevel(value) {
|
|
|
8062
8121
|
}
|
|
8063
8122
|
|
|
8064
8123
|
// ../services/claude-session-manager/src/sidecar-store.ts
|
|
8065
|
-
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readdirSync as readdirSync9, readFileSync as
|
|
8066
|
-
import { join as
|
|
8124
|
+
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readdirSync as readdirSync9, readFileSync as readFileSync16, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
|
|
8125
|
+
import { join as join15 } from "path";
|
|
8067
8126
|
function escapeRegExp(s) {
|
|
8068
8127
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8069
8128
|
}
|
|
@@ -8071,7 +8130,7 @@ function createSidecarStore(config) {
|
|
|
8071
8130
|
const { suffix, validate: validate2 } = config;
|
|
8072
8131
|
const suffixRe = new RegExp(`${escapeRegExp(suffix)}$`);
|
|
8073
8132
|
function pathFor(sessionsDir, id) {
|
|
8074
|
-
return
|
|
8133
|
+
return join15(sessionsDir, `${id}${suffix}`);
|
|
8075
8134
|
}
|
|
8076
8135
|
function write(sessionsDir, id, record) {
|
|
8077
8136
|
mkdirSync2(sessionsDir, { recursive: true });
|
|
@@ -8092,7 +8151,7 @@ function createSidecarStore(config) {
|
|
|
8092
8151
|
function readFileAt(path2) {
|
|
8093
8152
|
let raw;
|
|
8094
8153
|
try {
|
|
8095
|
-
raw =
|
|
8154
|
+
raw = readFileSync16(path2, "utf8");
|
|
8096
8155
|
} catch {
|
|
8097
8156
|
return null;
|
|
8098
8157
|
}
|
|
@@ -8115,10 +8174,10 @@ function createSidecarStore(config) {
|
|
|
8115
8174
|
const out = [];
|
|
8116
8175
|
for (const name of names) {
|
|
8117
8176
|
if (!suffixRe.test(name)) continue;
|
|
8118
|
-
const path2 =
|
|
8177
|
+
const path2 = join15(sessionsDir, name);
|
|
8119
8178
|
let raw;
|
|
8120
8179
|
try {
|
|
8121
|
-
raw =
|
|
8180
|
+
raw = readFileSync16(path2, "utf8");
|
|
8122
8181
|
} catch {
|
|
8123
8182
|
onSkip?.(name, "unreadable");
|
|
8124
8183
|
continue;
|
|
@@ -8192,10 +8251,10 @@ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9
|
|
|
8192
8251
|
function locateSession(sessionId) {
|
|
8193
8252
|
const cfg = claudeConfigDir();
|
|
8194
8253
|
if (!cfg) return { projectDir: null, channel: null };
|
|
8195
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
8254
|
+
for (const { path: path2 } of enumerateJsonls(join16(cfg, "projects"))) {
|
|
8196
8255
|
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
8197
8256
|
const dir = dirname3(path2);
|
|
8198
|
-
const meta = readSidecarMeta(
|
|
8257
|
+
const meta = readSidecarMeta(join16(dir, `${sessionId}.meta.json`));
|
|
8199
8258
|
return { projectDir: dir, channel: meta.channel };
|
|
8200
8259
|
}
|
|
8201
8260
|
}
|
|
@@ -8204,7 +8263,7 @@ function locateSession(sessionId) {
|
|
|
8204
8263
|
function locateSidecar(sessionId) {
|
|
8205
8264
|
const cfg = claudeConfigDir();
|
|
8206
8265
|
if (!cfg) return null;
|
|
8207
|
-
const projectsRoot =
|
|
8266
|
+
const projectsRoot = join16(cfg, "projects");
|
|
8208
8267
|
let slugs;
|
|
8209
8268
|
try {
|
|
8210
8269
|
slugs = readdirSync10(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -8212,7 +8271,7 @@ function locateSidecar(sessionId) {
|
|
|
8212
8271
|
return null;
|
|
8213
8272
|
}
|
|
8214
8273
|
for (const slug of slugs) {
|
|
8215
|
-
const metaPath =
|
|
8274
|
+
const metaPath = join16(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
8216
8275
|
if (existsSync9(metaPath)) {
|
|
8217
8276
|
const meta = readSidecarMeta(metaPath);
|
|
8218
8277
|
return { channel: meta.channel, adminUserId: meta.adminUserId };
|
|
@@ -8225,7 +8284,7 @@ function readTargetOwner(sessionId) {
|
|
|
8225
8284
|
if (sidecar !== null) return { found: true, owner: sidecar.adminUserId };
|
|
8226
8285
|
const { projectDir } = locateSession(sessionId);
|
|
8227
8286
|
if (projectDir !== null) {
|
|
8228
|
-
return { found: true, owner: readSidecarMeta(
|
|
8287
|
+
return { found: true, owner: readSidecarMeta(join16(projectDir, `${sessionId}.meta.json`)).adminUserId };
|
|
8229
8288
|
}
|
|
8230
8289
|
return { found: false, owner: null };
|
|
8231
8290
|
}
|
|
@@ -8239,7 +8298,7 @@ function sessionSidecarExists(sessionId) {
|
|
|
8239
8298
|
function jsonlSizeBytes(projectDir, sessionId) {
|
|
8240
8299
|
if (projectDir === null) return null;
|
|
8241
8300
|
try {
|
|
8242
|
-
return statSync6(
|
|
8301
|
+
return statSync6(join16(projectDir, `${sessionId}.jsonl`)).size;
|
|
8243
8302
|
} catch {
|
|
8244
8303
|
return null;
|
|
8245
8304
|
}
|
|
@@ -8327,10 +8386,10 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId) {
|
|
|
8327
8386
|
const cfg = claudeConfigDir();
|
|
8328
8387
|
if (!cfg) return null;
|
|
8329
8388
|
let best = null;
|
|
8330
|
-
for (const { path: path2, isSubagent, archived } of enumerateJsonls(
|
|
8389
|
+
for (const { path: path2, isSubagent, archived } of enumerateJsonls(join16(cfg, "projects"))) {
|
|
8331
8390
|
if (isSubagent || archived) continue;
|
|
8332
8391
|
const id = basename4(path2).slice(0, -".jsonl".length);
|
|
8333
|
-
const meta = readSidecarMeta(
|
|
8392
|
+
const meta = readSidecarMeta(join16(dirname3(path2), `${id}.meta.json`));
|
|
8334
8393
|
if (meta.role !== "admin" || meta.channel !== "webchat") continue;
|
|
8335
8394
|
let mtimeMs;
|
|
8336
8395
|
try {
|
|
@@ -8581,9 +8640,9 @@ ${note}` : note;
|
|
|
8581
8640
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-unresolved`);
|
|
8582
8641
|
return c.json({ error: "account unresolved" }, 503);
|
|
8583
8642
|
}
|
|
8584
|
-
const accountJsonPath =
|
|
8643
|
+
const accountJsonPath = join16(account.accountDir, "account.json");
|
|
8585
8644
|
try {
|
|
8586
|
-
const parsed = JSON.parse(
|
|
8645
|
+
const parsed = JSON.parse(readFileSync17(accountJsonPath, "utf8"));
|
|
8587
8646
|
if (op === "model") parsed.adminModel = value;
|
|
8588
8647
|
else if (op === "effort") parsed.effort = value;
|
|
8589
8648
|
else parsed.adminPermissionMode = value;
|
|
@@ -8628,7 +8687,7 @@ ${note}` : note;
|
|
|
8628
8687
|
const cfg2 = claudeConfigDir();
|
|
8629
8688
|
if (cfg2) {
|
|
8630
8689
|
const source2 = resolveBridgeSource(
|
|
8631
|
-
|
|
8690
|
+
join16(cfg2, "sessions"),
|
|
8632
8691
|
target,
|
|
8633
8692
|
(id) => locateSession(id).projectDir !== null
|
|
8634
8693
|
);
|
|
@@ -8660,7 +8719,7 @@ ${note}` : note;
|
|
|
8660
8719
|
const cfg = claudeConfigDir();
|
|
8661
8720
|
let projectDir = null;
|
|
8662
8721
|
if (cfg) {
|
|
8663
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
8722
|
+
for (const { path: path2 } of enumerateJsonls(join16(cfg, "projects"))) {
|
|
8664
8723
|
if (basename4(path2) === `${sessionId}.jsonl`) {
|
|
8665
8724
|
projectDir = dirname3(path2);
|
|
8666
8725
|
break;
|
|
@@ -8668,7 +8727,7 @@ ${note}` : note;
|
|
|
8668
8727
|
}
|
|
8669
8728
|
}
|
|
8670
8729
|
if (source === "latest" && requesterUserId !== null) {
|
|
8671
|
-
const owner = readSidecarMeta(
|
|
8730
|
+
const owner = readSidecarMeta(join16(projectDir ?? "", `${sessionId}.meta.json`)).adminUserId;
|
|
8672
8731
|
if (owner !== null && owner !== requesterUserId && requesterUserId !== primaryUserId) {
|
|
8673
8732
|
console.error(`[webchat:inbound] op=session-resolve-foreign key=${sessionId.slice(0, 8)} owner=${owner.slice(0, 8)} requester=${requesterUserId.slice(0, 8)}`);
|
|
8674
8733
|
}
|
|
@@ -8700,8 +8759,8 @@ ${note}` : note;
|
|
|
8700
8759
|
import { resolve as resolve13 } from "path";
|
|
8701
8760
|
|
|
8702
8761
|
// app/lib/claude-agent/specialist-roster.ts
|
|
8703
|
-
import { existsSync as existsSync10, readFileSync as
|
|
8704
|
-
import { join as
|
|
8762
|
+
import { existsSync as existsSync10, readFileSync as readFileSync18, readdirSync as readdirSync11 } from "fs";
|
|
8763
|
+
import { join as join17 } from "path";
|
|
8705
8764
|
function field(fm, name) {
|
|
8706
8765
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
8707
8766
|
if (!m) return null;
|
|
@@ -8720,7 +8779,7 @@ function readSpecialistRoster(specialistsDir) {
|
|
|
8720
8779
|
if (!file.endsWith(".md")) continue;
|
|
8721
8780
|
let raw;
|
|
8722
8781
|
try {
|
|
8723
|
-
raw =
|
|
8782
|
+
raw = readFileSync18(join17(specialistsDir, file), "utf-8");
|
|
8724
8783
|
} catch (err) {
|
|
8725
8784
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
8726
8785
|
continue;
|
|
@@ -8837,8 +8896,8 @@ var webchat_greeting_default = app6;
|
|
|
8837
8896
|
|
|
8838
8897
|
// server/routes/telegram.ts
|
|
8839
8898
|
import { homedir } from "os";
|
|
8840
|
-
import { resolve as resolve17, join as
|
|
8841
|
-
import { existsSync as existsSync11, readFileSync as
|
|
8899
|
+
import { resolve as resolve17, join as join18 } from "path";
|
|
8900
|
+
import { existsSync as existsSync11, readFileSync as readFileSync19 } from "fs";
|
|
8842
8901
|
|
|
8843
8902
|
// app/lib/channel-pty-bridge/bridge.ts
|
|
8844
8903
|
import { resolve as resolve16 } from "path";
|
|
@@ -9959,10 +10018,10 @@ var TAG26 = "[telegram-inbound]";
|
|
|
9959
10018
|
var DISPATCH_TIMEOUT_MS = 12e4;
|
|
9960
10019
|
function configDirName() {
|
|
9961
10020
|
const platformRoot4 = process.env.MAXY_PLATFORM_ROOT ?? resolve17(process.cwd(), "..");
|
|
9962
|
-
const brandPath =
|
|
10021
|
+
const brandPath = join18(platformRoot4, "config", "brand.json");
|
|
9963
10022
|
if (existsSync11(brandPath)) {
|
|
9964
10023
|
try {
|
|
9965
|
-
return JSON.parse(
|
|
10024
|
+
return JSON.parse(readFileSync19(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
9966
10025
|
} catch {
|
|
9967
10026
|
}
|
|
9968
10027
|
}
|
|
@@ -9998,7 +10057,7 @@ app7.post("/", async (c) => {
|
|
|
9998
10057
|
console.error(`${TAG26} op=reject reason=no-secret-file botType=${botType}`);
|
|
9999
10058
|
return c.json({ ok: false }, 401);
|
|
10000
10059
|
}
|
|
10001
|
-
const expected =
|
|
10060
|
+
const expected = readFileSync19(sp, "utf-8").trim();
|
|
10002
10061
|
const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
|
|
10003
10062
|
if (got !== expected) {
|
|
10004
10063
|
console.error(`${TAG26} op=reject reason=bad-secret botType=${botType}`);
|
|
@@ -10063,16 +10122,16 @@ app7.post("/", async (c) => {
|
|
|
10063
10122
|
var telegram_default = app7;
|
|
10064
10123
|
|
|
10065
10124
|
// server/routes/quickbooks.ts
|
|
10066
|
-
import { join as
|
|
10067
|
-
import { existsSync as existsSync12, readFileSync as
|
|
10125
|
+
import { join as join19 } from "path";
|
|
10126
|
+
import { existsSync as existsSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync8, mkdirSync as mkdirSync3, rmSync, renameSync as renameSync4 } from "fs";
|
|
10068
10127
|
var TAG27 = "[quickbooks]";
|
|
10069
10128
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
10070
10129
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
10071
10130
|
function pendingPath(accountDir, state) {
|
|
10072
|
-
return
|
|
10131
|
+
return join19(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
|
|
10073
10132
|
}
|
|
10074
10133
|
function storePath(accountDir) {
|
|
10075
|
-
return
|
|
10134
|
+
return join19(accountDir, "secrets", "quickbooks.json");
|
|
10076
10135
|
}
|
|
10077
10136
|
async function completeConsent(args) {
|
|
10078
10137
|
const { accountDir, code, realmId } = args;
|
|
@@ -10091,7 +10150,7 @@ async function completeConsent(args) {
|
|
|
10091
10150
|
try {
|
|
10092
10151
|
let pending;
|
|
10093
10152
|
try {
|
|
10094
|
-
pending = JSON.parse(
|
|
10153
|
+
pending = JSON.parse(readFileSync20(claimFile, "utf-8"));
|
|
10095
10154
|
} catch {
|
|
10096
10155
|
console.error(`${TAG27} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
|
|
10097
10156
|
return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
|
|
@@ -10107,7 +10166,7 @@ async function completeConsent(args) {
|
|
|
10107
10166
|
if (!existsSync12(storePath(accountDir))) {
|
|
10108
10167
|
return { ok: false, status: 500, message: "No QuickBooks credentials are stored for this account.", stateValid: true };
|
|
10109
10168
|
}
|
|
10110
|
-
const store2 = JSON.parse(
|
|
10169
|
+
const store2 = JSON.parse(readFileSync20(storePath(accountDir), "utf-8"));
|
|
10111
10170
|
const form = new URLSearchParams({
|
|
10112
10171
|
grant_type: "authorization_code",
|
|
10113
10172
|
code,
|
|
@@ -10139,9 +10198,9 @@ async function completeConsent(args) {
|
|
|
10139
10198
|
refreshTokenExpiry: now + (body.x_refresh_token_expires_in ?? 864e4) * 1e3,
|
|
10140
10199
|
lastRefresh: now
|
|
10141
10200
|
};
|
|
10142
|
-
mkdirSync3(
|
|
10201
|
+
mkdirSync3(join19(accountDir, "secrets"), { recursive: true });
|
|
10143
10202
|
writeFileSync8(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
10144
|
-
const persisted = JSON.parse(
|
|
10203
|
+
const persisted = JSON.parse(readFileSync20(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
10145
10204
|
console.error(`${TAG27} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
10146
10205
|
return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
|
|
10147
10206
|
} finally {
|
|
@@ -10172,12 +10231,12 @@ var quickbooks_default = app8;
|
|
|
10172
10231
|
|
|
10173
10232
|
// server/routes/onboarding.ts
|
|
10174
10233
|
import { spawn, spawnSync as spawnSync2, execFileSync as execFileSync2 } from "child_process";
|
|
10175
|
-
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeFileSync10, writeSync, existsSync as existsSync14, readFileSync as
|
|
10234
|
+
import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeFileSync10, writeSync, existsSync as existsSync14, readFileSync as readFileSync22, unlinkSync as unlinkSync2 } from "fs";
|
|
10176
10235
|
import { createHash as createHash3, randomUUID as randomUUID8 } from "crypto";
|
|
10177
10236
|
|
|
10178
10237
|
// ../lib/admins-write/src/index.ts
|
|
10179
|
-
import { existsSync as existsSync13, readFileSync as
|
|
10180
|
-
import { dirname as dirname4, join as
|
|
10238
|
+
import { existsSync as existsSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync9, renameSync as renameSync5, mkdirSync as mkdirSync4, readdirSync as readdirSync12, statSync as statSync7 } from "fs";
|
|
10239
|
+
import { dirname as dirname4, join as join20 } from "path";
|
|
10181
10240
|
function logLine(input, result) {
|
|
10182
10241
|
const userIdShort = input.userId.slice(0, 8);
|
|
10183
10242
|
console.error(
|
|
@@ -10195,7 +10254,7 @@ function writeAdminEntry(input) {
|
|
|
10195
10254
|
try {
|
|
10196
10255
|
let users = [];
|
|
10197
10256
|
if (existsSync13(input.usersFile)) {
|
|
10198
|
-
const raw =
|
|
10257
|
+
const raw = readFileSync21(input.usersFile, "utf-8").trim();
|
|
10199
10258
|
if (raw) {
|
|
10200
10259
|
const parsed = JSON.parse(raw);
|
|
10201
10260
|
if (!Array.isArray(parsed)) {
|
|
@@ -10219,11 +10278,11 @@ function writeAdminEntry(input) {
|
|
|
10219
10278
|
return result;
|
|
10220
10279
|
}
|
|
10221
10280
|
try {
|
|
10222
|
-
const accountJsonPath =
|
|
10281
|
+
const accountJsonPath = join20(input.accountDir, "account.json");
|
|
10223
10282
|
if (!existsSync13(accountJsonPath)) {
|
|
10224
10283
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
10225
10284
|
}
|
|
10226
|
-
const config = JSON.parse(
|
|
10285
|
+
const config = JSON.parse(readFileSync21(accountJsonPath, "utf-8"));
|
|
10227
10286
|
const admins = config.admins ?? [];
|
|
10228
10287
|
if (admins.some((a) => a.userId === input.userId)) {
|
|
10229
10288
|
result.accountJsonResult = "noop";
|
|
@@ -10249,7 +10308,7 @@ function checkAdminAuthInvariant(input) {
|
|
|
10249
10308
|
const usersUserIds = /* @__PURE__ */ new Set();
|
|
10250
10309
|
if (existsSync13(input.usersFile)) {
|
|
10251
10310
|
try {
|
|
10252
|
-
const raw =
|
|
10311
|
+
const raw = readFileSync21(input.usersFile, "utf-8").trim();
|
|
10253
10312
|
if (raw) {
|
|
10254
10313
|
const users = JSON.parse(raw);
|
|
10255
10314
|
for (const u of users) {
|
|
@@ -10274,17 +10333,17 @@ function checkAdminAuthInvariant(input) {
|
|
|
10274
10333
|
}
|
|
10275
10334
|
for (const entry of entries) {
|
|
10276
10335
|
if (entry.startsWith(".")) continue;
|
|
10277
|
-
const accountDir =
|
|
10336
|
+
const accountDir = join20(input.accountsDir, entry);
|
|
10278
10337
|
try {
|
|
10279
10338
|
if (!statSync7(accountDir).isDirectory()) continue;
|
|
10280
10339
|
} catch {
|
|
10281
10340
|
continue;
|
|
10282
10341
|
}
|
|
10283
|
-
const accountJsonPath =
|
|
10342
|
+
const accountJsonPath = join20(accountDir, "account.json");
|
|
10284
10343
|
if (!existsSync13(accountJsonPath)) continue;
|
|
10285
10344
|
let admins = [];
|
|
10286
10345
|
try {
|
|
10287
|
-
const config = JSON.parse(
|
|
10346
|
+
const config = JSON.parse(readFileSync21(accountJsonPath, "utf-8"));
|
|
10288
10347
|
admins = config.admins ?? [];
|
|
10289
10348
|
} catch (err) {
|
|
10290
10349
|
const msg = err instanceof Error ? err.message : String(err);
|
|
@@ -10325,7 +10384,7 @@ function hashPin2(pin) {
|
|
|
10325
10384
|
}
|
|
10326
10385
|
function readUsersFile2() {
|
|
10327
10386
|
if (!existsSync14(USERS_FILE)) return null;
|
|
10328
|
-
const raw =
|
|
10387
|
+
const raw = readFileSync22(USERS_FILE, "utf-8").trim();
|
|
10329
10388
|
if (!raw) return [];
|
|
10330
10389
|
return JSON.parse(raw);
|
|
10331
10390
|
}
|
|
@@ -10487,7 +10546,7 @@ app9.post("/set-pin", async (c) => {
|
|
|
10487
10546
|
let installOwner = null;
|
|
10488
10547
|
if (existsSync14(INSTALL_OWNER_FILE)) {
|
|
10489
10548
|
try {
|
|
10490
|
-
const raw =
|
|
10549
|
+
const raw = readFileSync22(INSTALL_OWNER_FILE, "utf-8").trim();
|
|
10491
10550
|
if (raw.length > 0) installOwner = raw;
|
|
10492
10551
|
} catch (err) {
|
|
10493
10552
|
console.error(`[set-pin] install-owner-read-failed path=${INSTALL_OWNER_FILE} error=${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -10569,8 +10628,8 @@ var onboarding_default = app9;
|
|
|
10569
10628
|
|
|
10570
10629
|
// server/routes/client-error.ts
|
|
10571
10630
|
import { appendFileSync, existsSync as existsSync15, renameSync as renameSync6, statSync as statSync8 } from "fs";
|
|
10572
|
-
import { join as
|
|
10573
|
-
var CLIENT_ERRORS_LOG =
|
|
10631
|
+
import { join as join21 } from "path";
|
|
10632
|
+
var CLIENT_ERRORS_LOG = join21(LOG_DIR, "client-errors.log");
|
|
10574
10633
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
10575
10634
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
10576
10635
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -10895,17 +10954,17 @@ app11.post("/", async (c) => {
|
|
|
10895
10954
|
var session_default = app11;
|
|
10896
10955
|
|
|
10897
10956
|
// server/routes/admin/logs.ts
|
|
10898
|
-
import { existsSync as existsSync17, readdirSync as readdirSync13, readFileSync as
|
|
10957
|
+
import { existsSync as existsSync17, readdirSync as readdirSync13, readFileSync as readFileSync23, statSync as statSync9 } from "fs";
|
|
10899
10958
|
import { resolve as resolve18, basename as basename6 } from "path";
|
|
10900
10959
|
|
|
10901
10960
|
// app/lib/logs-read-resolve.ts
|
|
10902
10961
|
import { existsSync as existsSync16 } from "fs";
|
|
10903
|
-
import { join as
|
|
10962
|
+
import { join as join22 } from "path";
|
|
10904
10963
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
10905
10964
|
const tried = [filename];
|
|
10906
10965
|
const hits = [];
|
|
10907
10966
|
for (const dir of logDirs) {
|
|
10908
|
-
const fullPath =
|
|
10967
|
+
const fullPath = join22(dir, filename);
|
|
10909
10968
|
if (existsSync16(fullPath)) {
|
|
10910
10969
|
hits.push({ path: fullPath, dir });
|
|
10911
10970
|
}
|
|
@@ -10934,7 +10993,7 @@ app12.get("/", async (c) => {
|
|
|
10934
10993
|
const filePath = resolve18(dir, safe);
|
|
10935
10994
|
searched.push(filePath);
|
|
10936
10995
|
try {
|
|
10937
|
-
const buffer =
|
|
10996
|
+
const buffer = readFileSync23(filePath);
|
|
10938
10997
|
const onDiskBytes = statSync9(filePath).size;
|
|
10939
10998
|
const headers = {
|
|
10940
10999
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -10999,7 +11058,7 @@ app12.get("/", async (c) => {
|
|
|
10999
11058
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
11000
11059
|
try {
|
|
11001
11060
|
const filename = basename6(hit.path);
|
|
11002
|
-
const buffer =
|
|
11061
|
+
const buffer = readFileSync23(hit.path);
|
|
11003
11062
|
const onDiskBytes = statSync9(hit.path).size;
|
|
11004
11063
|
const headers = {
|
|
11005
11064
|
"Content-Type": "text/plain; charset=utf-8",
|
|
@@ -11046,7 +11105,7 @@ app12.get("/", async (c) => {
|
|
|
11046
11105
|
files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync9(resolve18(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
|
|
11047
11106
|
seen.add(name);
|
|
11048
11107
|
try {
|
|
11049
|
-
const content =
|
|
11108
|
+
const content = readFileSync23(resolve18(dir, name));
|
|
11050
11109
|
const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
|
|
11051
11110
|
logs[name] = tail.trim() || "(empty)";
|
|
11052
11111
|
} catch (err) {
|
|
@@ -11131,7 +11190,7 @@ var attachment_default = app14;
|
|
|
11131
11190
|
|
|
11132
11191
|
// server/routes/admin/agents.ts
|
|
11133
11192
|
import { resolve as resolve20 } from "path";
|
|
11134
|
-
import { readdirSync as readdirSync14, readFileSync as
|
|
11193
|
+
import { readdirSync as readdirSync14, readFileSync as readFileSync24, existsSync as existsSync19, rmSync as rmSync2 } from "fs";
|
|
11135
11194
|
var app15 = new Hono();
|
|
11136
11195
|
app15.get("/", (c) => {
|
|
11137
11196
|
const account = resolveAccount();
|
|
@@ -11147,7 +11206,7 @@ app15.get("/", (c) => {
|
|
|
11147
11206
|
const configPath2 = resolve20(agentsDir, entry.name, "config.json");
|
|
11148
11207
|
if (!existsSync19(configPath2)) continue;
|
|
11149
11208
|
try {
|
|
11150
|
-
const config = JSON.parse(
|
|
11209
|
+
const config = JSON.parse(readFileSync24(configPath2, "utf-8"));
|
|
11151
11210
|
agents.push({
|
|
11152
11211
|
slug: entry.name,
|
|
11153
11212
|
displayName: config.displayName ?? entry.name,
|
|
@@ -11906,8 +11965,8 @@ app16.put("/:id/label", requireAdminSession, async (c) => {
|
|
|
11906
11965
|
var sessions_default = app16;
|
|
11907
11966
|
|
|
11908
11967
|
// app/lib/claude-agent/spawn-context.ts
|
|
11909
|
-
import { existsSync as existsSync21, readFileSync as
|
|
11910
|
-
import { dirname as dirname5, resolve as resolve21, join as
|
|
11968
|
+
import { existsSync as existsSync21, readFileSync as readFileSync25, readdirSync as readdirSync15, statSync as statSync10 } from "fs";
|
|
11969
|
+
import { dirname as dirname5, resolve as resolve21, join as join23 } from "path";
|
|
11911
11970
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
11912
11971
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
11913
11972
|
try {
|
|
@@ -11948,14 +12007,14 @@ function frontmatterField(manifest, field2) {
|
|
|
11948
12007
|
function extractPluginToolDescriptions(pluginDir) {
|
|
11949
12008
|
const out = /* @__PURE__ */ new Map();
|
|
11950
12009
|
const candidates = [
|
|
11951
|
-
|
|
11952
|
-
|
|
12010
|
+
join23(pluginDir, "mcp/dist/index.js"),
|
|
12011
|
+
join23(pluginDir, "mcp/src/index.ts")
|
|
11953
12012
|
];
|
|
11954
12013
|
let raw = null;
|
|
11955
12014
|
for (const path2 of candidates) {
|
|
11956
12015
|
if (!existsSync21(path2)) continue;
|
|
11957
12016
|
try {
|
|
11958
|
-
raw =
|
|
12017
|
+
raw = readFileSync25(path2, "utf-8");
|
|
11959
12018
|
break;
|
|
11960
12019
|
} catch {
|
|
11961
12020
|
}
|
|
@@ -12007,7 +12066,7 @@ function listPluginDirs() {
|
|
|
12007
12066
|
const platformPlugins = resolve21(PLATFORM_ROOT, "plugins");
|
|
12008
12067
|
if (existsSync21(platformPlugins)) {
|
|
12009
12068
|
for (const name of readdirSync15(platformPlugins)) {
|
|
12010
|
-
const dir =
|
|
12069
|
+
const dir = join23(platformPlugins, name);
|
|
12011
12070
|
try {
|
|
12012
12071
|
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
12013
12072
|
} catch {
|
|
@@ -12017,11 +12076,11 @@ function listPluginDirs() {
|
|
|
12017
12076
|
const premiumRoot = resolve21(dirname5(PLATFORM_ROOT), "premium-plugins");
|
|
12018
12077
|
if (existsSync21(premiumRoot)) {
|
|
12019
12078
|
for (const bundle of readdirSync15(premiumRoot)) {
|
|
12020
|
-
const bundlePlugins =
|
|
12079
|
+
const bundlePlugins = join23(premiumRoot, bundle, "plugins");
|
|
12021
12080
|
if (!existsSync21(bundlePlugins)) continue;
|
|
12022
12081
|
try {
|
|
12023
12082
|
for (const name of readdirSync15(bundlePlugins)) {
|
|
12024
|
-
const dir =
|
|
12083
|
+
const dir = join23(bundlePlugins, name);
|
|
12025
12084
|
try {
|
|
12026
12085
|
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
12027
12086
|
} catch {
|
|
@@ -12037,7 +12096,7 @@ function readEnabledPlugins(accountId) {
|
|
|
12037
12096
|
const accountFile = resolve21(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
|
|
12038
12097
|
if (!existsSync21(accountFile)) return /* @__PURE__ */ new Set();
|
|
12039
12098
|
try {
|
|
12040
|
-
const parsed = JSON.parse(
|
|
12099
|
+
const parsed = JSON.parse(readFileSync25(accountFile, "utf-8"));
|
|
12041
12100
|
return new Set(
|
|
12042
12101
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
12043
12102
|
);
|
|
@@ -12049,7 +12108,7 @@ function readFrontmatter(path2) {
|
|
|
12049
12108
|
if (!existsSync21(path2)) return null;
|
|
12050
12109
|
let raw;
|
|
12051
12110
|
try {
|
|
12052
|
-
raw =
|
|
12111
|
+
raw = readFileSync25(path2, "utf-8");
|
|
12053
12112
|
} catch {
|
|
12054
12113
|
return null;
|
|
12055
12114
|
}
|
|
@@ -12064,7 +12123,7 @@ function computeActivePlugins(accountId) {
|
|
|
12064
12123
|
for (const name of Array.from(enabled).sort()) {
|
|
12065
12124
|
const dir = pluginDirs.get(name);
|
|
12066
12125
|
if (!dir) continue;
|
|
12067
|
-
const fm = readFrontmatter(
|
|
12126
|
+
const fm = readFrontmatter(join23(dir, "PLUGIN.md"));
|
|
12068
12127
|
if (!fm) continue;
|
|
12069
12128
|
const description = frontmatterField(`---
|
|
12070
12129
|
${fm}
|
|
@@ -12081,7 +12140,7 @@ ${fm}
|
|
|
12081
12140
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
12082
12141
|
);
|
|
12083
12142
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
12084
|
-
const hasSource = existsSync21(
|
|
12143
|
+
const hasSource = existsSync21(join23(dir, "mcp/dist/index.js")) || existsSync21(join23(dir, "mcp/src/index.ts"));
|
|
12085
12144
|
if (hasSource) {
|
|
12086
12145
|
console.warn(
|
|
12087
12146
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -12091,7 +12150,7 @@ ${fm}
|
|
|
12091
12150
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
12092
12151
|
const skills = [];
|
|
12093
12152
|
for (const relPath of skillPaths) {
|
|
12094
|
-
const skillPath =
|
|
12153
|
+
const skillPath = join23(dir, relPath);
|
|
12095
12154
|
const skillFm = readFrontmatter(skillPath);
|
|
12096
12155
|
if (!skillFm) continue;
|
|
12097
12156
|
const skillName = frontmatterField(`---
|
|
@@ -12135,7 +12194,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
12135
12194
|
const out = [];
|
|
12136
12195
|
for (const file of entries.sort()) {
|
|
12137
12196
|
if (!file.endsWith(".md")) continue;
|
|
12138
|
-
const fm = readFrontmatter(
|
|
12197
|
+
const fm = readFrontmatter(join23(specialistsDir, file));
|
|
12139
12198
|
if (!fm) continue;
|
|
12140
12199
|
const wrapped = `---
|
|
12141
12200
|
${fm}
|
|
@@ -12157,7 +12216,7 @@ function computeDormantPlugins(accountId) {
|
|
|
12157
12216
|
if (!existsSync21(accountFile)) return [];
|
|
12158
12217
|
let enabled;
|
|
12159
12218
|
try {
|
|
12160
|
-
const raw =
|
|
12219
|
+
const raw = readFileSync25(accountFile, "utf-8");
|
|
12161
12220
|
const parsed = JSON.parse(raw);
|
|
12162
12221
|
enabled = new Set(
|
|
12163
12222
|
Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
|
|
@@ -12183,7 +12242,7 @@ function computeDormantPlugins(accountId) {
|
|
|
12183
12242
|
if (!existsSync21(manifestPath)) continue;
|
|
12184
12243
|
let manifest;
|
|
12185
12244
|
try {
|
|
12186
|
-
manifest =
|
|
12245
|
+
manifest = readFileSync25(manifestPath, "utf-8");
|
|
12187
12246
|
} catch {
|
|
12188
12247
|
continue;
|
|
12189
12248
|
}
|
|
@@ -12197,13 +12256,13 @@ function computeDormantPlugins(accountId) {
|
|
|
12197
12256
|
}
|
|
12198
12257
|
|
|
12199
12258
|
// server/routes/admin/claude-sessions.ts
|
|
12200
|
-
import { existsSync as existsSync22, readFileSync as
|
|
12259
|
+
import { existsSync as existsSync22, readFileSync as readFileSync26 } from "fs";
|
|
12201
12260
|
import { resolve as resolve22 } from "path";
|
|
12202
12261
|
function readTunnelState(brandConfigDir) {
|
|
12203
12262
|
const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
|
|
12204
12263
|
if (!existsSync22(statePath)) return null;
|
|
12205
12264
|
try {
|
|
12206
|
-
const parsed = JSON.parse(
|
|
12265
|
+
const parsed = JSON.parse(readFileSync26(statePath, "utf-8"));
|
|
12207
12266
|
const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
|
|
12208
12267
|
const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
|
|
12209
12268
|
const domain = typeof parsed.domain === "string" ? parsed.domain : null;
|
|
@@ -12217,7 +12276,7 @@ function resolveTunnelUrl() {
|
|
|
12217
12276
|
const platformRoot4 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve22(process.cwd(), "..");
|
|
12218
12277
|
let brand;
|
|
12219
12278
|
try {
|
|
12220
|
-
brand = JSON.parse(
|
|
12279
|
+
brand = JSON.parse(readFileSync26(resolve22(platformRoot4, "config", "brand.json"), "utf-8"));
|
|
12221
12280
|
} catch {
|
|
12222
12281
|
return null;
|
|
12223
12282
|
}
|
|
@@ -12463,7 +12522,7 @@ import { createReadStream as createReadStream2, createWriteStream as createWrite
|
|
|
12463
12522
|
import { readdir as readdir3, readFile as readFile5, stat as stat5, mkdir as mkdir3, unlink as unlink2, rename } from "fs/promises";
|
|
12464
12523
|
import { realpathSync as realpathSync6 } from "fs";
|
|
12465
12524
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
12466
|
-
import { basename as basename8, dirname as dirname6, join as
|
|
12525
|
+
import { basename as basename8, dirname as dirname6, join as join25, resolve as resolve24, sep as sep6 } from "path";
|
|
12467
12526
|
import { Readable as Readable2 } from "stream";
|
|
12468
12527
|
|
|
12469
12528
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -12781,7 +12840,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
12781
12840
|
|
|
12782
12841
|
// app/lib/file-index.ts
|
|
12783
12842
|
import * as fsp from "fs/promises";
|
|
12784
|
-
import { resolve as resolve23, relative as relative3, join as
|
|
12843
|
+
import { resolve as resolve23, relative as relative3, join as join24, basename as basename7, extname as extname2, sep as sep5 } from "path";
|
|
12785
12844
|
import { tmpdir as tmpdir2 } from "os";
|
|
12786
12845
|
import { execFile as execFile2 } from "child_process";
|
|
12787
12846
|
import { promisify as promisify2 } from "util";
|
|
@@ -12863,7 +12922,7 @@ async function extractPdf(absolute) {
|
|
|
12863
12922
|
return stdout.trim();
|
|
12864
12923
|
}
|
|
12865
12924
|
async function ocrPdf(absolute) {
|
|
12866
|
-
const outPdf =
|
|
12925
|
+
const outPdf = join24(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
12867
12926
|
try {
|
|
12868
12927
|
await execFileAsync2(
|
|
12869
12928
|
"ocrmypdf",
|
|
@@ -12925,7 +12984,7 @@ async function readDisplayName(absolute) {
|
|
|
12925
12984
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
12926
12985
|
if (base === `${stem}.meta.json`) return null;
|
|
12927
12986
|
try {
|
|
12928
|
-
const raw = await fsp.readFile(
|
|
12987
|
+
const raw = await fsp.readFile(join24(dir, `${stem}.meta.json`), "utf-8");
|
|
12929
12988
|
const meta = JSON.parse(raw);
|
|
12930
12989
|
const dn = meta.displayName ?? meta.filename;
|
|
12931
12990
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -12946,7 +13005,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
12946
13005
|
for (const entry of entries) {
|
|
12947
13006
|
if (entry.isSymbolicLink()) continue;
|
|
12948
13007
|
if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
|
|
12949
|
-
const abs =
|
|
13008
|
+
const abs = join24(root, entry.name);
|
|
12950
13009
|
if (entry.isDirectory()) {
|
|
12951
13010
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
12952
13011
|
if (!sub.clean) clean = false;
|
|
@@ -13219,7 +13278,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
|
13219
13278
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
13220
13279
|
async function readMeta(absDir, baseName) {
|
|
13221
13280
|
try {
|
|
13222
|
-
const raw = await readFile5(
|
|
13281
|
+
const raw = await readFile5(join25(absDir, `${baseName}.meta.json`), "utf8");
|
|
13223
13282
|
const parsed = JSON.parse(raw);
|
|
13224
13283
|
if (typeof parsed?.filename === "string") {
|
|
13225
13284
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -13257,7 +13316,7 @@ async function readAccountNames() {
|
|
|
13257
13316
|
}
|
|
13258
13317
|
async function enrich(absolute, entry, accountNames) {
|
|
13259
13318
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
13260
|
-
const meta = await readMeta(
|
|
13319
|
+
const meta = await readMeta(join25(absolute, entry.name), entry.name);
|
|
13261
13320
|
if (meta?.filename) {
|
|
13262
13321
|
entry.displayName = meta.filename;
|
|
13263
13322
|
entry.mimeType = meta.mimeType;
|
|
@@ -13421,7 +13480,7 @@ app20.get("/", requireAdminSession, async (c) => {
|
|
|
13421
13480
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
13422
13481
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
13423
13482
|
try {
|
|
13424
|
-
const entryPath =
|
|
13483
|
+
const entryPath = join25(absolute, name);
|
|
13425
13484
|
const s = await stat5(entryPath);
|
|
13426
13485
|
entries.push({
|
|
13427
13486
|
name,
|
|
@@ -13562,7 +13621,7 @@ app20.post("/upload", requireAdminSession, async (c) => {
|
|
|
13562
13621
|
const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
13563
13622
|
if (!base.ok) return c.json({ error: base.error }, base.status);
|
|
13564
13623
|
const relDir = relpath ? dirname6(relpath) : ".";
|
|
13565
|
-
const destRel = relDir === "." ? base.relative :
|
|
13624
|
+
const destRel = relDir === "." ? base.relative : join25(base.relative, relDir);
|
|
13566
13625
|
if (crossesForeignAccountPartition(destRel, accountId)) {
|
|
13567
13626
|
console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
13568
13627
|
return c.json({ error: "Not found" }, 404);
|
|
@@ -13739,7 +13798,7 @@ app20.delete("/", requireAdminSession, async (c) => {
|
|
|
13739
13798
|
}
|
|
13740
13799
|
const dot = base.lastIndexOf(".");
|
|
13741
13800
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
13742
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
13801
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join25(dirname6(absolute), `${stem}.meta.json`) : null;
|
|
13743
13802
|
await unlink2(absolute);
|
|
13744
13803
|
if (sidecarPath) {
|
|
13745
13804
|
try {
|
|
@@ -16215,6 +16274,7 @@ var session_rename_default = app31;
|
|
|
16215
16274
|
|
|
16216
16275
|
// server/routes/admin/session-rc-spawn.ts
|
|
16217
16276
|
import { randomUUID as randomUUID11 } from "crypto";
|
|
16277
|
+
var ACCOUNT_UUID_RE2 = /^[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}$/;
|
|
16218
16278
|
function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID11, adminUserId, authenticatedName) {
|
|
16219
16279
|
const operator = isOperatorHost(host, operatorDomains);
|
|
16220
16280
|
const resumeId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : void 0;
|
|
@@ -16225,6 +16285,7 @@ function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID11, ad
|
|
|
16225
16285
|
const pickedModel = kind === "new" && typeof body.model === "string" && isSelectableModel(body.model) ? body.model : null;
|
|
16226
16286
|
const pickedEffort = kind === "new" && typeof body.effort === "string" && isNewSessionEffortLevel(body.effort) ? body.effort : null;
|
|
16227
16287
|
const paramsSource = pickedModel !== null && pickedEffort !== null ? "picker" : "default";
|
|
16288
|
+
const targetAccountId = typeof body.targetAccountId === "string" && ACCOUNT_UUID_RE2.test(body.targetAccountId) ? body.targetAccountId : void 0;
|
|
16228
16289
|
const payload = {};
|
|
16229
16290
|
let sessionId;
|
|
16230
16291
|
if (webchatBind) {
|
|
@@ -16239,6 +16300,7 @@ function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID11, ad
|
|
|
16239
16300
|
if (pickedModel) payload.model = pickedModel;
|
|
16240
16301
|
if (pickedEffort) payload.effort = pickedEffort;
|
|
16241
16302
|
if (adminUserId) payload.adminUserId = adminUserId;
|
|
16303
|
+
if (targetAccountId) payload.targetAccountId = targetAccountId;
|
|
16242
16304
|
if (authenticatedName) payload.authenticatedName = authenticatedName;
|
|
16243
16305
|
} else {
|
|
16244
16306
|
sessionId = resumeId;
|
|
@@ -16549,14 +16611,14 @@ app34.get("/", async (c) => {
|
|
|
16549
16611
|
var system_stats_default = app34;
|
|
16550
16612
|
|
|
16551
16613
|
// server/routes/admin/health.ts
|
|
16552
|
-
import { existsSync as existsSync25, readFileSync as
|
|
16553
|
-
import { resolve as resolve26, join as
|
|
16614
|
+
import { existsSync as existsSync25, readFileSync as readFileSync27 } from "fs";
|
|
16615
|
+
import { resolve as resolve26, join as join26 } from "path";
|
|
16554
16616
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve26(process.cwd(), "..");
|
|
16555
16617
|
var brandHostname = "maxy";
|
|
16556
|
-
var brandJsonPath =
|
|
16618
|
+
var brandJsonPath = join26(PLATFORM_ROOT6, "config", "brand.json");
|
|
16557
16619
|
if (existsSync25(brandJsonPath)) {
|
|
16558
16620
|
try {
|
|
16559
|
-
const brand = JSON.parse(
|
|
16621
|
+
const brand = JSON.parse(readFileSync27(brandJsonPath, "utf-8"));
|
|
16560
16622
|
if (brand.hostname) brandHostname = brand.hostname;
|
|
16561
16623
|
} catch {
|
|
16562
16624
|
}
|
|
@@ -16566,7 +16628,7 @@ var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
|
|
|
16566
16628
|
var PROBE_TIMEOUT_MS = 1e3;
|
|
16567
16629
|
function readVersion() {
|
|
16568
16630
|
if (!existsSync25(VERSION_FILE)) return "unknown";
|
|
16569
|
-
return
|
|
16631
|
+
return readFileSync27(VERSION_FILE, "utf-8").trim() || "unknown";
|
|
16570
16632
|
}
|
|
16571
16633
|
async function probeConversationDb() {
|
|
16572
16634
|
let session;
|
|
@@ -17465,7 +17527,7 @@ app46.route("/request-magic-link", request_magic_link_default);
|
|
|
17465
17527
|
var access_default = app46;
|
|
17466
17528
|
|
|
17467
17529
|
// server/routes/sites.ts
|
|
17468
|
-
import { existsSync as existsSync26, readFileSync as
|
|
17530
|
+
import { existsSync as existsSync26, readFileSync as readFileSync28, realpathSync as realpathSync7, statSync as statSync11 } from "fs";
|
|
17469
17531
|
import { resolve as resolve28 } from "path";
|
|
17470
17532
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
17471
17533
|
var MIME = {
|
|
@@ -17569,7 +17631,7 @@ app47.get("/:rel{.*}", (c) => {
|
|
|
17569
17631
|
}
|
|
17570
17632
|
let body;
|
|
17571
17633
|
try {
|
|
17572
|
-
body =
|
|
17634
|
+
body = readFileSync28(realPath);
|
|
17573
17635
|
} catch (err) {
|
|
17574
17636
|
const code = err?.code;
|
|
17575
17637
|
if (code === "EISDIR") {
|
|
@@ -17605,7 +17667,7 @@ var sites_default = app47;
|
|
|
17605
17667
|
|
|
17606
17668
|
// app/lib/visitor-token.ts
|
|
17607
17669
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
17608
|
-
import { mkdirSync as mkdirSync6, readFileSync as
|
|
17670
|
+
import { mkdirSync as mkdirSync6, readFileSync as readFileSync29, writeFileSync as writeFileSync11 } from "fs";
|
|
17609
17671
|
import { dirname as dirname7 } from "path";
|
|
17610
17672
|
var TOKEN_PREFIX = "v1.";
|
|
17611
17673
|
var SECRET_BYTES = 32;
|
|
@@ -17614,7 +17676,7 @@ var cachedSecret = null;
|
|
|
17614
17676
|
function getSecret() {
|
|
17615
17677
|
if (cachedSecret) return cachedSecret;
|
|
17616
17678
|
try {
|
|
17617
|
-
const hex2 =
|
|
17679
|
+
const hex2 = readFileSync29(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
17618
17680
|
if (hex2.length === SECRET_BYTES * 2) {
|
|
17619
17681
|
cachedSecret = Buffer.from(hex2, "hex");
|
|
17620
17682
|
return cachedSecret;
|
|
@@ -17628,7 +17690,7 @@ function getSecret() {
|
|
|
17628
17690
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
17629
17691
|
} catch {
|
|
17630
17692
|
}
|
|
17631
|
-
const hex =
|
|
17693
|
+
const hex = readFileSync29(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
|
|
17632
17694
|
cachedSecret = Buffer.from(hex, "hex");
|
|
17633
17695
|
return cachedSecret;
|
|
17634
17696
|
}
|
|
@@ -17681,8 +17743,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
|
|
|
17681
17743
|
var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
17682
17744
|
|
|
17683
17745
|
// app/lib/brand-config.ts
|
|
17684
|
-
import { existsSync as existsSync27, readFileSync as
|
|
17685
|
-
import { join as
|
|
17746
|
+
import { existsSync as existsSync27, readFileSync as readFileSync30 } from "fs";
|
|
17747
|
+
import { join as join27 } from "path";
|
|
17686
17748
|
var cached2 = null;
|
|
17687
17749
|
var cachedAttempted = false;
|
|
17688
17750
|
function readBrandConfig() {
|
|
@@ -17690,10 +17752,10 @@ function readBrandConfig() {
|
|
|
17690
17752
|
cachedAttempted = true;
|
|
17691
17753
|
const platformRoot4 = process.env.MAXY_PLATFORM_ROOT;
|
|
17692
17754
|
if (!platformRoot4) return null;
|
|
17693
|
-
const brandPath =
|
|
17755
|
+
const brandPath = join27(platformRoot4, "config", "brand.json");
|
|
17694
17756
|
if (!existsSync27(brandPath)) return null;
|
|
17695
17757
|
try {
|
|
17696
|
-
cached2 = JSON.parse(
|
|
17758
|
+
cached2 = JSON.parse(readFileSync30(brandPath, "utf-8"));
|
|
17697
17759
|
return cached2;
|
|
17698
17760
|
} catch {
|
|
17699
17761
|
return null;
|
|
@@ -18494,7 +18556,7 @@ function startGraphHealthTimer() {
|
|
|
18494
18556
|
// app/lib/file-watcher.ts
|
|
18495
18557
|
import * as fsp2 from "fs/promises";
|
|
18496
18558
|
import { resolve as resolve30, sep as sep8 } from "path";
|
|
18497
|
-
var
|
|
18559
|
+
var ACCOUNT_UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
18498
18560
|
var DEFAULT_COALESCE_MS = 500;
|
|
18499
18561
|
var ROOTS = ["accounts"];
|
|
18500
18562
|
function _routeEvent(rootName, filename) {
|
|
@@ -18502,7 +18564,7 @@ function _routeEvent(rootName, filename) {
|
|
|
18502
18564
|
const segs = filename.split(sep8).filter(Boolean);
|
|
18503
18565
|
if (segs.length < 2) return null;
|
|
18504
18566
|
const accountId = segs[0];
|
|
18505
|
-
if (!
|
|
18567
|
+
if (!ACCOUNT_UUID_RE3.test(accountId)) return null;
|
|
18506
18568
|
return { accountId, relativePath: `${rootName}/${segs.join("/")}` };
|
|
18507
18569
|
}
|
|
18508
18570
|
async function startFileWatcher(opts = {}) {
|
|
@@ -18597,7 +18659,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
18597
18659
|
// app/lib/migrate-uploads.ts
|
|
18598
18660
|
import { mkdir as mkdir5, readdir as readdir5, rename as rename2, rm as rm3 } from "fs/promises";
|
|
18599
18661
|
import { dirname as dirname8, relative as relative5, resolve as resolve31 } from "path";
|
|
18600
|
-
var
|
|
18662
|
+
var ACCOUNT_UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
18601
18663
|
async function walkFiles(dir) {
|
|
18602
18664
|
const out = [];
|
|
18603
18665
|
let entries;
|
|
@@ -18673,7 +18735,7 @@ async function migrateUploads(opts = {}) {
|
|
|
18673
18735
|
try {
|
|
18674
18736
|
for (const entry of topEntries) {
|
|
18675
18737
|
const name = entry.name;
|
|
18676
|
-
if (
|
|
18738
|
+
if (ACCOUNT_UUID_RE4.test(name)) {
|
|
18677
18739
|
moved += await relocateTree(
|
|
18678
18740
|
resolve31(oldRoot, name),
|
|
18679
18741
|
resolve31(dataRoot, "accounts", name, "uploads"),
|
|
@@ -18720,7 +18782,7 @@ async function migrateUploads(opts = {}) {
|
|
|
18720
18782
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
18721
18783
|
import { readdir as readdir6, readFile as readFile7, rename as rename3, writeFile as writeFile4, unlink as unlink3 } from "fs/promises";
|
|
18722
18784
|
import { existsSync as existsSync29 } from "fs";
|
|
18723
|
-
import { join as
|
|
18785
|
+
import { join as join28 } from "path";
|
|
18724
18786
|
var ADMIN_ROLE2 = "admin";
|
|
18725
18787
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
18726
18788
|
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;
|
|
@@ -18765,7 +18827,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
18765
18827
|
}
|
|
18766
18828
|
for (const slug of slugs) {
|
|
18767
18829
|
if (!slug.isDirectory()) continue;
|
|
18768
|
-
const slugDir =
|
|
18830
|
+
const slugDir = join28(projectsRoot, slug.name);
|
|
18769
18831
|
let entries;
|
|
18770
18832
|
try {
|
|
18771
18833
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -18774,9 +18836,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
18774
18836
|
}
|
|
18775
18837
|
for (const entry of entries) {
|
|
18776
18838
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
18777
|
-
out.push(
|
|
18839
|
+
out.push(join28(slugDir, entry.name));
|
|
18778
18840
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
18779
|
-
const subDir =
|
|
18841
|
+
const subDir = join28(slugDir, entry.name);
|
|
18780
18842
|
let subs;
|
|
18781
18843
|
try {
|
|
18782
18844
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -18784,7 +18846,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
18784
18846
|
continue;
|
|
18785
18847
|
}
|
|
18786
18848
|
for (const s of subs) {
|
|
18787
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
18849
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join28(subDir, s.name));
|
|
18788
18850
|
}
|
|
18789
18851
|
}
|
|
18790
18852
|
}
|
|
@@ -18796,7 +18858,7 @@ function shortId(path2) {
|
|
|
18796
18858
|
return base.slice(0, 8);
|
|
18797
18859
|
}
|
|
18798
18860
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
18799
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
18861
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join28(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
18800
18862
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
18801
18863
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
18802
18864
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -19622,6 +19684,26 @@ function createWebchatChannelRoutes(deps) {
|
|
|
19622
19684
|
deps.onReceived?.(key, messageId);
|
|
19623
19685
|
return c.json({ ok: true });
|
|
19624
19686
|
});
|
|
19687
|
+
app53.post("/webchat-channel/turn-end", async (c) => {
|
|
19688
|
+
const body = await c.req.json().catch(() => null);
|
|
19689
|
+
const key = body?.key;
|
|
19690
|
+
const sessionId = body?.sessionId;
|
|
19691
|
+
const replied = body?.replied;
|
|
19692
|
+
if (typeof key !== "string" || typeof sessionId !== "string" || typeof replied !== "boolean") {
|
|
19693
|
+
return c.json({ error: "key, sessionId and replied required" }, 400);
|
|
19694
|
+
}
|
|
19695
|
+
const k = key.slice(0, 8);
|
|
19696
|
+
const sid = sessionId.slice(0, 8);
|
|
19697
|
+
if (replied) {
|
|
19698
|
+
return c.json({ ok: true, delivered: "reply" });
|
|
19699
|
+
}
|
|
19700
|
+
const finalBytes = typeof body?.finalBytes === "number" && Number.isFinite(body.finalBytes) ? body.finalBytes : 0;
|
|
19701
|
+
if (finalBytes <= 0) {
|
|
19702
|
+
return c.json({ ok: true, delivered: "none" });
|
|
19703
|
+
}
|
|
19704
|
+
console.error(`[webchat-native] op=turn-undelivered channel=webchat key=${k} sessionId=${sid} bytes=${finalBytes}`);
|
|
19705
|
+
return c.json({ ok: true, delivered: "undelivered" });
|
|
19706
|
+
});
|
|
19625
19707
|
return app53;
|
|
19626
19708
|
}
|
|
19627
19709
|
|
|
@@ -20114,7 +20196,7 @@ function broadcastAdminShutdown(reason) {
|
|
|
20114
20196
|
|
|
20115
20197
|
// ../lib/entitlement/src/index.ts
|
|
20116
20198
|
import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
|
|
20117
|
-
import { existsSync as existsSync30, readFileSync as
|
|
20199
|
+
import { existsSync as existsSync30, readFileSync as readFileSync31, statSync as statSync12 } from "fs";
|
|
20118
20200
|
import { resolve as resolve32 } from "path";
|
|
20119
20201
|
|
|
20120
20202
|
// ../lib/entitlement/src/canonicalize.ts
|
|
@@ -20178,7 +20260,7 @@ function resolveEntitlement(brand, account) {
|
|
|
20178
20260
|
function verifyAndResolve(brand, entitlementPath, account) {
|
|
20179
20261
|
let pubkeyPem;
|
|
20180
20262
|
try {
|
|
20181
|
-
pubkeyPem =
|
|
20263
|
+
pubkeyPem = readFileSync31(pubkeyPath(brand), "utf-8");
|
|
20182
20264
|
} catch (err) {
|
|
20183
20265
|
return logResolved(anonymousFallback("pubkey-missing"), {
|
|
20184
20266
|
reason: "pubkey-missing"
|
|
@@ -20192,7 +20274,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
|
|
|
20192
20274
|
}
|
|
20193
20275
|
let envelope;
|
|
20194
20276
|
try {
|
|
20195
|
-
envelope = JSON.parse(
|
|
20277
|
+
envelope = JSON.parse(readFileSync31(entitlementPath, "utf-8"));
|
|
20196
20278
|
} catch {
|
|
20197
20279
|
return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
|
|
20198
20280
|
}
|
|
@@ -20353,14 +20435,14 @@ function clientFrom(c) {
|
|
|
20353
20435
|
);
|
|
20354
20436
|
}
|
|
20355
20437
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
20356
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
20438
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join29(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
20357
20439
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
20358
20440
|
if (BRAND_JSON_PATH && !existsSync31(BRAND_JSON_PATH)) {
|
|
20359
20441
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
20360
20442
|
}
|
|
20361
20443
|
if (BRAND_JSON_PATH && existsSync31(BRAND_JSON_PATH)) {
|
|
20362
20444
|
try {
|
|
20363
|
-
const parsed = JSON.parse(
|
|
20445
|
+
const parsed = JSON.parse(readFileSync32(BRAND_JSON_PATH, "utf-8"));
|
|
20364
20446
|
BRAND = { ...BRAND, ...parsed };
|
|
20365
20447
|
} catch (err) {
|
|
20366
20448
|
console.error(`[brand] Failed to parse brand.json: ${err.message}`);
|
|
@@ -20379,11 +20461,11 @@ var brandLoginOpts = {
|
|
|
20379
20461
|
bodyFont: BRAND.defaultFonts?.body,
|
|
20380
20462
|
logoContainsName: !!BRAND.logoContainsName
|
|
20381
20463
|
};
|
|
20382
|
-
var ALIAS_DOMAINS_PATH =
|
|
20464
|
+
var ALIAS_DOMAINS_PATH = join29(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
20383
20465
|
function loadAliasDomains() {
|
|
20384
20466
|
try {
|
|
20385
20467
|
if (!existsSync31(ALIAS_DOMAINS_PATH)) return null;
|
|
20386
|
-
const parsed = JSON.parse(
|
|
20468
|
+
const parsed = JSON.parse(readFileSync32(ALIAS_DOMAINS_PATH, "utf-8"));
|
|
20387
20469
|
if (!Array.isArray(parsed)) {
|
|
20388
20470
|
console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
|
|
20389
20471
|
return null;
|
|
@@ -20411,7 +20493,7 @@ var app52 = new Hono();
|
|
|
20411
20493
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
20412
20494
|
var waGateway = new WaGateway({
|
|
20413
20495
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
20414
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve33(process.env.MAXY_PLATFORM_ROOT ??
|
|
20496
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve33(process.env.MAXY_PLATFORM_ROOT ?? join29(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
20415
20497
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
20416
20498
|
// account + path validation here and funnel through the shared send core.
|
|
20417
20499
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -20427,7 +20509,7 @@ var waGateway = new WaGateway({
|
|
|
20427
20509
|
caption,
|
|
20428
20510
|
accountId,
|
|
20429
20511
|
maxyAccountId,
|
|
20430
|
-
platformRoot: resolve33(process.env.MAXY_PLATFORM_ROOT ??
|
|
20512
|
+
platformRoot: resolve33(process.env.MAXY_PLATFORM_ROOT ?? join29(__dirname, ".."))
|
|
20431
20513
|
});
|
|
20432
20514
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
20433
20515
|
},
|
|
@@ -20902,7 +20984,7 @@ app52.get("/agent-assets/:slug/:filename", (c) => {
|
|
|
20902
20984
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
20903
20985
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
20904
20986
|
console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
|
|
20905
|
-
const body =
|
|
20987
|
+
const body = readFileSync32(filePath);
|
|
20906
20988
|
return c.body(body, 200, {
|
|
20907
20989
|
"Content-Type": contentType,
|
|
20908
20990
|
"Cache-Control": "public, max-age=3600"
|
|
@@ -20932,7 +21014,7 @@ app52.get("/generated/:filename", (c) => {
|
|
|
20932
21014
|
const ext = "." + filename.split(".").pop()?.toLowerCase();
|
|
20933
21015
|
const contentType = IMAGE_MIME[ext] || "application/octet-stream";
|
|
20934
21016
|
console.log(`[generated] serve file=${filename} status=200`);
|
|
20935
|
-
const body =
|
|
21017
|
+
const body = readFileSync32(filePath);
|
|
20936
21018
|
return c.body(body, 200, {
|
|
20937
21019
|
"Content-Type": contentType,
|
|
20938
21020
|
"Cache-Control": "public, max-age=86400"
|
|
@@ -20947,19 +21029,29 @@ var brandLogoPath = "/brand/maxy-monochrome.png";
|
|
|
20947
21029
|
var brandIconPath = "/brand/maxy-monochrome.png";
|
|
20948
21030
|
if (BRAND_JSON_PATH && existsSync31(BRAND_JSON_PATH)) {
|
|
20949
21031
|
try {
|
|
20950
|
-
const fullBrand = JSON.parse(
|
|
21032
|
+
const fullBrand = JSON.parse(readFileSync32(BRAND_JSON_PATH, "utf-8"));
|
|
20951
21033
|
if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
|
|
20952
21034
|
brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
|
|
20953
21035
|
} catch {
|
|
20954
21036
|
}
|
|
20955
21037
|
}
|
|
21038
|
+
var DEFAULT_PRIMARY_CONTAINER = { label: "Project", term: "Projects" };
|
|
21039
|
+
var rawPrimaryContainer = BRAND.primaryContainer;
|
|
21040
|
+
var primaryContainerValid = !!rawPrimaryContainer && typeof rawPrimaryContainer.label === "string" && typeof rawPrimaryContainer.term === "string";
|
|
21041
|
+
var brandPrimaryContainer = primaryContainerValid ? rawPrimaryContainer : DEFAULT_PRIMARY_CONTAINER;
|
|
21042
|
+
if (primaryContainerValid) {
|
|
21043
|
+
console.log(`[brand] op=inject primaryContainer=${brandPrimaryContainer.label}/${brandPrimaryContainer.term}`);
|
|
21044
|
+
} else {
|
|
21045
|
+
console.log(`[brand] op=primaryContainer-default reason=${rawPrimaryContainer ? "malformed" : "absent"} brand=${BRAND.hostname}`);
|
|
21046
|
+
}
|
|
20956
21047
|
var brandScript = `<script>window.__BRAND__=${JSON.stringify({
|
|
20957
21048
|
productName: BRAND.productName,
|
|
20958
21049
|
hostname: BRAND.hostname,
|
|
20959
21050
|
marketingUrl: BRAND.marketingUrl,
|
|
20960
21051
|
logo: brandLogoPath,
|
|
20961
21052
|
icon: brandIconPath,
|
|
20962
|
-
logoContainsName: !!BRAND.logoContainsName
|
|
21053
|
+
logoContainsName: !!BRAND.logoContainsName,
|
|
21054
|
+
primaryContainer: brandPrimaryContainer
|
|
20963
21055
|
})}</script>`;
|
|
20964
21056
|
var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
|
|
20965
21057
|
var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
|
|
@@ -20967,7 +21059,7 @@ var brandIconFsPath = resolve33(process.cwd(), "public", brandIconPath.replace(/
|
|
|
20967
21059
|
var brandIconExists = existsSync31(brandIconFsPath);
|
|
20968
21060
|
var SW_SOURCE = (() => {
|
|
20969
21061
|
try {
|
|
20970
|
-
return
|
|
21062
|
+
return readFileSync32(resolve33(process.cwd(), "public", "sw.js"), "utf-8");
|
|
20971
21063
|
} catch {
|
|
20972
21064
|
return null;
|
|
20973
21065
|
}
|
|
@@ -20975,9 +21067,9 @@ var SW_SOURCE = (() => {
|
|
|
20975
21067
|
function readInstalledVersion() {
|
|
20976
21068
|
try {
|
|
20977
21069
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
20978
|
-
const versionFile =
|
|
21070
|
+
const versionFile = join29(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
20979
21071
|
if (!existsSync31(versionFile)) return "unknown";
|
|
20980
|
-
const content =
|
|
21072
|
+
const content = readFileSync32(versionFile, "utf-8").trim();
|
|
20981
21073
|
return content || "unknown";
|
|
20982
21074
|
} catch {
|
|
20983
21075
|
return "unknown";
|
|
@@ -21018,7 +21110,7 @@ var clientErrorReporterScript = `<script>
|
|
|
21018
21110
|
function cachedHtml(file) {
|
|
21019
21111
|
let html = htmlCache.get(file);
|
|
21020
21112
|
if (!html) {
|
|
21021
|
-
html =
|
|
21113
|
+
html = readFileSync32(resolve33(process.cwd(), "public", file), "utf-8");
|
|
21022
21114
|
const productNameEsc = escapeHtml(BRAND.productName);
|
|
21023
21115
|
html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
|
|
21024
21116
|
html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
|
|
@@ -21035,13 +21127,13 @@ ${clientErrorReporterScript}
|
|
|
21035
21127
|
return html;
|
|
21036
21128
|
}
|
|
21037
21129
|
function loadBrandingCache(agentSlug) {
|
|
21038
|
-
const configDir2 =
|
|
21130
|
+
const configDir2 = join29(homedir3(), BRAND.configDir);
|
|
21039
21131
|
try {
|
|
21040
21132
|
const accountId = getDefaultAccountId();
|
|
21041
21133
|
if (!accountId) return null;
|
|
21042
|
-
const cachePath =
|
|
21134
|
+
const cachePath = join29(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
21043
21135
|
if (!existsSync31(cachePath)) return null;
|
|
21044
|
-
return JSON.parse(
|
|
21136
|
+
return JSON.parse(readFileSync32(cachePath, "utf-8"));
|
|
21045
21137
|
} catch {
|
|
21046
21138
|
return null;
|
|
21047
21139
|
}
|
|
@@ -21136,7 +21228,7 @@ app52.use("/vnc-popout.html", logViewerFetch);
|
|
|
21136
21228
|
app52.get("/vnc-popout.html", (c) => {
|
|
21137
21229
|
let html = htmlCache.get("vnc-popout.html");
|
|
21138
21230
|
if (!html) {
|
|
21139
|
-
html =
|
|
21231
|
+
html = readFileSync32(resolve33(process.cwd(), "public", "vnc-popout.html"), "utf-8");
|
|
21140
21232
|
const name = escapeHtml(BRAND.productName);
|
|
21141
21233
|
html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
|
|
21142
21234
|
html = html.replace("</head>", ` ${brandScript}
|
|
@@ -21347,7 +21439,7 @@ async function runAdminUserReconcileTick() {
|
|
|
21347
21439
|
console.error("[adminuser-self-heal] skip reason=no-users-file");
|
|
21348
21440
|
return;
|
|
21349
21441
|
}
|
|
21350
|
-
const usersRaw =
|
|
21442
|
+
const usersRaw = readFileSync32(USERS_FILE, "utf-8").trim();
|
|
21351
21443
|
if (!usersRaw) {
|
|
21352
21444
|
console.error("[adminuser-self-heal] skip reason=empty-users-file");
|
|
21353
21445
|
return;
|
|
@@ -21461,7 +21553,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
21461
21553
|
}
|
|
21462
21554
|
init({
|
|
21463
21555
|
configDir: configDirForWhatsApp,
|
|
21464
|
-
platformRoot: resolve33(process.env.MAXY_PLATFORM_ROOT ??
|
|
21556
|
+
platformRoot: resolve33(process.env.MAXY_PLATFORM_ROOT ?? join29(__dirname, "..")),
|
|
21465
21557
|
accountConfig: bootAccountConfig,
|
|
21466
21558
|
onMessage: async (msg) => {
|
|
21467
21559
|
if (msg.isOwnerMirror) {
|