@rubytech/create-maxy-code 0.1.371 → 0.1.373
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/lib/models/dist/index.d.ts +1 -1
- package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
- package/payload/platform/lib/models/dist/index.js +2 -2
- package/payload/platform/lib/models/dist/index.js.map +1 -1
- package/payload/platform/lib/models/src/index.ts +2 -2
- package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +5 -3
- package/payload/platform/plugins/admin/skills/plugin-management/SKILL.md +1 -1
- package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +2 -2
- package/payload/platform/plugins/docs/references/admin-ui.md +2 -2
- 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/scripts/check-no-esm-require.mjs +5 -0
- package/payload/platform/services/claude-session-manager/dist/http-server.js +1 -1
- package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
- 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/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/platform/templates/specialists/agents/data-manager.md +1 -1
- package/payload/platform/templates/specialists/agents/personal-assistant.md +1 -1
- package/payload/platform/templates/specialists/agents/project-manager.md +1 -1
- package/payload/premium-plugins/writer-craft/agents/writer-craft--manuscript-reviewer.md +1 -1
- package/payload/server/public/assets/{AdminLoginScreens-zXJJq-wN.js → AdminLoginScreens-CGTA9noi.js} +1 -1
- package/payload/server/public/assets/AdminShell-CNwb23_A.js +1 -0
- package/payload/server/public/assets/{Checkbox-BO0J7hn7.js → Checkbox-BagcrE4Q.js} +1 -1
- package/payload/server/public/assets/OperatorConversations-BX9t3jgm.css +1 -0
- package/payload/server/public/assets/{admin-B5blbG0q.js → admin-CodAEpgQ.js} +1 -1
- package/payload/server/public/assets/{browser-Cc38Ih6f.js → browser-CRTlI7ck.js} +1 -1
- package/payload/server/public/assets/{calendar-ZY9A8F44.js → calendar-BBEivUAw.js} +1 -1
- package/payload/server/public/assets/chat-r1qKuzHk.js +1 -0
- package/payload/server/public/assets/{data-DuoDaO1z.js → data-BkY0bFYS.js} +1 -1
- package/payload/server/public/assets/{graph-CSOYoN0i.js → graph-HoHcI7qv.js} +1 -1
- package/payload/server/public/assets/{graph-labels-DdiX7_Ot.js → graph-labels-BJfK0tbH.js} +1 -1
- package/payload/server/public/assets/{operator-Cvci_FDA.js → operator-5wtImBoF.js} +1 -1
- package/payload/server/public/assets/page-CzTgPTp3.js +32 -0
- package/payload/server/public/assets/public-CUopv7Ro.js +1 -0
- package/payload/server/public/assets/{rotate-ccw-Dahm1S_V.js → rotate-ccw-DttFB1nY.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 +253 -197
- package/payload/server/public/assets/AdminShell-BA24dbW1.js +0 -1
- package/payload/server/public/assets/OperatorConversations-BA1bRX1_.css +0 -1
- package/payload/server/public/assets/chat-zZuu4bcb.js +0 -1
- package/payload/server/public/assets/page-6HQSRX5P.js +0 -32
- package/payload/server/public/assets/public-DG-f7MFU.js +0 -1
- /package/payload/server/public/assets/{OperatorConversations-Cf-ejiJO.js → OperatorConversations-CivR0bnD.js} +0 -0
package/payload/server/server.js
CHANGED
|
@@ -1306,7 +1306,7 @@ var serveStatic = (options = { root: "" }) => {
|
|
|
1306
1306
|
// server/index.ts
|
|
1307
1307
|
import { readFileSync as readFileSync33, existsSync as existsSync32, watchFile } from "fs";
|
|
1308
1308
|
import { spawn as spawn3 } from "child_process";
|
|
1309
|
-
import { resolve as resolve32, join as
|
|
1309
|
+
import { resolve as resolve32, join as join33, basename as basename12 } from "path";
|
|
1310
1310
|
import { homedir as homedir3 } from "os";
|
|
1311
1311
|
import { monitorEventLoopDelay } from "perf_hooks";
|
|
1312
1312
|
|
|
@@ -3736,6 +3736,14 @@ var TAG12 = "[stt]";
|
|
|
3736
3736
|
var WHISPER_BINARY = process.env.WHISPER_BINARY ?? "/opt/whisper.cpp/build/bin/whisper-cli";
|
|
3737
3737
|
var WHISPER_MODEL = process.env.WHISPER_MODEL ?? "/opt/whisper.cpp/models/ggml-base.bin";
|
|
3738
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
|
+
}
|
|
3739
3747
|
async function transcribe(audioPath, mimetype) {
|
|
3740
3748
|
const startMs = Date.now();
|
|
3741
3749
|
let audioBytes = 0;
|
|
@@ -3777,12 +3785,10 @@ async function transcribe(audioPath, mimetype) {
|
|
|
3777
3785
|
wavPath,
|
|
3778
3786
|
"--no-timestamps",
|
|
3779
3787
|
"-l",
|
|
3780
|
-
"auto"
|
|
3781
|
-
"--print-special",
|
|
3782
|
-
"false"
|
|
3788
|
+
"auto"
|
|
3783
3789
|
], { timeout: WHISPER_TIMEOUT_MS, maxBuffer: 10 * 1024 * 1024 });
|
|
3784
|
-
const text = stdout.trim();
|
|
3785
3790
|
const durationMs = Date.now() - startMs;
|
|
3791
|
+
const { text, count: stripped } = stripSpecialTokens(stdout.trim());
|
|
3786
3792
|
if (!text) {
|
|
3787
3793
|
console.error(`${TAG12} failed: whisper returned empty output duration_ms=${durationMs}`);
|
|
3788
3794
|
return void 0;
|
|
@@ -3791,7 +3797,7 @@ async function transcribe(audioPath, mimetype) {
|
|
|
3791
3797
|
const language = langMatch?.[1] ?? "unknown";
|
|
3792
3798
|
const words = text.split(/\s+/).filter(Boolean).length;
|
|
3793
3799
|
console.error(
|
|
3794
|
-
`${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}`
|
|
3795
3801
|
);
|
|
3796
3802
|
return { text, language, durationMs };
|
|
3797
3803
|
} catch (err) {
|
|
@@ -4981,7 +4987,7 @@ import { resolve as resolve6, extname } from "path";
|
|
|
4981
4987
|
|
|
4982
4988
|
// app/lib/data-path.ts
|
|
4983
4989
|
import { realpathSync } from "fs";
|
|
4984
|
-
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";
|
|
4985
4991
|
var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve5(process.cwd(), "../platform");
|
|
4986
4992
|
var DATA_ROOT = resolve5(PLATFORM_ROOT4, "..", "data");
|
|
4987
4993
|
var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve5(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
|
|
@@ -5044,6 +5050,16 @@ function resolveClaudeUploadsPath(raw) {
|
|
|
5044
5050
|
}
|
|
5045
5051
|
return resolveUnderRoot(raw, CLAUDE_UPLOADS_ROOT, "CLAUDE_UPLOADS_ROOT");
|
|
5046
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
|
+
}
|
|
5047
5063
|
|
|
5048
5064
|
// app/lib/attachments.ts
|
|
5049
5065
|
function uploadsDirFor(accountId, subPath, attachmentId) {
|
|
@@ -5186,7 +5202,7 @@ async function storeComponentArtefact(accountId, attachmentId, mimeType, content
|
|
|
5186
5202
|
// app/lib/stt/voice-note.ts
|
|
5187
5203
|
import { writeFile as writeFile3, mkdtemp, rm } from "fs/promises";
|
|
5188
5204
|
import { tmpdir } from "os";
|
|
5189
|
-
import { join as
|
|
5205
|
+
import { join as join6 } from "path";
|
|
5190
5206
|
|
|
5191
5207
|
// app/lib/stt/audio-mime.ts
|
|
5192
5208
|
var AUDIO_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
@@ -5240,9 +5256,9 @@ async function transcribeVoiceNote(file, source) {
|
|
|
5240
5256
|
let tempDir;
|
|
5241
5257
|
let tempPath;
|
|
5242
5258
|
try {
|
|
5243
|
-
tempDir = await mkdtemp(
|
|
5259
|
+
tempDir = await mkdtemp(join6(tmpdir(), "voice-"));
|
|
5244
5260
|
const ext = audioExtension(mimeType);
|
|
5245
|
-
tempPath =
|
|
5261
|
+
tempPath = join6(tempDir, `recording${ext}`);
|
|
5246
5262
|
const buffer = Buffer.from(await file.arrayBuffer());
|
|
5247
5263
|
await writeFile3(tempPath, buffer);
|
|
5248
5264
|
} catch (err) {
|
|
@@ -5640,7 +5656,7 @@ ${result.result.text}` : result.result.text;
|
|
|
5640
5656
|
}
|
|
5641
5657
|
|
|
5642
5658
|
// server/routes/whatsapp.ts
|
|
5643
|
-
import { join as
|
|
5659
|
+
import { join as join9, resolve as resolve9 } from "path";
|
|
5644
5660
|
import { readdirSync as readdirSync3, readFileSync as readFileSync9, existsSync as existsSync5 } from "fs";
|
|
5645
5661
|
|
|
5646
5662
|
// app/lib/whatsapp/login.ts
|
|
@@ -5648,7 +5664,7 @@ import { randomUUID as randomUUID6 } from "crypto";
|
|
|
5648
5664
|
|
|
5649
5665
|
// app/lib/whatsapp/config-persist.ts
|
|
5650
5666
|
import { readFileSync as readFileSync8, writeFileSync as writeFileSync4, existsSync as existsSync4 } from "fs";
|
|
5651
|
-
import { resolve as resolve7, join as
|
|
5667
|
+
import { resolve as resolve7, join as join7 } from "path";
|
|
5652
5668
|
var TAG16 = "[whatsapp:config]";
|
|
5653
5669
|
function configPath(accountDir) {
|
|
5654
5670
|
return resolve7(accountDir, "account.json");
|
|
@@ -5800,7 +5816,7 @@ function setPublicAgent(accountDir, slug) {
|
|
|
5800
5816
|
if (!trimmed) {
|
|
5801
5817
|
return { ok: false, error: "Agent slug cannot be empty." };
|
|
5802
5818
|
}
|
|
5803
|
-
const agentConfigPath =
|
|
5819
|
+
const agentConfigPath = join7(accountDir, "agents", trimmed, "config.json");
|
|
5804
5820
|
if (!existsSync4(agentConfigPath)) {
|
|
5805
5821
|
return { ok: false, error: `Agent "${trimmed}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.` };
|
|
5806
5822
|
}
|
|
@@ -6184,7 +6200,7 @@ async function waitForLogin(opts) {
|
|
|
6184
6200
|
// app/lib/whatsapp/outbound/send-document.ts
|
|
6185
6201
|
import { realpathSync as realpathSync3 } from "fs";
|
|
6186
6202
|
import { readFile, stat as stat2 } from "fs/promises";
|
|
6187
|
-
import { resolve as resolve8, basename } from "path";
|
|
6203
|
+
import { resolve as resolve8, basename as basename2 } from "path";
|
|
6188
6204
|
var TAG18 = "[whatsapp:outbound]";
|
|
6189
6205
|
var WHATSAPP_DOCUMENT_MAX_BYTES = 100 * 1024 * 1024;
|
|
6190
6206
|
var lastDocumentOutboundAt = /* @__PURE__ */ new Map();
|
|
@@ -6239,7 +6255,7 @@ async function sendWhatsAppDocument(input) {
|
|
|
6239
6255
|
error: `File exceeds 100 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB)`
|
|
6240
6256
|
};
|
|
6241
6257
|
}
|
|
6242
|
-
const filename =
|
|
6258
|
+
const filename = basename2(resolvedPath);
|
|
6243
6259
|
const jid = normalizeJid2(to);
|
|
6244
6260
|
const sock = getSocket(accountId);
|
|
6245
6261
|
if (!sock) {
|
|
@@ -6374,11 +6390,11 @@ function serializeWhatsAppSchema() {
|
|
|
6374
6390
|
|
|
6375
6391
|
// app/lib/whatsapp/status-reconcile.ts
|
|
6376
6392
|
import { readdirSync as readdirSync2 } from "fs";
|
|
6377
|
-
import { join as
|
|
6393
|
+
import { join as join8 } from "path";
|
|
6378
6394
|
var TAG19 = "[whatsapp:reconcile]";
|
|
6379
6395
|
function listCredsAccountIds(credsRoot) {
|
|
6380
6396
|
try {
|
|
6381
|
-
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);
|
|
6382
6398
|
} catch {
|
|
6383
6399
|
return [];
|
|
6384
6400
|
}
|
|
@@ -6393,7 +6409,7 @@ function reconcileCredsOnDisk(opts) {
|
|
|
6393
6409
|
const entries = [];
|
|
6394
6410
|
for (const accountId of listCredsAccountIds(credsRoot)) {
|
|
6395
6411
|
if (liveAccountIds.has(accountId)) continue;
|
|
6396
|
-
const authDir =
|
|
6412
|
+
const authDir = join8(credsRoot, accountId);
|
|
6397
6413
|
const selfPhone = readSelfId(authDir).e164 ?? void 0;
|
|
6398
6414
|
const configured = accountDir ? isAccountConfigured(accountDir, accountId) : false;
|
|
6399
6415
|
console.error(
|
|
@@ -6420,7 +6436,7 @@ app2.get("/status", (c) => {
|
|
|
6420
6436
|
try {
|
|
6421
6437
|
const live = getStatus();
|
|
6422
6438
|
const liveIds = new Set(live.map((a) => a.accountId));
|
|
6423
|
-
const credsRoot =
|
|
6439
|
+
const credsRoot = join9(MAXY_DIR, "credentials", "whatsapp");
|
|
6424
6440
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
6425
6441
|
const reconciled = reconcileCredsOnDisk({ credsRoot, accountDir, liveAccountIds: liveIds });
|
|
6426
6442
|
const accounts = [...live, ...reconciled];
|
|
@@ -6441,7 +6457,7 @@ app2.post("/login/start", async (c) => {
|
|
|
6441
6457
|
if (!phone) {
|
|
6442
6458
|
return c.json({ error: 'Missing required field "phone" (E.164, e.g. +441234567890).' }, 400);
|
|
6443
6459
|
}
|
|
6444
|
-
const authDir =
|
|
6460
|
+
const authDir = join9(MAXY_DIR, "credentials", "whatsapp", accountId);
|
|
6445
6461
|
const accountDir = resolveAccount()?.accountDir ?? null;
|
|
6446
6462
|
const result = await startLogin({ accountId, authDir, phone, accountDir, force });
|
|
6447
6463
|
console.error(`${TAG20} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
|
|
@@ -6855,12 +6871,12 @@ app2.get("/group-info", async (c) => {
|
|
|
6855
6871
|
var whatsapp_default = app2;
|
|
6856
6872
|
|
|
6857
6873
|
// server/routes/whatsapp-reader.ts
|
|
6858
|
-
import { readFileSync as readFileSync13, watch, statSync as statSync4, openSync, readSync, closeSync, existsSync as existsSync7, readdirSync as readdirSync7 } from "fs";
|
|
6859
|
-
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";
|
|
6860
6876
|
|
|
6861
6877
|
// server/routes/admin/sidebar-sessions.ts
|
|
6862
6878
|
import { readdirSync as readdirSync4, readFileSync as readFileSync10, statSync as statSync2 } from "fs";
|
|
6863
|
-
import { join as
|
|
6879
|
+
import { basename as basename3, dirname, join as join10, resolve as resolve10 } from "path";
|
|
6864
6880
|
|
|
6865
6881
|
// app/lib/whatsapp-reader/select-sessions.ts
|
|
6866
6882
|
function isReaderChannelSession(role, channel) {
|
|
@@ -6909,6 +6925,14 @@ var app3 = new Hono();
|
|
|
6909
6925
|
function claudeConfigDir() {
|
|
6910
6926
|
return process.env.CLAUDE_CONFIG_DIR ?? null;
|
|
6911
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
|
+
}
|
|
6912
6936
|
function enumerateJsonls(projectsRoot) {
|
|
6913
6937
|
const out = [];
|
|
6914
6938
|
let slugs;
|
|
@@ -6919,7 +6943,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6919
6943
|
throw err;
|
|
6920
6944
|
}
|
|
6921
6945
|
for (const slug of slugs) {
|
|
6922
|
-
const slugDir =
|
|
6946
|
+
const slugDir = join10(projectsRoot, slug);
|
|
6923
6947
|
let entries;
|
|
6924
6948
|
try {
|
|
6925
6949
|
entries = readdirSync4(slugDir, { withFileTypes: true });
|
|
@@ -6930,9 +6954,9 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6930
6954
|
}
|
|
6931
6955
|
for (const entry of entries) {
|
|
6932
6956
|
if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
|
|
6933
|
-
out.push({ path:
|
|
6957
|
+
out.push({ path: join10(slugDir, entry.name), isSubagent: false, archived: false });
|
|
6934
6958
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
6935
|
-
const subDir =
|
|
6959
|
+
const subDir = join10(slugDir, entry.name);
|
|
6936
6960
|
let subEntries;
|
|
6937
6961
|
try {
|
|
6938
6962
|
subEntries = readdirSync4(subDir, { withFileTypes: true });
|
|
@@ -6943,11 +6967,11 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6943
6967
|
}
|
|
6944
6968
|
for (const sub of subEntries) {
|
|
6945
6969
|
if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
|
|
6946
|
-
out.push({ path:
|
|
6970
|
+
out.push({ path: join10(subDir, sub.name), isSubagent: true, archived: false });
|
|
6947
6971
|
}
|
|
6948
6972
|
}
|
|
6949
6973
|
} else if (entry.isDirectory() && entry.name === "archive") {
|
|
6950
|
-
const archiveDir =
|
|
6974
|
+
const archiveDir = join10(slugDir, entry.name);
|
|
6951
6975
|
let archiveEntries;
|
|
6952
6976
|
try {
|
|
6953
6977
|
archiveEntries = readdirSync4(archiveDir, { withFileTypes: true });
|
|
@@ -6958,7 +6982,7 @@ function enumerateJsonls(projectsRoot) {
|
|
|
6958
6982
|
}
|
|
6959
6983
|
for (const arc of archiveEntries) {
|
|
6960
6984
|
if (arc.isFile() && SESSION_ID_RE.test(arc.name)) {
|
|
6961
|
-
out.push({ path:
|
|
6985
|
+
out.push({ path: join10(archiveDir, arc.name), isSubagent: false, archived: true });
|
|
6962
6986
|
}
|
|
6963
6987
|
}
|
|
6964
6988
|
}
|
|
@@ -6991,7 +7015,7 @@ async function fetchLiveSessions() {
|
|
|
6991
7015
|
function loadUserTitles(accountDir) {
|
|
6992
7016
|
const out = /* @__PURE__ */ new Map();
|
|
6993
7017
|
if (!accountDir) return out;
|
|
6994
|
-
const path2 =
|
|
7018
|
+
const path2 = join10(accountDir, "session-titles.json");
|
|
6995
7019
|
let raw;
|
|
6996
7020
|
try {
|
|
6997
7021
|
raw = readFileSync10(path2, "utf8");
|
|
@@ -7131,7 +7155,7 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
7131
7155
|
console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
|
|
7132
7156
|
return c.json({ sessions: [], accountId, accounts });
|
|
7133
7157
|
}
|
|
7134
|
-
const projectsRoot =
|
|
7158
|
+
const projectsRoot = join10(configDir2, "projects");
|
|
7135
7159
|
const jsonls = enumerateJsonls(projectsRoot);
|
|
7136
7160
|
const liveSessions = await fetchLiveSessions();
|
|
7137
7161
|
const accountDir = accountId ? resolve10(ACCOUNTS_DIR, accountId) : null;
|
|
@@ -7167,7 +7191,7 @@ app3.get("/", requireAdminSession, async (c) => {
|
|
|
7167
7191
|
const pid = live ? liveSessions.get(sessionId) ?? null : null;
|
|
7168
7192
|
const resolved = resolveTitle(body, sessionId, userTitles);
|
|
7169
7193
|
titleSourceCounts[resolved.source] += 1;
|
|
7170
|
-
const metaPath =
|
|
7194
|
+
const metaPath = join10(projectDir, `${sessionId}.meta.json`);
|
|
7171
7195
|
const { bridgeIds, role, channel: sidecarChannel, personId, adminUserId, accountId: rowAccountId } = readSidecarMeta(metaPath);
|
|
7172
7196
|
if (isReaderChannelSession(role, sidecarChannel)) {
|
|
7173
7197
|
excludedChannelCount += 1;
|
|
@@ -7234,7 +7258,7 @@ var sidebar_sessions_default = app3;
|
|
|
7234
7258
|
// app/lib/admin-identity/pin-validator.ts
|
|
7235
7259
|
import { createHash } from "crypto";
|
|
7236
7260
|
import { existsSync as existsSync6, readFileSync as readFileSync11, readdirSync as readdirSync5, statSync as statSync3 } from "fs";
|
|
7237
|
-
import { join as
|
|
7261
|
+
import { join as join11 } from "path";
|
|
7238
7262
|
function hashPin(pin) {
|
|
7239
7263
|
return createHash("sha256").update(pin).digest("hex");
|
|
7240
7264
|
}
|
|
@@ -7299,7 +7323,7 @@ function resolveOperatorDisplay(userIdRes, nameRes) {
|
|
|
7299
7323
|
// app/lib/agent-errors.ts
|
|
7300
7324
|
function classifyAgentError(err) {
|
|
7301
7325
|
const msg = err instanceof Error ? err.message : String(err);
|
|
7302
|
-
if (/\b(401|authentication_error
|
|
7326
|
+
if (/\b(401|authentication_error)\b/i.test(msg)) return "auth_expired";
|
|
7303
7327
|
if (/\b(529|overloaded)\b/i.test(msg)) return "claude_overloaded";
|
|
7304
7328
|
if (/\b(404|model_not_found)\b/i.test(msg) || /issue with the selected model|may not have access to it/i.test(msg))
|
|
7305
7329
|
return "model_unavailable";
|
|
@@ -7316,6 +7340,7 @@ var CHANNEL_REPLY_DOCUMENT_TOOL = "mcp__channel__reply-document";
|
|
|
7316
7340
|
var SEND_USER_FILE_TOOL = "SendUserFile";
|
|
7317
7341
|
var CLI_MARKER_PREFIXES2 = ["<local-command-", "<command-name>", "<command-message>"];
|
|
7318
7342
|
var HARNESS_LIFECYCLE_PREFIXES = ["<task-notification>"];
|
|
7343
|
+
var CC_IMAGE_VISION_HINT = /^\[Image:[^\]]*Multiply coordinates by [\d.]+ to map to original image\.\]$/;
|
|
7319
7344
|
var COMPACT_SUMMARY_PREFIX = "This session is being continued from a previous conversation that ran out of context.";
|
|
7320
7345
|
function isCompactSummaryRow(row, content) {
|
|
7321
7346
|
return row.isCompactSummary === true || content !== null && content.startsWith(COMPACT_SUMMARY_PREFIX);
|
|
@@ -7507,6 +7532,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
7507
7532
|
if (text === null) continue;
|
|
7508
7533
|
if (CLI_MARKER_PREFIXES2.some((p) => text.startsWith(p))) continue;
|
|
7509
7534
|
if (HARNESS_LIFECYCLE_PREFIXES.some((p) => text.startsWith(p))) continue;
|
|
7535
|
+
if (CC_IMAGE_VISION_HINT.test(text)) continue;
|
|
7510
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
|
|
7511
7537
|
// `type:"user"` row whose content is the `<channel source="…">` wrapper, with no
|
|
7512
7538
|
// `isMeta`/`origin` stamp. Detect it by the wrapper so it is treated as the
|
|
@@ -7526,7 +7552,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
|
|
|
7526
7552
|
|
|
7527
7553
|
// app/lib/whatsapp-reader/enrich-attachments.ts
|
|
7528
7554
|
import { readFileSync as readFileSync12, readdirSync as readdirSync6 } from "fs";
|
|
7529
|
-
import { join as
|
|
7555
|
+
import { join as join12 } from "path";
|
|
7530
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;
|
|
7531
7557
|
function adminAttachmentIds(text) {
|
|
7532
7558
|
const ids = [];
|
|
@@ -7539,7 +7565,7 @@ function adminAttachmentIds(text) {
|
|
|
7539
7565
|
function adminAttachmentsFromText(text, uploadsBase) {
|
|
7540
7566
|
const out = [];
|
|
7541
7567
|
for (const id of adminAttachmentIds(text)) {
|
|
7542
|
-
const meta = readAttachmentMeta(
|
|
7568
|
+
const meta = readAttachmentMeta(join12(uploadsBase, id));
|
|
7543
7569
|
if (meta) out.push(meta);
|
|
7544
7570
|
}
|
|
7545
7571
|
return out;
|
|
@@ -7547,7 +7573,7 @@ function adminAttachmentsFromText(text, uploadsBase) {
|
|
|
7547
7573
|
function readSidecar(dir, attachmentId) {
|
|
7548
7574
|
let parsed;
|
|
7549
7575
|
try {
|
|
7550
|
-
parsed = JSON.parse(readFileSync12(
|
|
7576
|
+
parsed = JSON.parse(readFileSync12(join12(dir, `${attachmentId}.meta.json`), "utf8"));
|
|
7551
7577
|
} catch {
|
|
7552
7578
|
return null;
|
|
7553
7579
|
}
|
|
@@ -7576,7 +7602,7 @@ function listSessionAttachmentsInDir(dir) {
|
|
|
7576
7602
|
}
|
|
7577
7603
|
const sidecars = [];
|
|
7578
7604
|
for (const name of entries) {
|
|
7579
|
-
const sidecar = readSidecar(
|
|
7605
|
+
const sidecar = readSidecar(join12(dir, name), name);
|
|
7580
7606
|
if (sidecar) sidecars.push(sidecar);
|
|
7581
7607
|
}
|
|
7582
7608
|
sidecars.sort((a, b) => a.storedAt.localeCompare(b.storedAt));
|
|
@@ -7621,13 +7647,13 @@ var app4 = new Hono();
|
|
|
7621
7647
|
app4.get("/conversations", requireAdminSession, async (c) => {
|
|
7622
7648
|
const cfg = claudeConfigDir();
|
|
7623
7649
|
if (!cfg) return c.json({ conversations: [] });
|
|
7624
|
-
const projectsRoot =
|
|
7650
|
+
const projectsRoot = join13(cfg, "projects");
|
|
7625
7651
|
const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
|
|
7626
7652
|
const rows = [];
|
|
7627
7653
|
for (const { path: path2 } of enumerateJsonls(projectsRoot)) {
|
|
7628
|
-
const sessionId =
|
|
7629
|
-
const projectDir =
|
|
7630
|
-
const meta = readSidecarMeta(
|
|
7654
|
+
const sessionId = basename4(path2).replace(/\.jsonl$/, "");
|
|
7655
|
+
const projectDir = dirname2(path2);
|
|
7656
|
+
const meta = readSidecarMeta(join13(projectDir, `${sessionId}.meta.json`));
|
|
7631
7657
|
if (!isReaderChannelSession(meta.role, meta.channel)) continue;
|
|
7632
7658
|
let body = "";
|
|
7633
7659
|
try {
|
|
@@ -7715,11 +7741,30 @@ function resumeOffset(lastEventId, fileEnd) {
|
|
|
7715
7741
|
if (!Number.isFinite(n) || n < 0) return 0;
|
|
7716
7742
|
return Math.min(n, fileEnd);
|
|
7717
7743
|
}
|
|
7718
|
-
function enrichDownloads(turn) {
|
|
7744
|
+
function enrichDownloads(turn, scratchpadRoot) {
|
|
7719
7745
|
if (turn.kind !== "agent-file") return turn;
|
|
7746
|
+
let scratchpadReal = null;
|
|
7747
|
+
try {
|
|
7748
|
+
scratchpadReal = realpathSync4(scratchpadRoot);
|
|
7749
|
+
} catch {
|
|
7750
|
+
scratchpadReal = null;
|
|
7751
|
+
}
|
|
7720
7752
|
const downloads = turn.files.map((f) => {
|
|
7721
|
-
const
|
|
7722
|
-
|
|
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;
|
|
7723
7768
|
});
|
|
7724
7769
|
return { ...turn, downloads };
|
|
7725
7770
|
}
|
|
@@ -7764,7 +7809,7 @@ function openTaskKey(turns) {
|
|
|
7764
7809
|
}
|
|
7765
7810
|
function readSubagentMeta(dir, hex) {
|
|
7766
7811
|
try {
|
|
7767
|
-
const m = JSON.parse(readFileSync13(
|
|
7812
|
+
const m = JSON.parse(readFileSync13(join13(dir, `agent-${hex}.meta.json`), "utf8"));
|
|
7768
7813
|
if (typeof m.agentType === "string" && typeof m.description === "string" && typeof m.toolUseId === "string") {
|
|
7769
7814
|
return { agentType: m.agentType, description: m.description, toolUseId: m.toolUseId };
|
|
7770
7815
|
}
|
|
@@ -7796,7 +7841,7 @@ function runActivityTick(c) {
|
|
|
7796
7841
|
let size = 0;
|
|
7797
7842
|
let mtimeMs = 0;
|
|
7798
7843
|
try {
|
|
7799
|
-
const st = statSync4(
|
|
7844
|
+
const st = statSync4(join13(c.subagentsDir, name));
|
|
7800
7845
|
size = st.size;
|
|
7801
7846
|
mtimeMs = st.mtimeMs;
|
|
7802
7847
|
} catch {
|
|
@@ -7841,14 +7886,15 @@ app4.get("/stream", requireAdminSession, (c) => {
|
|
|
7841
7886
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
7842
7887
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
7843
7888
|
const cfg = claudeConfigDir();
|
|
7844
|
-
const projectsRoot = cfg ? resolve11(
|
|
7889
|
+
const projectsRoot = cfg ? resolve11(join13(cfg, "projects")) : null;
|
|
7845
7890
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
7846
7891
|
return c.json({ error: "bad session reference" }, 400);
|
|
7847
7892
|
}
|
|
7848
|
-
const jsonlPath = resolve11(
|
|
7893
|
+
const jsonlPath = resolve11(join13(projectDir, `${sessionId}.jsonl`));
|
|
7849
7894
|
if (!jsonlPath.startsWith(projectsRoot + sep3)) {
|
|
7850
7895
|
return c.json({ error: "bad session reference" }, 400);
|
|
7851
7896
|
}
|
|
7897
|
+
const scratchpadRoot = sessionScratchpadRoot(projectDir, sessionId);
|
|
7852
7898
|
const encoder = new TextEncoder();
|
|
7853
7899
|
const send = (controller, turn, id) => controller.enqueue(encoder.encode(`id: ${id}
|
|
7854
7900
|
data: ${JSON.stringify(turn)}
|
|
@@ -7869,7 +7915,7 @@ data: ${JSON.stringify(turn)}
|
|
|
7869
7915
|
let offset = resumeOffset(lastEventId, fileEnd0);
|
|
7870
7916
|
console.log(`[wa-stream] op=open conn=${connId} sessionId=${sessionId} channel=reader resume=${offset}`);
|
|
7871
7917
|
const sessionKey = c.req.query("session_key") ?? "";
|
|
7872
|
-
const subagentsDir = resolve11(
|
|
7918
|
+
const subagentsDir = resolve11(join13(projectDir, sessionId, "subagents"));
|
|
7873
7919
|
console.log(
|
|
7874
7920
|
`[webchat-activity] op=watch-subagents key=${sessionKey} dir=${subagentsDir} exists=${existsSync7(subagentsDir)}`
|
|
7875
7921
|
);
|
|
@@ -7896,7 +7942,7 @@ data: ${JSON.stringify(obj)}
|
|
|
7896
7942
|
offset = nextOffset;
|
|
7897
7943
|
let n = 0;
|
|
7898
7944
|
for (const turn of parseTranscript(lines, queuedPendingSuppress)) {
|
|
7899
|
-
send(controller, enrichAdminAttachments(enrichDownloads(turn)), offset);
|
|
7945
|
+
send(controller, enrichAdminAttachments(enrichDownloads(turn, scratchpadRoot)), offset);
|
|
7900
7946
|
actx.lastParentTurns.push(turn);
|
|
7901
7947
|
if (turn.kind === "agent-error") {
|
|
7902
7948
|
console.log(`[wa-stream] op=agent-error conn=${connId} sessionId=${sessionId} code=${turn.code} source=jsonl`);
|
|
@@ -7916,7 +7962,7 @@ data: ${JSON.stringify(obj)}
|
|
|
7916
7962
|
offset = end;
|
|
7917
7963
|
let n = 0;
|
|
7918
7964
|
for (const turn of parseTranscript(buf.toString("utf8").split("\n"), queuedPendingSuppress)) {
|
|
7919
|
-
send(controller, enrichAdminAttachments(enrichDownloads(turn)), offset);
|
|
7965
|
+
send(controller, enrichAdminAttachments(enrichDownloads(turn, scratchpadRoot)), offset);
|
|
7920
7966
|
actx.lastParentTurns.push(turn);
|
|
7921
7967
|
if (turn.kind === "agent-error") {
|
|
7922
7968
|
console.log(`[wa-stream] op=agent-error conn=${connId} sessionId=${sessionId} code=${turn.code} source=jsonl`);
|
|
@@ -7990,7 +8036,7 @@ app4.get("/directives", requireAdminSession, (c) => {
|
|
|
7990
8036
|
const pid = Number(pidPart);
|
|
7991
8037
|
let len = 0;
|
|
7992
8038
|
try {
|
|
7993
|
-
len = statSync4(
|
|
8039
|
+
len = statSync4(join13(dir, name)).size;
|
|
7994
8040
|
} catch {
|
|
7995
8041
|
}
|
|
7996
8042
|
return { name, secs, pid, ts: Number.isFinite(secs) ? new Date(secs * 1e3).toISOString() : null, len };
|
|
@@ -8005,7 +8051,7 @@ app4.get("/directive", requireAdminSession, (c) => {
|
|
|
8005
8051
|
}
|
|
8006
8052
|
const dir = directiveStoreDir(sessionId);
|
|
8007
8053
|
if (!dir) return c.json({ error: "no account" }, 404);
|
|
8008
|
-
const path2 = resolve11(
|
|
8054
|
+
const path2 = resolve11(join13(dir, name));
|
|
8009
8055
|
if (!path2.startsWith(dir + sep3)) return c.json({ error: "bad reference" }, 400);
|
|
8010
8056
|
let body;
|
|
8011
8057
|
try {
|
|
@@ -8019,7 +8065,7 @@ var whatsapp_reader_default = app4;
|
|
|
8019
8065
|
|
|
8020
8066
|
// server/routes/public-reader.ts
|
|
8021
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";
|
|
8022
|
-
import { basename as
|
|
8068
|
+
import { basename as basename5, dirname as dirname3, join as join14, resolve as resolve12, sep as sep4 } from "path";
|
|
8023
8069
|
|
|
8024
8070
|
// app/lib/whatsapp-reader/delivered-kinds.ts
|
|
8025
8071
|
var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -8093,10 +8139,10 @@ function enumeratePublicRows() {
|
|
|
8093
8139
|
const cfg = claudeConfigDir();
|
|
8094
8140
|
if (!cfg) return [];
|
|
8095
8141
|
const rows = [];
|
|
8096
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
8097
|
-
const sessionId =
|
|
8098
|
-
const projectDir =
|
|
8099
|
-
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`));
|
|
8100
8146
|
rows.push({
|
|
8101
8147
|
sessionId,
|
|
8102
8148
|
projectDir,
|
|
@@ -8172,15 +8218,15 @@ app5.get("/stream", (c) => {
|
|
|
8172
8218
|
const sessionId = c.req.query("sessionId") ?? "";
|
|
8173
8219
|
const projectDir = c.req.query("projectDir") ?? "";
|
|
8174
8220
|
const cfg = claudeConfigDir();
|
|
8175
|
-
const projectsRoot = cfg ? resolve12(
|
|
8221
|
+
const projectsRoot = cfg ? resolve12(join14(cfg, "projects")) : null;
|
|
8176
8222
|
if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
|
|
8177
8223
|
return c.json({ error: "bad session reference" }, 400);
|
|
8178
8224
|
}
|
|
8179
|
-
const jsonlPath = resolve12(
|
|
8225
|
+
const jsonlPath = resolve12(join14(projectDir, `${sessionId}.jsonl`));
|
|
8180
8226
|
if (!jsonlPath.startsWith(projectsRoot + sep4)) {
|
|
8181
8227
|
return c.json({ error: "bad session reference" }, 400);
|
|
8182
8228
|
}
|
|
8183
|
-
const meta = readSidecarMeta(
|
|
8229
|
+
const meta = readSidecarMeta(join14(projectDir, `${sessionId}.meta.json`));
|
|
8184
8230
|
const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
|
|
8185
8231
|
const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
|
|
8186
8232
|
if (!(isPublicWebchat && owns)) {
|
|
@@ -8313,17 +8359,17 @@ app5.get("/attachment/:attachmentId", (c) => {
|
|
|
8313
8359
|
var public_reader_default = app5;
|
|
8314
8360
|
|
|
8315
8361
|
// server/routes/webchat.ts
|
|
8316
|
-
import { basename as
|
|
8317
|
-
import { join as
|
|
8362
|
+
import { basename as basename6, dirname as dirname4 } from "path";
|
|
8363
|
+
import { join as join17 } from "path";
|
|
8318
8364
|
import { existsSync as existsSync9, readdirSync as readdirSync10, readFileSync as readFileSync17, renameSync as renameSync3, statSync as statSync6, writeFileSync as writeFileSync7 } from "fs";
|
|
8319
8365
|
|
|
8320
8366
|
// server/canonical-webchat-override.ts
|
|
8321
8367
|
import { readFileSync as readFileSync15, writeFileSync as writeFileSync5, renameSync } from "fs";
|
|
8322
|
-
import { join as
|
|
8368
|
+
import { join as join15 } from "path";
|
|
8323
8369
|
var FILE = "canonical-webchat-session.json";
|
|
8324
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}$/;
|
|
8325
8371
|
function canonicalOverridePath(accountDir) {
|
|
8326
|
-
return
|
|
8372
|
+
return join15(accountDir, FILE);
|
|
8327
8373
|
}
|
|
8328
8374
|
function readRaw(accountDir) {
|
|
8329
8375
|
try {
|
|
@@ -8373,7 +8419,7 @@ function adminSessionIdFor(accountId, senderId, personId) {
|
|
|
8373
8419
|
|
|
8374
8420
|
// ../lib/models/src/index.ts
|
|
8375
8421
|
var OPUS_MODEL = "claude-opus-4-8[1m]";
|
|
8376
|
-
var SONNET_MODEL = "claude-sonnet-
|
|
8422
|
+
var SONNET_MODEL = "claude-sonnet-5";
|
|
8377
8423
|
var HAIKU_MODEL = "claude-haiku-4-5";
|
|
8378
8424
|
var MODEL_CONTEXT_WINDOW = {
|
|
8379
8425
|
[OPUS_MODEL]: 1e6,
|
|
@@ -8385,7 +8431,7 @@ function contextWindow(model) {
|
|
|
8385
8431
|
}
|
|
8386
8432
|
var MODEL_DISPLAY_NAMES = {
|
|
8387
8433
|
[OPUS_MODEL]: "Opus 4.8 (1M context)",
|
|
8388
|
-
[SONNET_MODEL]: "Sonnet
|
|
8434
|
+
[SONNET_MODEL]: "Sonnet 5",
|
|
8389
8435
|
[HAIKU_MODEL]: "Haiku 4.5"
|
|
8390
8436
|
};
|
|
8391
8437
|
var SELECTABLE_MODELS = [OPUS_MODEL, SONNET_MODEL, HAIKU_MODEL];
|
|
@@ -8415,7 +8461,7 @@ function isNewSessionEffortLevel(value) {
|
|
|
8415
8461
|
|
|
8416
8462
|
// ../services/claude-session-manager/src/sidecar-store.ts
|
|
8417
8463
|
import { existsSync as existsSync8, mkdirSync as mkdirSync2, readdirSync as readdirSync9, readFileSync as readFileSync16, renameSync as renameSync2, unlinkSync, writeFileSync as writeFileSync6 } from "fs";
|
|
8418
|
-
import { join as
|
|
8464
|
+
import { join as join16 } from "path";
|
|
8419
8465
|
function escapeRegExp(s) {
|
|
8420
8466
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
8421
8467
|
}
|
|
@@ -8423,7 +8469,7 @@ function createSidecarStore(config) {
|
|
|
8423
8469
|
const { suffix, validate: validate2 } = config;
|
|
8424
8470
|
const suffixRe = new RegExp(`${escapeRegExp(suffix)}$`);
|
|
8425
8471
|
function pathFor(sessionsDir, id) {
|
|
8426
|
-
return
|
|
8472
|
+
return join16(sessionsDir, `${id}${suffix}`);
|
|
8427
8473
|
}
|
|
8428
8474
|
function write(sessionsDir, id, record) {
|
|
8429
8475
|
mkdirSync2(sessionsDir, { recursive: true });
|
|
@@ -8467,7 +8513,7 @@ function createSidecarStore(config) {
|
|
|
8467
8513
|
const out = [];
|
|
8468
8514
|
for (const name of names) {
|
|
8469
8515
|
if (!suffixRe.test(name)) continue;
|
|
8470
|
-
const path2 =
|
|
8516
|
+
const path2 = join16(sessionsDir, name);
|
|
8471
8517
|
let raw;
|
|
8472
8518
|
try {
|
|
8473
8519
|
raw = readFileSync16(path2, "utf8");
|
|
@@ -8542,21 +8588,15 @@ function resolveBridgeSource(sessionsDir, forkSessionId, jsonlExists, maxDepth =
|
|
|
8542
8588
|
var WEBCHAT_ADMIN_KEY = "webchat-admin";
|
|
8543
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;
|
|
8544
8590
|
function locateSession(sessionId) {
|
|
8545
|
-
const
|
|
8546
|
-
if (!
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
const dir = dirname3(path2);
|
|
8550
|
-
const meta = readSidecarMeta(join16(dir, `${sessionId}.meta.json`));
|
|
8551
|
-
return { projectDir: dir, channel: meta.channel };
|
|
8552
|
-
}
|
|
8553
|
-
}
|
|
8554
|
-
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 };
|
|
8555
8595
|
}
|
|
8556
8596
|
function locateSidecar(sessionId) {
|
|
8557
8597
|
const cfg = claudeConfigDir();
|
|
8558
8598
|
if (!cfg) return null;
|
|
8559
|
-
const projectsRoot =
|
|
8599
|
+
const projectsRoot = join17(cfg, "projects");
|
|
8560
8600
|
let slugs;
|
|
8561
8601
|
try {
|
|
8562
8602
|
slugs = readdirSync10(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
|
|
@@ -8564,7 +8604,7 @@ function locateSidecar(sessionId) {
|
|
|
8564
8604
|
return null;
|
|
8565
8605
|
}
|
|
8566
8606
|
for (const slug of slugs) {
|
|
8567
|
-
const metaPath =
|
|
8607
|
+
const metaPath = join17(projectsRoot, slug, `${sessionId}.meta.json`);
|
|
8568
8608
|
if (existsSync9(metaPath)) {
|
|
8569
8609
|
const meta = readSidecarMeta(metaPath);
|
|
8570
8610
|
return { channel: meta.channel, adminUserId: meta.adminUserId };
|
|
@@ -8577,7 +8617,7 @@ function readTargetOwner(sessionId) {
|
|
|
8577
8617
|
if (sidecar !== null) return { found: true, owner: sidecar.adminUserId };
|
|
8578
8618
|
const { projectDir } = locateSession(sessionId);
|
|
8579
8619
|
if (projectDir !== null) {
|
|
8580
|
-
return { found: true, owner: readSidecarMeta(
|
|
8620
|
+
return { found: true, owner: readSidecarMeta(join17(projectDir, `${sessionId}.meta.json`)).adminUserId };
|
|
8581
8621
|
}
|
|
8582
8622
|
return { found: false, owner: null };
|
|
8583
8623
|
}
|
|
@@ -8591,7 +8631,7 @@ function sessionSidecarExists(sessionId) {
|
|
|
8591
8631
|
function jsonlSizeBytes(projectDir, sessionId) {
|
|
8592
8632
|
if (projectDir === null) return null;
|
|
8593
8633
|
try {
|
|
8594
|
-
return statSync6(
|
|
8634
|
+
return statSync6(join17(projectDir, `${sessionId}.jsonl`)).size;
|
|
8595
8635
|
} catch {
|
|
8596
8636
|
return null;
|
|
8597
8637
|
}
|
|
@@ -8726,10 +8766,10 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId) {
|
|
|
8726
8766
|
const cfg = claudeConfigDir();
|
|
8727
8767
|
if (!cfg) return null;
|
|
8728
8768
|
let best = null;
|
|
8729
|
-
for (const { path: path2, isSubagent, archived } of enumerateJsonls(
|
|
8769
|
+
for (const { path: path2, isSubagent, archived } of enumerateJsonls(join17(cfg, "projects"))) {
|
|
8730
8770
|
if (isSubagent || archived) continue;
|
|
8731
|
-
const id =
|
|
8732
|
-
const meta = readSidecarMeta(
|
|
8771
|
+
const id = basename6(path2).slice(0, -".jsonl".length);
|
|
8772
|
+
const meta = readSidecarMeta(join17(dirname4(path2), `${id}.meta.json`));
|
|
8733
8773
|
if (meta.role !== "admin" || meta.channel !== "webchat") continue;
|
|
8734
8774
|
let mtimeMs;
|
|
8735
8775
|
try {
|
|
@@ -8751,7 +8791,7 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId) {
|
|
|
8751
8791
|
function overrideKnownNonArchived(id) {
|
|
8752
8792
|
const { projectDir } = locateSession(id);
|
|
8753
8793
|
if (projectDir === null) return sessionSidecarExists(id);
|
|
8754
|
-
return
|
|
8794
|
+
return basename6(projectDir) !== "archive";
|
|
8755
8795
|
}
|
|
8756
8796
|
function resolveCanonical(accountId, accountDir, requesterUserId, primaryUserId) {
|
|
8757
8797
|
if (requesterUserId === null) {
|
|
@@ -9024,7 +9064,7 @@ ${note}` : note;
|
|
|
9024
9064
|
console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-unresolved`);
|
|
9025
9065
|
return c.json({ error: "account unresolved" }, 503);
|
|
9026
9066
|
}
|
|
9027
|
-
const accountJsonPath =
|
|
9067
|
+
const accountJsonPath = join17(account.accountDir, "account.json");
|
|
9028
9068
|
try {
|
|
9029
9069
|
const parsed = JSON.parse(readFileSync17(accountJsonPath, "utf8"));
|
|
9030
9070
|
if (op === "model") parsed.adminModel = value;
|
|
@@ -9070,7 +9110,7 @@ ${note}` : note;
|
|
|
9070
9110
|
const cfg2 = claudeConfigDir();
|
|
9071
9111
|
if (cfg2) {
|
|
9072
9112
|
const source2 = resolveBridgeSource(
|
|
9073
|
-
|
|
9113
|
+
join17(cfg2, "sessions"),
|
|
9074
9114
|
target,
|
|
9075
9115
|
(id) => locateSession(id).projectDir !== null
|
|
9076
9116
|
);
|
|
@@ -9102,15 +9142,15 @@ ${note}` : note;
|
|
|
9102
9142
|
const cfg = claudeConfigDir();
|
|
9103
9143
|
let projectDir = null;
|
|
9104
9144
|
if (cfg) {
|
|
9105
|
-
for (const { path: path2 } of enumerateJsonls(
|
|
9106
|
-
if (
|
|
9107
|
-
projectDir =
|
|
9145
|
+
for (const { path: path2 } of enumerateJsonls(join17(cfg, "projects"))) {
|
|
9146
|
+
if (basename6(path2) === `${sessionId}.jsonl`) {
|
|
9147
|
+
projectDir = dirname4(path2);
|
|
9108
9148
|
break;
|
|
9109
9149
|
}
|
|
9110
9150
|
}
|
|
9111
9151
|
}
|
|
9112
9152
|
if (source === "latest" && requesterUserId !== null) {
|
|
9113
|
-
const owner = readSidecarMeta(
|
|
9153
|
+
const owner = readSidecarMeta(join17(projectDir ?? "", `${sessionId}.meta.json`)).adminUserId;
|
|
9114
9154
|
if (owner !== null && owner !== requesterUserId && requesterUserId !== primaryUserId) {
|
|
9115
9155
|
console.error(`[webchat:inbound] op=session-resolve-foreign key=${sessionId.slice(0, 8)} owner=${owner.slice(0, 8)} requester=${requesterUserId.slice(0, 8)}`);
|
|
9116
9156
|
}
|
|
@@ -9143,7 +9183,7 @@ import { resolve as resolve13 } from "path";
|
|
|
9143
9183
|
|
|
9144
9184
|
// app/lib/claude-agent/specialist-roster.ts
|
|
9145
9185
|
import { existsSync as existsSync10, readFileSync as readFileSync18, readdirSync as readdirSync11 } from "fs";
|
|
9146
|
-
import { join as
|
|
9186
|
+
import { join as join18 } from "path";
|
|
9147
9187
|
function field(fm, name) {
|
|
9148
9188
|
const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
|
|
9149
9189
|
if (!m) return null;
|
|
@@ -9162,7 +9202,7 @@ function readSpecialistRoster(specialistsDir) {
|
|
|
9162
9202
|
if (!file.endsWith(".md")) continue;
|
|
9163
9203
|
let raw;
|
|
9164
9204
|
try {
|
|
9165
|
-
raw = readFileSync18(
|
|
9205
|
+
raw = readFileSync18(join18(specialistsDir, file), "utf-8");
|
|
9166
9206
|
} catch (err) {
|
|
9167
9207
|
skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
|
|
9168
9208
|
continue;
|
|
@@ -9279,7 +9319,7 @@ var webchat_greeting_default = app6;
|
|
|
9279
9319
|
|
|
9280
9320
|
// server/routes/telegram.ts
|
|
9281
9321
|
import { homedir } from "os";
|
|
9282
|
-
import { resolve as resolve14, join as
|
|
9322
|
+
import { resolve as resolve14, join as join19 } from "path";
|
|
9283
9323
|
import { existsSync as existsSync11, readFileSync as readFileSync19 } from "fs";
|
|
9284
9324
|
|
|
9285
9325
|
// app/lib/telegram/gateway/instance.ts
|
|
@@ -9339,7 +9379,7 @@ function routeTelegramUpdate(input) {
|
|
|
9339
9379
|
var TAG22 = "[telegram-inbound]";
|
|
9340
9380
|
function configDirName() {
|
|
9341
9381
|
const platformRoot3 = process.env.MAXY_PLATFORM_ROOT ?? resolve14(process.cwd(), "..");
|
|
9342
|
-
const brandPath =
|
|
9382
|
+
const brandPath = join19(platformRoot3, "config", "brand.json");
|
|
9343
9383
|
if (existsSync11(brandPath)) {
|
|
9344
9384
|
try {
|
|
9345
9385
|
return JSON.parse(readFileSync19(brandPath, "utf-8")).configDir ?? ".maxy";
|
|
@@ -9441,16 +9481,16 @@ app7.post("/", async (c) => {
|
|
|
9441
9481
|
var telegram_default = app7;
|
|
9442
9482
|
|
|
9443
9483
|
// server/routes/quickbooks.ts
|
|
9444
|
-
import { join as
|
|
9484
|
+
import { join as join20 } from "path";
|
|
9445
9485
|
import { existsSync as existsSync12, readFileSync as readFileSync20, writeFileSync as writeFileSync8, mkdirSync as mkdirSync3, rmSync, renameSync as renameSync4 } from "fs";
|
|
9446
9486
|
var TAG23 = "[quickbooks]";
|
|
9447
9487
|
var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
|
|
9448
9488
|
var STATE_RE = /^[A-Za-z0-9_-]+$/;
|
|
9449
9489
|
function pendingPath(accountDir, state) {
|
|
9450
|
-
return
|
|
9490
|
+
return join20(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
|
|
9451
9491
|
}
|
|
9452
9492
|
function storePath(accountDir) {
|
|
9453
|
-
return
|
|
9493
|
+
return join20(accountDir, "secrets", "quickbooks.json");
|
|
9454
9494
|
}
|
|
9455
9495
|
async function completeConsent(args) {
|
|
9456
9496
|
const { accountDir, code, realmId } = args;
|
|
@@ -9517,7 +9557,7 @@ async function completeConsent(args) {
|
|
|
9517
9557
|
refreshTokenExpiry: now + (body.x_refresh_token_expires_in ?? 864e4) * 1e3,
|
|
9518
9558
|
lastRefresh: now
|
|
9519
9559
|
};
|
|
9520
|
-
mkdirSync3(
|
|
9560
|
+
mkdirSync3(join20(accountDir, "secrets"), { recursive: true });
|
|
9521
9561
|
writeFileSync8(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
|
|
9522
9562
|
const persisted = JSON.parse(readFileSync20(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
|
|
9523
9563
|
console.error(`${TAG23} op=token-exchange realmId=${realmId} persisted=${persisted}`);
|
|
@@ -9555,7 +9595,7 @@ import { createHash as createHash3, randomUUID as randomUUID7 } from "crypto";
|
|
|
9555
9595
|
|
|
9556
9596
|
// ../lib/admins-write/src/index.ts
|
|
9557
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";
|
|
9558
|
-
import { dirname as
|
|
9598
|
+
import { dirname as dirname5, join as join21 } from "path";
|
|
9559
9599
|
function id8(value) {
|
|
9560
9600
|
return value.slice(0, 8);
|
|
9561
9601
|
}
|
|
@@ -9568,7 +9608,7 @@ function appendUsersAuditLine(audit, fields) {
|
|
|
9568
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()}
|
|
9569
9609
|
`;
|
|
9570
9610
|
try {
|
|
9571
|
-
mkdirSync4(
|
|
9611
|
+
mkdirSync4(dirname5(audit.logFile), { recursive: true, mode: 448 });
|
|
9572
9612
|
appendFileSync(audit.logFile, line, { mode: 384 });
|
|
9573
9613
|
} catch (err) {
|
|
9574
9614
|
console.error(
|
|
@@ -9586,7 +9626,7 @@ function logLine(input, result) {
|
|
|
9586
9626
|
);
|
|
9587
9627
|
}
|
|
9588
9628
|
function writeFileAtomic(filePath, contents, mode) {
|
|
9589
|
-
mkdirSync4(
|
|
9629
|
+
mkdirSync4(dirname5(filePath), { recursive: true });
|
|
9590
9630
|
const tempPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;
|
|
9591
9631
|
writeFileSync9(tempPath, contents, mode !== void 0 ? { mode } : void 0);
|
|
9592
9632
|
renameSync5(tempPath, filePath);
|
|
@@ -9627,7 +9667,7 @@ function writeAdminEntry(input) {
|
|
|
9627
9667
|
return result;
|
|
9628
9668
|
}
|
|
9629
9669
|
try {
|
|
9630
|
-
const accountJsonPath =
|
|
9670
|
+
const accountJsonPath = join21(input.accountDir, "account.json");
|
|
9631
9671
|
if (!existsSync13(accountJsonPath)) {
|
|
9632
9672
|
throw new Error(`account.json not found at ${accountJsonPath}`);
|
|
9633
9673
|
}
|
|
@@ -9675,13 +9715,13 @@ function computeAdminStoreDivergence(input) {
|
|
|
9675
9715
|
}
|
|
9676
9716
|
for (const entry of entries) {
|
|
9677
9717
|
if (entry.startsWith(".")) continue;
|
|
9678
|
-
const accountDir =
|
|
9718
|
+
const accountDir = join21(input.accountsDir, entry);
|
|
9679
9719
|
try {
|
|
9680
9720
|
if (!statSync7(accountDir).isDirectory()) continue;
|
|
9681
9721
|
} catch {
|
|
9682
9722
|
continue;
|
|
9683
9723
|
}
|
|
9684
|
-
const accountJsonPath =
|
|
9724
|
+
const accountJsonPath = join21(accountDir, "account.json");
|
|
9685
9725
|
if (!existsSync13(accountJsonPath)) continue;
|
|
9686
9726
|
let admins = [];
|
|
9687
9727
|
try {
|
|
@@ -10078,8 +10118,8 @@ var onboarding_default = app9;
|
|
|
10078
10118
|
|
|
10079
10119
|
// server/routes/client-error.ts
|
|
10080
10120
|
import { appendFileSync as appendFileSync2, existsSync as existsSync15, renameSync as renameSync6, statSync as statSync8 } from "fs";
|
|
10081
|
-
import { join as
|
|
10082
|
-
var CLIENT_ERRORS_LOG =
|
|
10121
|
+
import { join as join22 } from "path";
|
|
10122
|
+
var CLIENT_ERRORS_LOG = join22(LOG_DIR, "client-errors.log");
|
|
10083
10123
|
var MAX_LOG_SIZE = 10 * 1024 * 1024;
|
|
10084
10124
|
var MAX_BODY_SIZE = 8 * 1024;
|
|
10085
10125
|
var MAX_STACK_LEN = 2e3;
|
|
@@ -10409,16 +10449,16 @@ var session_default = app11;
|
|
|
10409
10449
|
|
|
10410
10450
|
// server/routes/admin/logs.ts
|
|
10411
10451
|
import { existsSync as existsSync17, readdirSync as readdirSync13, readFileSync as readFileSync23, statSync as statSync9 } from "fs";
|
|
10412
|
-
import { resolve as resolve15, basename as
|
|
10452
|
+
import { resolve as resolve15, basename as basename7 } from "path";
|
|
10413
10453
|
|
|
10414
10454
|
// app/lib/logs-read-resolve.ts
|
|
10415
10455
|
import { existsSync as existsSync16 } from "fs";
|
|
10416
|
-
import { join as
|
|
10456
|
+
import { join as join23 } from "path";
|
|
10417
10457
|
function resolveSessionLogPaths(filename, logDirs) {
|
|
10418
10458
|
const tried = [filename];
|
|
10419
10459
|
const hits = [];
|
|
10420
10460
|
for (const dir of logDirs) {
|
|
10421
|
-
const fullPath =
|
|
10461
|
+
const fullPath = join23(dir, filename);
|
|
10422
10462
|
if (existsSync16(fullPath)) {
|
|
10423
10463
|
hits.push({ path: fullPath, dir });
|
|
10424
10464
|
}
|
|
@@ -10441,7 +10481,7 @@ app12.get("/", async (c) => {
|
|
|
10441
10481
|
if (accountLogDir) logDirs.push(accountLogDir);
|
|
10442
10482
|
logDirs.push(LOG_DIR);
|
|
10443
10483
|
if (fileParam) {
|
|
10444
|
-
const safe =
|
|
10484
|
+
const safe = basename7(fileParam);
|
|
10445
10485
|
const searched = [];
|
|
10446
10486
|
for (const dir of logDirs) {
|
|
10447
10487
|
const filePath = resolve15(dir, safe);
|
|
@@ -10511,7 +10551,7 @@ app12.get("/", async (c) => {
|
|
|
10511
10551
|
if (hit) {
|
|
10512
10552
|
console.info(`[admin/logs] resolved cacheKey=${cacheKeySlice} sessionId=${sessionIdSlice} via=${primaryId === cacheKey ? "cacheKey" : primaryId === sessionKeyFromConv ? "reverse-lookup" : "sessionId-fallback"}`);
|
|
10513
10553
|
try {
|
|
10514
|
-
const filename =
|
|
10554
|
+
const filename = basename7(hit.path);
|
|
10515
10555
|
const buffer = readFileSync23(hit.path);
|
|
10516
10556
|
const onDiskBytes = statSync9(hit.path).size;
|
|
10517
10557
|
const headers = {
|
|
@@ -11420,7 +11460,7 @@ var sessions_default = app16;
|
|
|
11420
11460
|
|
|
11421
11461
|
// app/lib/claude-agent/spawn-context.ts
|
|
11422
11462
|
import { existsSync as existsSync21, readFileSync as readFileSync25, readdirSync as readdirSync15, statSync as statSync10 } from "fs";
|
|
11423
|
-
import { dirname as
|
|
11463
|
+
import { dirname as dirname6, resolve as resolve18, join as join24 } from "path";
|
|
11424
11464
|
async function resolveOwnerProfileBlock(accountId, userId) {
|
|
11425
11465
|
if (!userId) return { ok: false, reason: "missing-user-id" };
|
|
11426
11466
|
try {
|
|
@@ -11461,8 +11501,8 @@ function frontmatterField(manifest, field2) {
|
|
|
11461
11501
|
function extractPluginToolDescriptions(pluginDir) {
|
|
11462
11502
|
const out = /* @__PURE__ */ new Map();
|
|
11463
11503
|
const candidates = [
|
|
11464
|
-
|
|
11465
|
-
|
|
11504
|
+
join24(pluginDir, "mcp/dist/index.js"),
|
|
11505
|
+
join24(pluginDir, "mcp/src/index.ts")
|
|
11466
11506
|
];
|
|
11467
11507
|
let raw = null;
|
|
11468
11508
|
for (const path2 of candidates) {
|
|
@@ -11520,21 +11560,21 @@ function listPluginDirs() {
|
|
|
11520
11560
|
const platformPlugins = resolve18(PLATFORM_ROOT, "plugins");
|
|
11521
11561
|
if (existsSync21(platformPlugins)) {
|
|
11522
11562
|
for (const name of readdirSync15(platformPlugins)) {
|
|
11523
|
-
const dir =
|
|
11563
|
+
const dir = join24(platformPlugins, name);
|
|
11524
11564
|
try {
|
|
11525
11565
|
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
11526
11566
|
} catch {
|
|
11527
11567
|
}
|
|
11528
11568
|
}
|
|
11529
11569
|
}
|
|
11530
|
-
const premiumRoot = resolve18(
|
|
11570
|
+
const premiumRoot = resolve18(dirname6(PLATFORM_ROOT), "premium-plugins");
|
|
11531
11571
|
if (existsSync21(premiumRoot)) {
|
|
11532
11572
|
for (const bundle of readdirSync15(premiumRoot)) {
|
|
11533
|
-
const bundlePlugins =
|
|
11573
|
+
const bundlePlugins = join24(premiumRoot, bundle, "plugins");
|
|
11534
11574
|
if (!existsSync21(bundlePlugins)) continue;
|
|
11535
11575
|
try {
|
|
11536
11576
|
for (const name of readdirSync15(bundlePlugins)) {
|
|
11537
|
-
const dir =
|
|
11577
|
+
const dir = join24(bundlePlugins, name);
|
|
11538
11578
|
try {
|
|
11539
11579
|
if (statSync10(dir).isDirectory()) out.set(name, dir);
|
|
11540
11580
|
} catch {
|
|
@@ -11577,7 +11617,7 @@ function computeActivePlugins(accountId) {
|
|
|
11577
11617
|
for (const name of Array.from(enabled).sort()) {
|
|
11578
11618
|
const dir = pluginDirs.get(name);
|
|
11579
11619
|
if (!dir) continue;
|
|
11580
|
-
const fm = readFrontmatter(
|
|
11620
|
+
const fm = readFrontmatter(join24(dir, "PLUGIN.md"));
|
|
11581
11621
|
if (!fm) continue;
|
|
11582
11622
|
const description = frontmatterField(`---
|
|
11583
11623
|
${fm}
|
|
@@ -11594,7 +11634,7 @@ ${fm}
|
|
|
11594
11634
|
`plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
|
|
11595
11635
|
);
|
|
11596
11636
|
if (toolNames.length > 0 && descMap.size === 0) {
|
|
11597
|
-
const hasSource = existsSync21(
|
|
11637
|
+
const hasSource = existsSync21(join24(dir, "mcp/dist/index.js")) || existsSync21(join24(dir, "mcp/src/index.ts"));
|
|
11598
11638
|
if (hasSource) {
|
|
11599
11639
|
console.warn(
|
|
11600
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`
|
|
@@ -11604,7 +11644,7 @@ ${fm}
|
|
|
11604
11644
|
const skillPaths = parseSkillPathsFromFrontmatter(fm);
|
|
11605
11645
|
const skills = [];
|
|
11606
11646
|
for (const relPath of skillPaths) {
|
|
11607
|
-
const skillPath =
|
|
11647
|
+
const skillPath = join24(dir, relPath);
|
|
11608
11648
|
const skillFm = readFrontmatter(skillPath);
|
|
11609
11649
|
if (!skillFm) continue;
|
|
11610
11650
|
const skillName = frontmatterField(`---
|
|
@@ -11648,7 +11688,7 @@ function computeSpecialistDomains(accountId) {
|
|
|
11648
11688
|
const out = [];
|
|
11649
11689
|
for (const file of entries.sort()) {
|
|
11650
11690
|
if (!file.endsWith(".md")) continue;
|
|
11651
|
-
const fm = readFrontmatter(
|
|
11691
|
+
const fm = readFrontmatter(join24(specialistsDir, file));
|
|
11652
11692
|
if (!fm) continue;
|
|
11653
11693
|
const wrapped = `---
|
|
11654
11694
|
${fm}
|
|
@@ -11974,9 +12014,9 @@ var events_default = app19;
|
|
|
11974
12014
|
// server/routes/admin/files.ts
|
|
11975
12015
|
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync23 } from "fs";
|
|
11976
12016
|
import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, unlink as unlink2, rename } from "fs/promises";
|
|
11977
|
-
import { realpathSync as
|
|
12017
|
+
import { realpathSync as realpathSync5 } from "fs";
|
|
11978
12018
|
import { randomUUID as randomUUID9 } from "crypto";
|
|
11979
|
-
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";
|
|
11980
12020
|
import { Readable as Readable2 } from "stream";
|
|
11981
12021
|
|
|
11982
12022
|
// ../lib/graph-trash/src/index.ts
|
|
@@ -12294,7 +12334,7 @@ async function cascadeDeleteDocument(params) {
|
|
|
12294
12334
|
|
|
12295
12335
|
// app/lib/file-index.ts
|
|
12296
12336
|
import * as fsp from "fs/promises";
|
|
12297
|
-
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";
|
|
12298
12338
|
import { tmpdir as tmpdir2 } from "os";
|
|
12299
12339
|
import { execFile as execFile2 } from "child_process";
|
|
12300
12340
|
import { promisify as promisify2 } from "util";
|
|
@@ -12376,7 +12416,7 @@ async function extractPdf(absolute) {
|
|
|
12376
12416
|
return stdout.trim();
|
|
12377
12417
|
}
|
|
12378
12418
|
async function ocrPdf(absolute) {
|
|
12379
|
-
const outPdf =
|
|
12419
|
+
const outPdf = join25(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
|
|
12380
12420
|
try {
|
|
12381
12421
|
await execFileAsync2(
|
|
12382
12422
|
"ocrmypdf",
|
|
@@ -12432,13 +12472,13 @@ async function extractFileContent(absolute) {
|
|
|
12432
12472
|
}
|
|
12433
12473
|
}
|
|
12434
12474
|
async function readDisplayName(absolute) {
|
|
12435
|
-
const dir = absolute.slice(0, absolute.length -
|
|
12436
|
-
const base =
|
|
12475
|
+
const dir = absolute.slice(0, absolute.length - basename8(absolute).length);
|
|
12476
|
+
const base = basename8(absolute);
|
|
12437
12477
|
const dot = base.lastIndexOf(".");
|
|
12438
12478
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
12439
12479
|
if (base === `${stem}.meta.json`) return null;
|
|
12440
12480
|
try {
|
|
12441
|
-
const raw = await fsp.readFile(
|
|
12481
|
+
const raw = await fsp.readFile(join25(dir, `${stem}.meta.json`), "utf-8");
|
|
12442
12482
|
const meta = JSON.parse(raw);
|
|
12443
12483
|
const dn = meta.displayName ?? meta.filename;
|
|
12444
12484
|
return typeof dn === "string" && dn.length > 0 ? dn : null;
|
|
@@ -12459,7 +12499,7 @@ async function walkSubtree(root, dataRoot, out) {
|
|
|
12459
12499
|
for (const entry of entries) {
|
|
12460
12500
|
if (entry.isSymbolicLink()) continue;
|
|
12461
12501
|
if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
|
|
12462
|
-
const abs =
|
|
12502
|
+
const abs = join25(root, entry.name);
|
|
12463
12503
|
if (entry.isDirectory()) {
|
|
12464
12504
|
const sub = await walkSubtree(abs, dataRoot, out);
|
|
12465
12505
|
if (!sub.clean) clean = false;
|
|
@@ -12571,7 +12611,7 @@ async function cascadeTrashLinkedKnowledgeDocs(session, accountId, relativePaths
|
|
|
12571
12611
|
return { kds, sections, chunks };
|
|
12572
12612
|
}
|
|
12573
12613
|
async function buildArtifact(accountId, wf, embed2) {
|
|
12574
|
-
const name =
|
|
12614
|
+
const name = basename8(wf.absolute);
|
|
12575
12615
|
const { content, route } = await extractFileContent(wf.absolute);
|
|
12576
12616
|
const displayName = await readDisplayName(wf.absolute);
|
|
12577
12617
|
const embedInput = `${name}
|
|
@@ -12815,7 +12855,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
|
|
|
12815
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;
|
|
12816
12856
|
async function readMeta(absDir, baseName) {
|
|
12817
12857
|
try {
|
|
12818
|
-
const raw = await readFile4(
|
|
12858
|
+
const raw = await readFile4(join26(absDir, `${baseName}.meta.json`), "utf8");
|
|
12819
12859
|
const parsed = JSON.parse(raw);
|
|
12820
12860
|
if (typeof parsed?.filename === "string") {
|
|
12821
12861
|
return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
|
|
@@ -12853,7 +12893,7 @@ async function readAccountNames() {
|
|
|
12853
12893
|
}
|
|
12854
12894
|
async function enrich(absolute, entry, accountNames) {
|
|
12855
12895
|
if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
|
|
12856
|
-
const meta = await readMeta(
|
|
12896
|
+
const meta = await readMeta(join26(absolute, entry.name), entry.name);
|
|
12857
12897
|
if (meta?.filename) {
|
|
12858
12898
|
entry.displayName = meta.filename;
|
|
12859
12899
|
entry.mimeType = meta.mimeType;
|
|
@@ -13017,7 +13057,7 @@ app20.get("/", requireAdminSession, async (c) => {
|
|
|
13017
13057
|
const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
|
|
13018
13058
|
const protectedEntry = isProtectedFromDeletion(childRel).protected;
|
|
13019
13059
|
try {
|
|
13020
|
-
const entryPath =
|
|
13060
|
+
const entryPath = join26(absolute, name);
|
|
13021
13061
|
const s = await stat4(entryPath);
|
|
13022
13062
|
entries.push({
|
|
13023
13063
|
name,
|
|
@@ -13057,11 +13097,27 @@ app20.get("/download", requireAdminSession, async (c) => {
|
|
|
13057
13097
|
const rawPath = c.req.query("path") ?? "";
|
|
13058
13098
|
if (!rawPath) return c.json({ error: "path required" }, 400);
|
|
13059
13099
|
const root = c.req.query("root") ?? "data";
|
|
13060
|
-
if (root !== "data" && root !== "claude-uploads") {
|
|
13100
|
+
if (root !== "data" && root !== "claude-uploads" && root !== "scratchpad") {
|
|
13061
13101
|
return c.json({ error: "invalid root" }, 400);
|
|
13062
13102
|
}
|
|
13063
13103
|
const disposition = c.req.query("disposition") ?? "attachment";
|
|
13064
|
-
|
|
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);
|
|
13065
13121
|
if (!resolution.ok) {
|
|
13066
13122
|
if (resolution.status === 403) {
|
|
13067
13123
|
console.error(`[data] path-traversal-blocked root="${root}" requested="${rawPath}" resolved="${resolution.resolved ?? "n/a"}"`);
|
|
@@ -13076,7 +13132,7 @@ app20.get("/download", requireAdminSession, async (c) => {
|
|
|
13076
13132
|
console.error(`[data] account-scope-blocked root="claude-uploads" attachmentId="${attachmentId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
|
|
13077
13133
|
return c.json({ error: "Not found" }, 404);
|
|
13078
13134
|
}
|
|
13079
|
-
} else if (crossesForeignAccountPartition(relPath, accountId)) {
|
|
13135
|
+
} else if (root === "data" && crossesForeignAccountPartition(relPath, accountId)) {
|
|
13080
13136
|
console.error(`[data] account-scope-blocked endpoint="/api/admin/files/download" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
13081
13137
|
return c.json({ error: "Not found" }, 404);
|
|
13082
13138
|
}
|
|
@@ -13085,7 +13141,7 @@ app20.get("/download", requireAdminSession, async (c) => {
|
|
|
13085
13141
|
if (!info.isFile()) {
|
|
13086
13142
|
return c.json({ error: "Path is not a file" }, 400);
|
|
13087
13143
|
}
|
|
13088
|
-
const filename =
|
|
13144
|
+
const filename = basename9(absolute);
|
|
13089
13145
|
const mimeType = detectMimeType(absolute);
|
|
13090
13146
|
const nodeStream = createReadStream2(absolute);
|
|
13091
13147
|
const webStream = Readable2.toWeb(nodeStream);
|
|
@@ -13141,7 +13197,7 @@ async function* walkRegularFiles(dirAbsolute) {
|
|
|
13141
13197
|
const dirents = await readdir3(dirAbsolute, { withFileTypes: true });
|
|
13142
13198
|
for (const d of dirents) {
|
|
13143
13199
|
if (d.isSymbolicLink()) continue;
|
|
13144
|
-
const child =
|
|
13200
|
+
const child = join26(dirAbsolute, d.name);
|
|
13145
13201
|
if (d.isDirectory()) {
|
|
13146
13202
|
yield* walkRegularFiles(child);
|
|
13147
13203
|
continue;
|
|
@@ -13190,7 +13246,7 @@ app20.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
13190
13246
|
const info = await stat4(absolute);
|
|
13191
13247
|
if (info.isDirectory()) {
|
|
13192
13248
|
dirsWalked++;
|
|
13193
|
-
const parentAbs =
|
|
13249
|
+
const parentAbs = dirname7(absolute);
|
|
13194
13250
|
for await (const fileAbs of walkRegularFiles(absolute)) {
|
|
13195
13251
|
const within = relative4(absolute, fileAbs).split(sep6).join("/");
|
|
13196
13252
|
const fileRel = relPath === "" || relPath === "." ? within : `${relPath}/${within}`;
|
|
@@ -13201,7 +13257,7 @@ app20.get("/download-zip", requireAdminSession, async (c) => {
|
|
|
13201
13257
|
if (over) return over;
|
|
13202
13258
|
}
|
|
13203
13259
|
} else if (info.isFile()) {
|
|
13204
|
-
const over = await addFile(absolute, info.size,
|
|
13260
|
+
const over = await addFile(absolute, info.size, basename9(absolute));
|
|
13205
13261
|
if (over) return over;
|
|
13206
13262
|
} else {
|
|
13207
13263
|
return c.json({ error: "Path is not a file or directory" }, 400);
|
|
@@ -13230,12 +13286,12 @@ function dataUploadCeiling() {
|
|
|
13230
13286
|
}
|
|
13231
13287
|
async function resolveUploadTarget(c, accountId, uid) {
|
|
13232
13288
|
const rawName = c.req.query("filename") ?? "";
|
|
13233
|
-
const safeName =
|
|
13289
|
+
const safeName = basename9(rawName).replace(/[\0/\\]/g, "_");
|
|
13234
13290
|
if (!safeName) return { ok: false, status: 400, error: "filename query param required" };
|
|
13235
13291
|
const rawRelpath = c.req.query("relpath") ?? "";
|
|
13236
13292
|
const relpath = rawRelpath !== "" ? rawRelpath : null;
|
|
13237
13293
|
const token = c.req.query("token") ?? "";
|
|
13238
|
-
const finalName = relpath ?
|
|
13294
|
+
const finalName = relpath ? basename9(relpath).replace(/[\0/\\]/g, "_") : `${Date.now()}-${safeName}`;
|
|
13239
13295
|
const mimeType = (c.req.header("content-type") ?? "").split(";")[0].trim();
|
|
13240
13296
|
if (!SUPPORTED_MIME_TYPES.has(mimeType)) {
|
|
13241
13297
|
console.error(`[data-upload] op=reject-mime uid=${uid} mime="${mimeType}" token=${token} rel="${relpath ?? ""}"`);
|
|
@@ -13244,8 +13300,8 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
13244
13300
|
const rawDir = c.req.query("path") ?? "";
|
|
13245
13301
|
const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
|
|
13246
13302
|
if (!base.ok) return { ok: false, status: base.status, error: base.error };
|
|
13247
|
-
const relDir = relpath ?
|
|
13248
|
-
const destRel = relDir === "." ? base.relative :
|
|
13303
|
+
const relDir = relpath ? dirname7(relpath) : ".";
|
|
13304
|
+
const destRel = relDir === "." ? base.relative : join26(base.relative, relDir);
|
|
13249
13305
|
if (crossesForeignAccountPartition(destRel, accountId)) {
|
|
13250
13306
|
console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
|
|
13251
13307
|
return { ok: false, status: 404, error: "Not found" };
|
|
@@ -13263,8 +13319,8 @@ async function resolveUploadTarget(c, accountId, uid) {
|
|
|
13263
13319
|
const info = await stat4(destDir).catch(() => null);
|
|
13264
13320
|
if (!info || !info.isDirectory()) return { ok: false, status: 400, error: "Upload destination is not a directory" };
|
|
13265
13321
|
}
|
|
13266
|
-
const dataRootReal =
|
|
13267
|
-
const destDirReal =
|
|
13322
|
+
const dataRootReal = realpathSync5(DATA_ROOT);
|
|
13323
|
+
const destDirReal = realpathSync5(destDir);
|
|
13268
13324
|
if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep6)) {
|
|
13269
13325
|
console.error(`[data-upload] op=path-traversal-blocked uid=${uid} requested="${destRel}" resolved="${destDirReal}"`);
|
|
13270
13326
|
return { ok: false, status: 403, error: "Upload destination escapes DATA_ROOT" };
|
|
@@ -13605,7 +13661,7 @@ app20.delete("/", requireAdminSession, async (c) => {
|
|
|
13605
13661
|
console.error(`[data] account-scope-blocked endpoint="DELETE /api/admin/files" path="${relPath}" account=${accountId.slice(0, 8)}\u2026`);
|
|
13606
13662
|
return c.json({ error: "Not found" }, 404);
|
|
13607
13663
|
}
|
|
13608
|
-
const base =
|
|
13664
|
+
const base = basename9(absolute);
|
|
13609
13665
|
const protection = isProtectedFromDeletion(relPath);
|
|
13610
13666
|
if (protection.protected) {
|
|
13611
13667
|
console.error(`[data] file-delete blocked path="${relPath}" reason="protected" rule="${protection.rule}"`);
|
|
@@ -13621,7 +13677,7 @@ app20.delete("/", requireAdminSession, async (c) => {
|
|
|
13621
13677
|
}
|
|
13622
13678
|
const dot = base.lastIndexOf(".");
|
|
13623
13679
|
const stem = dot === -1 ? base : base.slice(0, dot);
|
|
13624
|
-
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;
|
|
13625
13681
|
await unlink2(absolute);
|
|
13626
13682
|
if (sidecarPath) {
|
|
13627
13683
|
try {
|
|
@@ -13717,8 +13773,8 @@ app20.post("/rename", requireAdminSession, async (c) => {
|
|
|
13717
13773
|
console.error(`[data] file-rename blocked path="${src.relative}" reason="protected"`);
|
|
13718
13774
|
return c.json({ error: "Protected entry \u2014 refusing to rename" }, 403);
|
|
13719
13775
|
}
|
|
13720
|
-
const destAbs = resolve21(
|
|
13721
|
-
const newRel = `${
|
|
13776
|
+
const destAbs = resolve21(dirname7(src.absolute), newName);
|
|
13777
|
+
const newRel = `${dirname7(src.relative)}/${newName}`.replace(/^\.\//, "");
|
|
13722
13778
|
if (isProtectedFromRename(newRel)) {
|
|
13723
13779
|
console.error(`[data] file-rename blocked path="${newRel}" reason="protected-target"`);
|
|
13724
13780
|
return c.json({ error: "That name is reserved" }, 403);
|
|
@@ -15849,7 +15905,7 @@ var graph_default_view_default = app26;
|
|
|
15849
15905
|
|
|
15850
15906
|
// server/routes/admin/sidebar-artefacts.ts
|
|
15851
15907
|
import { readdir as readdir4, stat as stat5 } from "fs/promises";
|
|
15852
|
-
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";
|
|
15853
15909
|
import { existsSync as existsSync24 } from "fs";
|
|
15854
15910
|
var LIMIT = 50;
|
|
15855
15911
|
var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
|
|
@@ -15902,7 +15958,7 @@ async function fetchAccountFileArtefacts(accountId) {
|
|
|
15902
15958
|
const modifiedAt = r.get("modifiedAt") ?? "";
|
|
15903
15959
|
return {
|
|
15904
15960
|
id: `account-file:${relativePath}`,
|
|
15905
|
-
name: displayName ??
|
|
15961
|
+
name: displayName ?? basename10(relativePath),
|
|
15906
15962
|
kind: "account-file",
|
|
15907
15963
|
updatedAt: modifiedAt,
|
|
15908
15964
|
mimeType,
|
|
@@ -16555,10 +16611,10 @@ var system_stats_default = app34;
|
|
|
16555
16611
|
|
|
16556
16612
|
// server/routes/admin/health.ts
|
|
16557
16613
|
import { existsSync as existsSync25, readFileSync as readFileSync27 } from "fs";
|
|
16558
|
-
import { resolve as resolve23, join as
|
|
16614
|
+
import { resolve as resolve23, join as join27 } from "path";
|
|
16559
16615
|
var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve23(process.cwd(), "..");
|
|
16560
16616
|
var brandHostname = "maxy";
|
|
16561
|
-
var brandJsonPath =
|
|
16617
|
+
var brandJsonPath = join27(PLATFORM_ROOT6, "config", "brand.json");
|
|
16562
16618
|
if (existsSync25(brandJsonPath)) {
|
|
16563
16619
|
try {
|
|
16564
16620
|
const brand = JSON.parse(readFileSync27(brandJsonPath, "utf-8"));
|
|
@@ -17337,7 +17393,7 @@ var browser_default = app42;
|
|
|
17337
17393
|
|
|
17338
17394
|
// server/routes/admin/calendar.ts
|
|
17339
17395
|
import { existsSync as existsSync26 } from "fs";
|
|
17340
|
-
import { join as
|
|
17396
|
+
import { join as join29 } from "path";
|
|
17341
17397
|
|
|
17342
17398
|
// server/lib/calendar-ics.ts
|
|
17343
17399
|
var CRLF = "\r\n";
|
|
@@ -17437,7 +17493,7 @@ function countVEvents(ics) {
|
|
|
17437
17493
|
|
|
17438
17494
|
// server/lib/calendar-availability.ts
|
|
17439
17495
|
import { readFileSync as readFileSync28 } from "fs";
|
|
17440
|
-
import { join as
|
|
17496
|
+
import { join as join28 } from "path";
|
|
17441
17497
|
var AVAILABILITY_FILENAME = "calendar-availability.json";
|
|
17442
17498
|
var REQUIRED_KEYS = [
|
|
17443
17499
|
"timezone",
|
|
@@ -17446,7 +17502,7 @@ var REQUIRED_KEYS = [
|
|
|
17446
17502
|
"weekly"
|
|
17447
17503
|
];
|
|
17448
17504
|
function readAvailabilityConfig(accountDir) {
|
|
17449
|
-
const path2 =
|
|
17505
|
+
const path2 = join28(accountDir, AVAILABILITY_FILENAME);
|
|
17450
17506
|
let raw;
|
|
17451
17507
|
try {
|
|
17452
17508
|
raw = readFileSync28(path2, "utf-8");
|
|
@@ -17808,7 +17864,7 @@ app43.get("/booking-link", requireAdminSession, (c) => {
|
|
|
17808
17864
|
console.error('[calendar] op=booking-link-fail err="no account configured"');
|
|
17809
17865
|
return c.json({ bookingDomain: null });
|
|
17810
17866
|
}
|
|
17811
|
-
if (!existsSync26(
|
|
17867
|
+
if (!existsSync26(join29(account.accountDir, AVAILABILITY_FILENAME))) {
|
|
17812
17868
|
console.log("[calendar] op=booking-link bookingDomain=none source=availability-config");
|
|
17813
17869
|
return c.json({ bookingDomain: null });
|
|
17814
17870
|
}
|
|
@@ -18099,7 +18155,7 @@ app47.route("/request-magic-link", request_magic_link_default);
|
|
|
18099
18155
|
var access_default = app47;
|
|
18100
18156
|
|
|
18101
18157
|
// server/routes/sites.ts
|
|
18102
|
-
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";
|
|
18103
18159
|
import { resolve as resolve25 } from "path";
|
|
18104
18160
|
var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
|
|
18105
18161
|
var MIME = {
|
|
@@ -18191,8 +18247,8 @@ app48.get("/:rel{.*}", (c) => {
|
|
|
18191
18247
|
let realPath;
|
|
18192
18248
|
let realRoot;
|
|
18193
18249
|
try {
|
|
18194
|
-
realPath =
|
|
18195
|
-
realRoot =
|
|
18250
|
+
realPath = realpathSync6(filePath);
|
|
18251
|
+
realRoot = realpathSync6(rootDir);
|
|
18196
18252
|
} catch {
|
|
18197
18253
|
console.error(`[sites] not-found path=${reqPath} status=404`);
|
|
18198
18254
|
return c.text("Not found", 404);
|
|
@@ -18240,7 +18296,7 @@ var sites_default = app48;
|
|
|
18240
18296
|
// app/lib/visitor-token.ts
|
|
18241
18297
|
import { createHmac, randomBytes, timingSafeEqual } from "crypto";
|
|
18242
18298
|
import { mkdirSync as mkdirSync6, readFileSync as readFileSync30, writeFileSync as writeFileSync11 } from "fs";
|
|
18243
|
-
import { dirname as
|
|
18299
|
+
import { dirname as dirname8 } from "path";
|
|
18244
18300
|
var TOKEN_PREFIX = "v1.";
|
|
18245
18301
|
var SECRET_BYTES = 32;
|
|
18246
18302
|
var DEFAULT_TTL_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
@@ -18257,7 +18313,7 @@ function getSecret() {
|
|
|
18257
18313
|
}
|
|
18258
18314
|
const fresh = randomBytes(SECRET_BYTES).toString("hex");
|
|
18259
18315
|
try {
|
|
18260
|
-
mkdirSync6(
|
|
18316
|
+
mkdirSync6(dirname8(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
|
|
18261
18317
|
writeFileSync11(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
|
|
18262
18318
|
console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
|
|
18263
18319
|
} catch {
|
|
@@ -18316,7 +18372,7 @@ var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
|
|
|
18316
18372
|
|
|
18317
18373
|
// app/lib/brand-config.ts
|
|
18318
18374
|
import { existsSync as existsSync28, readFileSync as readFileSync31 } from "fs";
|
|
18319
|
-
import { join as
|
|
18375
|
+
import { join as join30 } from "path";
|
|
18320
18376
|
var cached2 = null;
|
|
18321
18377
|
var cachedAttempted = false;
|
|
18322
18378
|
function readBrandConfig() {
|
|
@@ -18324,7 +18380,7 @@ function readBrandConfig() {
|
|
|
18324
18380
|
cachedAttempted = true;
|
|
18325
18381
|
const platformRoot3 = process.env.MAXY_PLATFORM_ROOT;
|
|
18326
18382
|
if (!platformRoot3) return null;
|
|
18327
|
-
const brandPath =
|
|
18383
|
+
const brandPath = join30(platformRoot3, "config", "brand.json");
|
|
18328
18384
|
if (!existsSync28(brandPath)) return null;
|
|
18329
18385
|
try {
|
|
18330
18386
|
cached2 = JSON.parse(readFileSync31(brandPath, "utf-8"));
|
|
@@ -19365,7 +19421,7 @@ async function startFileWatcher(opts = {}) {
|
|
|
19365
19421
|
|
|
19366
19422
|
// app/lib/migrate-uploads.ts
|
|
19367
19423
|
import { mkdir as mkdir5, readdir as readdir5, rename as rename2, rm as rm3 } from "fs/promises";
|
|
19368
|
-
import { dirname as
|
|
19424
|
+
import { dirname as dirname9, relative as relative6, resolve as resolve28 } from "path";
|
|
19369
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;
|
|
19370
19426
|
async function walkFiles(dir) {
|
|
19371
19427
|
const out = [];
|
|
@@ -19397,7 +19453,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
|
|
|
19397
19453
|
for (const oldAbs of files) {
|
|
19398
19454
|
const suffix = relative6(srcDir, oldAbs);
|
|
19399
19455
|
const newAbs = resolve28(destDir, suffix);
|
|
19400
|
-
await mkdir5(
|
|
19456
|
+
await mkdir5(dirname9(newAbs), { recursive: true });
|
|
19401
19457
|
await rename2(oldAbs, newAbs);
|
|
19402
19458
|
moved++;
|
|
19403
19459
|
const oldRel = relative6(dataRoot, oldAbs);
|
|
@@ -19489,7 +19545,7 @@ async function migrateUploads(opts = {}) {
|
|
|
19489
19545
|
// app/lib/migrate-admin-webchat-sidecars.ts
|
|
19490
19546
|
import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as writeFile4, unlink as unlink3 } from "fs/promises";
|
|
19491
19547
|
import { existsSync as existsSync30 } from "fs";
|
|
19492
|
-
import { join as
|
|
19548
|
+
import { join as join31 } from "path";
|
|
19493
19549
|
var ADMIN_ROLE2 = "admin";
|
|
19494
19550
|
var WEBCHAT_CHANNEL2 = "webchat";
|
|
19495
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;
|
|
@@ -19534,7 +19590,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
19534
19590
|
}
|
|
19535
19591
|
for (const slug of slugs) {
|
|
19536
19592
|
if (!slug.isDirectory()) continue;
|
|
19537
|
-
const slugDir =
|
|
19593
|
+
const slugDir = join31(projectsRoot, slug.name);
|
|
19538
19594
|
let entries;
|
|
19539
19595
|
try {
|
|
19540
19596
|
entries = await readdir6(slugDir, { withFileTypes: true });
|
|
@@ -19543,9 +19599,9 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
19543
19599
|
}
|
|
19544
19600
|
for (const entry of entries) {
|
|
19545
19601
|
if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
|
|
19546
|
-
out.push(
|
|
19602
|
+
out.push(join31(slugDir, entry.name));
|
|
19547
19603
|
} else if (entry.isDirectory() && entry.name === "subagents") {
|
|
19548
|
-
const subDir =
|
|
19604
|
+
const subDir = join31(slugDir, entry.name);
|
|
19549
19605
|
let subs;
|
|
19550
19606
|
try {
|
|
19551
19607
|
subs = await readdir6(subDir, { withFileTypes: true });
|
|
@@ -19553,7 +19609,7 @@ async function collectLiveSidecars(projectsRoot) {
|
|
|
19553
19609
|
continue;
|
|
19554
19610
|
}
|
|
19555
19611
|
for (const s of subs) {
|
|
19556
|
-
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));
|
|
19557
19613
|
}
|
|
19558
19614
|
}
|
|
19559
19615
|
}
|
|
@@ -19565,7 +19621,7 @@ function shortId(path2) {
|
|
|
19565
19621
|
return base.slice(0, 8);
|
|
19566
19622
|
}
|
|
19567
19623
|
async function migrateAdminWebchatSidecars(opts = {}) {
|
|
19568
|
-
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) ?? "";
|
|
19569
19625
|
const usersFile = opts.usersFile ?? USERS_FILE;
|
|
19570
19626
|
const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
|
|
19571
19627
|
const resolveName = opts.resolveName ?? defaultResolveName;
|
|
@@ -21473,9 +21529,9 @@ function buildTelegramSpawnRequest(input) {
|
|
|
21473
21529
|
}
|
|
21474
21530
|
|
|
21475
21531
|
// app/lib/telegram/outbound/send-document.ts
|
|
21476
|
-
import { realpathSync as
|
|
21532
|
+
import { realpathSync as realpathSync7 } from "fs";
|
|
21477
21533
|
import { readFile as readFile7, stat as stat7 } from "fs/promises";
|
|
21478
|
-
import { resolve as resolve29, basename as
|
|
21534
|
+
import { resolve as resolve29, basename as basename11 } from "path";
|
|
21479
21535
|
var TAG35 = "[telegram:outbound]";
|
|
21480
21536
|
var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
|
|
21481
21537
|
async function sendTelegramDocument(input) {
|
|
@@ -21489,8 +21545,8 @@ async function sendTelegramDocument(input) {
|
|
|
21489
21545
|
const accountDir = resolve29(platformRoot3, "..", "data/accounts", maxyAccountId);
|
|
21490
21546
|
let resolvedPath;
|
|
21491
21547
|
try {
|
|
21492
|
-
resolvedPath =
|
|
21493
|
-
const accountResolved =
|
|
21548
|
+
resolvedPath = realpathSync7(filePath);
|
|
21549
|
+
const accountResolved = realpathSync7(accountDir);
|
|
21494
21550
|
if (!resolvedPath.startsWith(accountResolved + "/")) {
|
|
21495
21551
|
console.error(`${TAG35} document REJECTED reason=outside_account_directory`);
|
|
21496
21552
|
return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
|
|
@@ -21512,7 +21568,7 @@ async function sendTelegramDocument(input) {
|
|
|
21512
21568
|
error: `File exceeds 50 MB limit (${(fileStat.size / 1024 / 1024).toFixed(1)} MB)`
|
|
21513
21569
|
};
|
|
21514
21570
|
}
|
|
21515
|
-
const filename =
|
|
21571
|
+
const filename = basename11(resolvedPath);
|
|
21516
21572
|
const buffer = Buffer.from(await readFile7(resolvedPath));
|
|
21517
21573
|
const form = new FormData();
|
|
21518
21574
|
form.append("chat_id", String(chatId));
|
|
@@ -21622,12 +21678,12 @@ function startTelegramNativeFileFollower(input) {
|
|
|
21622
21678
|
}
|
|
21623
21679
|
|
|
21624
21680
|
// server/telegram-descriptor.ts
|
|
21625
|
-
import { resolve as resolve30, join as
|
|
21681
|
+
import { resolve as resolve30, join as join32 } from "path";
|
|
21626
21682
|
function telegramGatewayUrl() {
|
|
21627
21683
|
return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
|
|
21628
21684
|
}
|
|
21629
21685
|
function telegramServerPath() {
|
|
21630
|
-
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");
|
|
21631
21687
|
}
|
|
21632
21688
|
|
|
21633
21689
|
// app/lib/channel-pty-bridge/public-session-end-review.ts
|
|
@@ -22088,7 +22144,7 @@ function clientFrom(c) {
|
|
|
22088
22144
|
);
|
|
22089
22145
|
}
|
|
22090
22146
|
var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
|
|
22091
|
-
var BRAND_JSON_PATH = PLATFORM_ROOT8 ?
|
|
22147
|
+
var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join33(PLATFORM_ROOT8, "config", "brand.json") : "";
|
|
22092
22148
|
var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
|
|
22093
22149
|
if (BRAND_JSON_PATH && !existsSync32(BRAND_JSON_PATH)) {
|
|
22094
22150
|
console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
|
|
@@ -22127,7 +22183,7 @@ var brandLoginOpts = {
|
|
|
22127
22183
|
appleTouchIconPath: brandAppIcon512Path,
|
|
22128
22184
|
themeColor: BRAND.defaultColors?.primary
|
|
22129
22185
|
};
|
|
22130
|
-
var ALIAS_DOMAINS_PATH =
|
|
22186
|
+
var ALIAS_DOMAINS_PATH = join33(homedir3(), BRAND.configDir, "alias-domains.json");
|
|
22131
22187
|
function loadAliasDomains() {
|
|
22132
22188
|
try {
|
|
22133
22189
|
if (!existsSync32(ALIAS_DOMAINS_PATH)) return null;
|
|
@@ -22159,7 +22215,7 @@ var app54 = new Hono();
|
|
|
22159
22215
|
var nativeFileFollowers = /* @__PURE__ */ new Map();
|
|
22160
22216
|
var waGateway = new WaGateway({
|
|
22161
22217
|
gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
|
|
22162
|
-
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"),
|
|
22163
22219
|
// Task 751 — file delivery on the native channel: resolve the platform
|
|
22164
22220
|
// account + path validation here and funnel through the shared send core.
|
|
22165
22221
|
sendDocument: async ({ senderId, accountId, filePath, caption }) => {
|
|
@@ -22175,7 +22231,7 @@ var waGateway = new WaGateway({
|
|
|
22175
22231
|
caption,
|
|
22176
22232
|
accountId,
|
|
22177
22233
|
maxyAccountId,
|
|
22178
|
-
platformRoot: resolve32(process.env.MAXY_PLATFORM_ROOT ??
|
|
22234
|
+
platformRoot: resolve32(process.env.MAXY_PLATFORM_ROOT ?? join33(__dirname, ".."))
|
|
22179
22235
|
});
|
|
22180
22236
|
return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
|
|
22181
22237
|
},
|
|
@@ -22779,7 +22835,7 @@ var SW_SOURCE = (() => {
|
|
|
22779
22835
|
function readInstalledVersion() {
|
|
22780
22836
|
try {
|
|
22781
22837
|
if (!PLATFORM_ROOT8) return "unknown";
|
|
22782
|
-
const versionFile =
|
|
22838
|
+
const versionFile = join33(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
|
|
22783
22839
|
if (!existsSync32(versionFile)) return "unknown";
|
|
22784
22840
|
const content = readFileSync33(versionFile, "utf-8").trim();
|
|
22785
22841
|
return content || "unknown";
|
|
@@ -22839,11 +22895,11 @@ ${clientErrorReporterScript}
|
|
|
22839
22895
|
return html;
|
|
22840
22896
|
}
|
|
22841
22897
|
function loadBrandingCache(agentSlug) {
|
|
22842
|
-
const configDir2 =
|
|
22898
|
+
const configDir2 = join33(homedir3(), BRAND.configDir);
|
|
22843
22899
|
try {
|
|
22844
22900
|
const accountId = getDefaultAccountId();
|
|
22845
22901
|
if (!accountId) return null;
|
|
22846
|
-
const cachePath =
|
|
22902
|
+
const cachePath = join33(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
|
|
22847
22903
|
if (!existsSync32(cachePath)) return null;
|
|
22848
22904
|
return JSON.parse(readFileSync33(cachePath, "utf-8"));
|
|
22849
22905
|
} catch {
|
|
@@ -23063,7 +23119,7 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
|
|
|
23063
23119
|
var httpServer = serve({ fetch: app54.fetch, port, hostname });
|
|
23064
23120
|
console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
23065
23121
|
{
|
|
23066
|
-
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
23122
|
+
const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join33(__dirname, "..");
|
|
23067
23123
|
const reconcileScript = resolve32(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
|
|
23068
23124
|
const RECONCILE_INTERVAL_MS = 12e4;
|
|
23069
23125
|
const runReconcile = () => {
|
|
@@ -23085,7 +23141,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
|
|
|
23085
23141
|
loop.unref();
|
|
23086
23142
|
}
|
|
23087
23143
|
{
|
|
23088
|
-
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ??
|
|
23144
|
+
const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join33(__dirname, "..");
|
|
23089
23145
|
const auditScript = resolve32(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
|
|
23090
23146
|
const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
|
|
23091
23147
|
const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
|
|
@@ -23290,7 +23346,7 @@ try {
|
|
|
23290
23346
|
} catch (err) {
|
|
23291
23347
|
console.error(`[graph-health] account-enumeration unavailable reason=${err instanceof Error ? err.message : String(err)}`);
|
|
23292
23348
|
}
|
|
23293
|
-
var configDirForWhatsApp =
|
|
23349
|
+
var configDirForWhatsApp = basename12(MAXY_DIR) || ".maxy";
|
|
23294
23350
|
var bootAccount = resolveAccount();
|
|
23295
23351
|
if (bootAccount) {
|
|
23296
23352
|
migrateRemovedConfigKeys(bootAccount.accountDir);
|
|
@@ -23352,7 +23408,7 @@ if (bootAccountConfig?.whatsapp) {
|
|
|
23352
23408
|
}
|
|
23353
23409
|
init({
|
|
23354
23410
|
configDir: configDirForWhatsApp,
|
|
23355
|
-
platformRoot: resolve32(process.env.MAXY_PLATFORM_ROOT ??
|
|
23411
|
+
platformRoot: resolve32(process.env.MAXY_PLATFORM_ROOT ?? join33(__dirname, "..")),
|
|
23356
23412
|
accountConfig: bootAccountConfig,
|
|
23357
23413
|
onMessage: async (msg) => {
|
|
23358
23414
|
if (msg.isOwnerMirror) {
|