@rubytech/create-maxy-code 0.1.370 → 0.1.372

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