@rubytech/create-maxy-code 0.1.370 → 0.1.372
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +4 -2
- package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
- package/payload/platform/plugins/docs/references/platform.md +2 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js +2 -1
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.d.ts.map +1 -1
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js +1 -0
- package/payload/platform/plugins/scheduling/mcp/dist/tools/schedule-event.js.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.d.ts.map +1 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js +2 -1
- package/payload/platform/plugins/workflows/mcp/dist/tools/workflow-create.js.map +1 -1
- package/payload/platform/scripts/check-no-esm-require.mjs +5 -0
- package/payload/platform/services/claude-session-manager/dist/index.js +38 -5
- package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js +5 -1
- package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js.map +1 -1
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-recover.d.ts +19 -0
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-recover.d.ts.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-recover.js +28 -0
- package/payload/platform/services/claude-session-manager/dist/stuck-turn-recover.js.map +1 -0
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.d.ts +5 -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 +33 -6
- package/payload/platform/services/claude-session-manager/dist/stuck-turn.js.map +1 -1
- package/payload/server/{chunk-CXEC5RWB.js → chunk-OBZE2KCK.js} +42 -0
- package/payload/server/maxy-edge.js +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-B45MFjWG.js → AdminLoginScreens-Cv3mxJVn.js} +1 -1
- package/payload/server/public/assets/AdminShell-CR0AdnAx.js +1 -0
- package/payload/server/public/assets/{Checkbox-BPYEJJPq.js → Checkbox-DlXtucB_.js} +1 -1
- package/payload/server/public/assets/OperatorConversations-ka_b3K3l.css +1 -0
- package/payload/server/public/assets/OperatorConversations-tDWA0PWN.js +9 -0
- package/payload/server/public/assets/{admin-DcuJ3_xm.js → admin-VOx7YvPT.js} +1 -1
- package/payload/server/public/assets/{browser-Be9LRtM2.js → browser-DUrqC4lq.js} +1 -1
- package/payload/server/public/assets/calendar-1QEs24eI.js +1 -0
- package/payload/server/public/assets/chat-BYua7UiL.js +1 -0
- package/payload/server/public/assets/data-Dx1lRmMH.js +1 -0
- package/payload/server/public/assets/{graph-XYK2qT5D.js → graph-CJURDOED.js} +3 -3
- package/payload/server/public/assets/{graph-labels-DNCXtQVn.js → graph-labels-C-tGPoLE.js} +1 -1
- package/payload/server/public/assets/operator-B3_Odno9.js +1 -0
- package/payload/server/public/assets/page-Caf6BQNK.js +32 -0
- package/payload/server/public/assets/public-DGWDk4tx.js +1 -0
- package/payload/server/public/assets/{rotate-ccw-BxD1B_G-.js → rotate-ccw-DeTygixt.js} +1 -1
- package/payload/server/public/browser.html +4 -4
- package/payload/server/public/calendar.html +4 -4
- package/payload/server/public/chat.html +6 -6
- package/payload/server/public/data.html +4 -4
- package/payload/server/public/graph.html +7 -7
- package/payload/server/public/index.html +6 -6
- package/payload/server/public/operator.html +8 -8
- package/payload/server/public/public.html +6 -6
- package/payload/server/server.js +285 -195
- package/payload/server/public/assets/AdminShell-CyZPfbzd.js +0 -1
- package/payload/server/public/assets/OperatorConversations-Civ7TETM.css +0 -1
- package/payload/server/public/assets/OperatorConversations-D_o_59Oc.js +0 -9
- package/payload/server/public/assets/calendar-BeofvK7c.js +0 -1
- package/payload/server/public/assets/chat-nth30R3E.js +0 -1
- package/payload/server/public/assets/data-lTmU53k6.js +0 -1
- package/payload/server/public/assets/operator-As5Tw1vj.js +0 -1
- package/payload/server/public/assets/page-CII4OBX3.js +0 -32
- package/payload/server/public/assets/public-BxZBMrEL.js +0 -1
package/payload/server/server.js
CHANGED
|
@@ -34,6 +34,7 @@ import {
|
|
|
34
34
|
cleanupLeakedPremiumSubs,
|
|
35
35
|
clearRateLimit,
|
|
36
36
|
clientIpMiddleware,
|
|
37
|
+
createNewAdminConversation,
|
|
37
38
|
createRemoteSession,
|
|
38
39
|
deleteAgentProjection,
|
|
39
40
|
deleteConversation,
|
|
@@ -107,7 +108,7 @@ import {
|
|
|
107
108
|
vncLog,
|
|
108
109
|
walkPremiumBundles,
|
|
109
110
|
writeAdminUserAndPerson
|
|
110
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-OBZE2KCK.js";
|
|
111
112
|
import {
|
|
112
113
|
__commonJS,
|
|
113
114
|
__toESM
|
|
@@ -1305,7 +1306,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1305
1306
|
// server/index.ts
|
|
1306
1307
|
import { readFileSync as readFileSync33, existsSync as existsSync32, watchFile } from "fs";
|
|
1307
1308
|
import { spawn as spawn3 } from "child_process";
|
|
1308
|
-
import { resolve as resolve32, join as
|
|
1309
|
+
import { resolve as resolve32, join as join33, basename as basename12 } from "path";
|
|
1309
1310
|
import { homedir as homedir3 } from "os";
|
|
1310
1311
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1311
1312
|
|
|
@@ -3735,6 +3736,14 @@ var TAG12 = "[stt]";
|
|
|
3735
3736
|
var WHISPER_BINARY = process.env.WHISPER_BINARY ?? "/opt/whisper.cpp/build/bin/whisper-cli";
|
|
3736
3737
|
var WHISPER_MODEL = process.env.WHISPER_MODEL ?? "/opt/whisper.cpp/models/ggml-base.bin";
|
|
3737
3738
|
var WHISPER_TIMEOUT_MS = 20 * 60 * 1e3;
|
|
3739
|
+
var SPECIAL_TOKEN_RE = /\[_[A-Z]+(?:_\d+)?_?\]/g;
|
|
3740
|
+
function stripSpecialTokens(input) {
|
|
3741
|
+
const matches = input.match(SPECIAL_TOKEN_RE);
|
|
3742
|
+
const count = matches ? matches.length : 0;
|
|
3743
|
+
if (!count) return { text: input, count: 0 };
|
|
3744
|
+
const text = input.replace(SPECIAL_TOKEN_RE, "").replace(/[ \t]{2,}/g, " ").trim();
|
|
3745
|
+
return { text, count };
|
|
3746
|
+
}
|
|
3738
3747
|
async function transcribe(audioPath, mimetype) {
|
|
3739
3748
|
const startMs = Date.now();
|
|
3740
3749
|
let audioBytes = 0;
|
|
@@ -3776,12 +3785,10 @@ async function transcribe(audioPath, mimetype) {
|
|
|
3776
3785
|
wavPath,
|
|
3777
3786
|
"--no-timestamps",
|
|
3778
3787
|
"-l",
|
|
3779
|
-
"auto"
|
|
3780
|
-
"--print-special",
|
|
3781
|
-
"false"
|
|
3788
|
+
"auto"
|
|
3782
3789
|
], { timeout: WHISPER_TIMEOUT_MS, maxBuffer: 10 * 1024 * 1024 });
|
|
3783
|
-
const text = stdout.trim();
|
|
3784
3790
|
const durationMs = Date.now() - startMs;
|
|
3791
|
+
const { text, count: stripped } = stripSpecialTokens(stdout.trim());
|
|
3785
3792
|
if (!text) {
|
|
3786
3793
|
console.error(`${TAG12} failed: whisper returned empty output duration_ms=${durationMs}`);
|
|
3787
3794
|
return void 0;
|
|
@@ -3790,7 +3797,7 @@ async function transcribe(audioPath, mimetype) {
|
|
|
3790
3797
|
const language = langMatch?.[1] ?? "unknown";
|
|
3791
3798
|
const words = text.split(/\s+/).filter(Boolean).length;
|
|
3792
3799
|
console.error(
|
|
3793
|
-
`${TAG12} done provider=whisper-local duration_ms=${durationMs} words=${words} lang=${language}`
|
|
3800
|
+
`${TAG12} done provider=whisper-local duration_ms=${durationMs} words=${words} stripped=${stripped} lang=${language}`
|
|
3794
3801
|
);
|
|
3795
3802
|
return { text, language, durationMs };
|
|
3796
3803
|
} catch (err) {
|
|
@@ -4980,7 +4987,7 @@ import { resolve as resolve6, extname } from "path";
|
|
|
4980
4987
|
|
|
4981
4988
|
// app/lib/data-path.ts
|
|
4982
4989
|
import { realpathSync } from "fs";
|
|
4983
|
-
import { resolve as resolve5, normalize, sep as sep2, relative } from "path";
|
|
4990
|
+
import { resolve as resolve5, normalize, sep as sep2, relative, basename, join as join5 } from "path";
|
|
4984
4991
|
var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve5(process.cwd(), "../platform");
|
|
4985
4992
|
var DATA_ROOT = resolve5(PLATFORM_ROOT4, "..", "data");
|
|
4986
4993
|
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve5(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
|
|
@@ -5043,6 +5050,16 @@ function resolveClaudeUploadsPath(raw) {
|
|
|
5043
5050
|
}
|
|
5044
5051
|
return resolveUnderRoot(raw, CLAUDE_UPLOADS_ROOT, "CLAUDE_UPLOADS_ROOT");
|
|
5045
5052
|
}
|
|
5053
|
+
function scratchpadTmpBase() {
|
|
5054
|
+
return process.env.MAXY_SCRATCHPAD_BASE ?? "/tmp";
|
|
5055
|
+
}
|
|
5056
|
+
function sessionScratchpadRoot(projectDir, sessionId) {
|
|
5057
|
+
const uid = typeof process.geteuid === "function" ? process.geteuid() : 0;
|
|
5058
|
+
return join5(scratchpadTmpBase(), `claude-${uid}`, basename(projectDir), sessionId, "scratchpad");
|
|
5059
|
+
}
|
|
5060
|
+
function resolveScratchpadPath(raw, scratchpadRootAbs) {
|
|
5061
|
+
return resolveUnderRoot(raw, scratchpadRootAbs, "scratchpad");
|
|
5062
|
+
}
|
|
5046
5063
|
|
|
5047
5064
|
// app/lib/attachments.ts
|
|
5048
5065
|
function uploadsDirFor(accountId, subPath, attachmentId) {
|
|
@@ -5185,7 +5202,7 @@ async function storeComponentArtefact(accountId, attachmentId, mimeType, content
|
|
|
5185
5202
|
// app/lib/stt/voice-note.ts
|
|
5186
5203
|
import { writeFile as writeFile3, mkdtemp, rm } from "fs/promises";
|
|
5187
5204
|
import { tmpdir } from "os";
|
|
5188
|
-
import { join as
|
|
5205
|
+
import { join as join6 } from "path";
|
|
5189
5206
|
|
|
5190
5207
|
// app/lib/stt/audio-mime.ts
|
|
5191
5208
|
var AUDIO_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -5239,9 +5256,9 @@ async function transcribeVoiceNote(file, source) {
|
|
|
5239
5256
|
let tempDir;
|
|
5240
5257
|
let tempPath;
|
|
5241
5258
|
try {
|
|
5242
|
-
tempDir = await mkdtemp(
|
|
5259
|
+
tempDir = await mkdtemp(join6(tmpdir(), "voice-"));
|
|
5243
5260
|
const ext = audioExtension(mimeType);
|
|
5244
|
-
tempPath =
|
|
5261
|
+
tempPath = join6(tempDir, `recording${ext}`);
|
|
5245
5262
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
5246
5263
|
await writeFile3(tempPath, buffer);
|
|
5247
5264
|
} catch (err) {
|
|
@@ -5639,7 +5656,7 @@ ${result.result.text}` : result.result.text;
|
|
|
5639
5656
|
}
|
|
5640
5657
|
|
|
5641
5658
|
// server/routes/whatsapp.ts
|
|
5642
|
-
import { join as
|
|
5659
|
+
import { join as join9, resolve as resolve9 } from "path";
|
|
5643
5660
|
import { readdirSync as readdirSync3, readFileSync as readFileSync9, existsSync as existsSync5 } from "fs";
|
|
5644
5661
|
|
|
5645
5662
|
// app/lib/whatsapp/login.ts
|
|
@@ -5647,7 +5664,7 @@ import { randomUUID as randomUUID6 } from "crypto";
|
|
|
5647
5664
|
|
|
5648
5665
|
// app/lib/whatsapp/config-persist.ts
|
|
5649
5666
|
import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, existsSync as existsSync4 } from "fs";
|
|
5650
|
-
import { resolve as resolve7, join as
|
|
5667
|
+
import { resolve as resolve7, join as join7 } from "path";
|
|
5651
5668
|
var TAG16 = "[whatsapp:config]";
|
|
5652
5669
|
function configPath(accountDir) {
|
|
5653
5670
|
return resolve7(accountDir, "account.json");
|
|
@@ -5799,7 +5816,7 @@ function setPublicAgent(accountDir, slug) {
|
|
|
5799
5816
|
if (!trimmed) {
|
|
5800
5817
|
return { ok: false, error: "Agent slug cannot be empty." };
|
|
5801
5818
|
}
|
|
5802
|
-
const agentConfigPath =
|
|
5819
|
+
const agentConfigPath = join7(accountDir, "agents", trimmed, "config.json");
|
|
5803
5820
|
if (!existsSync4(agentConfigPath)) {
|
|
5804
5821
|
return { ok: false, error: `Agent "${trimmed}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.` };
|
|
5805
5822
|
}
|
|
@@ -6183,7 +6200,7 @@ async function waitForLogin(opts) {
|
|
|
6183
6200
|
// app/lib/whatsapp/outbound/send-document.ts
|
|
6184
6201
|
import { realpathSync as realpathSync3 } from "fs";
|
|
6185
6202
|
import { readFile, stat as stat2 } from "fs/promises";
|
|
6186
|
-
import { resolve as resolve8, basename } from "path";
|
|
6203
|
+
import { resolve as resolve8, basename as basename2 } from "path";
|
|
6187
6204
|
var TAG18 = "[whatsapp:outbound]";
|
|
6188
6205
|
var WHATSAPP_DOCUMENT_MAX_BYTES = 100 * 1024 * 1024;
|
|
6189
6206
|
var lastDocumentOutboundAt = /* @__PURE__ */ new Map();
|
|
@@ -6238,7 +6255,7 @@ async function sendWhatsAppDocument(input) {
|
|
|
6238
6255
|
error: `File exceeds 100 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB)`
|
|
6239
6256
|
};
|
|
6240
6257
|
}
|
|
6241
|
-
const filename =
|
|
6258
|
+
const filename = basename2(resolvedPath);
|
|
6242
6259
|
const jid = normalizeJid2(to);
|
|
6243
6260
|
const sock = getSocket(accountId);
|
|
6244
6261
|
if (!sock) {
|
|
@@ -6373,11 +6390,11 @@ function serializeWhatsAppSchema() {
|
|
|
6373
6390
|
|
|
6374
6391
|
// app/lib/whatsapp/status-reconcile.ts
|
|
6375
6392
|
import { readdirSync as readdirSync2 } from "fs";
|
|
6376
|
-
import { join as
|
|
6393
|
+
import { join as join8 } from "path";
|
|
6377
6394
|
var TAG19 = "[whatsapp:reconcile]";
|
|
6378
6395
|
function listCredsAccountIds(credsRoot) {
|
|
6379
6396
|
try {
|
|
6380
|
-
return readdirSync2(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(
|
|
6397
|
+
return readdirSync2(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(join8(credsRoot, e.name))).map((e) => e.name);
|
|
6381
6398
|
} catch {
|
|
6382
6399
|
return [];
|
|
6383
6400
|
}
|
|
@@ -6392,7 +6409,7 @@ function reconcileCredsOnDisk(opts) {
|
|
|
6392
6409
|
const entries = [];
|
|
6393
6410
|
for (const accountId of listCredsAccountIds(credsRoot)) {
|
|
6394
6411
|
if (liveAccountIds.has(accountId)) continue;
|
|
6395
|
-
const authDir =
|
|
6412
|
+
const authDir = join8(credsRoot, accountId);
|
|
6396
6413
|
const selfPhone = readSelfId(authDir).e164 ?? void 0;
|
|
6397
6414
|
const configured = accountDir ? isAccountConfigured(accountDir, accountId) : false;
|
|
6398
6415
|
console.error(
|
|
@@ -6419,7 +6436,7 @@ app2.get("/status", (c) => {
|
|
|
6419
6436
|
try {
|
|
6420
6437
|
const live = getStatus();
|
|
6421
6438
|
const liveIds = new Set(live.map((a) => a.accountId));
|
|
6422
|
-
const credsRoot =
|
|
6439
|
+
const credsRoot = join9(MAXY_DIR, "credentials", "whatsapp");
|
|
6423
6440
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
6424
6441
|
const reconciled = reconcileCredsOnDisk({ credsRoot, accountDir, liveAccountIds: liveIds });
|
|
6425
6442
|
const accounts = [...live, ...reconciled];
|
|
@@ -6440,7 +6457,7 @@ app2.post("/login/start", async (c) => {
|
|
|
6440
6457
|
if (!phone) {
|
|
6441
6458
|
return c.json({ error: 'Missing required field "phone" (E.164, e.g. +441234567890).' }, 400);
|
|
6442
6459
|
}
|
|
6443
|
-
const authDir =
|
|
6460
|
+
const authDir = join9(MAXY_DIR, "credentials", "whatsapp", accountId);
|
|
6444
6461
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
6445
6462
|
const result = await startLogin({ accountId, authDir, phone, accountDir, force });
|
|
6446
6463
|
console.error(`${TAG20} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
|
|
@@ -6854,12 +6871,12 @@ app2.get("/group-info", async (c) => {
|
|
|
6854
6871
|
var whatsapp_default = app2;
|
|
6855
6872
|
|
|
6856
6873
|
// server/routes/whatsapp-reader.ts
|
|
6857
|
-
import { readFileSync as readFileSync13, watch, statSync as statSync4, openSync, readSync, closeSync, existsSync as existsSync7, readdirSync as readdirSync7 } from "fs";
|
|
6858
|
-
import { basename as
|
|
6874
|
+
import { readFileSync as readFileSync13, watch, statSync as statSync4, openSync, readSync, closeSync, existsSync as existsSync7, readdirSync as readdirSync7, realpathSync as realpathSync4 } from "fs";
|
|
6875
|
+
import { basename as basename4, dirname as dirname2, isAbsolute, join as join13, relative as relative2, resolve as resolve11, sep as sep3 } from "path";
|
|
6859
6876
|
|
|
6860
6877
|
// server/routes/admin/sidebar-sessions.ts
|
|
6861
6878
|
import { readdirSync as readdirSync4, readFileSync as readFileSync10, statSync as statSync2 } from "fs";
|
|
6862
|
-
import { join as
|
|
6879
|
+
import { basename as basename3, dirname, join as join10, resolve as resolve10 } from "path";
|
|
6863
6880
|
|
|
6864
6881
|
// app/lib/whatsapp-reader/select-sessions.ts
|
|
6865
6882
|
function isReaderChannelSession(role, channel) {
|
|
@@ -6908,6 +6925,14 @@ var app3 = new Hono();
|
|
|
6908
6925
|
function claudeConfigDir() {
|
|
6909
6926
|
return process.env.CLAUDE_CONFIG_DIR ?? null;
|
|
6910
6927
|
}
|
|
6928
|
+
function findSessionProjectDir(sessionId) {
|
|
6929
|
+
const cfg = claudeConfigDir();
|
|
6930
|
+
if (!cfg) return null;
|
|
6931
|
+
for (const { path: path2 } of enumerateJsonls(join10(cfg, "projects"))) {
|
|
6932
|
+
if (basename3(path2) === `${sessionId}.jsonl`) return dirname(path2);
|
|
6933
|
+
}
|
|
6934
|
+
return null;
|
|
6935
|
+
}
|
|
6911
6936
|
function enumerateJsonls(projectsRoot) {
|
|
6912
6937
|
const out = [];
|
|
6913
6938
|
let slugs;
|
|
@@ -6918,7 +6943,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6918
6943
|
throw err;
|
|
6919
6944
|
}
|
|
6920
6945
|
for (const slug of slugs) {
|
|
6921
|
-
const slugDir =
|
|
6946
|
+
const slugDir = join10(projectsRoot, slug);
|
|
6922
6947
|
let entries;
|
|
6923
6948
|
try {
|
|
6924
6949
|
entries = readdirSync4(slugDir, { withFileTypes: true });
|
|
@@ -6929,9 +6954,9 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6929
6954
|
}
|
|
6930
6955
|
for (const entry of entries) {
|
|
6931
6956
|
if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
|
|
6932
|
-
out.push({ path:
|
|
6957
|
+
out.push({ path: join10(slugDir, entry.name), isSubagent: false, archived: false });
|
|
6933
6958
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
6934
|
-
const subDir =
|
|
6959
|
+
const subDir = join10(slugDir, entry.name);
|
|
6935
6960
|
let subEntries;
|
|
6936
6961
|
try {
|
|
6937
6962
|
subEntries = readdirSync4(subDir, { withFileTypes: true });
|
|
@@ -6942,11 +6967,11 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6942
6967
|
}
|
|
6943
6968
|
for (const sub of subEntries) {
|
|
6944
6969
|
if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
|
|
6945
|
-
out.push({ path:
|
|
6970
|
+
out.push({ path: join10(subDir, sub.name), isSubagent: true, archived: false });
|
|
6946
6971
|
}
|
|
6947
6972
|
}
|
|
6948
6973
|
} else if (entry.isDirectory() && entry.name === "archive") {
|
|
6949
|
-
const archiveDir =
|
|
6974
|
+
const archiveDir = join10(slugDir, entry.name);
|
|
6950
6975
|
let archiveEntries;
|
|
6951
6976
|
try {
|
|
6952
6977
|
archiveEntries = readdirSync4(archiveDir, { withFileTypes: true });
|
|
@@ -6957,7 +6982,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6957
6982
|
}
|
|
6958
6983
|
for (const arc of archiveEntries) {
|
|
6959
6984
|
if (arc.isFile() && SESSION_ID_RE.test(arc.name)) {
|
|
6960
|
-
out.push({ path:
|
|
6985
|
+
out.push({ path: join10(archiveDir, arc.name), isSubagent: false, archived: true });
|
|
6961
6986
|
}
|
|
6962
6987
|
}
|
|
6963
6988
|
}
|
|
@@ -6990,7 +7015,7 @@ async function fetchLiveSessions() {
|
|
|
6990
7015
|
function loadUserTitles(accountDir) {
|
|
6991
7016
|
const out = /* @__PURE__ */ new Map();
|
|
6992
7017
|
if (!accountDir) return out;
|
|
6993
|
-
const path2 =
|
|
7018
|
+
const path2 = join10(accountDir, "session-titles.json");
|
|
6994
7019
|
let raw;
|
|
6995
7020
|
try {
|
|
6996
7021
|
raw = readFileSync10(path2, "utf8");
|
|
@@ -7130,7 +7155,7 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
7130
7155
|
console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
|
|
7131
7156
|
return c.json({ sessions: [], accountId, accounts });
|
|
7132
7157
|
}
|
|
7133
|
-
const projectsRoot =
|
|
7158
|
+
const projectsRoot = join10(configDir2, "projects");
|
|
7134
7159
|
const jsonls = enumerateJsonls(projectsRoot);
|
|
7135
7160
|
const liveSessions = await fetchLiveSessions();
|
|
7136
7161
|
const accountDir = accountId ? resolve10(ACCOUNTS_DIR, accountId) : null;
|
|
@@ -7166,7 +7191,7 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
7166
7191
|
const pid = live ? liveSessions.get(sessionId) ?? null : null;
|
|
7167
7192
|
const resolved = resolveTitle(body, sessionId, userTitles);
|
|
7168
7193
|
titleSourceCounts[resolved.source] += 1;
|
|
7169
|
-
const metaPath =
|
|
7194
|
+
const metaPath = join10(projectDir, `${sessionId}.meta.json`);
|
|
7170
7195
|
const { bridgeIds, role, channel: sidecarChannel, personId, adminUserId, accountId: rowAccountId } = readSidecarMeta(metaPath);
|
|
7171
7196
|
if (isReaderChannelSession(role, sidecarChannel)) {
|
|
7172
7197
|
excludedChannelCount += 1;
|
|
@@ -7233,7 +7258,7 @@ var sidebar_sessions_default = app3;
|
|
|
7233
7258
|
// app/lib/admin-identity/pin-validator.ts
|
|
7234
7259
|
import { createHash } from "crypto";
|
|
7235
7260
|
import { existsSync as existsSync6, readFileSync as readFileSync11, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
|
|
7236
|
-
import { join as
|
|
7261
|
+
import { join as join11 } from "path";
|
|
7237
7262
|
function hashPin(pin) {
|
|
7238
7263
|
return createHash("sha256").update(pin).digest("hex");
|
|
7239
7264
|
}
|
|
@@ -7315,6 +7340,11 @@ var CHANNEL_REPLY_DOCUMENT_TOOL = "mcp__channel__reply-document";
|
|
|
7315
7340
|
var SEND_USER_FILE_TOOL = "SendUserFile";
|
|
7316
7341
|
var CLI_MARKER_PREFIXES2 = ["<local-command-", "<command-name>", "<command-message>"];
|
|
7317
7342
|
var HARNESS_LIFECYCLE_PREFIXES = ["<task-notification>"];
|
|
7343
|
+
var CC_IMAGE_VISION_HINT = /^\[Image:[^\]]*Multiply coordinates by [\d.]+ to map to original image\.\]$/;
|
|
7344
|
+
var COMPACT_SUMMARY_PREFIX = "This session is being continued from a previous conversation that ran out of context.";
|
|
7345
|
+
function isCompactSummaryRow(row, content) {
|
|
7346
|
+
return row.isCompactSummary === true || content !== null && content.startsWith(COMPACT_SUMMARY_PREFIX);
|
|
7347
|
+
}
|
|
7318
7348
|
var CHANNEL_WRAPPER2 = /^<channel\b([^>]*)>\n?([\s\S]*?)\n?<\/channel>$/;
|
|
7319
7349
|
var SOURCE_ATTR2 = /\bsource="([^"]+)"/;
|
|
7320
7350
|
var SOURCE_MAP = {
|
|
@@ -7490,6 +7520,10 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
7490
7520
|
continue;
|
|
7491
7521
|
}
|
|
7492
7522
|
if (row.type !== "user" || !msg) continue;
|
|
7523
|
+
if (isCompactSummaryRow(row, asString(msg.content))) {
|
|
7524
|
+
out.push({ kind: "session-continued", ts });
|
|
7525
|
+
continue;
|
|
7526
|
+
}
|
|
7493
7527
|
if (Array.isArray(msg.content)) {
|
|
7494
7528
|
out.push(...toolResultTurns(msg.content, ts));
|
|
7495
7529
|
continue;
|
|
@@ -7498,6 +7532,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
7498
7532
|
if (text === null) continue;
|
|
7499
7533
|
if (CLI_MARKER_PREFIXES2.some((p) => text.startsWith(p))) continue;
|
|
7500
7534
|
if (HARNESS_LIFECYCLE_PREFIXES.some((p) => text.startsWith(p))) continue;
|
|
7535
|
+
if (CC_IMAGE_VISION_HINT.test(text)) continue;
|
|
7501
7536
|
const isChannel = row.isMeta === true && typeof row.origin === "object" && row.origin !== null && row.origin.kind === "channel" || // Native Claude Code channels (maxy-lite) journal the delivery twin as a PLAIN
|
|
7502
7537
|
// `type:"user"` row whose content is the `<channel source="…">` wrapper, with no
|
|
7503
7538
|
// `isMeta`/`origin` stamp. Detect it by the wrapper so it is treated as the
|
|
@@ -7517,7 +7552,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
7517
7552
|
|
|
7518
7553
|
// app/lib/whatsapp-reader/enrich-attachments.ts
|
|
7519
7554
|
import { readFileSync as readFileSync12, readdirSync as readdirSync6 } from "fs";
|
|
7520
|
-
import { join as
|
|
7555
|
+
import { join as join12 } from "path";
|
|
7521
7556
|
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;
|
|
7522
7557
|
function adminAttachmentIds(text) {
|
|
7523
7558
|
const ids = [];
|
|
@@ -7530,7 +7565,7 @@ function adminAttachmentIds(text) {
|
|
|
7530
7565
|
function adminAttachmentsFromText(text, uploadsBase) {
|
|
7531
7566
|
const out = [];
|
|
7532
7567
|
for (const id of adminAttachmentIds(text)) {
|
|
7533
|
-
const meta = readAttachmentMeta(
|
|
7568
|
+
const meta = readAttachmentMeta(join12(uploadsBase, id));
|
|
7534
7569
|
if (meta) out.push(meta);
|
|
7535
7570
|
}
|
|
7536
7571
|
return out;
|
|
@@ -7538,7 +7573,7 @@ function adminAttachmentsFromText(text, uploadsBase) {
|
|
|
7538
7573
|
function readSidecar(dir, attachmentId) {
|
|
7539
7574
|
let parsed;
|
|
7540
7575
|
try {
|
|
7541
|
-
parsed = JSON.parse(readFileSync12(
|
|
7576
|
+
parsed = JSON.parse(readFileSync12(join12(dir, `${attachmentId}.meta.json`), "utf8"));
|
|
7542
7577
|
} catch {
|
|
7543
7578
|
return null;
|
|
7544
7579
|
}
|
|
@@ -7567,7 +7602,7 @@ function listSessionAttachmentsInDir(dir) {
|
|
|
7567
7602
|
}
|
|
7568
7603
|
const sidecars = [];
|
|
7569
7604
|
for (const name of entries) {
|
|
7570
|
-
const sidecar = readSidecar(
|
|
7605
|
+
const sidecar = readSidecar(join12(dir, name), name);
|
|
7571
7606
|
if (sidecar) sidecars.push(sidecar);
|
|
7572
7607
|
}
|
|
7573
7608
|
sidecars.sort((a, b) => a.storedAt.localeCompare(b.storedAt));
|
|
@@ -7612,13 +7647,13 @@ var app4 = new Hono();
|
|
|
7612
7647
|
app4.get("/conversations", requireAdminSession, async (c) => {
|
|
7613
7648
|
const cfg = claudeConfigDir();
|
|
7614
7649
|
if (!cfg) return c.json({ conversations: [] });
|
|
7615
|
-
const projectsRoot =
|
|
7650
|
+
const projectsRoot = join13(cfg, "projects");
|
|
7616
7651
|
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
7617
7652
|
const rows = [];
|
|
7618
7653
|
for (const { path: path2 } of enumerateJsonls(projectsRoot)) {
|
|
7619
|
-
const sessionId =
|
|
7620
|
-
const projectDir =
|
|
7621
|
-
const meta = readSidecarMeta(
|
|
7654
|
+
const sessionId = basename4(path2).replace(/\.jsonl$/, "");
|
|
7655
|
+
const projectDir = dirname2(path2);
|
|
7656
|
+
const meta = readSidecarMeta(join13(projectDir, `${sessionId}.meta.json`));
|
|
7622
7657
|
if (!isReaderChannelSession(meta.role, meta.channel)) continue;
|
|
7623
7658
|
let body = "";
|
|
7624
7659
|
try {
|
|
@@ -7706,11 +7741,30 @@ function resumeOffset(lastEventId, fileEnd) {
|
|
|
7706
7741
|
if (!Number.isFinite(n) || n < 0) return 0;
|
|
7707
7742
|
return Math.min(n, fileEnd);
|
|
7708
7743
|
}
|
|
7709
|
-
function enrichDownloads(turn) {
|
|
7744
|
+
function enrichDownloads(turn, scratchpadRoot) {
|
|
7710
7745
|
if (turn.kind !== "agent-file") return turn;
|
|
7746
|
+
let scratchpadReal = null;
|
|
7747
|
+
try {
|
|
7748
|
+
scratchpadReal = realpathSync4(scratchpadRoot);
|
|
7749
|
+
} catch {
|
|
7750
|
+
scratchpadReal = null;
|
|
7751
|
+
}
|
|
7711
7752
|
const downloads = turn.files.map((f) => {
|
|
7712
|
-
const
|
|
7713
|
-
|
|
7753
|
+
const dataRel = relative2(DATA_ROOT, f);
|
|
7754
|
+
if (dataRel && !dataRel.startsWith("..") && !isAbsolute(dataRel)) {
|
|
7755
|
+
return { root: "data", path: dataRel };
|
|
7756
|
+
}
|
|
7757
|
+
if (scratchpadReal) {
|
|
7758
|
+
try {
|
|
7759
|
+
const fileReal = realpathSync4(f);
|
|
7760
|
+
if (fileReal === scratchpadReal || fileReal.startsWith(scratchpadReal + sep3)) {
|
|
7761
|
+
return { root: "scratchpad", path: relative2(scratchpadReal, fileReal) };
|
|
7762
|
+
}
|
|
7763
|
+
} catch {
|
|
7764
|
+
}
|
|
7765
|
+
}
|
|
7766
|
+
console.error(`[data] op=agent-file-unmapped path="${f}"`);
|
|
7767
|
+
return null;
|
|
7714
7768
|
});
|
|
7715
7769
|
return { ...turn, downloads };
|
|
7716
7770
|
}
|
|
@@ -7755,7 +7809,7 @@ function openTaskKey(turns) {
|
|
|
7755
7809
|
}
|
|
7756
7810
|
function readSubagentMeta(dir, hex) {
|
|
7757
7811
|
try {
|
|
7758
|
-
const m = JSON.parse(readFileSync13(
|
|
7812
|
+
const m = JSON.parse(readFileSync13(join13(dir, `agent-${hex}.meta.json`), "utf8"));
|
|
7759
7813
|
if (typeof m.agentType === "string" && typeof m.description === "string" && typeof m.toolUseId === "string") {
|
|
7760
7814
|
return { agentType: m.agentType, description: m.description, toolUseId: m.toolUseId };
|
|
7761
7815
|
}
|
|
@@ -7787,7 +7841,7 @@ function runActivityTick(c) {
|
|
|
7787
7841
|
let size = 0;
|
|
7788
7842
|
let mtimeMs = 0;
|
|
7789
7843
|
try {
|
|
7790
|
-
const st = statSync4(
|
|
7844
|
+
const st = statSync4(join13(c.subagentsDir, name));
|
|
7791
7845
|
size = st.size;
|
|
7792
7846
|
mtimeMs = st.mtimeMs;
|
|
7793
7847
|
} catch {
|
|
@@ -7832,14 +7886,15 @@ app4.get("/stream", requireAdminSession, (c) => {
|
|
|
7832
7886
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
7833
7887
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
7834
7888
|
const cfg = claudeConfigDir();
|
|
7835
|
-
const projectsRoot = cfg ? resolve11(
|
|
7889
|
+
const projectsRoot = cfg ? resolve11(join13(cfg, "projects")) : null;
|
|
7836
7890
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
7837
7891
|
return c.json({ error: "bad session reference" }, 400);
|
|
7838
7892
|
}
|
|
7839
|
-
const jsonlPath = resolve11(
|
|
7893
|
+
const jsonlPath = resolve11(join13(projectDir, `${sessionId}.jsonl`));
|
|
7840
7894
|
if (!jsonlPath.startsWith(projectsRoot + sep3)) {
|
|
7841
7895
|
return c.json({ error: "bad session reference" }, 400);
|
|
7842
7896
|
}
|
|
7897
|
+
const scratchpadRoot = sessionScratchpadRoot(projectDir, sessionId);
|
|
7843
7898
|
const encoder = new TextEncoder();
|
|
7844
7899
|
const send = (controller, turn, id) => controller.enqueue(encoder.encode(`id: ${id}
|
|
7845
7900
|
data: ${JSON.stringify(turn)}
|
|
@@ -7860,7 +7915,7 @@ data: ${JSON.stringify(turn)}
|
|
|
7860
7915
|
let offset = resumeOffset(lastEventId, fileEnd0);
|
|
7861
7916
|
console.log(`[wa-stream] op=open conn=${connId} sessionId=${sessionId} channel=reader resume=${offset}`);
|
|
7862
7917
|
const sessionKey = c.req.query("session_key") ?? "";
|
|
7863
|
-
const subagentsDir = resolve11(
|
|
7918
|
+
const subagentsDir = resolve11(join13(projectDir, sessionId, "subagents"));
|
|
7864
7919
|
console.log(
|
|
7865
7920
|
`[webchat-activity] op=watch-subagents key=${sessionKey} dir=${subagentsDir} exists=${existsSync7(subagentsDir)}`
|
|
7866
7921
|
);
|
|
@@ -7887,7 +7942,7 @@ data: ${JSON.stringify(obj)}
|
|
|
7887
7942
|
offset = nextOffset;
|
|
7888
7943
|
let n = 0;
|
|
7889
7944
|
for (const turn of parseTranscript(lines, queuedPendingSuppress)) {
|
|
7890
|
-
send(controller, enrichAdminAttachments(enrichDownloads(turn)), offset);
|
|
7945
|
+
send(controller, enrichAdminAttachments(enrichDownloads(turn, scratchpadRoot)), offset);
|
|
7891
7946
|
actx.lastParentTurns.push(turn);
|
|
7892
7947
|
if (turn.kind === "agent-error") {
|
|
7893
7948
|
console.log(`[wa-stream] op=agent-error conn=${connId} sessionId=${sessionId} code=${turn.code} source=jsonl`);
|
|
@@ -7907,7 +7962,7 @@ data: ${JSON.stringify(obj)}
|
|
|
7907
7962
|
offset = end;
|
|
7908
7963
|
let n = 0;
|
|
7909
7964
|
for (const turn of parseTranscript(buf.toString("utf8").split("\n"), queuedPendingSuppress)) {
|
|
7910
|
-
send(controller, enrichAdminAttachments(enrichDownloads(turn)), offset);
|
|
7965
|
+
send(controller, enrichAdminAttachments(enrichDownloads(turn, scratchpadRoot)), offset);
|
|
7911
7966
|
actx.lastParentTurns.push(turn);
|
|
7912
7967
|
if (turn.kind === "agent-error") {
|
|
7913
7968
|
console.log(`[wa-stream] op=agent-error conn=${connId} sessionId=${sessionId} code=${turn.code} source=jsonl`);
|
|
@@ -7981,7 +8036,7 @@ app4.get("/directives", requireAdminSession, (c) => {
|
|
|
7981
8036
|
const pid = Number(pidPart);
|
|
7982
8037
|
let len = 0;
|
|
7983
8038
|
try {
|
|
7984
|
-
len = statSync4(
|
|
8039
|
+
len = statSync4(join13(dir, name)).size;
|
|
7985
8040
|
} catch {
|
|
7986
8041
|
}
|
|
7987
8042
|
return { name, secs, pid, ts: Number.isFinite(secs) ? new Date(secs * 1e3).toISOString() : null, len };
|
|
@@ -7996,7 +8051,7 @@ app4.get("/directive", requireAdminSession, (c) => {
|
|
|
7996
8051
|
}
|
|
7997
8052
|
const dir = directiveStoreDir(sessionId);
|
|
7998
8053
|
if (!dir) return c.json({ error: "no account" }, 404);
|
|
7999
|
-
const path2 = resolve11(
|
|
8054
|
+
const path2 = resolve11(join13(dir, name));
|
|
8000
8055
|
if (!path2.startsWith(dir + sep3)) return c.json({ error: "bad reference" }, 400);
|
|
8001
8056
|
let body;
|
|
8002
8057
|
try {
|
|
@@ -8010,7 +8065,7 @@ var whatsapp_reader_default = app4;
|
|
|
8010
8065
|
|
|
8011
8066
|
// server/routes/public-reader.ts
|
|
8012
8067
|
import { statSync as statSync5, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2, readFileSync as readFileSync14, readdirSync as readdirSync8 } from "fs";
|
|
8013
|
-
import { basename as
|
|
8068
|
+
import { basename as basename5, dirname as dirname3, join as join14, resolve as resolve12, sep as sep4 } from "path";
|
|
8014
8069
|
|
|
8015
8070
|
// app/lib/whatsapp-reader/delivered-kinds.ts
|
|
8016
8071
|
var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -8084,10 +8139,10 @@ function enumeratePublicRows() {
|
|
|
8084
8139
|
const cfg = claudeConfigDir();
|
|
8085
8140
|
if (!cfg) return [];
|
|
8086
8141
|
const rows = [];
|
|
8087
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
8088
|
-
const sessionId =
|
|
8089
|
-
const projectDir =
|
|
8090
|
-
const meta = readSidecarMeta(
|
|
8142
|
+
for (const { path: path2 } of enumerateJsonls(join14(cfg, "projects"))) {
|
|
8143
|
+
const sessionId = basename5(path2).replace(/\.jsonl$/, "");
|
|
8144
|
+
const projectDir = dirname3(path2);
|
|
8145
|
+
const meta = readSidecarMeta(join14(projectDir, `${sessionId}.meta.json`));
|
|
8091
8146
|
rows.push({
|
|
8092
8147
|
sessionId,
|
|
8093
8148
|
projectDir,
|
|
@@ -8163,15 +8218,15 @@ app5.get("/stream", (c) => {
|
|
|
8163
8218
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
8164
8219
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
8165
8220
|
const cfg = claudeConfigDir();
|
|
8166
|
-
const projectsRoot = cfg ? resolve12(
|
|
8221
|
+
const projectsRoot = cfg ? resolve12(join14(cfg, "projects")) : null;
|
|
8167
8222
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
8168
8223
|
return c.json({ error: "bad session reference" }, 400);
|
|
8169
8224
|
}
|
|
8170
|
-
const jsonlPath = resolve12(
|
|
8225
|
+
const jsonlPath = resolve12(join14(projectDir, `${sessionId}.jsonl`));
|
|
8171
8226
|
if (!jsonlPath.startsWith(projectsRoot + sep4)) {
|
|
8172
8227
|
return c.json({ error: "bad session reference" }, 400);
|
|
8173
8228
|
}
|
|
8174
|
-
const meta = readSidecarMeta(
|
|
8229
|
+
const meta = readSidecarMeta(join14(projectDir, `${sessionId}.meta.json`));
|
|
8175
8230
|
const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
|
|
8176
8231
|
const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
|
|
8177
8232
|
if (!(isPublicWebchat && owns)) {
|
|
@@ -8304,17 +8359,17 @@ app5.get("/attachment/:attachmentId", (c) => {
|
|
|
8304
8359
|
var public_reader_default = app5;
|
|
8305
8360
|
|
|
8306
8361
|
// server/routes/webchat.ts
|
|
8307
|
-
import { basename as
|
|
8308
|
-
import { join as
|
|
8362
|
+
import { basename as basename6, dirname as dirname4 } from "path";
|
|
8363
|
+
import { join as join17 } from "path";
|
|
8309
8364
|
import { existsSync as existsSync9, readdirSync as readdirSync10, readFileSync as readFileSync17, renameSync as renameSync3, statSync as statSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
8310
8365
|
|
|
8311
8366
|
// server/canonical-webchat-override.ts
|
|
8312
8367
|
import { readFileSync as readFileSync15, writeFileSync as writeFileSync5, renameSync } from "fs";
|
|
8313
|
-
import { join as
|
|
8368
|
+
import { join as join15 } from "path";
|
|
8314
8369
|
var FILE = "canonical-webchat-session.json";
|
|
8315
8370
|
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}$/;
|
|
8316
8371
|
function canonicalOverridePath(accountDir) {
|
|
8317
|
-
return
|
|
8372
|
+
return join15(accountDir, FILE);
|
|
8318
8373
|
}
|
|
8319
8374
|
function readRaw(accountDir) {
|
|
8320
8375
|
try {
|
|
@@ -8406,7 +8461,7 @@ function isNewSessionEffortLevel(value) {
|
|
|
8406
8461
|
|
|
8407
8462
|
// ../services/claude-session-manager/src/sidecar-store.ts
|
|
8408
8463
|
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readdirSync as readdirSync9, readFileSync as readFileSync16, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
|
|
8409
|
-
import { join as
|
|
8464
|
+
import { join as join16 } from "path";
|
|
8410
8465
|
function escapeRegExp(s) {
|
|
8411
8466
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8412
8467
|
}
|
|
@@ -8414,7 +8469,7 @@ function createSidecarStore(config) {
|
|
|
8414
8469
|
const { suffix, validate: validate2 } = config;
|
|
8415
8470
|
const suffixRe = new RegExp(`${escapeRegExp(suffix)}$`);
|
|
8416
8471
|
function pathFor(sessionsDir, id) {
|
|
8417
|
-
return
|
|
8472
|
+
return join16(sessionsDir, `${id}${suffix}`);
|
|
8418
8473
|
}
|
|
8419
8474
|
function write(sessionsDir, id, record) {
|
|
8420
8475
|
mkdirSync2(sessionsDir, { recursive: true });
|
|
@@ -8458,7 +8513,7 @@ function createSidecarStore(config) {
|
|
|
8458
8513
|
const out = [];
|
|
8459
8514
|
for (const name of names) {
|
|
8460
8515
|
if (!suffixRe.test(name)) continue;
|
|
8461
|
-
const path2 =
|
|
8516
|
+
const path2 = join16(sessionsDir, name);
|
|
8462
8517
|
let raw;
|
|
8463
8518
|
try {
|
|
8464
8519
|
raw = readFileSync16(path2, "utf8");
|
|
@@ -8533,21 +8588,15 @@ function resolveBridgeSource(sessionsDir, forkSessionId, jsonlExists, maxDepth =
|
|
|
8533
8588
|
var WEBCHAT_ADMIN_KEY = "webchat-admin";
|
|
8534
8589
|
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
8535
8590
|
function locateSession(sessionId) {
|
|
8536
|
-
const
|
|
8537
|
-
if (!
|
|
8538
|
-
|
|
8539
|
-
|
|
8540
|
-
const dir = dirname3(path2);
|
|
8541
|
-
const meta = readSidecarMeta(join16(dir, `${sessionId}.meta.json`));
|
|
8542
|
-
return { projectDir: dir, channel: meta.channel };
|
|
8543
|
-
}
|
|
8544
|
-
}
|
|
8545
|
-
return { projectDir: null, channel: null };
|
|
8591
|
+
const dir = findSessionProjectDir(sessionId);
|
|
8592
|
+
if (!dir) return { projectDir: null, channel: null };
|
|
8593
|
+
const meta = readSidecarMeta(join17(dir, `${sessionId}.meta.json`));
|
|
8594
|
+
return { projectDir: dir, channel: meta.channel };
|
|
8546
8595
|
}
|
|
8547
8596
|
function locateSidecar(sessionId) {
|
|
8548
8597
|
const cfg = claudeConfigDir();
|
|
8549
8598
|
if (!cfg) return null;
|
|
8550
|
-
const projectsRoot =
|
|
8599
|
+
const projectsRoot = join17(cfg, "projects");
|
|
8551
8600
|
let slugs;
|
|
8552
8601
|
try {
|
|
8553
8602
|
slugs = readdirSync10(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -8555,7 +8604,7 @@ function locateSidecar(sessionId) {
|
|
|
8555
8604
|
return null;
|
|
8556
8605
|
}
|
|
8557
8606
|
for (const slug of slugs) {
|
|
8558
|
-
const metaPath =
|
|
8607
|
+
const metaPath = join17(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
8559
8608
|
if (existsSync9(metaPath)) {
|
|
8560
8609
|
const meta = readSidecarMeta(metaPath);
|
|
8561
8610
|
return { channel: meta.channel, adminUserId: meta.adminUserId };
|
|
@@ -8568,7 +8617,7 @@ function readTargetOwner(sessionId) {
|
|
|
8568
8617
|
if (sidecar !== null) return { found: true, owner: sidecar.adminUserId };
|
|
8569
8618
|
const { projectDir } = locateSession(sessionId);
|
|
8570
8619
|
if (projectDir !== null) {
|
|
8571
|
-
return { found: true, owner: readSidecarMeta(
|
|
8620
|
+
return { found: true, owner: readSidecarMeta(join17(projectDir, `${sessionId}.meta.json`)).adminUserId };
|
|
8572
8621
|
}
|
|
8573
8622
|
return { found: false, owner: null };
|
|
8574
8623
|
}
|
|
@@ -8582,7 +8631,7 @@ function sessionSidecarExists(sessionId) {
|
|
|
8582
8631
|
function jsonlSizeBytes(projectDir, sessionId) {
|
|
8583
8632
|
if (projectDir === null) return null;
|
|
8584
8633
|
try {
|
|
8585
|
-
return statSync6(
|
|
8634
|
+
return statSync6(join17(projectDir, `${sessionId}.jsonl`)).size;
|
|
8586
8635
|
} catch {
|
|
8587
8636
|
return null;
|
|
8588
8637
|
}
|
|
@@ -8717,10 +8766,10 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId) {
|
|
|
8717
8766
|
const cfg = claudeConfigDir();
|
|
8718
8767
|
if (!cfg) return null;
|
|
8719
8768
|
let best = null;
|
|
8720
|
-
for (const { path: path2, isSubagent, archived } of enumerateJsonls(
|
|
8769
|
+
for (const { path: path2, isSubagent, archived } of enumerateJsonls(join17(cfg, "projects"))) {
|
|
8721
8770
|
if (isSubagent || archived) continue;
|
|
8722
|
-
const id =
|
|
8723
|
-
const meta = readSidecarMeta(
|
|
8771
|
+
const id = basename6(path2).slice(0, -".jsonl".length);
|
|
8772
|
+
const meta = readSidecarMeta(join17(dirname4(path2), `${id}.meta.json`));
|
|
8724
8773
|
if (meta.role !== "admin" || meta.channel !== "webchat") continue;
|
|
8725
8774
|
let mtimeMs;
|
|
8726
8775
|
try {
|
|
@@ -8742,7 +8791,7 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId) {
|
|
|
8742
8791
|
function overrideKnownNonArchived(id) {
|
|
8743
8792
|
const { projectDir } = locateSession(id);
|
|
8744
8793
|
if (projectDir === null) return sessionSidecarExists(id);
|
|
8745
|
-
return
|
|
8794
|
+
return basename6(projectDir) !== "archive";
|
|
8746
8795
|
}
|
|
8747
8796
|
function resolveCanonical(accountId, accountDir, requesterUserId, primaryUserId) {
|
|
8748
8797
|
if (requesterUserId === null) {
|
|
@@ -9015,7 +9064,7 @@ ${note}` : note;
|
|
|
9015
9064
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-unresolved`);
|
|
9016
9065
|
return c.json({ error: "account unresolved" }, 503);
|
|
9017
9066
|
}
|
|
9018
|
-
const accountJsonPath =
|
|
9067
|
+
const accountJsonPath = join17(account.accountDir, "account.json");
|
|
9019
9068
|
try {
|
|
9020
9069
|
const parsed = JSON.parse(readFileSync17(accountJsonPath, "utf8"));
|
|
9021
9070
|
if (op === "model") parsed.adminModel = value;
|
|
@@ -9061,7 +9110,7 @@ ${note}` : note;
|
|
|
9061
9110
|
const cfg2 = claudeConfigDir();
|
|
9062
9111
|
if (cfg2) {
|
|
9063
9112
|
const source2 = resolveBridgeSource(
|
|
9064
|
-
|
|
9113
|
+
join17(cfg2, "sessions"),
|
|
9065
9114
|
target,
|
|
9066
9115
|
(id) => locateSession(id).projectDir !== null
|
|
9067
9116
|
);
|
|
@@ -9093,15 +9142,15 @@ ${note}` : note;
|
|
|
9093
9142
|
const cfg = claudeConfigDir();
|
|
9094
9143
|
let projectDir = null;
|
|
9095
9144
|
if (cfg) {
|
|
9096
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
9097
|
-
if (
|
|
9098
|
-
projectDir =
|
|
9145
|
+
for (const { path: path2 } of enumerateJsonls(join17(cfg, "projects"))) {
|
|
9146
|
+
if (basename6(path2) === `${sessionId}.jsonl`) {
|
|
9147
|
+
projectDir = dirname4(path2);
|
|
9099
9148
|
break;
|
|
9100
9149
|
}
|
|
9101
9150
|
}
|
|
9102
9151
|
}
|
|
9103
9152
|
if (source === "latest" && requesterUserId !== null) {
|
|
9104
|
-
const owner = readSidecarMeta(
|
|
9153
|
+
const owner = readSidecarMeta(join17(projectDir ?? "", `${sessionId}.meta.json`)).adminUserId;
|
|
9105
9154
|
if (owner !== null && owner !== requesterUserId && requesterUserId !== primaryUserId) {
|
|
9106
9155
|
console.error(`[webchat:inbound] op=session-resolve-foreign key=${sessionId.slice(0, 8)} owner=${owner.slice(0, 8)} requester=${requesterUserId.slice(0, 8)}`);
|
|
9107
9156
|
}
|
|
@@ -9134,7 +9183,7 @@ import { resolve as resolve13 } from "path";
|
|
|
9134
9183
|
|
|
9135
9184
|
// app/lib/claude-agent/specialist-roster.ts
|
|
9136
9185
|
import { existsSync as existsSync10, readFileSync as readFileSync18, readdirSync as readdirSync11 } from "fs";
|
|
9137
|
-
import { join as
|
|
9186
|
+
import { join as join18 } from "path";
|
|
9138
9187
|
function field(fm, name) {
|
|
9139
9188
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
9140
9189
|
if (!m) return null;
|
|
@@ -9153,7 +9202,7 @@ function readSpecialistRoster(specialistsDir) {
|
|
|
9153
9202
|
if (!file.endsWith(".md")) continue;
|
|
9154
9203
|
let raw;
|
|
9155
9204
|
try {
|
|
9156
|
-
raw = readFileSync18(
|
|
9205
|
+
raw = readFileSync18(join18(specialistsDir, file), "utf-8");
|
|
9157
9206
|
} catch (err) {
|
|
9158
9207
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
9159
9208
|
continue;
|
|
@@ -9270,7 +9319,7 @@ var webchat_greeting_default = app6;
|
|
|
9270
9319
|
|
|
9271
9320
|
// server/routes/telegram.ts
|
|
9272
9321
|
import { homedir } from "os";
|
|
9273
|
-
import { resolve as resolve14, join as
|
|
9322
|
+
import { resolve as resolve14, join as join19 } from "path";
|
|
9274
9323
|
import { existsSync as existsSync11, readFileSync as readFileSync19 } from "fs";
|
|
9275
9324
|
|
|
9276
9325
|
// app/lib/telegram/gateway/instance.ts
|
|
@@ -9330,7 +9379,7 @@ function routeTelegramUpdate(input) {
|
|
|
9330
9379
|
var TAG22 = "[telegram-inbound]";
|
|
9331
9380
|
function configDirName() {
|
|
9332
9381
|
const platformRoot3 = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "..");
|
|
9333
|
-
const brandPath =
|
|
9382
|
+
const brandPath = join19(platformRoot3, "config", "brand.json");
|
|
9334
9383
|
if (existsSync11(brandPath)) {
|
|
9335
9384
|
try {
|
|
9336
9385
|
return JSON.parse(readFileSync19(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
@@ -9432,16 +9481,16 @@ app7.post("/", async (c) => {
|
|
|
9432
9481
|
var telegram_default = app7;
|
|
9433
9482
|
|
|
9434
9483
|
// server/routes/quickbooks.ts
|
|
9435
|
-
import { join as
|
|
9484
|
+
import { join as join20 } from "path";
|
|
9436
9485
|
import { existsSync as existsSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync8, mkdirSync as mkdirSync3, rmSync, renameSync as renameSync4 } from "fs";
|
|
9437
9486
|
var TAG23 = "[quickbooks]";
|
|
9438
9487
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
9439
9488
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
9440
9489
|
function pendingPath(accountDir, state) {
|
|
9441
|
-
return
|
|
9490
|
+
return join20(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
|
|
9442
9491
|
}
|
|
9443
9492
|
function storePath(accountDir) {
|
|
9444
|
-
return
|
|
9493
|
+
return join20(accountDir, "secrets", "quickbooks.json");
|
|
9445
9494
|
}
|
|
9446
9495
|
async function completeConsent(args) {
|
|
9447
9496
|
const { accountDir, code, realmId } = args;
|
|
@@ -9508,7 +9557,7 @@ async function completeConsent(args) {
|
|
|
9508
9557
|
refreshTokenExpiry: now + (body.x_refresh_token_expires_in ?? 864e4) * 1e3,
|
|
9509
9558
|
lastRefresh: now
|
|
9510
9559
|
};
|
|
9511
|
-
mkdirSync3(
|
|
9560
|
+
mkdirSync3(join20(accountDir, "secrets"), { recursive: true });
|
|
9512
9561
|
writeFileSync8(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
9513
9562
|
const persisted = JSON.parse(readFileSync20(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
9514
9563
|
console.error(`${TAG23} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
@@ -9546,7 +9595,7 @@ import { createHash as createHash3, randomUUID as randomUUID7 } from "crypto";
|
|
|
9546
9595
|
|
|
9547
9596
|
// ../lib/admins-write/src/index.ts
|
|
9548
9597
|
import { existsSync as existsSync13, readFileSync as readFileSync21, writeFileSync as writeFileSync9, renameSync as renameSync5, mkdirSync as mkdirSync4, readdirSync as readdirSync12, statSync as statSync7, appendFileSync } from "fs";
|
|
9549
|
-
import { dirname as
|
|
9598
|
+
import { dirname as dirname5, join as join21 } from "path";
|
|
9550
9599
|
function id8(value) {
|
|
9551
9600
|
return value.slice(0, 8);
|
|
9552
9601
|
}
|
|
@@ -9559,7 +9608,7 @@ function appendUsersAuditLine(audit, fields) {
|
|
|
9559
9608
|
const line = `[users-audit] action=${fields.action} actor=${actor}${sess} field=${fields.field} rowsBefore=${fields.rowsBefore} rowsAfter=${fields.rowsAfter} ts=${(/* @__PURE__ */ new Date()).toISOString()}
|
|
9560
9609
|
`;
|
|
9561
9610
|
try {
|
|
9562
|
-
mkdirSync4(
|
|
9611
|
+
mkdirSync4(dirname5(audit.logFile), { recursive: true, mode: 448 });
|
|
9563
9612
|
appendFileSync(audit.logFile, line, { mode: 384 });
|
|
9564
9613
|
} catch (err) {
|
|
9565
9614
|
console.error(
|
|
@@ -9577,7 +9626,7 @@ function logLine(input, result) {
|
|
|
9577
9626
|
);
|
|
9578
9627
|
}
|
|
9579
9628
|
function writeFileAtomic(filePath, contents, mode) {
|
|
9580
|
-
mkdirSync4(
|
|
9629
|
+
mkdirSync4(dirname5(filePath), { recursive: true });
|
|
9581
9630
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
9582
9631
|
writeFileSync9(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
9583
9632
|
renameSync5(tempPath, filePath);
|
|
@@ -9618,7 +9667,7 @@ function writeAdminEntry(input) {
|
|
|
9618
9667
|
return result;
|
|
9619
9668
|
}
|
|
9620
9669
|
try {
|
|
9621
|
-
const accountJsonPath =
|
|
9670
|
+
const accountJsonPath = join21(input.accountDir, "account.json");
|
|
9622
9671
|
if (!existsSync13(accountJsonPath)) {
|
|
9623
9672
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
9624
9673
|
}
|
|
@@ -9666,13 +9715,13 @@ function computeAdminStoreDivergence(input) {
|
|
|
9666
9715
|
}
|
|
9667
9716
|
for (const entry of entries) {
|
|
9668
9717
|
if (entry.startsWith(".")) continue;
|
|
9669
|
-
const accountDir =
|
|
9718
|
+
const accountDir = join21(input.accountsDir, entry);
|
|
9670
9719
|
try {
|
|
9671
9720
|
if (!statSync7(accountDir).isDirectory()) continue;
|
|
9672
9721
|
} catch {
|
|
9673
9722
|
continue;
|
|
9674
9723
|
}
|
|
9675
|
-
const accountJsonPath =
|
|
9724
|
+
const accountJsonPath = join21(accountDir, "account.json");
|
|
9676
9725
|
if (!existsSync13(accountJsonPath)) continue;
|
|
9677
9726
|
let admins = [];
|
|
9678
9727
|
try {
|
|
@@ -10069,8 +10118,8 @@ var onboarding_default = app9;
|
|
|
10069
10118
|
|
|
10070
10119
|
// server/routes/client-error.ts
|
|
10071
10120
|
import { appendFileSync as appendFileSync2, existsSync as existsSync15, renameSync as renameSync6, statSync as statSync8 } from "fs";
|
|
10072
|
-
import { join as
|
|
10073
|
-
var CLIENT_ERRORS_LOG =
|
|
10121
|
+
import { join as join22 } from "path";
|
|
10122
|
+
var CLIENT_ERRORS_LOG = join22(LOG_DIR, "client-errors.log");
|
|
10074
10123
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
10075
10124
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
10076
10125
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -10400,16 +10449,16 @@ var session_default = app11;
|
|
|
10400
10449
|
|
|
10401
10450
|
// server/routes/admin/logs.ts
|
|
10402
10451
|
import { existsSync as existsSync17, readdirSync as readdirSync13, readFileSync as readFileSync23, statSync as statSync9 } from "fs";
|
|
10403
|
-
import { resolve as resolve15, basename as
|
|
10452
|
+
import { resolve as resolve15, basename as basename7 } from "path";
|
|
10404
10453
|
|
|
10405
10454
|
// app/lib/logs-read-resolve.ts
|
|
10406
10455
|
import { existsSync as existsSync16 } from "fs";
|
|
10407
|
-
import { join as
|
|
10456
|
+
import { join as join23 } from "path";
|
|
10408
10457
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
10409
10458
|
const tried = [filename];
|
|
10410
10459
|
const hits = [];
|
|
10411
10460
|
for (const dir of logDirs) {
|
|
10412
|
-
const fullPath =
|
|
10461
|
+
const fullPath = join23(dir, filename);
|
|
10413
10462
|
if (existsSync16(fullPath)) {
|
|
10414
10463
|
hits.push({ path: fullPath, dir });
|
|
10415
10464
|
}
|
|
@@ -10432,7 +10481,7 @@ app12.get("/", async (c) => {
|
|
|
10432
10481
|
if (accountLogDir) logDirs.push(accountLogDir);
|
|
10433
10482
|
logDirs.push(LOG_DIR);
|
|
10434
10483
|
if (fileParam) {
|
|
10435
|
-
const safe =
|
|
10484
|
+
const safe = basename7(fileParam);
|
|
10436
10485
|
const searched = [];
|
|
10437
10486
|
for (const dir of logDirs) {
|
|
10438
10487
|
const filePath = resolve15(dir, safe);
|
|
@@ -10502,7 +10551,7 @@ app12.get("/", async (c) => {
|
|
|
10502
10551
|
if (hit) {
|
|
10503
10552
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
10504
10553
|
try {
|
|
10505
|
-
const filename =
|
|
10554
|
+
const filename = basename7(hit.path);
|
|
10506
10555
|
const buffer = readFileSync23(hit.path);
|
|
10507
10556
|
const onDiskBytes = statSync9(hit.path).size;
|
|
10508
10557
|
const headers = {
|
|
@@ -11411,7 +11460,7 @@ var sessions_default = app16;
|
|
|
11411
11460
|
|
|
11412
11461
|
// app/lib/claude-agent/spawn-context.ts
|
|
11413
11462
|
import { existsSync as existsSync21, readFileSync as readFileSync25, readdirSync as readdirSync15, statSync as statSync10 } from "fs";
|
|
11414
|
-
import { dirname as
|
|
11463
|
+
import { dirname as dirname6, resolve as resolve18, join as join24 } from "path";
|
|
11415
11464
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
11416
11465
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
11417
11466
|
try {
|
|
@@ -11452,8 +11501,8 @@ function frontmatterField(manifest, field2) {
|
|
|
11452
11501
|
function extractPluginToolDescriptions(pluginDir) {
|
|
11453
11502
|
const out = /* @__PURE__ */ new Map();
|
|
11454
11503
|
const candidates = [
|
|
11455
|
-
|
|
11456
|
-
|
|
11504
|
+
join24(pluginDir, "mcp/dist/index.js"),
|
|
11505
|
+
join24(pluginDir, "mcp/src/index.ts")
|
|
11457
11506
|
];
|
|
11458
11507
|
let raw = null;
|
|
11459
11508
|
for (const path2 of candidates) {
|
|
@@ -11511,21 +11560,21 @@ function listPluginDirs() {
|
|
|
11511
11560
|
const platformPlugins = resolve18(PLATFORM_ROOT, "plugins");
|
|
11512
11561
|
if (existsSync21(platformPlugins)) {
|
|
11513
11562
|
for (const name of readdirSync15(platformPlugins)) {
|
|
11514
|
-
const dir =
|
|
11563
|
+
const dir = join24(platformPlugins, name);
|
|
11515
11564
|
try {
|
|
11516
11565
|
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
11517
11566
|
} catch {
|
|
11518
11567
|
}
|
|
11519
11568
|
}
|
|
11520
11569
|
}
|
|
11521
|
-
const premiumRoot = resolve18(
|
|
11570
|
+
const premiumRoot = resolve18(dirname6(PLATFORM_ROOT), "premium-plugins");
|
|
11522
11571
|
if (existsSync21(premiumRoot)) {
|
|
11523
11572
|
for (const bundle of readdirSync15(premiumRoot)) {
|
|
11524
|
-
const bundlePlugins =
|
|
11573
|
+
const bundlePlugins = join24(premiumRoot, bundle, "plugins");
|
|
11525
11574
|
if (!existsSync21(bundlePlugins)) continue;
|
|
11526
11575
|
try {
|
|
11527
11576
|
for (const name of readdirSync15(bundlePlugins)) {
|
|
11528
|
-
const dir =
|
|
11577
|
+
const dir = join24(bundlePlugins, name);
|
|
11529
11578
|
try {
|
|
11530
11579
|
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
11531
11580
|
} catch {
|
|
@@ -11568,7 +11617,7 @@ function computeActivePlugins(accountId) {
|
|
|
11568
11617
|
for (const name of Array.from(enabled).sort()) {
|
|
11569
11618
|
const dir = pluginDirs.get(name);
|
|
11570
11619
|
if (!dir) continue;
|
|
11571
|
-
const fm = readFrontmatter(
|
|
11620
|
+
const fm = readFrontmatter(join24(dir, "PLUGIN.md"));
|
|
11572
11621
|
if (!fm) continue;
|
|
11573
11622
|
const description = frontmatterField(`---
|
|
11574
11623
|
${fm}
|
|
@@ -11585,7 +11634,7 @@ ${fm}
|
|
|
11585
11634
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
11586
11635
|
);
|
|
11587
11636
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
11588
|
-
const hasSource = existsSync21(
|
|
11637
|
+
const hasSource = existsSync21(join24(dir, "mcp/dist/index.js")) || existsSync21(join24(dir, "mcp/src/index.ts"));
|
|
11589
11638
|
if (hasSource) {
|
|
11590
11639
|
console.warn(
|
|
11591
11640
|
`[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
|
|
@@ -11595,7 +11644,7 @@ ${fm}
|
|
|
11595
11644
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
11596
11645
|
const skills = [];
|
|
11597
11646
|
for (const relPath of skillPaths) {
|
|
11598
|
-
const skillPath =
|
|
11647
|
+
const skillPath = join24(dir, relPath);
|
|
11599
11648
|
const skillFm = readFrontmatter(skillPath);
|
|
11600
11649
|
if (!skillFm) continue;
|
|
11601
11650
|
const skillName = frontmatterField(`---
|
|
@@ -11639,7 +11688,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
11639
11688
|
const out = [];
|
|
11640
11689
|
for (const file of entries.sort()) {
|
|
11641
11690
|
if (!file.endsWith(".md")) continue;
|
|
11642
|
-
const fm = readFrontmatter(
|
|
11691
|
+
const fm = readFrontmatter(join24(specialistsDir, file));
|
|
11643
11692
|
if (!fm) continue;
|
|
11644
11693
|
const wrapped = `---
|
|
11645
11694
|
${fm}
|
|
@@ -11965,9 +12014,9 @@ var events_default = app19;
|
|
|
11965
12014
|
// server/routes/admin/files.ts
|
|
11966
12015
|
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync23 } from "fs";
|
|
11967
12016
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename } from "fs/promises";
|
|
11968
|
-
import { realpathSync as
|
|
12017
|
+
import { realpathSync as realpathSync5 } from "fs";
|
|
11969
12018
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
11970
|
-
import { basename as
|
|
12019
|
+
import { basename as basename9, dirname as dirname7, join as join26, relative as relative4, resolve as resolve21, sep as sep6 } from "path";
|
|
11971
12020
|
import { Readable as Readable2 } from "stream";
|
|
11972
12021
|
|
|
11973
12022
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -12285,7 +12334,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
12285
12334
|
|
|
12286
12335
|
// app/lib/file-index.ts
|
|
12287
12336
|
import * as fsp from "fs/promises";
|
|
12288
|
-
import { resolve as resolve20, relative as relative3, join as
|
|
12337
|
+
import { resolve as resolve20, relative as relative3, join as join25, basename as basename8, extname as extname2, sep as sep5 } from "path";
|
|
12289
12338
|
import { tmpdir as tmpdir2 } from "os";
|
|
12290
12339
|
import { execFile as execFile2 } from "child_process";
|
|
12291
12340
|
import { promisify as promisify2 } from "util";
|
|
@@ -12367,7 +12416,7 @@ async function extractPdf(absolute) {
|
|
|
12367
12416
|
return stdout.trim();
|
|
12368
12417
|
}
|
|
12369
12418
|
async function ocrPdf(absolute) {
|
|
12370
|
-
const outPdf =
|
|
12419
|
+
const outPdf = join25(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
12371
12420
|
try {
|
|
12372
12421
|
await execFileAsync2(
|
|
12373
12422
|
"ocrmypdf",
|
|
@@ -12423,13 +12472,13 @@ async function extractFileContent(absolute) {
|
|
|
12423
12472
|
}
|
|
12424
12473
|
}
|
|
12425
12474
|
async function readDisplayName(absolute) {
|
|
12426
|
-
const dir = absolute.slice(0, absolute.length -
|
|
12427
|
-
const base =
|
|
12475
|
+
const dir = absolute.slice(0, absolute.length - basename8(absolute).length);
|
|
12476
|
+
const base = basename8(absolute);
|
|
12428
12477
|
const dot = base.lastIndexOf(".");
|
|
12429
12478
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
12430
12479
|
if (base === `${stem}.meta.json`) return null;
|
|
12431
12480
|
try {
|
|
12432
|
-
const raw = await fsp.readFile(
|
|
12481
|
+
const raw = await fsp.readFile(join25(dir, `${stem}.meta.json`), "utf-8");
|
|
12433
12482
|
const meta = JSON.parse(raw);
|
|
12434
12483
|
const dn = meta.displayName ?? meta.filename;
|
|
12435
12484
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -12450,7 +12499,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
12450
12499
|
for (const entry of entries) {
|
|
12451
12500
|
if (entry.isSymbolicLink()) continue;
|
|
12452
12501
|
if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
|
|
12453
|
-
const abs =
|
|
12502
|
+
const abs = join25(root, entry.name);
|
|
12454
12503
|
if (entry.isDirectory()) {
|
|
12455
12504
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
12456
12505
|
if (!sub.clean) clean = false;
|
|
@@ -12562,7 +12611,7 @@ async function cascadeTrashLinkedKnowledgeDocs(session, accountId, relativePaths
|
|
|
12562
12611
|
return { kds, sections, chunks };
|
|
12563
12612
|
}
|
|
12564
12613
|
async function buildArtifact(accountId, wf, embed2) {
|
|
12565
|
-
const name =
|
|
12614
|
+
const name = basename8(wf.absolute);
|
|
12566
12615
|
const { content, route } = await extractFileContent(wf.absolute);
|
|
12567
12616
|
const displayName = await readDisplayName(wf.absolute);
|
|
12568
12617
|
const embedInput = `${name}
|
|
@@ -12806,7 +12855,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
|
12806
12855
|
var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
12807
12856
|
async function readMeta(absDir, baseName) {
|
|
12808
12857
|
try {
|
|
12809
|
-
const raw = await readFile4(
|
|
12858
|
+
const raw = await readFile4(join26(absDir, `${baseName}.meta.json`), "utf8");
|
|
12810
12859
|
const parsed = JSON.parse(raw);
|
|
12811
12860
|
if (typeof parsed?.filename === "string") {
|
|
12812
12861
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -12844,7 +12893,7 @@ async function readAccountNames() {
|
|
|
12844
12893
|
}
|
|
12845
12894
|
async function enrich(absolute, entry, accountNames) {
|
|
12846
12895
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
12847
|
-
const meta = await readMeta(
|
|
12896
|
+
const meta = await readMeta(join26(absolute, entry.name), entry.name);
|
|
12848
12897
|
if (meta?.filename) {
|
|
12849
12898
|
entry.displayName = meta.filename;
|
|
12850
12899
|
entry.mimeType = meta.mimeType;
|
|
@@ -13008,7 +13057,7 @@ app20.get("/", requireAdminSession, async (c) => {
|
|
|
13008
13057
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
13009
13058
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
13010
13059
|
try {
|
|
13011
|
-
const entryPath =
|
|
13060
|
+
const entryPath = join26(absolute, name);
|
|
13012
13061
|
const s = await stat4(entryPath);
|
|
13013
13062
|
entries.push({
|
|
13014
13063
|
name,
|
|
@@ -13048,11 +13097,27 @@ app20.get("/download", requireAdminSession, async (c) => {
|
|
|
13048
13097
|
const rawPath = c.req.query("path") ?? "";
|
|
13049
13098
|
if (!rawPath) return c.json({ error: "path required" }, 400);
|
|
13050
13099
|
const root = c.req.query("root") ?? "data";
|
|
13051
|
-
if (root !== "data" && root !== "claude-uploads") {
|
|
13100
|
+
if (root !== "data" && root !== "claude-uploads" && root !== "scratchpad") {
|
|
13052
13101
|
return c.json({ error: "invalid root" }, 400);
|
|
13053
13102
|
}
|
|
13054
13103
|
const disposition = c.req.query("disposition") ?? "attachment";
|
|
13055
|
-
|
|
13104
|
+
let scratchpadRoot = null;
|
|
13105
|
+
if (root === "scratchpad") {
|
|
13106
|
+
const sessionId = c.req.query("sessionId") ?? "";
|
|
13107
|
+
if (!SESSION_ID_RE2.test(sessionId)) return c.json({ error: "bad session reference" }, 400);
|
|
13108
|
+
const projectDir = findSessionProjectDir(sessionId);
|
|
13109
|
+
if (!projectDir) {
|
|
13110
|
+
console.error(`[data] op=scratchpad-no-session sessionId="${sessionId.slice(0, 8)}\u2026"`);
|
|
13111
|
+
return c.json({ error: "Not found" }, 404);
|
|
13112
|
+
}
|
|
13113
|
+
const meta = readSidecarMeta(join26(projectDir, `${sessionId}.meta.json`));
|
|
13114
|
+
if (!meta.accountId || meta.accountId !== accountId) {
|
|
13115
|
+
console.error(`[data] account-scope-blocked root="scratchpad" sessionId="${sessionId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
|
|
13116
|
+
return c.json({ error: "Not found" }, 404);
|
|
13117
|
+
}
|
|
13118
|
+
scratchpadRoot = sessionScratchpadRoot(projectDir, sessionId);
|
|
13119
|
+
}
|
|
13120
|
+
const resolution = root === "scratchpad" ? resolveScratchpadPath(rawPath, scratchpadRoot) : root === "claude-uploads" ? resolveClaudeUploadsPath(rawPath) : resolveDataPath(rawPath);
|
|
13056
13121
|
if (!resolution.ok) {
|
|
13057
13122
|
if (resolution.status === 403) {
|
|
13058
13123
|
console.error(`[data] path-traversal-blocked root="${root}" requested="${rawPath}" resolved="${resolution.resolved ?? "n/a"}"`);
|
|
@@ -13067,7 +13132,7 @@ app20.get("/download", requireAdminSession, async (c) => {
|
|
|
13067
13132
|
console.error(`[data] account-scope-blocked root="claude-uploads" attachmentId="${attachmentId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
|
|
13068
13133
|
return c.json({ error: "Not found" }, 404);
|
|
13069
13134
|
}
|
|
13070
|
-
} else if (crossesForeignAccountPartition(relPath, accountId)) {
|
|
13135
|
+
} else if (root === "data" && crossesForeignAccountPartition(relPath, accountId)) {
|
|
13071
13136
|
console.error(`[data] account-scope-blocked endpoint="/api/admin/files/download" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
13072
13137
|
return c.json({ error: "Not found" }, 404);
|
|
13073
13138
|
}
|
|
@@ -13076,7 +13141,7 @@ app20.get("/download", requireAdminSession, async (c) => {
|
|
|
13076
13141
|
if (!info.isFile()) {
|
|
13077
13142
|
return c.json({ error: "Path is not a file" }, 400);
|
|
13078
13143
|
}
|
|
13079
|
-
const filename =
|
|
13144
|
+
const filename = basename9(absolute);
|
|
13080
13145
|
const mimeType = detectMimeType(absolute);
|
|
13081
13146
|
const nodeStream = createReadStream2(absolute);
|
|
13082
13147
|
const webStream = Readable2.toWeb(nodeStream);
|
|
@@ -13132,7 +13197,7 @@ async function* walkRegularFiles(dirAbsolute) {
|
|
|
13132
13197
|
const dirents = await readdir3(dirAbsolute, { withFileTypes: true });
|
|
13133
13198
|
for (const d of dirents) {
|
|
13134
13199
|
if (d.isSymbolicLink()) continue;
|
|
13135
|
-
const child =
|
|
13200
|
+
const child = join26(dirAbsolute, d.name);
|
|
13136
13201
|
if (d.isDirectory()) {
|
|
13137
13202
|
yield* walkRegularFiles(child);
|
|
13138
13203
|
continue;
|
|
@@ -13181,7 +13246,7 @@ app20.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
13181
13246
|
const info = await stat4(absolute);
|
|
13182
13247
|
if (info.isDirectory()) {
|
|
13183
13248
|
dirsWalked++;
|
|
13184
|
-
const parentAbs =
|
|
13249
|
+
const parentAbs = dirname7(absolute);
|
|
13185
13250
|
for await (const fileAbs of walkRegularFiles(absolute)) {
|
|
13186
13251
|
const within = relative4(absolute, fileAbs).split(sep6).join("/");
|
|
13187
13252
|
const fileRel = relPath === "" || relPath === "." ? within : `${relPath}/${within}`;
|
|
@@ -13192,7 +13257,7 @@ app20.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
13192
13257
|
if (over) return over;
|
|
13193
13258
|
}
|
|
13194
13259
|
} else if (info.isFile()) {
|
|
13195
|
-
const over = await addFile(absolute, info.size,
|
|
13260
|
+
const over = await addFile(absolute, info.size, basename9(absolute));
|
|
13196
13261
|
if (over) return over;
|
|
13197
13262
|
} else {
|
|
13198
13263
|
return c.json({ error: "Path is not a file or directory" }, 400);
|
|
@@ -13221,12 +13286,12 @@ function dataUploadCeiling() {
|
|
|
13221
13286
|
}
|
|
13222
13287
|
async function resolveUploadTarget(c, accountId, uid) {
|
|
13223
13288
|
const rawName = c.req.query("filename") ?? "";
|
|
13224
|
-
const safeName =
|
|
13289
|
+
const safeName = basename9(rawName).replace(/[\0/\\]/g, "_");
|
|
13225
13290
|
if (!safeName) return { ok: false, status: 400, error: "filename query param required" };
|
|
13226
13291
|
const rawRelpath = c.req.query("relpath") ?? "";
|
|
13227
13292
|
const relpath = rawRelpath !== "" ? rawRelpath : null;
|
|
13228
13293
|
const token = c.req.query("token") ?? "";
|
|
13229
|
-
const finalName = relpath ?
|
|
13294
|
+
const finalName = relpath ? basename9(relpath).replace(/[\0/\\]/g, "_") : `${Date.now()}-${safeName}`;
|
|
13230
13295
|
const mimeType = (c.req.header("content-type") ?? "").split(";")[0].trim();
|
|
13231
13296
|
if (!SUPPORTED_MIME_TYPES.has(mimeType)) {
|
|
13232
13297
|
console.error(`[data-upload] op=reject-mime uid=${uid} mime="${mimeType}" token=${token} rel="${relpath ?? ""}"`);
|
|
@@ -13235,8 +13300,8 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
13235
13300
|
const rawDir = c.req.query("path") ?? "";
|
|
13236
13301
|
const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
13237
13302
|
if (!base.ok) return { ok: false, status: base.status, error: base.error };
|
|
13238
|
-
const relDir = relpath ?
|
|
13239
|
-
const destRel = relDir === "." ? base.relative :
|
|
13303
|
+
const relDir = relpath ? dirname7(relpath) : ".";
|
|
13304
|
+
const destRel = relDir === "." ? base.relative : join26(base.relative, relDir);
|
|
13240
13305
|
if (crossesForeignAccountPartition(destRel, accountId)) {
|
|
13241
13306
|
console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
13242
13307
|
return { ok: false, status: 404, error: "Not found" };
|
|
@@ -13254,8 +13319,8 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
13254
13319
|
const info = await stat4(destDir).catch(() => null);
|
|
13255
13320
|
if (!info || !info.isDirectory()) return { ok: false, status: 400, error: "Upload destination is not a directory" };
|
|
13256
13321
|
}
|
|
13257
|
-
const dataRootReal =
|
|
13258
|
-
const destDirReal =
|
|
13322
|
+
const dataRootReal = realpathSync5(DATA_ROOT);
|
|
13323
|
+
const destDirReal = realpathSync5(destDir);
|
|
13259
13324
|
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep6)) {
|
|
13260
13325
|
console.error(`[data-upload] op=path-traversal-blocked uid=${uid} requested="${destRel}" resolved="${destDirReal}"`);
|
|
13261
13326
|
return { ok: false, status: 403, error: "Upload destination escapes DATA_ROOT" };
|
|
@@ -13596,7 +13661,7 @@ app20.delete("/", requireAdminSession, async (c) => {
|
|
|
13596
13661
|
console.error(`[data] account-scope-blocked endpoint="DELETE /api/admin/files" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
13597
13662
|
return c.json({ error: "Not found" }, 404);
|
|
13598
13663
|
}
|
|
13599
|
-
const base =
|
|
13664
|
+
const base = basename9(absolute);
|
|
13600
13665
|
const protection = isProtectedFromDeletion(relPath);
|
|
13601
13666
|
if (protection.protected) {
|
|
13602
13667
|
console.error(`[data] file-delete blocked path="${relPath}" reason="protected" rule="${protection.rule}"`);
|
|
@@ -13612,7 +13677,7 @@ app20.delete("/", requireAdminSession, async (c) => {
|
|
|
13612
13677
|
}
|
|
13613
13678
|
const dot = base.lastIndexOf(".");
|
|
13614
13679
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
13615
|
-
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ?
|
|
13680
|
+
const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join26(dirname7(absolute), `${stem}.meta.json`) : null;
|
|
13616
13681
|
await unlink2(absolute);
|
|
13617
13682
|
if (sidecarPath) {
|
|
13618
13683
|
try {
|
|
@@ -13708,8 +13773,8 @@ app20.post("/rename", requireAdminSession, async (c) => {
|
|
|
13708
13773
|
console.error(`[data] file-rename blocked path="${src.relative}" reason="protected"`);
|
|
13709
13774
|
return c.json({ error: "Protected entry \u2014 refusing to rename" }, 403);
|
|
13710
13775
|
}
|
|
13711
|
-
const destAbs = resolve21(
|
|
13712
|
-
const newRel = `${
|
|
13776
|
+
const destAbs = resolve21(dirname7(src.absolute), newName);
|
|
13777
|
+
const newRel = `${dirname7(src.relative)}/${newName}`.replace(/^\.\//, "");
|
|
13713
13778
|
if (isProtectedFromRename(newRel)) {
|
|
13714
13779
|
console.error(`[data] file-rename blocked path="${newRel}" reason="protected-target"`);
|
|
13715
13780
|
return c.json({ error: "That name is reserved" }, 403);
|
|
@@ -15840,7 +15905,7 @@ var graph_default_view_default = app26;
|
|
|
15840
15905
|
|
|
15841
15906
|
// server/routes/admin/sidebar-artefacts.ts
|
|
15842
15907
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
15843
|
-
import { resolve as resolve22, relative as relative5, isAbsolute as isAbsolute2, sep as sep7, basename as
|
|
15908
|
+
import { resolve as resolve22, relative as relative5, isAbsolute as isAbsolute2, sep as sep7, basename as basename10 } from "path";
|
|
15844
15909
|
import { existsSync as existsSync24 } from "fs";
|
|
15845
15910
|
var LIMIT = 50;
|
|
15846
15911
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
@@ -15893,7 +15958,7 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
15893
15958
|
const modifiedAt = r.get("modifiedAt") ?? "";
|
|
15894
15959
|
return {
|
|
15895
15960
|
id: `account-file:${relativePath}`,
|
|
15896
|
-
name: displayName ??
|
|
15961
|
+
name: displayName ?? basename10(relativePath),
|
|
15897
15962
|
kind: "account-file",
|
|
15898
15963
|
updatedAt: modifiedAt,
|
|
15899
15964
|
mimeType,
|
|
@@ -16277,6 +16342,31 @@ app32.post("/", requireAdminSession, async (c) => {
|
|
|
16277
16342
|
console.log(
|
|
16278
16343
|
`[chat-spawn] op=acquired spawnReqId=${spawnReqId} pid=${parsed?.spawnedPid ?? "none"} sessionId=${plan.sessionId}`
|
|
16279
16344
|
);
|
|
16345
|
+
if (plan.kind === "new") {
|
|
16346
|
+
const convAccountId = plan.payload.targetAccountId ?? accountId;
|
|
16347
|
+
if (adminUserId && convAccountId) {
|
|
16348
|
+
try {
|
|
16349
|
+
const ensured = await createNewAdminConversation(
|
|
16350
|
+
adminUserId,
|
|
16351
|
+
convAccountId,
|
|
16352
|
+
`session:${plan.sessionId}`,
|
|
16353
|
+
authenticatedName,
|
|
16354
|
+
plan.sessionId
|
|
16355
|
+
);
|
|
16356
|
+
console.log(
|
|
16357
|
+
`[chat-spawn] op=conversation-ensured spawnReqId=${spawnReqId} sessionId=${plan.sessionId} created=${ensured !== null}`
|
|
16358
|
+
);
|
|
16359
|
+
} catch (err) {
|
|
16360
|
+
console.error(
|
|
16361
|
+
`[chat-spawn] op=conversation-ensure-failed spawnReqId=${spawnReqId} sessionId=${plan.sessionId} err=${err instanceof Error ? err.message : String(err)}`
|
|
16362
|
+
);
|
|
16363
|
+
}
|
|
16364
|
+
} else {
|
|
16365
|
+
console.error(
|
|
16366
|
+
`[chat-spawn] op=conversation-ensure-skipped spawnReqId=${spawnReqId} sessionId=${plan.sessionId} reason=missing-${!adminUserId ? "userId" : "accountId"}`
|
|
16367
|
+
);
|
|
16368
|
+
}
|
|
16369
|
+
}
|
|
16280
16370
|
console.log(`[chat-spawn] op=navigate spawnReqId=${spawnReqId} target=${target}`);
|
|
16281
16371
|
console.log(`[chat-spawn] op=exit spawnReqId=${spawnReqId} outcome=bound`);
|
|
16282
16372
|
return c.json(shapeWebchatResponse(plan.sessionId, parsed));
|
|
@@ -16521,10 +16611,10 @@ var system_stats_default = app34;
|
|
|
16521
16611
|
|
|
16522
16612
|
// server/routes/admin/health.ts
|
|
16523
16613
|
import { existsSync as existsSync25, readFileSync as readFileSync27 } from "fs";
|
|
16524
|
-
import { resolve as resolve23, join as
|
|
16614
|
+
import { resolve as resolve23, join as join27 } from "path";
|
|
16525
16615
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve23(process.cwd(), "..");
|
|
16526
16616
|
var brandHostname = "maxy";
|
|
16527
|
-
var brandJsonPath =
|
|
16617
|
+
var brandJsonPath = join27(PLATFORM_ROOT6, "config", "brand.json");
|
|
16528
16618
|
if (existsSync25(brandJsonPath)) {
|
|
16529
16619
|
try {
|
|
16530
16620
|
const brand = JSON.parse(readFileSync27(brandJsonPath, "utf-8"));
|
|
@@ -17303,7 +17393,7 @@ var browser_default = app42;
|
|
|
17303
17393
|
|
|
17304
17394
|
// server/routes/admin/calendar.ts
|
|
17305
17395
|
import { existsSync as existsSync26 } from "fs";
|
|
17306
|
-
import { join as
|
|
17396
|
+
import { join as join29 } from "path";
|
|
17307
17397
|
|
|
17308
17398
|
// server/lib/calendar-ics.ts
|
|
17309
17399
|
var CRLF = "\r\n";
|
|
@@ -17403,7 +17493,7 @@ function countVEvents(ics) {
|
|
|
17403
17493
|
|
|
17404
17494
|
// server/lib/calendar-availability.ts
|
|
17405
17495
|
import { readFileSync as readFileSync28 } from "fs";
|
|
17406
|
-
import { join as
|
|
17496
|
+
import { join as join28 } from "path";
|
|
17407
17497
|
var AVAILABILITY_FILENAME = "calendar-availability.json";
|
|
17408
17498
|
var REQUIRED_KEYS = [
|
|
17409
17499
|
"timezone",
|
|
@@ -17412,7 +17502,7 @@ var REQUIRED_KEYS = [
|
|
|
17412
17502
|
"weekly"
|
|
17413
17503
|
];
|
|
17414
17504
|
function readAvailabilityConfig(accountDir) {
|
|
17415
|
-
const path2 =
|
|
17505
|
+
const path2 = join28(accountDir, AVAILABILITY_FILENAME);
|
|
17416
17506
|
let raw;
|
|
17417
17507
|
try {
|
|
17418
17508
|
raw = readFileSync28(path2, "utf-8");
|
|
@@ -17774,7 +17864,7 @@ app43.get("/booking-link", requireAdminSession, (c) => {
|
|
|
17774
17864
|
console.error('[calendar] op=booking-link-fail err="no account configured"');
|
|
17775
17865
|
return c.json({ bookingDomain: null });
|
|
17776
17866
|
}
|
|
17777
|
-
if (!existsSync26(
|
|
17867
|
+
if (!existsSync26(join29(account.accountDir, AVAILABILITY_FILENAME))) {
|
|
17778
17868
|
console.log("[calendar] op=booking-link bookingDomain=none source=availability-config");
|
|
17779
17869
|
return c.json({ bookingDomain: null });
|
|
17780
17870
|
}
|
|
@@ -18065,7 +18155,7 @@ app47.route("/request-magic-link", request_magic_link_default);
|
|
|
18065
18155
|
var access_default = app47;
|
|
18066
18156
|
|
|
18067
18157
|
// server/routes/sites.ts
|
|
18068
|
-
import { existsSync as existsSync27, readFileSync as readFileSync29, realpathSync as
|
|
18158
|
+
import { existsSync as existsSync27, readFileSync as readFileSync29, realpathSync as realpathSync6, statSync as statSync11 } from "fs";
|
|
18069
18159
|
import { resolve as resolve25 } from "path";
|
|
18070
18160
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
18071
18161
|
var MIME = {
|
|
@@ -18157,8 +18247,8 @@ app48.get("/:rel{.*}", (c) => {
|
|
|
18157
18247
|
let realPath;
|
|
18158
18248
|
let realRoot;
|
|
18159
18249
|
try {
|
|
18160
|
-
realPath =
|
|
18161
|
-
realRoot =
|
|
18250
|
+
realPath = realpathSync6(filePath);
|
|
18251
|
+
realRoot = realpathSync6(rootDir);
|
|
18162
18252
|
} catch {
|
|
18163
18253
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
18164
18254
|
return c.text("Not found", 404);
|
|
@@ -18206,7 +18296,7 @@ var sites_default = app48;
|
|
|
18206
18296
|
// app/lib/visitor-token.ts
|
|
18207
18297
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
18208
18298
|
import { mkdirSync as mkdirSync6, readFileSync as readFileSync30, writeFileSync as writeFileSync11 } from "fs";
|
|
18209
|
-
import { dirname as
|
|
18299
|
+
import { dirname as dirname8 } from "path";
|
|
18210
18300
|
var TOKEN_PREFIX = "v1.";
|
|
18211
18301
|
var SECRET_BYTES = 32;
|
|
18212
18302
|
var DEFAULT_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -18223,7 +18313,7 @@ function getSecret() {
|
|
|
18223
18313
|
}
|
|
18224
18314
|
const fresh = randomBytes(SECRET_BYTES).toString("hex");
|
|
18225
18315
|
try {
|
|
18226
|
-
mkdirSync6(
|
|
18316
|
+
mkdirSync6(dirname8(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
18227
18317
|
writeFileSync11(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
18228
18318
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
18229
18319
|
} catch {
|
|
@@ -18282,7 +18372,7 @@ var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
|
18282
18372
|
|
|
18283
18373
|
// app/lib/brand-config.ts
|
|
18284
18374
|
import { existsSync as existsSync28, readFileSync as readFileSync31 } from "fs";
|
|
18285
|
-
import { join as
|
|
18375
|
+
import { join as join30 } from "path";
|
|
18286
18376
|
var cached2 = null;
|
|
18287
18377
|
var cachedAttempted = false;
|
|
18288
18378
|
function readBrandConfig() {
|
|
@@ -18290,7 +18380,7 @@ function readBrandConfig() {
|
|
|
18290
18380
|
cachedAttempted = true;
|
|
18291
18381
|
const platformRoot3 = process.env.MAXY_PLATFORM_ROOT;
|
|
18292
18382
|
if (!platformRoot3) return null;
|
|
18293
|
-
const brandPath =
|
|
18383
|
+
const brandPath = join30(platformRoot3, "config", "brand.json");
|
|
18294
18384
|
if (!existsSync28(brandPath)) return null;
|
|
18295
18385
|
try {
|
|
18296
18386
|
cached2 = JSON.parse(readFileSync31(brandPath, "utf-8"));
|
|
@@ -19331,7 +19421,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
19331
19421
|
|
|
19332
19422
|
// app/lib/migrate-uploads.ts
|
|
19333
19423
|
import { mkdir as mkdir5, readdir as readdir5, rename as rename2, rm as rm3 } from "fs/promises";
|
|
19334
|
-
import { dirname as
|
|
19424
|
+
import { dirname as dirname9, relative as relative6, resolve as resolve28 } from "path";
|
|
19335
19425
|
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;
|
|
19336
19426
|
async function walkFiles(dir) {
|
|
19337
19427
|
const out = [];
|
|
@@ -19363,7 +19453,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
19363
19453
|
for (const oldAbs of files) {
|
|
19364
19454
|
const suffix = relative6(srcDir, oldAbs);
|
|
19365
19455
|
const newAbs = resolve28(destDir, suffix);
|
|
19366
|
-
await mkdir5(
|
|
19456
|
+
await mkdir5(dirname9(newAbs), { recursive: true });
|
|
19367
19457
|
await rename2(oldAbs, newAbs);
|
|
19368
19458
|
moved++;
|
|
19369
19459
|
const oldRel = relative6(dataRoot, oldAbs);
|
|
@@ -19455,7 +19545,7 @@ async function migrateUploads(opts = {}) {
|
|
|
19455
19545
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
19456
19546
|
import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as writeFile4, unlink as unlink3 } from "fs/promises";
|
|
19457
19547
|
import { existsSync as existsSync30 } from "fs";
|
|
19458
|
-
import { join as
|
|
19548
|
+
import { join as join31 } from "path";
|
|
19459
19549
|
var ADMIN_ROLE2 = "admin";
|
|
19460
19550
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
19461
19551
|
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;
|
|
@@ -19500,7 +19590,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
19500
19590
|
}
|
|
19501
19591
|
for (const slug of slugs) {
|
|
19502
19592
|
if (!slug.isDirectory()) continue;
|
|
19503
|
-
const slugDir =
|
|
19593
|
+
const slugDir = join31(projectsRoot, slug.name);
|
|
19504
19594
|
let entries;
|
|
19505
19595
|
try {
|
|
19506
19596
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -19509,9 +19599,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
19509
19599
|
}
|
|
19510
19600
|
for (const entry of entries) {
|
|
19511
19601
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
19512
|
-
out.push(
|
|
19602
|
+
out.push(join31(slugDir, entry.name));
|
|
19513
19603
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
19514
|
-
const subDir =
|
|
19604
|
+
const subDir = join31(slugDir, entry.name);
|
|
19515
19605
|
let subs;
|
|
19516
19606
|
try {
|
|
19517
19607
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -19519,7 +19609,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
19519
19609
|
continue;
|
|
19520
19610
|
}
|
|
19521
19611
|
for (const s of subs) {
|
|
19522
|
-
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(
|
|
19612
|
+
if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join31(subDir, s.name));
|
|
19523
19613
|
}
|
|
19524
19614
|
}
|
|
19525
19615
|
}
|
|
@@ -19531,7 +19621,7 @@ function shortId(path2) {
|
|
|
19531
19621
|
return base.slice(0, 8);
|
|
19532
19622
|
}
|
|
19533
19623
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
19534
|
-
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ?
|
|
19624
|
+
const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join31(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
|
|
19535
19625
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
19536
19626
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
19537
19627
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -21439,9 +21529,9 @@ function buildTelegramSpawnRequest(input) {
|
|
|
21439
21529
|
}
|
|
21440
21530
|
|
|
21441
21531
|
// app/lib/telegram/outbound/send-document.ts
|
|
21442
|
-
import { realpathSync as
|
|
21532
|
+
import { realpathSync as realpathSync7 } from "fs";
|
|
21443
21533
|
import { readFile as readFile7, stat as stat7 } from "fs/promises";
|
|
21444
|
-
import { resolve as resolve29, basename as
|
|
21534
|
+
import { resolve as resolve29, basename as basename11 } from "path";
|
|
21445
21535
|
var TAG35 = "[telegram:outbound]";
|
|
21446
21536
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
21447
21537
|
async function sendTelegramDocument(input) {
|
|
@@ -21455,8 +21545,8 @@ async function sendTelegramDocument(input) {
|
|
|
21455
21545
|
const accountDir = resolve29(platformRoot3, "..", "data/accounts", maxyAccountId);
|
|
21456
21546
|
let resolvedPath;
|
|
21457
21547
|
try {
|
|
21458
|
-
resolvedPath =
|
|
21459
|
-
const accountResolved =
|
|
21548
|
+
resolvedPath = realpathSync7(filePath);
|
|
21549
|
+
const accountResolved = realpathSync7(accountDir);
|
|
21460
21550
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
21461
21551
|
console.error(`${TAG35} document REJECTED reason=outside_account_directory`);
|
|
21462
21552
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
@@ -21478,7 +21568,7 @@ async function sendTelegramDocument(input) {
|
|
|
21478
21568
|
error: `File exceeds 50 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB)`
|
|
21479
21569
|
};
|
|
21480
21570
|
}
|
|
21481
|
-
const filename =
|
|
21571
|
+
const filename = basename11(resolvedPath);
|
|
21482
21572
|
const buffer = Buffer.from(await readFile7(resolvedPath));
|
|
21483
21573
|
const form = new FormData();
|
|
21484
21574
|
form.append("chat_id", String(chatId));
|
|
@@ -21588,12 +21678,12 @@ function startTelegramNativeFileFollower(input) {
|
|
|
21588
21678
|
}
|
|
21589
21679
|
|
|
21590
21680
|
// server/telegram-descriptor.ts
|
|
21591
|
-
import { resolve as resolve30, join as
|
|
21681
|
+
import { resolve as resolve30, join as join32 } from "path";
|
|
21592
21682
|
function telegramGatewayUrl() {
|
|
21593
21683
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
21594
21684
|
}
|
|
21595
21685
|
function telegramServerPath() {
|
|
21596
|
-
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ??
|
|
21686
|
+
return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ?? join32(__dirname, ".."), "services/telegram-channel/dist/server.js");
|
|
21597
21687
|
}
|
|
21598
21688
|
|
|
21599
21689
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
@@ -22054,7 +22144,7 @@ function clientFrom(c) {
|
|
|
22054
22144
|
);
|
|
22055
22145
|
}
|
|
22056
22146
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
22057
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
22147
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join33(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
22058
22148
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
22059
22149
|
if (BRAND_JSON_PATH && !existsSync32(BRAND_JSON_PATH)) {
|
|
22060
22150
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -22093,7 +22183,7 @@ var brandLoginOpts = {
|
|
|
22093
22183
|
appleTouchIconPath: brandAppIcon512Path,
|
|
22094
22184
|
themeColor: BRAND.defaultColors?.primary
|
|
22095
22185
|
};
|
|
22096
|
-
var ALIAS_DOMAINS_PATH =
|
|
22186
|
+
var ALIAS_DOMAINS_PATH = join33(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
22097
22187
|
function loadAliasDomains() {
|
|
22098
22188
|
try {
|
|
22099
22189
|
if (!existsSync32(ALIAS_DOMAINS_PATH)) return null;
|
|
@@ -22125,7 +22215,7 @@ var app54 = new Hono();
|
|
|
22125
22215
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
22126
22216
|
var waGateway = new WaGateway({
|
|
22127
22217
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
22128
|
-
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve32(process.env.MAXY_PLATFORM_ROOT ??
|
|
22218
|
+
serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve32(process.env.MAXY_PLATFORM_ROOT ?? join33(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
|
|
22129
22219
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
22130
22220
|
// account + path validation here and funnel through the shared send core.
|
|
22131
22221
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -22141,7 +22231,7 @@ var waGateway = new WaGateway({
|
|
|
22141
22231
|
caption,
|
|
22142
22232
|
accountId,
|
|
22143
22233
|
maxyAccountId,
|
|
22144
|
-
platformRoot: resolve32(process.env.MAXY_PLATFORM_ROOT ??
|
|
22234
|
+
platformRoot: resolve32(process.env.MAXY_PLATFORM_ROOT ?? join33(__dirname, ".."))
|
|
22145
22235
|
});
|
|
22146
22236
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
22147
22237
|
},
|
|
@@ -22745,7 +22835,7 @@ var SW_SOURCE = (() => {
|
|
|
22745
22835
|
function readInstalledVersion() {
|
|
22746
22836
|
try {
|
|
22747
22837
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
22748
|
-
const versionFile =
|
|
22838
|
+
const versionFile = join33(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
22749
22839
|
if (!existsSync32(versionFile)) return "unknown";
|
|
22750
22840
|
const content = readFileSync33(versionFile, "utf-8").trim();
|
|
22751
22841
|
return content || "unknown";
|
|
@@ -22805,11 +22895,11 @@ ${clientErrorReporterScript}
|
|
|
22805
22895
|
return html;
|
|
22806
22896
|
}
|
|
22807
22897
|
function loadBrandingCache(agentSlug) {
|
|
22808
|
-
const configDir2 =
|
|
22898
|
+
const configDir2 = join33(homedir3(), BRAND.configDir);
|
|
22809
22899
|
try {
|
|
22810
22900
|
const accountId = getDefaultAccountId();
|
|
22811
22901
|
if (!accountId) return null;
|
|
22812
|
-
const cachePath =
|
|
22902
|
+
const cachePath = join33(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
22813
22903
|
if (!existsSync32(cachePath)) return null;
|
|
22814
22904
|
return JSON.parse(readFileSync33(cachePath, "utf-8"));
|
|
22815
22905
|
} catch {
|
|
@@ -23029,7 +23119,7 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
|
23029
23119
|
var httpServer = serve({ fetch: app54.fetch, port, hostname });
|
|
23030
23120
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
23031
23121
|
{
|
|
23032
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
23122
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join33(__dirname, "..");
|
|
23033
23123
|
const reconcileScript = resolve32(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
23034
23124
|
const RECONCILE_INTERVAL_MS = 12e4;
|
|
23035
23125
|
const runReconcile = () => {
|
|
@@ -23051,7 +23141,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
23051
23141
|
loop.unref();
|
|
23052
23142
|
}
|
|
23053
23143
|
{
|
|
23054
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
23144
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join33(__dirname, "..");
|
|
23055
23145
|
const auditScript = resolve32(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
23056
23146
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
23057
23147
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
@@ -23256,7 +23346,7 @@ try {
|
|
|
23256
23346
|
} catch (err) {
|
|
23257
23347
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
23258
23348
|
}
|
|
23259
|
-
var configDirForWhatsApp =
|
|
23349
|
+
var configDirForWhatsApp = basename12(MAXY_DIR) || ".maxy";
|
|
23260
23350
|
var bootAccount = resolveAccount();
|
|
23261
23351
|
if (bootAccount) {
|
|
23262
23352
|
migrateRemovedConfigKeys(bootAccount.accountDir);
|
|
@@ -23318,7 +23408,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
23318
23408
|
}
|
|
23319
23409
|
init({
|
|
23320
23410
|
configDir: configDirForWhatsApp,
|
|
23321
|
-
platformRoot: resolve32(process.env.MAXY_PLATFORM_ROOT ??
|
|
23411
|
+
platformRoot: resolve32(process.env.MAXY_PLATFORM_ROOT ?? join33(__dirname, "..")),
|
|
23322
23412
|
accountConfig: bootAccountConfig,
|
|
23323
23413
|
onMessage: async (msg) => {
|
|
23324
23414
|
if (msg.isOwnerMirror) {
|