@rubytech/create-maxy-code 0.1.505 → 0.1.506

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 (75) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/lib/account-schema-regions/dist/index.d.ts +60 -0
  3. package/payload/platform/lib/account-schema-regions/dist/index.d.ts.map +1 -0
  4. package/payload/platform/lib/account-schema-regions/dist/index.js +101 -0
  5. package/payload/platform/lib/account-schema-regions/dist/index.js.map +1 -0
  6. package/payload/platform/lib/account-schema-regions/package.json +7 -0
  7. package/payload/platform/lib/account-schema-regions/src/index.ts +121 -0
  8. package/payload/platform/lib/account-schema-regions/tsconfig.json +9 -0
  9. package/payload/platform/package.json +3 -3
  10. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +59 -17
  11. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +3 -3
  12. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
  13. package/payload/platform/plugins/docs/references/admin-ui.md +58 -16
  14. package/payload/platform/scripts/check-no-esm-require.mjs +5 -0
  15. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts +1 -1
  16. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
  17. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +50 -3
  18. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
  19. package/payload/server/{chunk-HN4HFTXE.js → chunk-5ADBNEJA.js} +1410 -1409
  20. package/payload/server/maxy-edge.js +1 -1
  21. package/payload/server/public/activity.html +5 -5
  22. package/payload/server/public/agents.html +4 -4
  23. package/payload/server/public/assets/{AdminLoginScreens-DeWt3H7l.js → AdminLoginScreens-D5KOQA8S.js} +1 -1
  24. package/payload/server/public/assets/{AdminShell-u32d8puE.js → AdminShell-C8wazpnz.js} +2 -2
  25. package/payload/server/public/assets/{activity-DjP45-DD.js → activity-CFqkDhTs.js} +1 -1
  26. package/payload/server/public/assets/admin-B-EGUWS4.js +1 -0
  27. package/payload/server/public/assets/agents-DPulfmrd.js +1 -0
  28. package/payload/server/public/assets/{browser-ULvl_K5x.js → browser-T_5xbnJh.js} +1 -1
  29. package/payload/server/public/assets/{calendar-CGMrT6WZ.js → calendar-CKjuiG8c.js} +1 -1
  30. package/payload/server/public/assets/chat-DWLYAA70.js +1 -0
  31. package/payload/server/public/assets/chevron-left-DBMCTKlT.js +1 -0
  32. package/payload/server/public/assets/chevron-right-SBAr6zzc.js +1 -0
  33. package/payload/server/public/assets/clock-kkzt7Scf.js +1 -0
  34. package/payload/server/public/assets/data-CV8N9qcy.js +1 -0
  35. package/payload/server/public/assets/{file-text-C5K6DMcK.js → file-text-c6cA4Evd.js} +1 -1
  36. package/payload/server/public/assets/{graph-CO6e1bgD.js → graph-DIk-o45J.js} +2 -2
  37. package/payload/server/public/assets/{graph-labels-iliQjlfE.js → graph-labels-5bjxhC_p.js} +1 -1
  38. package/payload/server/public/assets/{maximize-2-D-64XK6V.js → maximize-2-BCQkFb1_.js} +1 -1
  39. package/payload/server/public/assets/{operator-DyXgogJ1.js → operator-0UnNo2ms.js} +1 -1
  40. package/payload/server/public/assets/page-HVtUfub2.js +32 -0
  41. package/payload/server/public/assets/page-JJa2xdzf.js +1 -0
  42. package/payload/server/public/assets/{public-B9NVDBxW.js → public-CKEYyIPn.js} +1 -1
  43. package/payload/server/public/assets/{rotate-ccw-P35h7ogS.js → rotate-ccw-dTpO5dhL.js} +1 -1
  44. package/payload/server/public/assets/{routines-BeiynLF7.js → routines-C6P1-Dto.js} +1 -1
  45. package/payload/server/public/assets/{skills-C5H7ohLp.js → skills-ClrpVqlz.js} +1 -1
  46. package/payload/server/public/assets/tasks-C8SNhSFC.js +1 -0
  47. package/payload/server/public/assets/{time-entry-format-CDhHCMrW.js → time-entry-format-CCO6N6XZ.js} +1 -1
  48. package/payload/server/public/assets/{triangle-alert-OgY71rDV.js → triangle-alert-CHjdKpag.js} +1 -1
  49. package/payload/server/public/assets/{useCopyFeedback-jOGmWwa3.js → useCopyFeedback-BTUu3-l8.js} +1 -1
  50. package/payload/server/public/assets/{useSubAccountSwitcher-6AFuRawP.js → useSubAccountSwitcher-DSW9vDi2.js} +1 -1
  51. package/payload/server/public/assets/{useSubAccountSwitcher-AFSwtthL.css → useSubAccountSwitcher-DyrH8DA8.css} +1 -1
  52. package/payload/server/public/assets/{useVoiceRecorder-CnE3fhfV.js → useVoiceRecorder-BeNqxmm2.js} +1 -1
  53. package/payload/server/public/assets/{wrench-B1hsCj0R.js → wrench-CeNnc7oO.js} +1 -1
  54. package/payload/server/public/browser.html +4 -4
  55. package/payload/server/public/calendar.html +7 -7
  56. package/payload/server/public/chat.html +13 -13
  57. package/payload/server/public/data.html +11 -11
  58. package/payload/server/public/graph.html +9 -9
  59. package/payload/server/public/index.html +14 -14
  60. package/payload/server/public/operator.html +14 -14
  61. package/payload/server/public/public.html +13 -13
  62. package/payload/server/public/routines.html +6 -6
  63. package/payload/server/public/skills.html +5 -5
  64. package/payload/server/public/tasks.html +6 -6
  65. package/payload/server/server.js +1329 -826
  66. package/payload/server/public/assets/admin-Bo-Y6Vjx.js +0 -1
  67. package/payload/server/public/assets/agents-C80aCXd8.js +0 -1
  68. package/payload/server/public/assets/chat-DnWXaWD4.js +0 -1
  69. package/payload/server/public/assets/chevron-left-BB5Iljw-.js +0 -1
  70. package/payload/server/public/assets/chevron-right-DijU96_j.js +0 -1
  71. package/payload/server/public/assets/clock-DsmnhhJh.js +0 -1
  72. package/payload/server/public/assets/data-JPlhOLGC.js +0 -1
  73. package/payload/server/public/assets/page-DrbiAFS-.js +0 -32
  74. package/payload/server/public/assets/page-WeM2ry61.js +0 -1
  75. package/payload/server/public/assets/tasks-CI74_b6H.js +0 -1
@@ -91,6 +91,7 @@ import {
91
91
  requirePortEnv,
92
92
  resolveAccount,
93
93
  resolveAgentConfig,
94
+ resolveCacheKey,
94
95
  resolveCallback,
95
96
  resolveClientIp,
96
97
  resolveDefaultAgentSlug,
@@ -117,7 +118,7 @@ import {
117
118
  vncLog,
118
119
  walkPremiumBundles,
119
120
  writeAdminUserAndPerson
120
- } from "./chunk-HN4HFTXE.js";
121
+ } from "./chunk-5ADBNEJA.js";
121
122
  import {
122
123
  D1_MAX_SQL_STATEMENT_BYTES,
123
124
  D1_QUERY_MAX_BODY_BYTES,
@@ -217,8 +218,69 @@ ${lines.join("\n")}`;
217
218
  }
218
219
  });
219
220
 
220
- // ../lib/graph-trash/dist/index.js
221
+ // ../lib/account-schema-regions/dist/index.js
221
222
  var require_dist2 = __commonJS({
223
+ "../lib/account-schema-regions/dist/index.js"(exports) {
224
+ "use strict";
225
+ Object.defineProperty(exports, "__esModule", { value: true });
226
+ exports.HOME_FIXED = void 0;
227
+ exports.parseSchemaRegions = parseSchemaRegions2;
228
+ exports.HOME_FIXED = Object.freeze(["projects", "contacts", "documents"]);
229
+ var ONT_START2 = "<!-- ontology-buckets:start -->";
230
+ var ONT_END2 = "<!-- ontology-buckets:end -->";
231
+ var PLUGIN_START = "<!-- plugin-owned-dirs:start -->";
232
+ var PLUGIN_END = "<!-- plugin-owned-dirs:end -->";
233
+ var ALLOWED_FENCE = "```allowed-top-level";
234
+ var DIR_LINE = /^-\s+`([^`/]+)\/`/;
235
+ function regionLines(text, start, end) {
236
+ const from = text.indexOf(start);
237
+ if (from === -1)
238
+ return [];
239
+ const to = text.indexOf(end, from);
240
+ if (to === -1)
241
+ return [];
242
+ return text.slice(from + start.length, to).split("\n");
243
+ }
244
+ function dirsIn(lines) {
245
+ const out = [];
246
+ for (const line of lines) {
247
+ const m = DIR_LINE.exec(line.trim());
248
+ if (m && !out.includes(m[1]))
249
+ out.push(m[1]);
250
+ }
251
+ return out;
252
+ }
253
+ function fenceEntries(text) {
254
+ const from = text.indexOf(ALLOWED_FENCE);
255
+ if (from === -1)
256
+ return [];
257
+ const bodyStart = text.indexOf("\n", from);
258
+ if (bodyStart === -1)
259
+ return [];
260
+ const to = text.indexOf("```", bodyStart);
261
+ if (to === -1)
262
+ return [];
263
+ return text.slice(bodyStart + 1, to).split("\n").map((s) => s.trim()).filter((s) => s.length > 0);
264
+ }
265
+ function parseSchemaRegions2(schemaMd) {
266
+ if (schemaMd === null || schemaMd.length === 0) {
267
+ return { ontologyRoots: [], pluginOwned: [], allowedTopLevel: [], parsed: false, reason: "schema-absent" };
268
+ }
269
+ const allowedTopLevel = fenceEntries(schemaMd);
270
+ const parsed = allowedTopLevel.length > 0;
271
+ return {
272
+ ontologyRoots: dirsIn(regionLines(schemaMd, ONT_START2, ONT_END2)),
273
+ pluginOwned: dirsIn(regionLines(schemaMd, PLUGIN_START, PLUGIN_END)),
274
+ allowedTopLevel,
275
+ parsed,
276
+ reason: parsed ? "ok" : "fence-absent"
277
+ };
278
+ }
279
+ }
280
+ });
281
+
282
+ // ../lib/graph-trash/dist/index.js
283
+ var require_dist3 = __commonJS({
222
284
  "../lib/graph-trash/dist/index.js"(exports) {
223
285
  "use strict";
224
286
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -499,7 +561,7 @@ var require_dist2 = __commonJS({
499
561
  });
500
562
 
501
563
  // ../lib/graph-style/dist/index.js
502
- var require_dist3 = __commonJS({
564
+ var require_dist4 = __commonJS({
503
565
  "../lib/graph-style/dist/index.js"(exports) {
504
566
  "use strict";
505
567
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -1228,7 +1290,7 @@ var require_conversation_provenance = __commonJS({
1228
1290
  "use strict";
1229
1291
  Object.defineProperty(exports, "__esModule", { value: true });
1230
1292
  exports.injectConversationProvenance = injectConversationProvenance;
1231
- var index_js_1 = require_dist4();
1293
+ var index_js_1 = require_dist5();
1232
1294
  async function injectConversationProvenance(params) {
1233
1295
  const { session, relationships, accountId, writeLabels, conversationNodeId, logNamespace, tool } = params;
1234
1296
  const original = [...relationships];
@@ -1278,7 +1340,7 @@ var require_conversation_provenance = __commonJS({
1278
1340
  });
1279
1341
 
1280
1342
  // ../lib/graph-write/dist/index.js
1281
- var require_dist4 = __commonJS({
1343
+ var require_dist5 = __commonJS({
1282
1344
  "../lib/graph-write/dist/index.js"(exports) {
1283
1345
  "use strict";
1284
1346
  var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
@@ -1756,194 +1818,138 @@ var serveStatic = (options = { root: "" }) => {
1756
1818
  import { readFileSync as readFileSync47, existsSync as existsSync46, watchFile, readdirSync as readdirSync28, statSync as statSync20 } from "fs";
1757
1819
  import { spawn as spawn3 } from "child_process";
1758
1820
  import { createHash as createHash7 } from "crypto";
1759
- import { resolve as resolve44, join as join47, basename as basename14 } from "path";
1821
+ import { resolve as resolve45, join as join47, basename as basename14 } from "path";
1760
1822
  import { homedir as homedir4 } from "os";
1761
- import { monitorEventLoopDelay } from "perf_hooks";
1762
1823
 
1763
- // app/lib/whatsapp/inbound/media-download-guard.ts
1764
- var TAG = "[media-guard]";
1765
- var inFlight = 0;
1766
- var containedCount = 0;
1767
- function containedSinceBoot() {
1768
- return containedCount;
1769
- }
1770
- function beginMediaDownload() {
1771
- inFlight += 1;
1772
- }
1773
- function endMediaDownload() {
1774
- if (inFlight > 0) inFlight -= 1;
1775
- }
1776
- function mediaDownloadsInFlight() {
1777
- return inFlight;
1778
- }
1779
- function stackOf(err) {
1780
- if (err instanceof Error) return err.stack ?? err.message;
1781
- return String(err);
1782
- }
1783
- function causeCode(err) {
1784
- const cause = err?.cause;
1785
- const code = cause?.code;
1786
- return typeof code === "string" ? code : "none";
1787
- }
1788
- function handleEscapedMediaError(err, channel) {
1789
- const stack = stackOf(err);
1790
- const undiciFrame = /node_modules[\\/]undici|node:internal[\\/]deps[\\/]undici/.test(stack);
1791
- if (undiciFrame && inFlight > 0) {
1792
- containedCount += 1;
1793
- console.error(
1794
- `${TAG} op=contained channel=${channel} inFlight=${inFlight} err=${err instanceof Error ? err.message : String(err)} cause=${causeCode(err)}
1795
- ${stack}`
1796
- );
1797
- return true;
1798
- }
1799
- console.error(
1800
- `${TAG} op=escaped channel=${channel} inFlight=${inFlight} undiciFrame=${undiciFrame} err=${err instanceof Error ? err.message : String(err)} cause=${causeCode(err)} contained=false`
1824
+ // server/lib/route-cache-watchers.ts
1825
+ import { watch } from "fs";
1826
+ import { resolve as resolve2 } from "path";
1827
+
1828
+ // server/lib/route-cache.ts
1829
+ var BACKSTOP_MS = 3e4;
1830
+ var NOTIFY_COALESCE_MS = 1e3;
1831
+ var RECOMPUTE_FLOOR_FACTOR = 10;
1832
+ var MIN_RECOMPUTE_FLOOR_MS = 1e3;
1833
+ var MAX_RECOMPUTE_FLOOR_MS = 1e4;
1834
+ var entries = /* @__PURE__ */ new Map();
1835
+ var inFlight = /* @__PURE__ */ new Map();
1836
+ var keyGenerations = /* @__PURE__ */ new Map();
1837
+ var resourceGenerations = /* @__PURE__ */ new Map();
1838
+ var listeners = /* @__PURE__ */ new Set();
1839
+ var pendingNotifications = /* @__PURE__ */ new Map();
1840
+ var notifyTimer = null;
1841
+ function keyOf(resource, accountId) {
1842
+ return `${resource}::${accountId}`;
1843
+ }
1844
+ function generationOf(resource, key) {
1845
+ return (keyGenerations.get(key) ?? 0) + (resourceGenerations.get(resource) ?? 0);
1846
+ }
1847
+ function recomputeFloorMs(entry) {
1848
+ return Math.min(
1849
+ Math.max(entry.computeMs * RECOMPUTE_FLOOR_FACTOR, MIN_RECOMPUTE_FLOOR_MS),
1850
+ MAX_RECOMPUTE_FLOOR_MS
1801
1851
  );
1802
- return false;
1803
- }
1804
- var installed = false;
1805
- function guardInstalled() {
1806
- return installed;
1807
- }
1808
- function installMediaDownloadGuard() {
1809
- if (installed) return;
1810
- installed = true;
1811
- process.on("uncaughtException", (err) => {
1812
- if (handleEscapedMediaError(err, "uncaughtException")) return;
1813
- process.stderr.write(`${err instanceof Error ? err.stack ?? err.message : String(err)}
1814
- `);
1815
- process.exit(1);
1816
- });
1817
- process.on("unhandledRejection", (reason) => {
1818
- if (handleEscapedMediaError(reason, "unhandledRejection")) return;
1819
- process.stderr.write(
1820
- `Unhandled rejection: ${reason instanceof Error ? reason.stack ?? reason.message : String(reason)}
1821
- `
1822
- );
1823
- process.exit(1);
1824
- });
1825
- console.error(`${TAG} op=installed`);
1826
1852
  }
1827
-
1828
- // app/lib/whatsapp/ingest-audit.ts
1829
- import { readdirSync as readdirSync3, readFileSync as readFileSync3, statSync as statSync3 } from "fs";
1830
- import { join as join4 } from "path";
1831
-
1832
- // app/lib/whatsapp/ingest-ledger.ts
1833
- import { existsSync as existsSync2, mkdirSync, appendFileSync, readFileSync, writeFileSync, readdirSync } from "fs";
1834
- import { join as join2 } from "path";
1835
- var TAG2 = "[wa-ingest-ledger]";
1836
- var LEDGER_ROOT = () => join2(process.env.MAXY_DIR_OVERRIDE ?? MAXY_DIR, "data", "whatsapp-ingest-ledger");
1837
- var ensuredRoots = /* @__PURE__ */ new Set();
1838
- function ledgerFilePath(account) {
1839
- const root = LEDGER_ROOT();
1840
- if (!ensuredRoots.has(root)) {
1841
- if (!existsSync2(root)) mkdirSync(root, { recursive: true });
1842
- ensuredRoots.add(root);
1853
+ async function getOrCompute(resource, accountId, compute) {
1854
+ const key = keyOf(resource, accountId);
1855
+ const entry = entries.get(key);
1856
+ if (entry !== void 0) {
1857
+ const age = Date.now() - entry.computedAt;
1858
+ if (!entry.dirty && age <= BACKSTOP_MS) {
1859
+ return { value: entry.value, state: "hit" };
1860
+ }
1861
+ const sinceAttempt = Date.now() - entry.lastAttemptAt;
1862
+ if (entry.dirty && sinceAttempt < recomputeFloorMs(entry) && age <= BACKSTOP_MS) {
1863
+ return { value: entry.value, state: "dirty-floor" };
1864
+ }
1843
1865
  }
1844
- return join2(root, `${account}.jsonl`);
1845
- }
1846
- function appendStanza(entry) {
1847
- try {
1848
- const row = {
1849
- msgId: entry.msgId,
1850
- from: entry.from,
1851
- type: entry.type,
1852
- ts: (/* @__PURE__ */ new Date()).toISOString()
1853
- };
1854
- appendFileSync(ledgerFilePath(entry.account), JSON.stringify(row) + "\n");
1855
- } catch (err) {
1856
- console.error(
1857
- `${TAG2} FAIL op=append msgId=${entry.msgId} err=${err instanceof Error ? err.message : String(err)}`
1858
- );
1866
+ const state = entry === void 0 ? "miss" : "stale-backstop";
1867
+ const existing = inFlight.get(key);
1868
+ if (existing) return { value: await existing, state };
1869
+ const startedGeneration = generationOf(resource, key);
1870
+ const startedAt = Date.now();
1871
+ const pending = compute();
1872
+ inFlight.set(key, pending);
1873
+ try {
1874
+ const value = await pending;
1875
+ const finishedAt = Date.now();
1876
+ const computeMs = finishedAt - startedAt;
1877
+ if (value !== null && generationOf(resource, key) === startedGeneration) {
1878
+ entries.set(key, {
1879
+ value,
1880
+ computedAt: finishedAt,
1881
+ computeMs,
1882
+ dirty: false,
1883
+ lastAttemptAt: finishedAt
1884
+ });
1885
+ } else {
1886
+ const prior = entries.get(key);
1887
+ if (prior) {
1888
+ prior.lastAttemptAt = finishedAt;
1889
+ prior.computeMs = computeMs;
1890
+ }
1891
+ }
1892
+ return { value, state };
1893
+ } finally {
1894
+ inFlight.delete(key);
1859
1895
  }
1860
1896
  }
1861
- function markDeclined(entry) {
1862
- try {
1863
- const row = {
1864
- declined: entry.msgId,
1865
- reason: entry.reason,
1866
- ts: (/* @__PURE__ */ new Date()).toISOString()
1867
- };
1868
- appendFileSync(ledgerFilePath(entry.account), JSON.stringify(row) + "\n");
1869
- } catch (err) {
1870
- console.error(
1871
- `${TAG2} FAIL op=decline msgId=${entry.msgId} err=${err instanceof Error ? err.message : String(err)}`
1872
- );
1897
+ function flushNotifications() {
1898
+ notifyTimer = null;
1899
+ const batch = [...pendingNotifications.values()];
1900
+ pendingNotifications.clear();
1901
+ for (const { resource, accountId } of batch) {
1902
+ for (const fn of listeners) fn(resource, accountId);
1873
1903
  }
1874
1904
  }
1875
- function readDeclined(account) {
1876
- const path3 = ledgerFilePath(account);
1877
- const out = /* @__PURE__ */ new Set();
1878
- if (!existsSync2(path3)) return out;
1879
- for (const line of readFileSync(path3, "utf8").split("\n")) {
1880
- if (!line.trim()) continue;
1881
- try {
1882
- const row = JSON.parse(line);
1883
- if (typeof row.declined === "string") out.add(row.declined);
1884
- } catch {
1905
+ function invalidate(resource, accountId, source = "action") {
1906
+ const markOrDrop = (key) => {
1907
+ if (source === "action") {
1908
+ entries.delete(key);
1909
+ return;
1885
1910
  }
1886
- }
1887
- return out;
1888
- }
1889
- function readLedger(account) {
1890
- const path3 = ledgerFilePath(account);
1891
- if (!existsSync2(path3)) return [];
1892
- const out = [];
1893
- for (const line of readFileSync(path3, "utf8").split("\n")) {
1894
- if (!line.trim()) continue;
1895
- try {
1896
- const row = JSON.parse(line);
1897
- if (row && typeof row.msgId === "string") out.push(row);
1898
- } catch {
1911
+ const entry = entries.get(key);
1912
+ if (entry) entry.dirty = true;
1913
+ };
1914
+ if (accountId === null) {
1915
+ resourceGenerations.set(resource, (resourceGenerations.get(resource) ?? 0) + 1);
1916
+ for (const key of [...entries.keys()]) {
1917
+ if (key.startsWith(`${resource}::`)) markOrDrop(key);
1899
1918
  }
1919
+ } else {
1920
+ const key = keyOf(resource, accountId);
1921
+ keyGenerations.set(key, (keyGenerations.get(key) ?? 0) + 1);
1922
+ markOrDrop(key);
1900
1923
  }
1901
- return out;
1902
- }
1903
- function pruneLedger(account, olderThanMs) {
1904
- const path3 = ledgerFilePath(account);
1905
- if (!existsSync2(path3)) return 0;
1906
- const lines = readFileSync(path3, "utf8").split("\n").filter((l) => l.trim());
1907
- const cutoff = Date.now() - olderThanMs;
1908
- const kept = lines.filter((line) => {
1909
- try {
1910
- const row = JSON.parse(line);
1911
- const t = typeof row.ts === "string" ? Date.parse(row.ts) : NaN;
1912
- return Number.isFinite(t) && t >= cutoff;
1913
- } catch {
1914
- return false;
1915
- }
1916
- });
1917
- if (kept.length === lines.length) return 0;
1918
- writeFileSync(path3, kept.join("\n") + (kept.length ? "\n" : ""));
1919
- return lines.length - kept.length;
1920
- }
1921
- function listLedgerAccounts() {
1922
- const root = LEDGER_ROOT();
1923
- if (!existsSync2(root)) return [];
1924
- try {
1925
- return readdirSync(root).filter((f) => f.endsWith(".jsonl")).map((f) => f.slice(0, -".jsonl".length));
1926
- } catch {
1927
- return [];
1924
+ pendingNotifications.set(`${resource}::${accountId ?? "*"}`, { resource, accountId });
1925
+ if (notifyTimer === null) {
1926
+ notifyTimer = setTimeout(flushNotifications, NOTIFY_COALESCE_MS);
1927
+ if (typeof notifyTimer === "object" && "unref" in notifyTimer) notifyTimer.unref();
1928
1928
  }
1929
1929
  }
1930
+ function onInvalidate(fn) {
1931
+ listeners.add(fn);
1932
+ return () => {
1933
+ listeners.delete(fn);
1934
+ };
1935
+ }
1930
1936
 
1931
1937
  // app/lib/whatsapp/message-store.ts
1932
- import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, appendFileSync as appendFileSync2, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
1933
- import { dirname, join as join3 } from "path";
1938
+ import { existsSync as existsSync2, mkdirSync, readFileSync, appendFileSync, readdirSync, statSync as statSync2 } from "fs";
1939
+ import { dirname, join as join2 } from "path";
1934
1940
  function isReactionRecord(r) {
1935
1941
  return r.kind === "reaction";
1936
1942
  }
1937
- var STORE_ROOT = () => join3(process.env.MAXY_DIR_OVERRIDE ?? MAXY_DIR, "data", "whatsapp-messages");
1943
+ var STORE_ROOT = () => join2(process.env.MAXY_DIR_OVERRIDE ?? MAXY_DIR, "data", "whatsapp-messages");
1938
1944
  function conversationFile(platformAccountId, remoteJid) {
1939
- return join3(STORE_ROOT(), platformAccountId, `${remoteJid}.jsonl`);
1945
+ return join2(STORE_ROOT(), platformAccountId, `${remoteJid}.jsonl`);
1940
1946
  }
1941
1947
  function listStoredAccountIds() {
1942
1948
  const root = STORE_ROOT();
1943
- if (!existsSync3(root)) return [];
1944
- return readdirSync2(root).filter((name) => {
1949
+ if (!existsSync2(root)) return [];
1950
+ return readdirSync(root).filter((name) => {
1945
1951
  try {
1946
- return statSync2(join3(root, name)).isDirectory();
1952
+ return statSync2(join2(root, name)).isDirectory();
1947
1953
  } catch {
1948
1954
  return false;
1949
1955
  }
@@ -1970,7 +1976,7 @@ var byDateSentAsc = (a, b) => a.dateSent.localeCompare(b.dateSent);
1970
1976
  function appendMessage(platformAccountId, record, altDedupeRemoteJids = []) {
1971
1977
  const file = conversationFile(platformAccountId, record.remoteJid);
1972
1978
  try {
1973
- mkdirSync2(dirname(file), { recursive: true });
1979
+ mkdirSync(dirname(file), { recursive: true });
1974
1980
  } catch (err) {
1975
1981
  const reason = err instanceof Error ? err.message : String(err);
1976
1982
  console.error(`[whatsapp-message-store] FAIL op=append reason=${reason.slice(0, 100)} messageId=${record.messageId}`);
@@ -1979,8 +1985,8 @@ function appendMessage(platformAccountId, record, altDedupeRemoteJids = []) {
1979
1985
  try {
1980
1986
  const filesToCheck = [file, ...altDedupeRemoteJids.filter((jid) => jid && jid !== record.remoteJid).map((jid) => conversationFile(platformAccountId, jid))];
1981
1987
  for (const candidate of new Set(filesToCheck)) {
1982
- if (!existsSync3(candidate)) continue;
1983
- const existing = parseLines(readFileSync2(candidate, "utf8"));
1988
+ if (!existsSync2(candidate)) continue;
1989
+ const existing = parseLines(readFileSync(candidate, "utf8"));
1984
1990
  if (existing.some((r) => r.messageId === record.messageId)) {
1985
1991
  return { created: false };
1986
1992
  }
@@ -1991,7 +1997,7 @@ function appendMessage(platformAccountId, record, altDedupeRemoteJids = []) {
1991
1997
  return { created: false };
1992
1998
  }
1993
1999
  try {
1994
- appendFileSync2(file, JSON.stringify(record) + "\n");
2000
+ appendFileSync(file, JSON.stringify(record) + "\n");
1995
2001
  } catch (err) {
1996
2002
  const reason = err instanceof Error ? err.message : String(err);
1997
2003
  console.error(`[whatsapp-message-store] FAIL op=append reason=${reason.slice(0, 100)} messageId=${record.messageId}`);
@@ -2002,8 +2008,8 @@ function appendMessage(platformAccountId, record, altDedupeRemoteJids = []) {
2002
2008
  function readConversation(platformAccountId, remoteJid) {
2003
2009
  const file = conversationFile(platformAccountId, remoteJid);
2004
2010
  try {
2005
- if (!existsSync3(file)) return [];
2006
- return parseLines(readFileSync2(file, "utf8")).sort(byDateSentAsc);
2011
+ if (!existsSync2(file)) return [];
2012
+ return parseLines(readFileSync(file, "utf8")).sort(byDateSentAsc);
2007
2013
  } catch (err) {
2008
2014
  const reason = err instanceof Error ? err.message : String(err);
2009
2015
  console.error(`[whatsapp-message-store] FAIL op=read reason=${reason.slice(0, 100)} remoteJid=${remoteJid}`);
@@ -2013,8 +2019,8 @@ function readConversation(platformAccountId, remoteJid) {
2013
2019
  function appendReaction(platformAccountId, record) {
2014
2020
  const file = conversationFile(platformAccountId, record.remoteJid);
2015
2021
  try {
2016
- mkdirSync2(dirname(file), { recursive: true });
2017
- appendFileSync2(file, JSON.stringify(record) + "\n");
2022
+ mkdirSync(dirname(file), { recursive: true });
2023
+ appendFileSync(file, JSON.stringify(record) + "\n");
2018
2024
  } catch (err) {
2019
2025
  const reason = err instanceof Error ? err.message : String(err);
2020
2026
  console.error(
@@ -2027,9 +2033,9 @@ function appendReaction(platformAccountId, record) {
2027
2033
  function readReactions(platformAccountId, remoteJid) {
2028
2034
  const file = conversationFile(platformAccountId, remoteJid);
2029
2035
  try {
2030
- if (!existsSync3(file)) return [];
2036
+ if (!existsSync2(file)) return [];
2031
2037
  const out = [];
2032
- for (const line of readFileSync2(file, "utf8").split("\n")) {
2038
+ for (const line of readFileSync(file, "utf8").split("\n")) {
2033
2039
  if (!line.trim()) continue;
2034
2040
  try {
2035
2041
  const rec = JSON.parse(line);
@@ -2073,18 +2079,18 @@ function summariseRecords(records) {
2073
2079
  };
2074
2080
  }
2075
2081
  function readConversationSummaries(platformAccountId) {
2076
- const dir = join3(STORE_ROOT(), platformAccountId);
2082
+ const dir = join2(STORE_ROOT(), platformAccountId);
2077
2083
  const out = /* @__PURE__ */ new Map();
2078
2084
  const seen = /* @__PURE__ */ new Set();
2079
2085
  let fullReads = 0;
2080
2086
  let cacheHits = 0;
2081
2087
  let bytesRead = 0;
2082
2088
  try {
2083
- if (!existsSync3(dir)) return out;
2084
- for (const entry of readdirSync2(dir)) {
2089
+ if (!existsSync2(dir)) return out;
2090
+ for (const entry of readdirSync(dir)) {
2085
2091
  if (!entry.endsWith(".jsonl")) continue;
2086
2092
  const remoteJid = entry.slice(0, -".jsonl".length);
2087
- const file = join3(dir, entry);
2093
+ const file = join2(dir, entry);
2088
2094
  seen.add(file);
2089
2095
  let size;
2090
2096
  let mtimeMs;
@@ -2103,7 +2109,7 @@ function readConversationSummaries(platformAccountId) {
2103
2109
  }
2104
2110
  let summary;
2105
2111
  try {
2106
- const raw = readFileSync2(file, "utf8");
2112
+ const raw = readFileSync(file, "utf8");
2107
2113
  bytesRead += Buffer.byteLength(raw);
2108
2114
  fullReads++;
2109
2115
  summary = summariseRecords(parseLines(raw));
@@ -2129,11 +2135,11 @@ function readConversationSummaries(platformAccountId) {
2129
2135
  return out;
2130
2136
  }
2131
2137
  function readAllConversations(platformAccountId) {
2132
- const dir = join3(STORE_ROOT(), platformAccountId);
2138
+ const dir = join2(STORE_ROOT(), platformAccountId);
2133
2139
  const out = /* @__PURE__ */ new Map();
2134
2140
  try {
2135
- if (!existsSync3(dir)) return out;
2136
- for (const entry of readdirSync2(dir)) {
2141
+ if (!existsSync2(dir)) return out;
2142
+ for (const entry of readdirSync(dir)) {
2137
2143
  if (!entry.endsWith(".jsonl")) continue;
2138
2144
  const remoteJid = entry.slice(0, -".jsonl".length);
2139
2145
  out.set(remoteJid, readConversation(platformAccountId, remoteJid));
@@ -2145,6 +2151,303 @@ function readAllConversations(platformAccountId) {
2145
2151
  return out;
2146
2152
  }
2147
2153
 
2154
+ // ../lib/account-enumeration/src/index.ts
2155
+ import { readdirSync as readdirSync2, readFileSync as readFileSync2 } from "fs";
2156
+ import { resolve } from "path";
2157
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2158
+ var cache = /* @__PURE__ */ new Map();
2159
+ function enumerateValidAccountIds(accountsDir) {
2160
+ const cached3 = cache.get(accountsDir);
2161
+ if (cached3 !== void 0) return cached3;
2162
+ let names;
2163
+ try {
2164
+ names = readdirSync2(accountsDir);
2165
+ } catch (err) {
2166
+ if (err.code === "ENOENT") {
2167
+ cache.set(accountsDir, []);
2168
+ return [];
2169
+ }
2170
+ throw err;
2171
+ }
2172
+ const valid = [];
2173
+ for (const name of names) {
2174
+ if (!UUID_RE.test(name)) continue;
2175
+ const configPath2 = resolve(accountsDir, name, "account.json");
2176
+ try {
2177
+ JSON.parse(readFileSync2(configPath2, "utf-8"));
2178
+ valid.push(name);
2179
+ } catch (err) {
2180
+ const code = err.code;
2181
+ if (code === "ENOENT") continue;
2182
+ }
2183
+ }
2184
+ cache.set(accountsDir, valid);
2185
+ return valid;
2186
+ }
2187
+ function resolveHouseOrSoleAccountId(accountsDir) {
2188
+ const valid = enumerateValidAccountIds(accountsDir);
2189
+ const houses = [];
2190
+ for (const id of valid) {
2191
+ const configPath2 = resolve(accountsDir, id, "account.json");
2192
+ try {
2193
+ const cfg = JSON.parse(readFileSync2(configPath2, "utf-8"));
2194
+ if (cfg.role === "house") houses.push(id);
2195
+ } catch {
2196
+ }
2197
+ }
2198
+ if (houses.length === 1) return houses[0];
2199
+ if (houses.length === 0 && valid.length === 1) return valid[0];
2200
+ throw new Error(
2201
+ `[account-registry] resolveHouseOrSoleAccountId: houses=${houses.length} total=${valid.length} under ${accountsDir} \u2014 expected exactly one role:"house" (or a single unlabelled account). Loud-fail rather than picking one silently.`
2202
+ );
2203
+ }
2204
+ function getAccountsDirFromEnv() {
2205
+ const root = process.env.MAXY_PLATFORM_ROOT;
2206
+ if (!root) {
2207
+ throw new Error(
2208
+ "[graph-write] MAXY_PLATFORM_ROOT not set \u2014 cannot enforce accountId gate. Set MAXY_PLATFORM_ROOT in the spawning process or pass `accountsDir` explicitly."
2209
+ );
2210
+ }
2211
+ return resolve(root, "..", "data/accounts");
2212
+ }
2213
+ function validateAccountIdEnv(envValue, diskIds) {
2214
+ if (!envValue) {
2215
+ return { ok: false, reason: "missing", envId: null, diskIds };
2216
+ }
2217
+ if (diskIds.length === 0) {
2218
+ return { ok: false, reason: "no-on-disk-account", envId: envValue, diskIds };
2219
+ }
2220
+ if (!diskIds.includes(envValue)) {
2221
+ return { ok: false, reason: "mismatch", envId: envValue, diskIds };
2222
+ }
2223
+ return { ok: true, envId: envValue, diskIds };
2224
+ }
2225
+
2226
+ // server/lib/route-cache-watchers.ts
2227
+ function watchDirInto(dir, resource, accountId) {
2228
+ try {
2229
+ const w = watch(dir, { recursive: true }, () => {
2230
+ invalidate(resource, accountId, "watcher");
2231
+ });
2232
+ w.on("error", (err) => {
2233
+ console.error(`[admin-events] op=watch-failed resource=${resource} reason=${String(err)}`);
2234
+ });
2235
+ return { stop: () => {
2236
+ w.close();
2237
+ }, attached: true };
2238
+ } catch (err) {
2239
+ console.error(`[admin-events] op=watch-failed resource=${resource} reason=${String(err)}`);
2240
+ return { stop: () => {
2241
+ }, attached: false };
2242
+ }
2243
+ }
2244
+ var perAccountAttached = /* @__PURE__ */ new Set();
2245
+ function ensureAccountWatchers(accountId, accountDir) {
2246
+ for (const [dir, resource] of [
2247
+ [resolve2(accountDir, "plugins"), "skills"],
2248
+ [resolve2(accountDir, "agents", "admin"), "sidebar-artefacts"],
2249
+ [resolve2(accountDir, "specialists", "agents"), "sidebar-artefacts"]
2250
+ ]) {
2251
+ if (perAccountAttached.has(dir)) continue;
2252
+ const { attached: attached2 } = watchDirInto(dir, resource, accountId);
2253
+ if (attached2) perAccountAttached.add(dir);
2254
+ }
2255
+ }
2256
+ var attached = false;
2257
+ function attachRouteCacheWatchers() {
2258
+ if (attached) return;
2259
+ attached = true;
2260
+ const configDir2 = process.env.CLAUDE_CONFIG_DIR;
2261
+ if (configDir2) {
2262
+ watchDirInto(resolve2(configDir2, "projects"), "sidebar-sessions", null);
2263
+ } else {
2264
+ console.error("[admin-events] op=watch-failed resource=sidebar-sessions reason=CLAUDE_CONFIG_DIR-unset");
2265
+ }
2266
+ watchDirInto(resolve2(PLATFORM_ROOT, "templates", "specialists", "agents"), "sidebar-artefacts", null);
2267
+ let houseId = null;
2268
+ try {
2269
+ houseId = resolveHouseOrSoleAccountId(ACCOUNTS_DIR);
2270
+ } catch {
2271
+ houseId = null;
2272
+ }
2273
+ if (houseId) {
2274
+ watchDirInto(STORE_ROOT(), "conversations-all", houseId);
2275
+ } else {
2276
+ console.error("[admin-events] op=watch-failed resource=conversations-all reason=house-account-unresolved");
2277
+ }
2278
+ }
2279
+
2280
+ // server/index.ts
2281
+ import { monitorEventLoopDelay } from "perf_hooks";
2282
+
2283
+ // app/lib/whatsapp/inbound/media-download-guard.ts
2284
+ var TAG = "[media-guard]";
2285
+ var inFlight2 = 0;
2286
+ var containedCount = 0;
2287
+ function containedSinceBoot() {
2288
+ return containedCount;
2289
+ }
2290
+ function beginMediaDownload() {
2291
+ inFlight2 += 1;
2292
+ }
2293
+ function endMediaDownload() {
2294
+ if (inFlight2 > 0) inFlight2 -= 1;
2295
+ }
2296
+ function mediaDownloadsInFlight() {
2297
+ return inFlight2;
2298
+ }
2299
+ function stackOf(err) {
2300
+ if (err instanceof Error) return err.stack ?? err.message;
2301
+ return String(err);
2302
+ }
2303
+ function causeCode(err) {
2304
+ const cause = err?.cause;
2305
+ const code = cause?.code;
2306
+ return typeof code === "string" ? code : "none";
2307
+ }
2308
+ function handleEscapedMediaError(err, channel) {
2309
+ const stack = stackOf(err);
2310
+ const undiciFrame = /node_modules[\\/]undici|node:internal[\\/]deps[\\/]undici/.test(stack);
2311
+ if (undiciFrame && inFlight2 > 0) {
2312
+ containedCount += 1;
2313
+ console.error(
2314
+ `${TAG} op=contained channel=${channel} inFlight=${inFlight2} err=${err instanceof Error ? err.message : String(err)} cause=${causeCode(err)}
2315
+ ${stack}`
2316
+ );
2317
+ return true;
2318
+ }
2319
+ console.error(
2320
+ `${TAG} op=escaped channel=${channel} inFlight=${inFlight2} undiciFrame=${undiciFrame} err=${err instanceof Error ? err.message : String(err)} cause=${causeCode(err)} contained=false`
2321
+ );
2322
+ return false;
2323
+ }
2324
+ var installed = false;
2325
+ function guardInstalled() {
2326
+ return installed;
2327
+ }
2328
+ function installMediaDownloadGuard() {
2329
+ if (installed) return;
2330
+ installed = true;
2331
+ process.on("uncaughtException", (err) => {
2332
+ if (handleEscapedMediaError(err, "uncaughtException")) return;
2333
+ process.stderr.write(`${err instanceof Error ? err.stack ?? err.message : String(err)}
2334
+ `);
2335
+ process.exit(1);
2336
+ });
2337
+ process.on("unhandledRejection", (reason) => {
2338
+ if (handleEscapedMediaError(reason, "unhandledRejection")) return;
2339
+ process.stderr.write(
2340
+ `Unhandled rejection: ${reason instanceof Error ? reason.stack ?? reason.message : String(reason)}
2341
+ `
2342
+ );
2343
+ process.exit(1);
2344
+ });
2345
+ console.error(`${TAG} op=installed`);
2346
+ }
2347
+
2348
+ // app/lib/whatsapp/ingest-audit.ts
2349
+ import { readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync3 } from "fs";
2350
+ import { join as join4 } from "path";
2351
+
2352
+ // app/lib/whatsapp/ingest-ledger.ts
2353
+ import { existsSync as existsSync3, mkdirSync as mkdirSync2, appendFileSync as appendFileSync2, readFileSync as readFileSync3, writeFileSync, readdirSync as readdirSync3 } from "fs";
2354
+ import { join as join3 } from "path";
2355
+ var TAG2 = "[wa-ingest-ledger]";
2356
+ var LEDGER_ROOT = () => join3(process.env.MAXY_DIR_OVERRIDE ?? MAXY_DIR, "data", "whatsapp-ingest-ledger");
2357
+ var ensuredRoots = /* @__PURE__ */ new Set();
2358
+ function ledgerFilePath(account) {
2359
+ const root = LEDGER_ROOT();
2360
+ if (!ensuredRoots.has(root)) {
2361
+ if (!existsSync3(root)) mkdirSync2(root, { recursive: true });
2362
+ ensuredRoots.add(root);
2363
+ }
2364
+ return join3(root, `${account}.jsonl`);
2365
+ }
2366
+ function appendStanza(entry) {
2367
+ try {
2368
+ const row = {
2369
+ msgId: entry.msgId,
2370
+ from: entry.from,
2371
+ type: entry.type,
2372
+ ts: (/* @__PURE__ */ new Date()).toISOString()
2373
+ };
2374
+ appendFileSync2(ledgerFilePath(entry.account), JSON.stringify(row) + "\n");
2375
+ } catch (err) {
2376
+ console.error(
2377
+ `${TAG2} FAIL op=append msgId=${entry.msgId} err=${err instanceof Error ? err.message : String(err)}`
2378
+ );
2379
+ }
2380
+ }
2381
+ function markDeclined(entry) {
2382
+ try {
2383
+ const row = {
2384
+ declined: entry.msgId,
2385
+ reason: entry.reason,
2386
+ ts: (/* @__PURE__ */ new Date()).toISOString()
2387
+ };
2388
+ appendFileSync2(ledgerFilePath(entry.account), JSON.stringify(row) + "\n");
2389
+ } catch (err) {
2390
+ console.error(
2391
+ `${TAG2} FAIL op=decline msgId=${entry.msgId} err=${err instanceof Error ? err.message : String(err)}`
2392
+ );
2393
+ }
2394
+ }
2395
+ function readDeclined(account) {
2396
+ const path3 = ledgerFilePath(account);
2397
+ const out = /* @__PURE__ */ new Set();
2398
+ if (!existsSync3(path3)) return out;
2399
+ for (const line of readFileSync3(path3, "utf8").split("\n")) {
2400
+ if (!line.trim()) continue;
2401
+ try {
2402
+ const row = JSON.parse(line);
2403
+ if (typeof row.declined === "string") out.add(row.declined);
2404
+ } catch {
2405
+ }
2406
+ }
2407
+ return out;
2408
+ }
2409
+ function readLedger(account) {
2410
+ const path3 = ledgerFilePath(account);
2411
+ if (!existsSync3(path3)) return [];
2412
+ const out = [];
2413
+ for (const line of readFileSync3(path3, "utf8").split("\n")) {
2414
+ if (!line.trim()) continue;
2415
+ try {
2416
+ const row = JSON.parse(line);
2417
+ if (row && typeof row.msgId === "string") out.push(row);
2418
+ } catch {
2419
+ }
2420
+ }
2421
+ return out;
2422
+ }
2423
+ function pruneLedger(account, olderThanMs) {
2424
+ const path3 = ledgerFilePath(account);
2425
+ if (!existsSync3(path3)) return 0;
2426
+ const lines = readFileSync3(path3, "utf8").split("\n").filter((l) => l.trim());
2427
+ const cutoff = Date.now() - olderThanMs;
2428
+ const kept = lines.filter((line) => {
2429
+ try {
2430
+ const row = JSON.parse(line);
2431
+ const t = typeof row.ts === "string" ? Date.parse(row.ts) : NaN;
2432
+ return Number.isFinite(t) && t >= cutoff;
2433
+ } catch {
2434
+ return false;
2435
+ }
2436
+ });
2437
+ if (kept.length === lines.length) return 0;
2438
+ writeFileSync(path3, kept.join("\n") + (kept.length ? "\n" : ""));
2439
+ return lines.length - kept.length;
2440
+ }
2441
+ function listLedgerAccounts() {
2442
+ const root = LEDGER_ROOT();
2443
+ if (!existsSync3(root)) return [];
2444
+ try {
2445
+ return readdirSync3(root).filter((f) => f.endsWith(".jsonl")).map((f) => f.slice(0, -".jsonl".length));
2446
+ } catch {
2447
+ return [];
2448
+ }
2449
+ }
2450
+
2148
2451
  // app/lib/whatsapp/ingest-audit.ts
2149
2452
  var TAG3 = "[wa-ingest-audit]";
2150
2453
  var DEFAULT_GRACE_MS = 10 * 60 * 1e3;
@@ -2164,7 +2467,7 @@ function readAllConversationsCached(accountId) {
2164
2467
  const out = /* @__PURE__ */ new Map();
2165
2468
  let dir;
2166
2469
  try {
2167
- dir = readdirSync3(join4(STORE_ROOT(), accountId));
2470
+ dir = readdirSync4(join4(STORE_ROOT(), accountId));
2168
2471
  } catch {
2169
2472
  return out;
2170
2473
  }
@@ -2184,7 +2487,7 @@ function readAllConversationsCached(accountId) {
2184
2487
  }
2185
2488
  const parsed = [];
2186
2489
  try {
2187
- for (const line of readFileSync3(path3, "utf8").split("\n")) {
2490
+ for (const line of readFileSync4(path3, "utf8").split("\n")) {
2188
2491
  if (!line.trim()) continue;
2189
2492
  try {
2190
2493
  const row = JSON.parse(line);
@@ -2347,19 +2650,19 @@ function pwaCensus(d) {
2347
2650
  }
2348
2651
 
2349
2652
  // server/webchat-descriptor.ts
2350
- import { resolve, join as join5 } from "path";
2653
+ import { resolve as resolve3, join as join5 } from "path";
2351
2654
  function webchatGatewayUrl() {
2352
2655
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
2353
2656
  }
2354
2657
  function webchatServerPath() {
2355
- return process.env.MAXY_WEBCHAT_CHANNEL_SERVER_PATH ?? resolve(process.env.MAXY_PLATFORM_ROOT ?? join5(__dirname, ".."), "services/webchat-channel/dist/server.js");
2658
+ return process.env.MAXY_WEBCHAT_CHANNEL_SERVER_PATH ?? resolve3(process.env.MAXY_PLATFORM_ROOT ?? join5(__dirname, ".."), "services/webchat-channel/dist/server.js");
2356
2659
  }
2357
2660
  function webchatChannelDescriptor(key) {
2358
2661
  return { key, gatewayUrl: webchatGatewayUrl(), serverPath: webchatServerPath() };
2359
2662
  }
2360
2663
 
2361
2664
  // app/lib/claude-auth.ts
2362
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, renameSync, unlinkSync } from "fs";
2665
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync2, renameSync, unlinkSync } from "fs";
2363
2666
  import { sep } from "path";
2364
2667
  import { lock } from "proper-lockfile";
2365
2668
  if (!CLAUDE_CREDENTIALS_FILE.startsWith(MAXY_DIR + sep)) {
@@ -2376,7 +2679,7 @@ var REFRESH_NOT_FIRING_THRESHOLD = 2;
2376
2679
  function readCredentials() {
2377
2680
  let raw;
2378
2681
  try {
2379
- raw = readFileSync4(CLAUDE_CREDENTIALS_FILE, "utf-8");
2682
+ raw = readFileSync5(CLAUDE_CREDENTIALS_FILE, "utf-8");
2380
2683
  } catch {
2381
2684
  return null;
2382
2685
  }
@@ -2404,7 +2707,7 @@ function writeOAuthCredentials(tokens) {
2404
2707
  try {
2405
2708
  let fileData = {};
2406
2709
  try {
2407
- const rawFile = readFileSync4(CLAUDE_CREDENTIALS_FILE, "utf-8");
2710
+ const rawFile = readFileSync5(CLAUDE_CREDENTIALS_FILE, "utf-8");
2408
2711
  fileData = JSON.parse(rawFile);
2409
2712
  } catch {
2410
2713
  }
@@ -2634,9 +2937,9 @@ import { networkInterfaces } from "os";
2634
2937
  function getLanIp() {
2635
2938
  const nets = networkInterfaces();
2636
2939
  let fallback = null;
2637
- for (const entries of Object.values(nets)) {
2638
- if (!entries) continue;
2639
- for (const entry of entries) {
2940
+ for (const entries2 of Object.values(nets)) {
2941
+ if (!entries2) continue;
2942
+ for (const entry of entries2) {
2640
2943
  if (entry.family !== "IPv4" || entry.internal) continue;
2641
2944
  if (entry.address.startsWith("192.168.") || entry.address.startsWith("10.")) {
2642
2945
  return entry.address;
@@ -2880,8 +3183,8 @@ function discardAuthDirSync(authDir) {
2880
3183
  function listCredentialAccountIds(configDir2) {
2881
3184
  const credsRoot = path.join(os.homedir(), configDir2, "credentials", "whatsapp");
2882
3185
  try {
2883
- const entries = fsSync.readdirSync(credsRoot, { withFileTypes: true });
2884
- return entries.filter((e) => e.isDirectory() && hasCredsSync(path.join(credsRoot, e.name))).map((e) => e.name);
3186
+ const entries2 = fsSync.readdirSync(credsRoot, { withFileTypes: true });
3187
+ return entries2.filter((e) => e.isDirectory() && hasCredsSync(path.join(credsRoot, e.name))).map((e) => e.name);
2885
3188
  } catch {
2886
3189
  return [];
2887
3190
  }
@@ -2910,7 +3213,7 @@ var SENTINEL_BASENAME = "baileys-debug-until";
2910
3213
  var STAT_INTERVAL_MS = 1e3;
2911
3214
  var VALID_LEVELS = /* @__PURE__ */ new Set(["trace", "debug", "info"]);
2912
3215
  var INACTIVE = { active: false, level: "warn" };
2913
- var cache = /* @__PURE__ */ new Map();
3216
+ var cache2 = /* @__PURE__ */ new Map();
2914
3217
  function sentinelPath(authDir) {
2915
3218
  return path2.join(authDir, SENTINEL_BASENAME);
2916
3219
  }
@@ -2937,7 +3240,7 @@ function readSentinel(authDir, nowMs) {
2937
3240
  }
2938
3241
  function resolveDebugWindow(authDir, nowMs = Date.now()) {
2939
3242
  if (!authDir) return INACTIVE;
2940
- const prev = cache.get(authDir);
3243
+ const prev = cache2.get(authDir);
2941
3244
  if (prev && nowMs - prev.checkedAtMs < STAT_INTERVAL_MS) {
2942
3245
  return prev.state;
2943
3246
  }
@@ -2952,7 +3255,7 @@ function resolveDebugWindow(authDir, nowMs = Date.now()) {
2952
3255
  `${TAG5} op=baileys-debug-window-close account=${path2.basename(authDir)}`
2953
3256
  );
2954
3257
  }
2955
- cache.set(authDir, { checkedAtMs: nowMs, state });
3258
+ cache2.set(authDir, { checkedAtMs: nowMs, state });
2956
3259
  return state;
2957
3260
  }
2958
3261
 
@@ -3030,7 +3333,7 @@ var credsSaveQueue = Promise.resolve();
3030
3333
  async function drainCredsSaveQueue(timeoutMs = 5e3) {
3031
3334
  console.error(`${TAG6} draining credential save queue\u2026`);
3032
3335
  const timer = new Promise(
3033
- (resolve45) => setTimeout(() => resolve45("timeout"), timeoutMs)
3336
+ (resolve46) => setTimeout(() => resolve46("timeout"), timeoutMs)
3034
3337
  );
3035
3338
  const result = await Promise.race([
3036
3339
  credsSaveQueue.then(() => "drained"),
@@ -3207,11 +3510,11 @@ async function createWaSocket(opts) {
3207
3510
  return sock;
3208
3511
  }
3209
3512
  async function waitForConnection(sock) {
3210
- return new Promise((resolve45, reject) => {
3513
+ return new Promise((resolve46, reject) => {
3211
3514
  const handler = (update) => {
3212
3515
  if (update.connection === "open") {
3213
3516
  sock.ev.off("connection.update", handler);
3214
- resolve45();
3517
+ resolve46();
3215
3518
  }
3216
3519
  if (update.connection === "close") {
3217
3520
  sock.ev.off("connection.update", handler);
@@ -3319,7 +3622,7 @@ function isTimeoutError(err) {
3319
3622
  return Boolean(err?.__maxyTimeout);
3320
3623
  }
3321
3624
  function withTimeout(label, promise, timeoutMs) {
3322
- return new Promise((resolve45, reject) => {
3625
+ return new Promise((resolve46, reject) => {
3323
3626
  const timer = setTimeout(() => {
3324
3627
  const err = new Error(`${label} timed out after ${timeoutMs}ms`);
3325
3628
  err.__maxyTimeout = true;
@@ -3329,7 +3632,7 @@ function withTimeout(label, promise, timeoutMs) {
3329
3632
  promise.then(
3330
3633
  (value) => {
3331
3634
  clearTimeout(timer);
3332
- resolve45(value);
3635
+ resolve46(value);
3333
3636
  },
3334
3637
  (err) => {
3335
3638
  clearTimeout(timer);
@@ -3559,7 +3862,7 @@ async function resolveCanonicalConversationJid(remoteJid, lidMapping) {
3559
3862
  }
3560
3863
 
3561
3864
  // app/lib/whatsapp/inbound/lid-map.ts
3562
- import { existsSync as existsSync4, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
3865
+ import { existsSync as existsSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
3563
3866
  function resolveViaLidMap(map, senderPhone) {
3564
3867
  const key = normalizeE164(senderPhone);
3565
3868
  if (!key) return null;
@@ -3577,7 +3880,7 @@ function lidCaptureFor(senderJid, senderPhone) {
3577
3880
  function readLidMap() {
3578
3881
  try {
3579
3882
  if (!existsSync4(LID_MAP_FILE)) return null;
3580
- const raw = readFileSync5(LID_MAP_FILE, "utf-8").trim();
3883
+ const raw = readFileSync6(LID_MAP_FILE, "utf-8").trim();
3581
3884
  if (!raw) return null;
3582
3885
  const parsed = JSON.parse(raw);
3583
3886
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
@@ -3836,16 +4139,16 @@ function decideDispatch(conn, payload, deps) {
3836
4139
 
3837
4140
  // app/lib/access-gate.ts
3838
4141
  import neo4j from "neo4j-driver";
3839
- import { readFileSync as readFileSync6 } from "fs";
3840
- import { resolve as resolve2 } from "path";
4142
+ import { readFileSync as readFileSync7 } from "fs";
4143
+ import { resolve as resolve4 } from "path";
3841
4144
  import { randomUUID as randomUUID2 } from "crypto";
3842
- var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve2(process.cwd(), "..");
4145
+ var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve4(process.cwd(), "..");
3843
4146
  var driver = null;
3844
4147
  function readPassword() {
3845
4148
  if (process.env.NEO4J_PASSWORD) return process.env.NEO4J_PASSWORD;
3846
- const passwordFile = resolve2(PLATFORM_ROOT2, "config/.neo4j-password");
4149
+ const passwordFile = resolve4(PLATFORM_ROOT2, "config/.neo4j-password");
3847
4150
  try {
3848
- return readFileSync6(passwordFile, "utf-8").trim();
4151
+ return readFileSync7(passwordFile, "utf-8").trim();
3849
4152
  } catch {
3850
4153
  throw new Error(
3851
4154
  `Neo4j password not found. Expected at ${passwordFile} or in NEO4J_PASSWORD env var.`
@@ -4394,8 +4697,8 @@ async function persistWhatsAppMessage(input) {
4394
4697
  const { givenName, familyName } = splitName(input.pushName);
4395
4698
  const prev = sessionWriteLocks.get(input.cacheKey);
4396
4699
  let release;
4397
- const mine = new Promise((resolve45) => {
4398
- release = resolve45;
4700
+ const mine = new Promise((resolve46) => {
4701
+ release = resolve46;
4399
4702
  });
4400
4703
  const chained = (prev ?? Promise.resolve()).then(() => mine);
4401
4704
  sessionWriteLocks.set(input.cacheKey, chained);
@@ -4489,124 +4792,52 @@ function splitName(pushName) {
4489
4792
  const trimmed = pushName.trim();
4490
4793
  if (!trimmed) return { givenName: null, familyName: null };
4491
4794
  const firstSpace = trimmed.search(/\s/);
4492
- if (firstSpace === -1) return { givenName: trimmed, familyName: null };
4493
- return {
4494
- givenName: trimmed.slice(0, firstSpace).trim(),
4495
- familyName: trimmed.slice(firstSpace + 1).trim() || null
4496
- };
4497
- }
4498
- function sanitizeReason(err) {
4499
- if (!(err instanceof Error)) return String(err).slice(0, 200);
4500
- const msg = err.message.replace(/bolt:\/\/[^\s)]+/g, "bolt://<redacted>").replace(/\b(neo4j|admin|password)=[^\s)]+/gi, "$1=<redacted>").slice(0, 200);
4501
- return `${err.name}:${msg}`;
4502
- }
4503
-
4504
- // app/lib/whatsapp/ensure-conversation.ts
4505
- var TAG12 = "[whatsapp-persist]";
4506
- async function ensureWhatsAppConversation(input) {
4507
- const t0 = Date.now();
4508
- try {
4509
- const result = await ensureConversation(
4510
- input.platformAccountId,
4511
- input.agentType,
4512
- input.cacheKey
4513
- );
4514
- const ms = Date.now() - t0;
4515
- if (!result.sessionId) {
4516
- console.error(
4517
- `${TAG12} conversation-merged FAIL cacheKey=${input.cacheKey} reason=null-sessionId ms=${ms}`
4518
- );
4519
- return null;
4520
- }
4521
- console.error(
4522
- `${TAG12} conversation-merged cacheKey=${input.cacheKey} agentType=${input.agentType} channel=whatsapp accountId=${input.platformAccountId} connectionAccountId=${input.connectionAccountId ?? input.platformAccountId} created=${result.created} ms=${ms}`
4523
- );
4524
- return { sessionId: result.sessionId, created: result.created };
4525
- } catch (err) {
4526
- const ms = Date.now() - t0;
4527
- const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
4528
- console.error(
4529
- `${TAG12} conversation-merged FAIL cacheKey=${input.cacheKey} reason=${reason} ms=${ms}`
4530
- );
4531
- return null;
4532
- }
4533
- }
4534
-
4535
- // ../lib/account-enumeration/src/index.ts
4536
- import { readdirSync as readdirSync4, readFileSync as readFileSync7 } from "fs";
4537
- import { resolve as resolve3 } from "path";
4538
- var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
4539
- var cache2 = /* @__PURE__ */ new Map();
4540
- function enumerateValidAccountIds(accountsDir) {
4541
- const cached3 = cache2.get(accountsDir);
4542
- if (cached3 !== void 0) return cached3;
4543
- let names;
4544
- try {
4545
- names = readdirSync4(accountsDir);
4546
- } catch (err) {
4547
- if (err.code === "ENOENT") {
4548
- cache2.set(accountsDir, []);
4549
- return [];
4550
- }
4551
- throw err;
4552
- }
4553
- const valid = [];
4554
- for (const name of names) {
4555
- if (!UUID_RE.test(name)) continue;
4556
- const configPath2 = resolve3(accountsDir, name, "account.json");
4557
- try {
4558
- JSON.parse(readFileSync7(configPath2, "utf-8"));
4559
- valid.push(name);
4560
- } catch (err) {
4561
- const code = err.code;
4562
- if (code === "ENOENT") continue;
4563
- }
4564
- }
4565
- cache2.set(accountsDir, valid);
4566
- return valid;
4567
- }
4568
- function resolveHouseOrSoleAccountId(accountsDir) {
4569
- const valid = enumerateValidAccountIds(accountsDir);
4570
- const houses = [];
4571
- for (const id of valid) {
4572
- const configPath2 = resolve3(accountsDir, id, "account.json");
4573
- try {
4574
- const cfg = JSON.parse(readFileSync7(configPath2, "utf-8"));
4575
- if (cfg.role === "house") houses.push(id);
4576
- } catch {
4577
- }
4578
- }
4579
- if (houses.length === 1) return houses[0];
4580
- if (houses.length === 0 && valid.length === 1) return valid[0];
4581
- throw new Error(
4582
- `[account-registry] resolveHouseOrSoleAccountId: houses=${houses.length} total=${valid.length} under ${accountsDir} \u2014 expected exactly one role:"house" (or a single unlabelled account). Loud-fail rather than picking one silently.`
4583
- );
4795
+ if (firstSpace === -1) return { givenName: trimmed, familyName: null };
4796
+ return {
4797
+ givenName: trimmed.slice(0, firstSpace).trim(),
4798
+ familyName: trimmed.slice(firstSpace + 1).trim() || null
4799
+ };
4584
4800
  }
4585
- function getAccountsDirFromEnv() {
4586
- const root = process.env.MAXY_PLATFORM_ROOT;
4587
- if (!root) {
4588
- throw new Error(
4589
- "[graph-write] MAXY_PLATFORM_ROOT not set \u2014 cannot enforce accountId gate. Set MAXY_PLATFORM_ROOT in the spawning process or pass `accountsDir` explicitly."
4590
- );
4591
- }
4592
- return resolve3(root, "..", "data/accounts");
4801
+ function sanitizeReason(err) {
4802
+ if (!(err instanceof Error)) return String(err).slice(0, 200);
4803
+ const msg = err.message.replace(/bolt:\/\/[^\s)]+/g, "bolt://<redacted>").replace(/\b(neo4j|admin|password)=[^\s)]+/gi, "$1=<redacted>").slice(0, 200);
4804
+ return `${err.name}:${msg}`;
4593
4805
  }
4594
- function validateAccountIdEnv(envValue, diskIds) {
4595
- if (!envValue) {
4596
- return { ok: false, reason: "missing", envId: null, diskIds };
4597
- }
4598
- if (diskIds.length === 0) {
4599
- return { ok: false, reason: "no-on-disk-account", envId: envValue, diskIds };
4600
- }
4601
- if (!diskIds.includes(envValue)) {
4602
- return { ok: false, reason: "mismatch", envId: envValue, diskIds };
4806
+
4807
+ // app/lib/whatsapp/ensure-conversation.ts
4808
+ var TAG12 = "[whatsapp-persist]";
4809
+ async function ensureWhatsAppConversation(input) {
4810
+ const t0 = Date.now();
4811
+ try {
4812
+ const result = await ensureConversation(
4813
+ input.platformAccountId,
4814
+ input.agentType,
4815
+ input.cacheKey
4816
+ );
4817
+ const ms = Date.now() - t0;
4818
+ if (!result.sessionId) {
4819
+ console.error(
4820
+ `${TAG12} conversation-merged FAIL cacheKey=${input.cacheKey} reason=null-sessionId ms=${ms}`
4821
+ );
4822
+ return null;
4823
+ }
4824
+ console.error(
4825
+ `${TAG12} conversation-merged cacheKey=${input.cacheKey} agentType=${input.agentType} channel=whatsapp accountId=${input.platformAccountId} connectionAccountId=${input.connectionAccountId ?? input.platformAccountId} created=${result.created} ms=${ms}`
4826
+ );
4827
+ return { sessionId: result.sessionId, created: result.created };
4828
+ } catch (err) {
4829
+ const ms = Date.now() - t0;
4830
+ const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
4831
+ console.error(
4832
+ `${TAG12} conversation-merged FAIL cacheKey=${input.cacheKey} reason=${reason} ms=${ms}`
4833
+ );
4834
+ return null;
4603
4835
  }
4604
- return { ok: true, envId: envValue, diskIds };
4605
4836
  }
4606
4837
 
4607
4838
  // app/lib/whatsapp/platform-account-id.ts
4608
4839
  import { readFileSync as readFileSync8 } from "fs";
4609
- import { resolve as resolve4 } from "path";
4840
+ import { resolve as resolve5 } from "path";
4610
4841
  var cachedHouseId = null;
4611
4842
  var cachedHouseAccountsDir = null;
4612
4843
  function resolveHouseId(accountsDir) {
@@ -4617,7 +4848,7 @@ function resolveHouseId(accountsDir) {
4617
4848
  return cachedHouseId;
4618
4849
  }
4619
4850
  function readChannelRoutingOverride(accountsDir, houseId) {
4620
- const configPath2 = resolve4(accountsDir, houseId, "account.json");
4851
+ const configPath2 = resolve5(accountsDir, houseId, "account.json");
4621
4852
  let raw;
4622
4853
  try {
4623
4854
  raw = readFileSync8(configPath2, "utf-8");
@@ -4682,14 +4913,14 @@ import {
4682
4913
  import { randomUUID as randomUUID3 } from "crypto";
4683
4914
  import { mkdir, writeFile } from "fs/promises";
4684
4915
  import { realpathSync as realpathSync2, existsSync as existsSync5, readFileSync as readFileSync10, readdirSync as readdirSync5 } from "fs";
4685
- import { resolve as resolve6, extname } from "path";
4916
+ import { resolve as resolve7, extname } from "path";
4686
4917
 
4687
4918
  // app/lib/data-path.ts
4688
4919
  import { realpathSync } from "fs";
4689
- import { resolve as resolve5, normalize, sep as sep2, relative, basename, join as join7 } from "path";
4690
- var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve5(process.cwd(), "../platform");
4691
- var DATA_ROOT = resolve5(PLATFORM_ROOT3, "..", "data");
4692
- var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve5(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
4920
+ import { resolve as resolve6, normalize, sep as sep2, relative, basename, join as join7 } from "path";
4921
+ var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve6(process.cwd(), "../platform");
4922
+ var DATA_ROOT = resolve6(PLATFORM_ROOT3, "..", "data");
4923
+ var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve6(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
4693
4924
  var ACCOUNT_PARTITION_DIRS = /* @__PURE__ */ new Set(["accounts"]);
4694
4925
  var ACCOUNT_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
4695
4926
  function crossesForeignAccountPartition(relPath, accountId) {
@@ -4706,7 +4937,7 @@ function isWithinOwnAccountPartition(relPath, accountId) {
4706
4937
  }
4707
4938
  function resolveUnderRoot(raw, rootAbs, rootLabel) {
4708
4939
  const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
4709
- const absolute = resolve5(rootAbs, cleaned);
4940
+ const absolute = resolve6(rootAbs, cleaned);
4710
4941
  let rootReal;
4711
4942
  try {
4712
4943
  rootReal = realpathSync(rootAbs);
@@ -4928,7 +5159,7 @@ function docToText(buffer, mimeType) {
4928
5159
 
4929
5160
  // app/lib/attachments.ts
4930
5161
  function uploadsDirFor(accountId, subPath, attachmentId) {
4931
- return subPath ? resolve6(DATA_ROOT, "accounts", accountId, "uploads", subPath, attachmentId) : resolve6(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
5162
+ return subPath ? resolve7(DATA_ROOT, "accounts", accountId, "uploads", subPath, attachmentId) : resolve7(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
4932
5163
  }
4933
5164
  var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
4934
5165
  "image/jpeg",
@@ -5005,14 +5236,14 @@ async function storeMediaBuffer(accountId, attachmentId, filename, mimeType, buf
5005
5236
  return writeAttachment(accountId, "", filename, mimeType, buffer.byteLength, buffer, attachmentId);
5006
5237
  }
5007
5238
  function attachmentExists(accountId, attachmentId) {
5008
- return existsSync5(resolve6(uploadsDirFor(accountId, "", attachmentId), `${attachmentId}.meta.json`));
5239
+ return existsSync5(resolve7(uploadsDirFor(accountId, "", attachmentId), `${attachmentId}.meta.json`));
5009
5240
  }
5010
5241
  function resolveStoredAttachment(accountId, attachmentId) {
5011
5242
  if (!ATTACHMENT_ID_RE.test(attachmentId)) return null;
5012
5243
  const dir = uploadsDirFor(accountId, "", attachmentId);
5013
5244
  let meta;
5014
5245
  try {
5015
- meta = JSON.parse(readFileSync10(resolve6(dir, `${attachmentId}.meta.json`), "utf8"));
5246
+ meta = JSON.parse(readFileSync10(resolve7(dir, `${attachmentId}.meta.json`), "utf8"));
5016
5247
  } catch {
5017
5248
  return null;
5018
5249
  }
@@ -5020,25 +5251,25 @@ function resolveStoredAttachment(accountId, attachmentId) {
5020
5251
  const { filename, mimeType, sizeBytes } = meta;
5021
5252
  if (typeof filename !== "string" || typeof mimeType !== "string") return null;
5022
5253
  const resolvedSizeBytes = typeof sizeBytes === "number" ? sizeBytes : void 0;
5023
- let entries;
5254
+ let entries2;
5024
5255
  try {
5025
- entries = readdirSync5(dir, { withFileTypes: true });
5256
+ entries2 = readdirSync5(dir, { withFileTypes: true });
5026
5257
  } catch {
5027
5258
  return null;
5028
5259
  }
5029
- const dataFile = entries.find((e) => e.isFile() && !e.name.endsWith(".meta.json") && !e.name.endsWith(EXTRACTED_TEXT_SUFFIX));
5260
+ const dataFile = entries2.find((e) => e.isFile() && !e.name.endsWith(".meta.json") && !e.name.endsWith(EXTRACTED_TEXT_SUFFIX));
5030
5261
  if (!dataFile) return null;
5031
5262
  const readableSibling = `${attachmentId}${EXTRACTED_TEXT_SUFFIX}`;
5032
- const readableTextPath = entries.some((e) => e.isFile() && e.name === readableSibling) ? resolve6(dir, readableSibling) : void 0;
5033
- return { attachmentId, filename, mimeType, sizeBytes: resolvedSizeBytes, path: resolve6(dir, dataFile.name), readableTextPath };
5263
+ const readableTextPath = entries2.some((e) => e.isFile() && e.name === readableSibling) ? resolve7(dir, readableSibling) : void 0;
5264
+ return { attachmentId, filename, mimeType, sizeBytes: resolvedSizeBytes, path: resolve7(dir, dataFile.name), readableTextPath };
5034
5265
  }
5035
5266
  async function writeAttachment(accountId, subPath, filename, mimeType, sizeBytes, buffer, explicitId) {
5036
5267
  const attachmentId = explicitId ?? randomUUID3();
5037
5268
  const dir = uploadsDirFor(accountId, subPath, attachmentId);
5038
5269
  await mkdir(dir, { recursive: true });
5039
5270
  const ext = extname(filename) || "";
5040
- const storagePath = resolve6(dir, `${attachmentId}${ext}`);
5041
- const metaPath = resolve6(dir, `${attachmentId}.meta.json`);
5271
+ const storagePath = resolve7(dir, `${attachmentId}${ext}`);
5272
+ const metaPath = resolve7(dir, `${attachmentId}.meta.json`);
5042
5273
  const meta = {
5043
5274
  attachmentId,
5044
5275
  scope: subPath || accountId,
@@ -5060,7 +5291,7 @@ async function writeAttachment(accountId, subPath, filename, mimeType, sizeBytes
5060
5291
  }
5061
5292
  console.error(`[doc-to-text] op=convert mime=${bare} ok=${text !== null} chars=${text?.length ?? 0}`);
5062
5293
  if (text) {
5063
- const siblingPath = resolve6(dir, `${attachmentId}${EXTRACTED_TEXT_SUFFIX}`);
5294
+ const siblingPath = resolve7(dir, `${attachmentId}${EXTRACTED_TEXT_SUFFIX}`);
5064
5295
  try {
5065
5296
  await writeFile(siblingPath, text);
5066
5297
  readableTextPath = siblingPath;
@@ -5144,8 +5375,8 @@ async function storeComponentArtefact(accountId, attachmentId, mimeType, content
5144
5375
  const dir = uploadsDirFor(accountId, "", attachmentId);
5145
5376
  await mkdir(dir, { recursive: true });
5146
5377
  const ext = extname(filename) || (mimeType === "text/html" ? ".html" : ".md");
5147
- const storagePath = resolve6(dir, `${attachmentId}${ext}`);
5148
- const metaPath = resolve6(dir, `${attachmentId}.meta.json`);
5378
+ const storagePath = resolve7(dir, `${attachmentId}${ext}`);
5379
+ const metaPath = resolve7(dir, `${attachmentId}.meta.json`);
5149
5380
  const meta = {
5150
5381
  attachmentId,
5151
5382
  scope: accountId,
@@ -5468,10 +5699,10 @@ function createInboundDebouncer(opts) {
5468
5699
  }
5469
5700
 
5470
5701
  // app/lib/whatsapp/inbound/combine-batch.ts
5471
- function combineInboundBatch(entries) {
5472
- const last = entries[entries.length - 1];
5473
- const combinedText = entries.map((e) => e.text).filter(Boolean).join("\n");
5474
- const media = entries.flatMap((e) => e.media);
5702
+ function combineInboundBatch(entries2) {
5703
+ const last = entries2[entries2.length - 1];
5704
+ const combinedText = entries2.map((e) => e.text).filter(Boolean).join("\n");
5705
+ const media = entries2.flatMap((e) => e.media);
5475
5706
  return { ...last, text: combinedText, media };
5476
5707
  }
5477
5708
 
@@ -5718,15 +5949,15 @@ function messageStoreKey(accountId, remoteJid) {
5718
5949
  return `${accountId}:${remoteJid}`;
5719
5950
  }
5720
5951
  function storeMessage(storeKey, entry) {
5721
- let entries = messageStore.get(storeKey);
5722
- if (!entries) {
5723
- entries = [];
5724
- messageStore.set(storeKey, entries);
5725
- }
5726
- entries.push(entry);
5727
- if (entries.length > MESSAGE_STORE_MAX) {
5728
- const trimmed = entries.length - MESSAGE_STORE_MAX;
5729
- entries.splice(0, trimmed);
5952
+ let entries2 = messageStore.get(storeKey);
5953
+ if (!entries2) {
5954
+ entries2 = [];
5955
+ messageStore.set(storeKey, entries2);
5956
+ }
5957
+ entries2.push(entry);
5958
+ if (entries2.length > MESSAGE_STORE_MAX) {
5959
+ const trimmed = entries2.length - MESSAGE_STORE_MAX;
5960
+ entries2.splice(0, trimmed);
5730
5961
  console.error(`${TAG17} message store trimmed for ${storeKey}: ${trimmed} oldest messages removed`);
5731
5962
  }
5732
5963
  }
@@ -6132,11 +6363,11 @@ async function connectWithReconnect(conn) {
6132
6363
  console.error(
6133
6364
  `${TAG17} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
6134
6365
  );
6135
- await new Promise((resolve45) => {
6136
- const timer = setTimeout(resolve45, delay);
6366
+ await new Promise((resolve46) => {
6367
+ const timer = setTimeout(resolve46, delay);
6137
6368
  conn.abortController.signal.addEventListener("abort", () => {
6138
6369
  clearTimeout(timer);
6139
- resolve45();
6370
+ resolve46();
6140
6371
  }, { once: true });
6141
6372
  });
6142
6373
  }
@@ -6144,16 +6375,16 @@ async function connectWithReconnect(conn) {
6144
6375
  }
6145
6376
  }
6146
6377
  function waitForDisconnectEvent(conn) {
6147
- return new Promise((resolve45) => {
6378
+ return new Promise((resolve46) => {
6148
6379
  if (!conn.sock) {
6149
- resolve45();
6380
+ resolve46();
6150
6381
  return;
6151
6382
  }
6152
6383
  const sock = conn.sock;
6153
6384
  const handler = (update) => {
6154
6385
  if (update.connection === "close") {
6155
6386
  sock.ev.off("connection.update", handler);
6156
- resolve45();
6387
+ resolve46();
6157
6388
  }
6158
6389
  };
6159
6390
  sock.ev.on("connection.update", handler);
@@ -6201,12 +6432,12 @@ function monitorInbound(conn) {
6201
6432
  const conversationKey = payload.isGroup ? payload.groupJid : payload.senderPhone;
6202
6433
  return `${payload.accountId}:${conversationKey ?? payload.senderPhone}:${payload.senderPhone}`;
6203
6434
  },
6204
- onFlush: (entries) => {
6435
+ onFlush: (entries2) => {
6205
6436
  if (!onInboundMessage) return;
6206
- if (entries.length > 1) {
6207
- console.error(`${TAG17} debounce: combining ${entries.length} messages account=${conn.accountId} from=${entries[0].senderPhone}`);
6437
+ if (entries2.length > 1) {
6438
+ console.error(`${TAG17} debounce: combining ${entries2.length} messages account=${conn.accountId} from=${entries2[0].senderPhone}`);
6208
6439
  }
6209
- dispatchInboundPayload(conn, combineInboundBatch(entries));
6440
+ dispatchInboundPayload(conn, combineInboundBatch(entries2));
6210
6441
  },
6211
6442
  onError: (err) => {
6212
6443
  console.error(`${TAG17} debounce flush error account=${conn.accountId}: ${String(err)}`);
@@ -6261,9 +6492,9 @@ function monitorInbound(conn) {
6261
6492
  quoted: extracted.quotedMessage ? { id: extracted.quotedMessage.id, body: extracted.quotedMessage.text, sender: extracted.quotedMessage.sender } : void 0
6262
6493
  });
6263
6494
  }
6264
- const entries = messageStore.get(storeKey);
6495
+ const entries2 = messageStore.get(storeKey);
6265
6496
  console.error(
6266
- `${TAG17} stored message ${msg.key.id ?? "?"} for ${remoteJid} (type: ${upsert.type}, store size: ${entries?.length ?? 0}/${MESSAGE_STORE_MAX}) storeAccount=${persistAccountId} socketOwner=${conn.platformAccountId}`
6497
+ `${TAG17} stored message ${msg.key.id ?? "?"} for ${remoteJid} (type: ${upsert.type}, store size: ${entries2?.length ?? 0}/${MESSAGE_STORE_MAX}) storeAccount=${persistAccountId} socketOwner=${conn.platformAccountId}`
6267
6498
  );
6268
6499
  recordActivity({
6269
6500
  accountId: conn.accountId,
@@ -6627,8 +6858,8 @@ async function handleInboundMessage(conn, msg) {
6627
6858
  const conversationKey = isGroup ? remoteJid : senderPhone;
6628
6859
  const debounceKey = `${conn.accountId}:${conversationKey}:${senderPhone}`;
6629
6860
  let resolvePending;
6630
- const sttPending = new Promise((resolve45) => {
6631
- resolvePending = resolve45;
6861
+ const sttPending = new Promise((resolve46) => {
6862
+ resolvePending = resolve46;
6632
6863
  });
6633
6864
  if (conn.debouncer) conn.debouncer.registerPending(debounceKey, sttPending);
6634
6865
  try {
@@ -6715,9 +6946,9 @@ async function handleInboundMessage(conn, msg) {
6715
6946
  import { spawnSync, execFileSync } from "child_process";
6716
6947
  import { createConnection } from "net";
6717
6948
  import { mkdirSync as mkdirSync3, readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "fs";
6718
- import { resolve as resolve7 } from "path";
6719
- var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve7(process.cwd(), "..");
6720
- var VNC_SCRIPT = resolve7(PLATFORM_ROOT4, "scripts/vnc.sh");
6949
+ import { resolve as resolve8 } from "path";
6950
+ var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve8(process.cwd(), "..");
6951
+ var VNC_SCRIPT = resolve8(PLATFORM_ROOT4, "scripts/vnc.sh");
6721
6952
  var displayMode = process.env.DISPLAY_MODE ?? "virtual";
6722
6953
  if (displayMode === "native") {
6723
6954
  console.log(`[vnc] DISPLAY_MODE=native \u2014 local requests use desktop display, remote requests use VNC`);
@@ -6830,7 +7061,7 @@ function ensureLogDir() {
6830
7061
  mkdirSync3(LOG_DIR, { recursive: true });
6831
7062
  }
6832
7063
  function logPath(name) {
6833
- return resolve7(LOG_DIR, `${name}.log`);
7064
+ return resolve8(LOG_DIR, `${name}.log`);
6834
7065
  }
6835
7066
  async function ensureVnc() {
6836
7067
  if (process.platform !== "linux") {
@@ -6917,7 +7148,7 @@ function killChromium() {
6917
7148
  }
6918
7149
  function writeChromiumWrapper() {
6919
7150
  mkdirSync3(BIN_DIR, { recursive: true });
6920
- const wrapperPath = resolve7(BIN_DIR, "chromium");
7151
+ const wrapperPath = resolve8(BIN_DIR, "chromium");
6921
7152
  writeFileSync4(wrapperPath, `#!/bin/bash
6922
7153
  LOG="${LOG_DIR}/chromium.log"
6923
7154
  echo "==== [$(date)] chromium wrapper ====" >> "$LOG"
@@ -7017,20 +7248,20 @@ function buildX11Env(chromiumWrapperPath, transport = "vnc") {
7017
7248
 
7018
7249
  // server/routes/health.ts
7019
7250
  function checkPort(port2, timeoutMs = 500) {
7020
- return new Promise((resolve45) => {
7251
+ return new Promise((resolve46) => {
7021
7252
  const socket = createConnection2(port2, "127.0.0.1");
7022
7253
  socket.setTimeout(timeoutMs);
7023
7254
  socket.once("connect", () => {
7024
7255
  socket.destroy();
7025
- resolve45(true);
7256
+ resolve46(true);
7026
7257
  });
7027
7258
  socket.once("error", () => {
7028
7259
  socket.destroy();
7029
- resolve45(false);
7260
+ resolve46(false);
7030
7261
  });
7031
7262
  socket.once("timeout", () => {
7032
7263
  socket.destroy();
7033
- resolve45(false);
7264
+ resolve46(false);
7034
7265
  });
7035
7266
  });
7036
7267
  }
@@ -7690,7 +7921,7 @@ function createScheduleInjectRoutes(deps) {
7690
7921
  }
7691
7922
 
7692
7923
  // server/index.ts
7693
- var import_dist8 = __toESM(require_dist(), 1);
7924
+ var import_dist9 = __toESM(require_dist(), 1);
7694
7925
 
7695
7926
  // app/lib/whatsapp/socket-resolution-error.ts
7696
7927
  function formatPresentKeys(presentKeys) {
@@ -7731,7 +7962,7 @@ async function sendTelegramText(botToken, chatId, text) {
7731
7962
  }
7732
7963
 
7733
7964
  // server/routes/whatsapp.ts
7734
- import { join as join12, resolve as resolve10 } from "path";
7965
+ import { join as join12, resolve as resolve11 } from "path";
7735
7966
  import { readdirSync as readdirSync7, readFileSync as readFileSync14, existsSync as existsSync8 } from "fs";
7736
7967
 
7737
7968
  // app/lib/whatsapp/login.ts
@@ -7739,10 +7970,10 @@ import { randomUUID as randomUUID6 } from "crypto";
7739
7970
 
7740
7971
  // app/lib/whatsapp/config-persist.ts
7741
7972
  import { readFileSync as readFileSync13, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "fs";
7742
- import { resolve as resolve8, join as join10, dirname as dirname2, basename as basename2 } from "path";
7973
+ import { resolve as resolve9, join as join10, dirname as dirname2, basename as basename2 } from "path";
7743
7974
  var TAG21 = "[whatsapp:config]";
7744
7975
  function configPath(accountDir) {
7745
- return resolve8(accountDir, "account.json");
7976
+ return resolve9(accountDir, "account.json");
7746
7977
  }
7747
7978
  function readConfig(accountDir) {
7748
7979
  const path3 = configPath(accountDir);
@@ -7814,8 +8045,8 @@ function addAdminPhone(accountDir, phone) {
7814
8045
  }
7815
8046
  try {
7816
8047
  const config = readConfig(accountDir);
7817
- const targetId = typeof config.accountId === "string" && config.accountId ? config.accountId : basename2(resolve8(accountDir));
7818
- const socketOwner = resolveHouseOrSoleAccountId(dirname2(resolve8(accountDir)));
8048
+ const targetId = typeof config.accountId === "string" && config.accountId ? config.accountId : basename2(resolve9(accountDir));
8049
+ const socketOwner = resolveHouseOrSoleAccountId(dirname2(resolve9(accountDir)));
7819
8050
  if (targetId !== socketOwner) {
7820
8051
  console.error(`${TAG21} add-admin-phone rejected accountId=${targetId} reason=not-socket-account`);
7821
8052
  return {
@@ -7904,7 +8135,7 @@ function purgeNonSocketAdminPhones(accountDir, socketOwnerId) {
7904
8135
  const config = readConfig(accountDir);
7905
8136
  const wa = config.whatsapp;
7906
8137
  if (!wa || typeof wa !== "object") return { removed: [] };
7907
- const targetId = typeof config.accountId === "string" && config.accountId ? config.accountId : basename2(resolve8(accountDir));
8138
+ const targetId = typeof config.accountId === "string" && config.accountId ? config.accountId : basename2(resolve9(accountDir));
7908
8139
  if (targetId === socketOwnerId) return { removed: [] };
7909
8140
  const adminPhones = Array.isArray(wa.adminPhones) ? wa.adminPhones.filter((p) => typeof p === "string") : [];
7910
8141
  if (adminPhones.length === 0) return { removed: [] };
@@ -8369,8 +8600,8 @@ async function startLogin(opts) {
8369
8600
  await clearAuth(authDir);
8370
8601
  let resolveCode = null;
8371
8602
  let rejectCode = null;
8372
- const codePromise = new Promise((resolve45, reject) => {
8373
- resolveCode = resolve45;
8603
+ const codePromise = new Promise((resolve46, reject) => {
8604
+ resolveCode = resolve46;
8374
8605
  rejectCode = reject;
8375
8606
  });
8376
8607
  const codeTimer = setTimeout(
@@ -8521,7 +8752,7 @@ function reconcileMessageStoreAccountKeys(input) {
8521
8752
  // app/lib/whatsapp/outbound/send-document.ts
8522
8753
  import { realpathSync as realpathSync3 } from "fs";
8523
8754
  import { readFile, stat as stat2 } from "fs/promises";
8524
- import { resolve as resolve9, basename as basename3 } from "path";
8755
+ import { resolve as resolve10, basename as basename3 } from "path";
8525
8756
  var TAG23 = "[whatsapp:outbound]";
8526
8757
  var lastDocumentOutboundAt = /* @__PURE__ */ new Map();
8527
8758
  var lastRouteDocumentOutboundAt = /* @__PURE__ */ new Map();
@@ -8548,7 +8779,7 @@ async function sendWhatsAppDocument(input) {
8548
8779
  if (!maxyAccountId || !platformRoot5) {
8549
8780
  return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
8550
8781
  }
8551
- const accountDir = resolve9(platformRoot5, "..", "data/accounts", maxyAccountId);
8782
+ const accountDir = resolve10(platformRoot5, "..", "data/accounts", maxyAccountId);
8552
8783
  let accountResolved;
8553
8784
  try {
8554
8785
  accountResolved = realpathSync3(accountDir);
@@ -8740,25 +8971,25 @@ function isAccountConfigured(accountDir, accountId) {
8740
8971
  }
8741
8972
  function reconcileCredsOnDisk(opts) {
8742
8973
  const { credsRoot, accountDir, liveAccountIds, activeLoginAccountIds } = opts;
8743
- const entries = [];
8974
+ const entries2 = [];
8744
8975
  for (const accountId of listCredsAccountIds(credsRoot)) {
8745
8976
  if (liveAccountIds.has(accountId)) continue;
8746
8977
  const authDir = join11(credsRoot, accountId);
8747
8978
  const census = credsCensus(authDir);
8748
8979
  if (census.registered && !census.hasAccountSignature) {
8749
- const inFlight2 = activeLoginAccountIds.has(accountId);
8980
+ const inFlight3 = activeLoginAccountIds.has(accountId);
8750
8981
  const ageMs2 = getAuthAgeMs(authDir);
8751
- const abandoned = !inFlight2 && ageMs2 !== null && ageMs2 >= HALF_REGISTERED_MIN_AGE_MS;
8982
+ const abandoned = !inFlight3 && ageMs2 !== null && ageMs2 >= HALF_REGISTERED_MIN_AGE_MS;
8752
8983
  if (!abandoned) {
8753
- console.error(`${TAG24} op=half-registered account=${accountId} registered=true hasAccount=false inFlight=${inFlight2} ageMs=${ageMs2 ?? "null"}`);
8754
- entries.push({ accountId, connected: false, linkedUnconfigured: true });
8984
+ console.error(`${TAG24} op=half-registered account=${accountId} registered=true hasAccount=false inFlight=${inFlight3} ageMs=${ageMs2 ?? "null"}`);
8985
+ entries2.push({ accountId, connected: false, linkedUnconfigured: true });
8755
8986
  continue;
8756
8987
  }
8757
8988
  console.error(`${TAG24} op=discard-half-registered account=${accountId} registered=true hasAccount=false ageMs=${ageMs2}`);
8758
8989
  const removed = discardAuthDirSync(authDir);
8759
8990
  if (!removed) {
8760
8991
  console.error(`${TAG24} op=discard-half-registered-failed account=${accountId} \u2014 residue persists`);
8761
- entries.push({ accountId, connected: false, linkedUnconfigured: true });
8992
+ entries2.push({ accountId, connected: false, linkedUnconfigured: true });
8762
8993
  }
8763
8994
  continue;
8764
8995
  }
@@ -8775,9 +9006,9 @@ function reconcileCredsOnDisk(opts) {
8775
9006
  console.error(`${TAG24} self-heal FAILED account=${accountId}: ${result.error}`);
8776
9007
  }
8777
9008
  }
8778
- entries.push({ accountId, selfPhone, connected: false, linkedUnconfigured: !configured });
9009
+ entries2.push({ accountId, selfPhone, connected: false, linkedUnconfigured: !configured });
8779
9010
  }
8780
- return entries;
9011
+ return entries2;
8781
9012
  }
8782
9013
 
8783
9014
  // app/lib/whatsapp/outbound/reply-guard.ts
@@ -9165,14 +9396,14 @@ app2.post("/config", async (c) => {
9165
9396
  return c.json({ ok: true, slug: resolved?.slug ?? null, source: resolved?.source ?? null });
9166
9397
  }
9167
9398
  case "list-public-agents": {
9168
- const agentsDir = resolve10(account.accountDir, "agents");
9399
+ const agentsDir = resolve11(account.accountDir, "agents");
9169
9400
  const agents = [];
9170
9401
  if (existsSync8(agentsDir)) {
9171
9402
  try {
9172
- const entries = readdirSync7(agentsDir, { withFileTypes: true });
9173
- for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
9403
+ const entries2 = readdirSync7(agentsDir, { withFileTypes: true });
9404
+ for (const entry of entries2.sort((a, b) => a.name.localeCompare(b.name))) {
9174
9405
  if (!entry.isDirectory() || entry.name === "admin") continue;
9175
- const configPath2 = resolve10(agentsDir, entry.name, "config.json");
9406
+ const configPath2 = resolve11(agentsDir, entry.name, "config.json");
9176
9407
  if (!existsSync8(configPath2)) continue;
9177
9408
  try {
9178
9409
  const config = JSON.parse(readFileSync14(configPath2, "utf-8"));
@@ -9664,7 +9895,7 @@ var bodyLimit = (options) => {
9664
9895
  };
9665
9896
 
9666
9897
  // server/routes/storage-broker.ts
9667
- import { join as join13, resolve as resolve11 } from "path";
9898
+ import { join as join13, resolve as resolve12 } from "path";
9668
9899
  import { readdirSync as readdirSync8, readFileSync as readFileSync15, existsSync as existsSync9, realpathSync as realpathSync4 } from "fs";
9669
9900
  import { randomUUID as randomUUID7 } from "crypto";
9670
9901
  var app3 = new Hono();
@@ -9742,9 +9973,9 @@ var pagesDeployBodyLimit = bodyLimit({
9742
9973
  function resolveSiteDir(account, site) {
9743
9974
  if (!site || site === "." || site === "..") return null;
9744
9975
  if (site.includes("/") || site.includes("\\") || site.includes("\0")) return null;
9745
- const accountsDir = resolve11(platformRoot(), "..", "data", "accounts");
9746
- const base = resolve11(accountsDir, account, "sites");
9747
- const dir = resolve11(base, site);
9976
+ const accountsDir = resolve12(platformRoot(), "..", "data", "accounts");
9977
+ const base = resolve12(accountsDir, account, "sites");
9978
+ const dir = resolve12(base, site);
9748
9979
  if (dir !== base && !dir.startsWith(base + "/")) return null;
9749
9980
  try {
9750
9981
  const realBase = realpathSync4(base);
@@ -10177,7 +10408,7 @@ var storage_broker_default = app3;
10177
10408
  async function runStorageAudit(root) {
10178
10409
  const { reconcileStorage } = await import("./src-JN6PIAJN.js");
10179
10410
  const cf = await makeHouseCfExec(root);
10180
- const accountsDir = resolve11(root, "..", "data", "accounts");
10411
+ const accountsDir = resolve12(root, "..", "data", "accounts");
10181
10412
  const strays = (await reconcileStorage({
10182
10413
  cfD1: async () => (await cf.d1List()).map((d) => d.name),
10183
10414
  cfR2: async () => (await cf.r2List()).map((b) => b.name),
@@ -10275,7 +10506,7 @@ function auditErrorText(message) {
10275
10506
  function readLastPushAgeSec(platformRoot5, accountId, nowMs) {
10276
10507
  try {
10277
10508
  const raw = readFileSync15(
10278
- resolve11(platformRoot5, "..", "data", "portal-index-state.json"),
10509
+ resolve12(platformRoot5, "..", "data", "portal-index-state.json"),
10279
10510
  "utf-8"
10280
10511
  );
10281
10512
  const state = JSON.parse(raw);
@@ -10289,7 +10520,7 @@ function readLastPushAgeSec(platformRoot5, accountId, nowMs) {
10289
10520
  function countConfigAbsent(platformRoot5, present) {
10290
10521
  try {
10291
10522
  const raw = readFileSync15(
10292
- resolve11(platformRoot5, "..", "data", "portal-index-state.json"),
10523
+ resolve12(platformRoot5, "..", "data", "portal-index-state.json"),
10293
10524
  "utf-8"
10294
10525
  );
10295
10526
  const state = JSON.parse(raw);
@@ -10316,7 +10547,7 @@ function discoverPortalAccounts(accountsDir) {
10316
10547
  return found;
10317
10548
  }
10318
10549
  async function runDataPortalAudit(root) {
10319
- const portals = discoverPortalAccounts(resolve11(root, "..", "data", "accounts"));
10550
+ const portals = discoverPortalAccounts(resolve12(root, "..", "data", "accounts"));
10320
10551
  const configAbsent = countConfigAbsent(root, portals);
10321
10552
  if (portals.length === 0) {
10322
10553
  if (configAbsent > 0) {
@@ -10386,7 +10617,7 @@ async function runDataPortalAudit(root) {
10386
10617
  // server/portal-uploads-pull.ts
10387
10618
  import { existsSync as existsSync10 } from "fs";
10388
10619
  import { mkdir as mkdir3, readFile as readFile2, rename, stat as stat3, unlink as unlink2, writeFile as writeFile4 } from "fs/promises";
10389
- import { basename as basename4, dirname as dirname4, join as join14, relative as relative2, resolve as resolve12, sep as sep3 } from "path";
10620
+ import { basename as basename4, dirname as dirname4, join as join14, relative as relative2, resolve as resolve13, sep as sep3 } from "path";
10390
10621
 
10391
10622
  // ../plugins/cloudflare/bin/schema-exposed-dirs.mjs
10392
10623
  var ONT_START = "<!-- ontology-buckets:start -->";
@@ -10483,10 +10714,10 @@ function resolveDestination(accountDir, row, exposed) {
10483
10714
  const segments = row.targetPath.split("/");
10484
10715
  if (!segments.every(safeSegment)) return { ok: false, reason: "bad-target" };
10485
10716
  if (!exposed.includes(segments[0])) return { ok: false, reason: "bad-target" };
10486
- root = resolve12(accountDir);
10717
+ root = resolve13(accountDir);
10487
10718
  dir = join14(root, ...segments);
10488
10719
  } else {
10489
- root = resolve12(accountDir, "uploads");
10720
+ root = resolve13(accountDir, "uploads");
10490
10721
  dir = join14(root, row.ownerId);
10491
10722
  }
10492
10723
  const final = join14(dir, row.filename);
@@ -10498,7 +10729,7 @@ function resolveDestination(accountDir, row, exposed) {
10498
10729
  dir,
10499
10730
  tmp: join14(dir, ".uploads-tmp", row.filename),
10500
10731
  final,
10501
- relative: relative2(resolve12(accountDir), final).split(sep3).join("/")
10732
+ relative: relative2(resolve13(accountDir), final).split(sep3).join("/")
10502
10733
  };
10503
10734
  }
10504
10735
  function nextFreePath(final) {
@@ -10553,7 +10784,7 @@ async function pullAccount(opts) {
10553
10784
  `${TAG26} op=collision account=${accountId}${idField} suffix="${basename4(finalPath)}" result=suffixed`
10554
10785
  );
10555
10786
  }
10556
- const relPath = relative2(resolve12(accountDir), finalPath).split(sep3).join("/");
10787
+ const relPath = relative2(resolve13(accountDir), finalPath).split(sep3).join("/");
10557
10788
  try {
10558
10789
  await mkdir3(dirname4(dest.tmp), { recursive: true });
10559
10790
  await writeFile4(dest.tmp, bytes);
@@ -10613,8 +10844,8 @@ async function withdrawRow(opts) {
10613
10844
  log2(`${head} removed=false result=bad-path`);
10614
10845
  return false;
10615
10846
  }
10616
- const absolute = join14(resolve12(accountDir), ...segments);
10617
- if (!absolute.startsWith(resolve12(accountDir) + sep3)) {
10847
+ const absolute = join14(resolve13(accountDir), ...segments);
10848
+ if (!absolute.startsWith(resolve13(accountDir) + sep3)) {
10618
10849
  log2(`${head} removed=false result=bad-path`);
10619
10850
  return false;
10620
10851
  }
@@ -10693,7 +10924,7 @@ async function readExposedDirs(accountDir) {
10693
10924
  return exposed;
10694
10925
  }
10695
10926
  async function runPortalUploadsPull(root) {
10696
- const accountsRoot = resolve12(root, "..", "data", "accounts");
10927
+ const accountsRoot = resolve13(root, "..", "data", "accounts");
10697
10928
  const portals = discoverPortalAccounts(accountsRoot);
10698
10929
  if (portals.length === 0) return "portals=0 pulled=0";
10699
10930
  const cf = await makeHouseCfExec(root);
@@ -10742,7 +10973,7 @@ async function runPortalUploadsPull(root) {
10742
10973
  import { readFile as readFile3, readdir, stat as stat4 } from "fs/promises";
10743
10974
  import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync6 } from "fs";
10744
10975
  import { execFileSync as execFileSync2 } from "child_process";
10745
- import { join as join15, resolve as resolve13 } from "path";
10976
+ import { join as join15, resolve as resolve14 } from "path";
10746
10977
  import { fileURLToPath } from "url";
10747
10978
 
10748
10979
  // ../plugins/cloudflare/bin/d1-http.mjs
@@ -10827,9 +11058,9 @@ async function readExposeFolders(accountDir) {
10827
11058
  async function walkExposed(accountDir, exposed) {
10828
11059
  const out = [];
10829
11060
  async function walk(rel) {
10830
- let entries;
11061
+ let entries2;
10831
11062
  try {
10832
- entries = await readdir(join15(accountDir, rel), { withFileTypes: true });
11063
+ entries2 = await readdir(join15(accountDir, rel), { withFileTypes: true });
10833
11064
  } catch {
10834
11065
  return;
10835
11066
  }
@@ -10838,7 +11069,7 @@ async function walkExposed(accountDir, exposed) {
10838
11069
  out.push({ relPath: rel, sizeBytes: 0, modifiedAt: st.mtime.toISOString(), isDir: true });
10839
11070
  } catch {
10840
11071
  }
10841
- for (const e of entries) {
11072
+ for (const e of entries2) {
10842
11073
  if (e.name.startsWith(".")) continue;
10843
11074
  const childRel = `${rel}/${e.name}`;
10844
11075
  if (e.isDirectory()) {
@@ -10938,7 +11169,7 @@ async function pushAccount(opts) {
10938
11169
  return { exposed: r.exposed, rows: rows.length, schemaPresent: true, generation: next };
10939
11170
  }
10940
11171
  function stateFilePath(platformRoot5) {
10941
- return resolve13(platformRoot5, "..", "data", "portal-index-state.json");
11172
+ return resolve14(platformRoot5, "..", "data", "portal-index-state.json");
10942
11173
  }
10943
11174
  function readState(platformRoot5) {
10944
11175
  try {
@@ -11005,7 +11236,7 @@ function resolveCloudflareCredentials(platformRoot5) {
11005
11236
  return { cfAccountId: house.CLOUDFLARE_ACCOUNT_ID, token };
11006
11237
  }
11007
11238
  async function pushAllAccounts(platformRoot5) {
11008
- const accountsRoot = resolve13(platformRoot5, "..", "data", "accounts");
11239
+ const accountsRoot = resolve14(platformRoot5, "..", "data", "accounts");
11009
11240
  const targets = await portalAccounts(accountsRoot);
11010
11241
  console.error(`${TAG27} op=enumerate accountsRoot="${accountsRoot}" accounts=${targets.length}`);
11011
11242
  if (targets.length === 0) return { accounts: 0, pushed: 0, failed: 0 };
@@ -11084,8 +11315,8 @@ async function main() {
11084
11315
  ]);
11085
11316
  if (r.failed > 0) process.exit(1);
11086
11317
  }
11087
- var invokedPath = process.argv[1] ? resolve13(process.argv[1]) : "";
11088
- if (invokedPath && invokedPath.endsWith("/portal-index-push.mjs") && invokedPath === resolve13(fileURLToPath(import.meta.url))) {
11318
+ var invokedPath = process.argv[1] ? resolve14(process.argv[1]) : "";
11319
+ if (invokedPath && invokedPath.endsWith("/portal-index-push.mjs") && invokedPath === resolve14(fileURLToPath(import.meta.url))) {
11089
11320
  void main();
11090
11321
  }
11091
11322
 
@@ -11164,12 +11395,12 @@ function runReconcileLivenessAudit(statePath, nowMs, intervalMs, emit) {
11164
11395
  }
11165
11396
 
11166
11397
  // server/routes/whatsapp-reader.ts
11167
- import { readFileSync as readFileSync21, watch, statSync as statSync8, openSync, readSync, closeSync, existsSync as existsSync17, readdirSync as readdirSync14, realpathSync as realpathSync6 } from "fs";
11168
- import { basename as basename6, dirname as dirname7, isAbsolute, join as join21, relative as relative3, resolve as resolve16, sep as sep5 } from "path";
11398
+ import { readFileSync as readFileSync21, watch as watch2, statSync as statSync8, openSync, readSync, closeSync, existsSync as existsSync17, readdirSync as readdirSync14, realpathSync as realpathSync6 } from "fs";
11399
+ import { basename as basename6, dirname as dirname7, isAbsolute, join as join21, relative as relative3, resolve as resolve17, sep as sep5 } from "path";
11169
11400
 
11170
11401
  // server/routes/admin/sidebar-sessions.ts
11171
11402
  import { readdirSync as readdirSync12, readFileSync as readFileSync19, statSync as statSync6 } from "fs";
11172
- import { dirname as dirname5, join as join19, resolve as resolve14 } from "path";
11403
+ import { dirname as dirname5, join as join19, resolve as resolve15 } from "path";
11173
11404
 
11174
11405
  // ../services/claude-session-manager/src/jsonl-path.ts
11175
11406
  import { existsSync as existsSync14, readdirSync as readdirSync10 } from "fs";
@@ -11329,15 +11560,15 @@ function enumerateJsonls(projectsRoot) {
11329
11560
  }
11330
11561
  for (const slug of slugs) {
11331
11562
  const slugDir = join19(projectsRoot, slug);
11332
- let entries;
11563
+ let entries2;
11333
11564
  try {
11334
- entries = readdirSync12(slugDir, { withFileTypes: true });
11565
+ entries2 = readdirSync12(slugDir, { withFileTypes: true });
11335
11566
  } catch (err) {
11336
11567
  const code = err.code ?? "unknown";
11337
11568
  console.error(`[admin-sessions-list] slug-skipped slug=${slug} code=${code}`);
11338
11569
  continue;
11339
11570
  }
11340
- for (const entry of entries) {
11571
+ for (const entry of entries2) {
11341
11572
  if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
11342
11573
  out.push({ path: join19(slugDir, entry.name), isSubagent: false, archived: false });
11343
11574
  } else if (entry.isDirectory() && entry.name === "subagents") {
@@ -11520,17 +11751,30 @@ function resolveTitle(body, sessionId, userTitles) {
11520
11751
  app4.get("/", requireAdminSession, async (c) => {
11521
11752
  const cacheKey = c.var.cacheKey;
11522
11753
  const scopeAccountId = getAccountIdForSession(cacheKey) ?? null;
11754
+ const start = Date.now();
11755
+ const { value, state } = await getOrCompute(
11756
+ "sidebar-sessions",
11757
+ scopeAccountId ?? NO_ACCOUNT_KEY,
11758
+ () => computeSessionList(scopeAccountId)
11759
+ );
11760
+ console.log(
11761
+ `[admin-sessions-list] op=list-cache cache=${state} accountId=${scopeAccountId ? scopeAccountId.slice(0, 8) : "unset"} ms=${Date.now() - start}`
11762
+ );
11763
+ return c.json(value);
11764
+ });
11765
+ var NO_ACCOUNT_KEY = "no-account";
11766
+ async function computeSessionList(scopeAccountId) {
11523
11767
  const validAccounts = listValidAccounts();
11524
11768
  const multiAccount = validAccounts.length > 1;
11525
11769
  const configDir2 = claudeConfigDir();
11526
11770
  if (!configDir2) {
11527
11771
  console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
11528
- return c.json({ sessions: [], accountId: scopeAccountId });
11772
+ return { sessions: [], accountId: scopeAccountId };
11529
11773
  }
11530
11774
  const projectsRoot = join19(configDir2, "projects");
11531
11775
  const jsonls = enumerateJsonls(projectsRoot);
11532
11776
  const liveSessions = await fetchLiveSessions();
11533
- const accountDir = scopeAccountId ? resolve14(ACCOUNTS_DIR, scopeAccountId) : null;
11777
+ const accountDir = scopeAccountId ? resolve15(ACCOUNTS_DIR, scopeAccountId) : null;
11534
11778
  const userTitles = loadUserTitles(accountDir);
11535
11779
  const account = multiAccount ? validAccounts.find((a) => a.accountId === scopeAccountId) ?? null : resolveAccount();
11536
11780
  let channelUsers = [];
@@ -11701,8 +11945,8 @@ app4.get("/", requireAdminSession, async (c) => {
11701
11945
  if (multiAccount) {
11702
11946
  console.log(`[admin-sessions-list] untagged-accountId-rows=${untaggedCount}`);
11703
11947
  }
11704
- return c.json({ sessions: rows, accountId: scopeAccountId });
11705
- });
11948
+ return { sessions: rows, accountId: scopeAccountId };
11949
+ }
11706
11950
  var sidebar_sessions_default = app4;
11707
11951
 
11708
11952
  // app/lib/agent-errors.ts
@@ -11983,7 +12227,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
11983
12227
 
11984
12228
  // app/lib/whatsapp-reader/enrich-attachments.ts
11985
12229
  import { readFileSync as readFileSync20, readdirSync as readdirSync13, existsSync as existsSync16, statSync as statSync7, realpathSync as realpathSync5 } from "fs";
11986
- import { basename as basename5, dirname as dirname6, join as join20, resolve as resolve15, sep as sep4 } from "path";
12230
+ import { basename as basename5, dirname as dirname6, join as join20, resolve as resolve16, sep as sep4 } from "path";
11987
12231
  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;
11988
12232
  function adminAttachmentIds(text) {
11989
12233
  const ids = [];
@@ -12002,19 +12246,19 @@ function adminAttachmentsFromText(text, uploadsBase) {
12002
12246
  return out;
12003
12247
  }
12004
12248
  function claudeUploadsRoot() {
12005
- return process.env.CLAUDE_CONFIG_DIR ? resolve15(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
12249
+ return process.env.CLAUDE_CONFIG_DIR ? resolve16(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
12006
12250
  }
12007
12251
  var CC_MENTION_RE = /@"([^"]+)"/g;
12008
12252
  function claudeUploadAttachmentsFromText(text, sessionId) {
12009
12253
  const root = claudeUploadsRoot();
12010
12254
  if (!root) return { attachments: [], strippedText: text };
12011
- const sessionDir = resolve15(root, sessionId);
12255
+ const sessionDir = resolve16(root, sessionId);
12012
12256
  const attachments = [];
12013
12257
  const accepted = [];
12014
12258
  for (const m of text.matchAll(CC_MENTION_RE)) {
12015
12259
  let abs;
12016
12260
  try {
12017
- abs = resolve15(m[1]);
12261
+ abs = resolve16(m[1]);
12018
12262
  } catch {
12019
12263
  continue;
12020
12264
  }
@@ -12067,14 +12311,14 @@ function readAttachmentMeta(dir) {
12067
12311
  return render;
12068
12312
  }
12069
12313
  function listSessionAttachmentsInDir(dir) {
12070
- let entries;
12314
+ let entries2;
12071
12315
  try {
12072
- entries = readdirSync13(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
12316
+ entries2 = readdirSync13(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
12073
12317
  } catch {
12074
12318
  return [];
12075
12319
  }
12076
12320
  const sidecars = [];
12077
- for (const name of entries) {
12321
+ for (const name of entries2) {
12078
12322
  const sidecar = readSidecar(join20(dir, name), name);
12079
12323
  if (sidecar) sidecars.push(sidecar);
12080
12324
  }
@@ -12124,8 +12368,8 @@ function managerBase(tag) {
12124
12368
  }
12125
12369
 
12126
12370
  // server/routes/activity-scan.ts
12127
- function pickActivity(entries, grown, nowMs, concurrencyWindowMs) {
12128
- const candidates = entries.filter((e) => grown.has(e.hex));
12371
+ function pickActivity(entries2, grown, nowMs, concurrencyWindowMs) {
12372
+ const candidates = entries2.filter((e) => grown.has(e.hex));
12129
12373
  if (candidates.length === 0) return null;
12130
12374
  let newest = candidates[0];
12131
12375
  for (const e of candidates) if (e.mtimeMs > newest.mtimeMs) newest = e;
@@ -12370,83 +12614,87 @@ app5.get("/conversations-all", requireAdminSession, async (c) => {
12370
12614
  console.log(`[wa-reader] op=conversations-all-gate decision=deny caller=${caller2?.slice(0, 8) ?? "null"} house=${houseId?.slice(0, 8) ?? "null"}`);
12371
12615
  return c.json({ error: "house-only" }, 403);
12372
12616
  }
12373
- const cfg = claudeConfigDir();
12374
- if (!cfg) return c.json({ conversations: [] });
12375
- const projectsRoot = join21(cfg, "projects");
12376
- const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
12377
- const validAccounts = listValidAccounts();
12378
- const validIds = new Set(validAccounts.map((a) => a.accountId));
12379
- const houseIds = new Set(validAccounts.filter((a) => a.config.role === "house").map((a) => a.accountId));
12380
- const rawByAccount = /* @__PURE__ */ new Map();
12381
- for (const { path: path3 } of enumerateJsonls(projectsRoot)) {
12382
- const sessionId = basename6(path3).replace(/\.jsonl$/, "");
12383
- const projectDir = dirname7(path3);
12384
- const meta = readSidecarMeta(join21(projectDir, `${sessionId}.meta.json`));
12385
- if (!isReaderChannelSession(meta.role, meta.channel)) continue;
12386
- if (meta.accountId === null || !validIds.has(meta.accountId)) continue;
12387
- let body = "";
12617
+ const { value, state } = await getOrCompute("conversations-all", houseId, async () => {
12618
+ const cfg = claudeConfigDir();
12619
+ if (!cfg) return { conversations: [] };
12620
+ const projectsRoot = join21(cfg, "projects");
12621
+ const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
12622
+ const validAccounts = listValidAccounts();
12623
+ const validIds = new Set(validAccounts.map((a) => a.accountId));
12624
+ const houseIds = new Set(validAccounts.filter((a) => a.config.role === "house").map((a) => a.accountId));
12625
+ const rawByAccount = /* @__PURE__ */ new Map();
12626
+ for (const { path: path3 } of enumerateJsonls(projectsRoot)) {
12627
+ const sessionId = basename6(path3).replace(/\.jsonl$/, "");
12628
+ const projectDir = dirname7(path3);
12629
+ const meta = readSidecarMeta(join21(projectDir, `${sessionId}.meta.json`));
12630
+ if (!isReaderChannelSession(meta.role, meta.channel)) continue;
12631
+ if (meta.accountId === null || !validIds.has(meta.accountId)) continue;
12632
+ let body = "";
12633
+ try {
12634
+ body = readFileSync21(path3, "utf8");
12635
+ } catch {
12636
+ }
12637
+ const { title } = resolveTitle(body, sessionId, userTitles);
12638
+ const turns = parseTranscript(body.split("\n"));
12639
+ const row = {
12640
+ sessionId,
12641
+ projectDir,
12642
+ title,
12643
+ startedAt: meta.startedAt ?? "",
12644
+ role: meta.role,
12645
+ channel: meta.channel,
12646
+ senderId: meta.senderId,
12647
+ lastMessageAt: lastTurnTs(turns),
12648
+ modelGated: isModelGated(turns),
12649
+ model: lastAssistantModel(body)
12650
+ };
12651
+ const list = rawByAccount.get(meta.accountId) ?? [];
12652
+ list.push(row);
12653
+ rawByAccount.set(meta.accountId, list);
12654
+ }
12655
+ let users = [];
12388
12656
  try {
12389
- body = readFileSync21(path3, "utf8");
12390
- } catch {
12657
+ users = readUsersFile(USERS_FILE) ?? [];
12658
+ } catch (err) {
12659
+ console.error(`[wa-reader] op=users-file-unreadable reason=${err instanceof Error ? err.message : String(err)}`);
12660
+ users = [];
12391
12661
  }
12392
- const { title } = resolveTitle(body, sessionId, userTitles);
12393
- const turns = parseTranscript(body.split("\n"));
12394
- const row = {
12395
- sessionId,
12396
- projectDir,
12397
- title,
12398
- startedAt: meta.startedAt ?? "",
12399
- role: meta.role,
12400
- channel: meta.channel,
12401
- senderId: meta.senderId,
12402
- lastMessageAt: lastTurnTs(turns),
12403
- modelGated: isModelGated(turns),
12404
- model: lastAssistantModel(body)
12405
- };
12406
- const list = rawByAccount.get(meta.accountId) ?? [];
12407
- list.push(row);
12408
- rawByAccount.set(meta.accountId, list);
12409
- }
12410
- let users = [];
12411
- try {
12412
- users = readUsersFile(USERS_FILE) ?? [];
12413
- } catch (err) {
12414
- console.error(`[wa-reader] op=users-file-unreadable reason=${err instanceof Error ? err.message : String(err)}`);
12415
- users = [];
12416
- }
12417
- const perAccount = [];
12418
- for (const account of validAccounts) {
12419
- const isHouse = houseIds.has(account.accountId);
12420
- const sessionRows = selectReaderChannelSessions(rawByAccount.get(account.accountId) ?? []).filter((r) => r.channel !== "whatsapp");
12421
- const admins = account.config.admins ?? [];
12422
- const distinct = [...new Set(sessionRows.map((r) => r.senderId).filter((s) => !!s))];
12423
- const resolved = await resolveOperatorNamesBySender(users, admins, distinct);
12424
- const nameBySender = /* @__PURE__ */ new Map();
12425
- for (const senderId of distinct) nameBySender.set(senderId, resolved.get(senderId)?.name ?? null);
12426
- const named = sessionRows.map((r) => ({
12427
- ...r,
12428
- operatorName: r.senderId ? nameBySender.get(r.senderId) ?? null : null
12429
- }));
12430
- const storeRows = buildStoreConversationRows(account.accountId, readConversationSummaries(account.accountId));
12431
- perAccount.push({ isHouse, rows: [...named, ...storeRows] });
12432
- }
12433
- const houseAccount = validAccounts.find((a) => a.accountId === houseId) ?? null;
12434
- const subManagerPhones = /* @__PURE__ */ new Map();
12435
- if (houseAccount) {
12436
- const managers = readAccountManagers(houseAccount.accountDir);
12437
- for (const a of validAccounts) {
12438
- if (houseIds.has(a.accountId)) continue;
12439
- const phones = managerPhonesForAccount(managers, a.accountId);
12440
- if (phones.length > 0) subManagerPhones.set(a.accountId, phones);
12441
- }
12442
- }
12443
- const merged = tagAndMergeInstallConversations(perAccount);
12444
- const conversations = dropHouseRowsOwnedBySubAccount(merged, subManagerPhones);
12445
- const houseRows = conversations.filter((r) => r.isHouse).length;
12446
- console.log(
12447
- `[wa-reader] op=conversations-all accounts=${validAccounts.length} rows=${conversations.length} house=${houseRows} sub=${conversations.length - houseRows} deduped=${merged.length - conversations.length}`
12448
- );
12449
- return c.json({ conversations });
12662
+ const perAccount = [];
12663
+ for (const account of validAccounts) {
12664
+ const isHouse = houseIds.has(account.accountId);
12665
+ const sessionRows = selectReaderChannelSessions(rawByAccount.get(account.accountId) ?? []).filter((r) => r.channel !== "whatsapp");
12666
+ const admins = account.config.admins ?? [];
12667
+ const distinct = [...new Set(sessionRows.map((r) => r.senderId).filter((s) => !!s))];
12668
+ const resolved = await resolveOperatorNamesBySender(users, admins, distinct);
12669
+ const nameBySender = /* @__PURE__ */ new Map();
12670
+ for (const senderId of distinct) nameBySender.set(senderId, resolved.get(senderId)?.name ?? null);
12671
+ const named = sessionRows.map((r) => ({
12672
+ ...r,
12673
+ operatorName: r.senderId ? nameBySender.get(r.senderId) ?? null : null
12674
+ }));
12675
+ const storeRows = buildStoreConversationRows(account.accountId, readConversationSummaries(account.accountId));
12676
+ perAccount.push({ isHouse, rows: [...named, ...storeRows] });
12677
+ }
12678
+ const houseAccount = validAccounts.find((a) => a.accountId === houseId) ?? null;
12679
+ const subManagerPhones = /* @__PURE__ */ new Map();
12680
+ if (houseAccount) {
12681
+ const managers = readAccountManagers(houseAccount.accountDir);
12682
+ for (const a of validAccounts) {
12683
+ if (houseIds.has(a.accountId)) continue;
12684
+ const phones = managerPhonesForAccount(managers, a.accountId);
12685
+ if (phones.length > 0) subManagerPhones.set(a.accountId, phones);
12686
+ }
12687
+ }
12688
+ const merged = tagAndMergeInstallConversations(perAccount);
12689
+ const conversations = dropHouseRowsOwnedBySubAccount(merged, subManagerPhones);
12690
+ const houseRows = conversations.filter((r) => r.isHouse).length;
12691
+ console.log(
12692
+ `[wa-reader] op=conversations-all accounts=${validAccounts.length} rows=${conversations.length} house=${houseRows} sub=${conversations.length - houseRows} deduped=${merged.length - conversations.length}`
12693
+ );
12694
+ return { conversations };
12695
+ });
12696
+ console.log(`[wa-reader] op=conversations-all cache=${state} house=${houseId.slice(0, 8)}`);
12697
+ return c.json(value);
12450
12698
  });
12451
12699
  function readFrom(path3, from) {
12452
12700
  const end = statSync8(path3).size;
@@ -12500,7 +12748,7 @@ function enrichAdminAttachments(turn, sessionId) {
12500
12748
  if (turn.kind !== "operator-inbound") return turn;
12501
12749
  if (!turn.text.includes('@"') && adminAttachmentIds(turn.text).length === 0) return turn;
12502
12750
  const account = resolveAccount();
12503
- const store2 = account ? adminAttachmentsFromText(turn.text, resolve16(DATA_ROOT, "accounts", account.accountId, "uploads")) : [];
12751
+ const store2 = account ? adminAttachmentsFromText(turn.text, resolve17(DATA_ROOT, "accounts", account.accountId, "uploads")) : [];
12504
12752
  const cc = claudeUploadAttachmentsFromText(turn.text, sessionId);
12505
12753
  if (cc.attachments.length > 0) {
12506
12754
  console.log(`[session-upload-shape] op=mention accepted=${cc.attachments.length} session=${sessionId.slice(0, 8)}`);
@@ -12569,7 +12817,7 @@ function runActivityTick(c) {
12569
12817
  names = readdirSync14(c.subagentsDir).filter((n) => AGENT_JSONL_RE.test(n));
12570
12818
  } catch {
12571
12819
  }
12572
- const entries = [];
12820
+ const entries2 = [];
12573
12821
  for (const name of names) {
12574
12822
  const hex = name.replace(AGENT_JSONL_RE, "$1");
12575
12823
  let size = 0;
@@ -12583,14 +12831,14 @@ function runActivityTick(c) {
12583
12831
  }
12584
12832
  if (!c.initialSize.has(hex)) c.initialSize.set(hex, size);
12585
12833
  if (size > (c.initialSize.get(hex) ?? size)) c.grown.add(hex);
12586
- entries.push({ hex, size, mtimeMs });
12834
+ entries2.push({ hex, size, mtimeMs });
12587
12835
  }
12588
12836
  const openKey = openTaskKey(c.lastParentTurns);
12589
12837
  if (openKey && c.subagentFrames === 0 && !c.reconcileLogged.has(openKey)) {
12590
12838
  c.reconcileLogged.add(openKey);
12591
12839
  c.log(`[webchat-activity] op=reconcile-gap key=${c.sessionKey} toolUseId=${openKey} framesEmitted=0`);
12592
12840
  }
12593
- const pick = pickActivity(entries, c.grown, c.now, CONCURRENCY_WINDOW_MS);
12841
+ const pick = pickActivity(entries2, c.grown, c.now, CONCURRENCY_WINDOW_MS);
12594
12842
  if (!pick) return;
12595
12843
  const meta = readSubagentMeta(c.subagentsDir, pick.hex);
12596
12844
  if (!meta) return;
@@ -12620,11 +12868,11 @@ app5.get("/stream", requireAdminSession, (c) => {
12620
12868
  const sessionId = c.req.query("sessionId") ?? "";
12621
12869
  const projectDir = c.req.query("projectDir") ?? "";
12622
12870
  const cfg = claudeConfigDir();
12623
- const projectsRoot = cfg ? resolve16(join21(cfg, "projects")) : null;
12871
+ const projectsRoot = cfg ? resolve17(join21(cfg, "projects")) : null;
12624
12872
  if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
12625
12873
  return c.json({ error: "bad session reference" }, 400);
12626
12874
  }
12627
- const jsonlPath = resolve16(join21(projectDir, `${sessionId}.jsonl`));
12875
+ const jsonlPath = resolve17(join21(projectDir, `${sessionId}.jsonl`));
12628
12876
  if (!jsonlPath.startsWith(projectsRoot + sep5)) {
12629
12877
  return c.json({ error: "bad session reference" }, 400);
12630
12878
  }
@@ -12651,7 +12899,7 @@ data: ${JSON.stringify(turn)}
12651
12899
  let offset = resumeOffset(lastEventId, fileEnd0);
12652
12900
  console.log(`[wa-stream] op=open conn=${connId} sessionId=${sessionId} channel=reader resume=${offset}`);
12653
12901
  const sessionKey = c.req.query("session_key") ?? "";
12654
- const subagentsDir = resolve16(join21(projectDir, sessionId, "subagents"));
12902
+ const subagentsDir = resolve17(join21(projectDir, sessionId, "subagents"));
12655
12903
  console.log(
12656
12904
  `[webchat-activity] op=watch-subagents key=${sessionKey} dir=${subagentsDir} exists=${existsSync17(subagentsDir)}`
12657
12905
  );
@@ -12715,7 +12963,7 @@ data: ${JSON.stringify(obj)}
12715
12963
  }
12716
12964
  let watcher = null;
12717
12965
  try {
12718
- watcher = watch(jsonlPath, drain);
12966
+ watcher = watch2(jsonlPath, drain);
12719
12967
  } catch {
12720
12968
  }
12721
12969
  const tick = () => {
@@ -12761,7 +13009,7 @@ var DIRECTIVE_NAME_RE = /^\d+-\d+\.txt$/;
12761
13009
  function directiveStoreDir(sessionId) {
12762
13010
  const account = resolveAccount();
12763
13011
  if (!account) return null;
12764
- return resolve16(account.accountDir, "logs", "prompt-optimiser-directives", sessionId);
13012
+ return resolve17(account.accountDir, "logs", "prompt-optimiser-directives", sessionId);
12765
13013
  }
12766
13014
  app5.get("/directives", requireAdminSession, (c) => {
12767
13015
  const sessionId = c.req.query("sessionId") ?? "";
@@ -12774,7 +13022,7 @@ app5.get("/directives", requireAdminSession, (c) => {
12774
13022
  } catch {
12775
13023
  return c.json({ entries: [] });
12776
13024
  }
12777
- const entries = names.map((name) => {
13025
+ const entries2 = names.map((name) => {
12778
13026
  const [secsPart, pidPart] = name.replace(/\.txt$/, "").split("-");
12779
13027
  const secs = Number(secsPart);
12780
13028
  const pid = Number(pidPart);
@@ -12785,7 +13033,7 @@ app5.get("/directives", requireAdminSession, (c) => {
12785
13033
  }
12786
13034
  return { name, secs, pid, ts: Number.isFinite(secs) ? new Date(secs * 1e3).toISOString() : null, len };
12787
13035
  }).sort((a, b) => a.secs - b.secs || a.pid - b.pid).map(({ name, ts, len }) => ({ name, ts, len }));
12788
- return c.json({ entries });
13036
+ return c.json({ entries: entries2 });
12789
13037
  });
12790
13038
  app5.get("/directive", requireAdminSession, (c) => {
12791
13039
  const sessionId = c.req.query("sessionId") ?? "";
@@ -12795,7 +13043,7 @@ app5.get("/directive", requireAdminSession, (c) => {
12795
13043
  }
12796
13044
  const dir = directiveStoreDir(sessionId);
12797
13045
  if (!dir) return c.json({ error: "no account" }, 404);
12798
- const path3 = resolve16(join21(dir, name));
13046
+ const path3 = resolve17(join21(dir, name));
12799
13047
  if (!path3.startsWith(dir + sep5)) return c.json({ error: "bad reference" }, 400);
12800
13048
  let body;
12801
13049
  try {
@@ -12825,7 +13073,7 @@ app5.get("/store-stream", requireAdminSession, (c) => {
12825
13073
  const connId = `${remoteJid.slice(0, 12)}-${process.hrtime.bigint().toString(36).slice(-6)}`;
12826
13074
  const startedAt = Date.now();
12827
13075
  const lastEventId = c.req.header("Last-Event-ID");
12828
- const uploadsBase = resolve16(DATA_ROOT, "accounts", accountId, "uploads");
13076
+ const uploadsBase = resolve17(DATA_ROOT, "accounts", accountId, "uploads");
12829
13077
  const byMsgKeyId = /* @__PURE__ */ new Map();
12830
13078
  const reactionRecords = [];
12831
13079
  const reactionsForTarget = (msgKeyId) => foldReactions(reactionRecords).get(msgKeyId);
@@ -12954,7 +13202,7 @@ data: ${JSON.stringify(payload)}
12954
13202
  };
12955
13203
  let watcher = null;
12956
13204
  try {
12957
- watcher = watch(file, drain);
13205
+ watcher = watch2(file, drain);
12958
13206
  } catch {
12959
13207
  }
12960
13208
  const lifecycle = openStream(connId, "store", startedAt);
@@ -13233,8 +13481,8 @@ app5.post("/reply", requireAdminSession, async (c) => {
13233
13481
  var whatsapp_reader_default = app5;
13234
13482
 
13235
13483
  // server/routes/public-reader.ts
13236
- import { statSync as statSync9, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2, readFileSync as readFileSync22, readdirSync as readdirSync15 } from "fs";
13237
- import { basename as basename7, dirname as dirname8, join as join22, resolve as resolve17, sep as sep6 } from "path";
13484
+ import { statSync as statSync9, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch3, readFileSync as readFileSync22, readdirSync as readdirSync15 } from "fs";
13485
+ import { basename as basename7, dirname as dirname8, join as join22, resolve as resolve18, sep as sep6 } from "path";
13238
13486
 
13239
13487
  // app/lib/whatsapp-reader/delivered-kinds.ts
13240
13488
  var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
@@ -13356,7 +13604,7 @@ app6.get("/session", (c) => {
13356
13604
  return c.json({ sessionId: null, projectDir: null, sessionKey });
13357
13605
  });
13358
13606
  function publicUploadsDir(accountId, sessionId) {
13359
- return resolve17(DATA_ROOT, "accounts", accountId, "uploads", "public", sessionId);
13607
+ return resolve18(DATA_ROOT, "accounts", accountId, "uploads", "public", sessionId);
13360
13608
  }
13361
13609
  function enrichPublicAttachments(turns, sessionAttachments, cursor) {
13362
13610
  for (const turn of turns) {
@@ -13387,11 +13635,11 @@ app6.get("/stream", (c) => {
13387
13635
  const sessionId = c.req.query("sessionId") ?? "";
13388
13636
  const projectDir = c.req.query("projectDir") ?? "";
13389
13637
  const cfg = claudeConfigDir();
13390
- const projectsRoot = cfg ? resolve17(join22(cfg, "projects")) : null;
13638
+ const projectsRoot = cfg ? resolve18(join22(cfg, "projects")) : null;
13391
13639
  if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
13392
13640
  return c.json({ error: "bad session reference" }, 400);
13393
13641
  }
13394
- const jsonlPath = resolve17(join22(projectDir, `${sessionId}.jsonl`));
13642
+ const jsonlPath = resolve18(join22(projectDir, `${sessionId}.jsonl`));
13395
13643
  if (!jsonlPath.startsWith(projectsRoot + sep6)) {
13396
13644
  return c.json({ error: "bad session reference" }, 400);
13397
13645
  }
@@ -13440,7 +13688,7 @@ data: ${JSON.stringify(turn)}
13440
13688
  };
13441
13689
  let watcher = null;
13442
13690
  try {
13443
- watcher = watch2(jsonlPath, drain);
13691
+ watcher = watch3(jsonlPath, drain);
13444
13692
  } catch {
13445
13693
  }
13446
13694
  const poll = setInterval(drain, 1e3);
@@ -13495,7 +13743,7 @@ app6.get("/attachment/:attachmentId", (c) => {
13495
13743
  return new Response("Not found", { status: 404 });
13496
13744
  }
13497
13745
  const uploadsRoot = publicUploadsDir(account.accountId, sessionId);
13498
- const dir = resolve17(uploadsRoot, attachmentId);
13746
+ const dir = resolve18(uploadsRoot, attachmentId);
13499
13747
  if (!dir.startsWith(uploadsRoot + sep6)) {
13500
13748
  console.error(`${ATT_TAG} op=denied session=${ses} att=${at} reason=bad-id`);
13501
13749
  return new Response("Not found", { status: 404 });
@@ -13510,7 +13758,7 @@ app6.get("/attachment/:attachmentId", (c) => {
13510
13758
  try {
13511
13759
  dataFile = readdirSync15(dir).find((f) => !f.endsWith(".meta.json") && !f.endsWith(EXTRACTED_TEXT_SUFFIX));
13512
13760
  if (!dataFile) throw new Error("no data file");
13513
- buffer = readFileSync22(resolve17(dir, dataFile));
13761
+ buffer = readFileSync22(resolve18(dir, dataFile));
13514
13762
  } catch {
13515
13763
  console.error(`${ATT_TAG} op=denied session=${ses} att=${at} reason=not-found`);
13516
13764
  return new Response("Not found", { status: 404 });
@@ -14364,7 +14612,7 @@ ${note}` : note;
14364
14612
  }
14365
14613
 
14366
14614
  // server/routes/webchat-greeting.ts
14367
- import { resolve as resolve18 } from "path";
14615
+ import { resolve as resolve19 } from "path";
14368
14616
 
14369
14617
  // app/lib/claude-agent/specialist-roster.ts
14370
14618
  import { existsSync as existsSync20, readFileSync as readFileSync26, readdirSync as readdirSync18 } from "fs";
@@ -14380,10 +14628,10 @@ function field(fm, name) {
14380
14628
  }
14381
14629
  function readSpecialistRoster(specialistsDir) {
14382
14630
  if (!existsSync20(specialistsDir)) return { specialists: [], skipped: [] };
14383
- const entries = readdirSync18(specialistsDir);
14631
+ const entries2 = readdirSync18(specialistsDir);
14384
14632
  const specialists = [];
14385
14633
  const skipped = [];
14386
- for (const file of entries.sort()) {
14634
+ for (const file of entries2.sort()) {
14387
14635
  if (!file.endsWith(".md")) continue;
14388
14636
  let raw;
14389
14637
  try {
@@ -14469,7 +14717,7 @@ app7.get("/", requireAdminSession, async (c) => {
14469
14717
  let specialists = [];
14470
14718
  try {
14471
14719
  const roster = readSpecialistRoster(
14472
- resolve18(ACCOUNTS_DIR, accountId, "specialists", "agents")
14720
+ resolve19(ACCOUNTS_DIR, accountId, "specialists", "agents")
14473
14721
  );
14474
14722
  specialists = roster.specialists;
14475
14723
  for (const s of roster.skipped) {
@@ -14504,7 +14752,7 @@ var webchat_greeting_default = app7;
14504
14752
 
14505
14753
  // server/routes/telegram.ts
14506
14754
  import { homedir as homedir2 } from "os";
14507
- import { resolve as resolve19, join as join27 } from "path";
14755
+ import { resolve as resolve20, join as join27 } from "path";
14508
14756
  import { existsSync as existsSync21, readFileSync as readFileSync27 } from "fs";
14509
14757
 
14510
14758
  // app/lib/telegram/gateway/instance.ts
@@ -14563,7 +14811,7 @@ function routeTelegramUpdate(input) {
14563
14811
  // server/routes/telegram.ts
14564
14812
  var TAG29 = "[telegram-inbound]";
14565
14813
  function configDirName() {
14566
- const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve19(process.cwd(), "..");
14814
+ const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
14567
14815
  const brandPath = join27(platformRoot5, "config", "brand.json");
14568
14816
  if (existsSync21(brandPath)) {
14569
14817
  try {
@@ -14575,7 +14823,7 @@ function configDirName() {
14575
14823
  }
14576
14824
  function secretPath(botType) {
14577
14825
  const filename = botType === "admin" ? ".telegram-admin-webhook-secret" : ".telegram-webhook-secret";
14578
- return resolve19(homedir2(), configDirName(), filename);
14826
+ return resolve20(homedir2(), configDirName(), filename);
14579
14827
  }
14580
14828
  var app8 = new Hono();
14581
14829
  app8.post("/", async (c) => {
@@ -15013,14 +15261,14 @@ function computeAdminStoreDivergence(input) {
15013
15261
  }
15014
15262
  const accountUserIds = /* @__PURE__ */ new Set();
15015
15263
  if (existsSync23(input.accountsDir)) {
15016
- let entries;
15264
+ let entries2;
15017
15265
  try {
15018
- entries = readdirSync19(input.accountsDir);
15266
+ entries2 = readdirSync19(input.accountsDir);
15019
15267
  } catch (err) {
15020
15268
  result.errors.push({ source: input.accountsDir, detail: err instanceof Error ? err.message : String(err) });
15021
15269
  return result;
15022
15270
  }
15023
- for (const entry of entries) {
15271
+ for (const entry of entries2) {
15024
15272
  if (entry.startsWith(".")) continue;
15025
15273
  const accountDir = join29(input.accountsDir, entry);
15026
15274
  try {
@@ -15716,15 +15964,15 @@ function operatorRoleFor(config, userId) {
15716
15964
  async function buildAccountOptionList(accounts, userId) {
15717
15965
  const houseAccount = accounts.find((a) => a.config.role === "house");
15718
15966
  console.log(`[admin-accounts] op=list count=${accounts.length} house=${houseAccount?.accountId ?? "none"}`);
15719
- const resolve45 = async (a) => {
15967
+ const resolve46 = async (a) => {
15720
15968
  const businessName = await fetchAccountName(a.accountId) || void 0;
15721
15969
  return { accountId: a.accountId, businessName, role: operatorRoleFor(a.config, userId), isHouse: a.config.role === "house" };
15722
15970
  };
15723
15971
  const houseOptions = await Promise.all(
15724
- accounts.filter((a) => a.config.role === "house").map(resolve45)
15972
+ accounts.filter((a) => a.config.role === "house").map(resolve46)
15725
15973
  );
15726
15974
  const nonHouseOptions = await Promise.all(
15727
- accounts.filter((a) => a.config.role !== "house").map(resolve45)
15975
+ accounts.filter((a) => a.config.role !== "house").map(resolve46)
15728
15976
  );
15729
15977
  const sortKey = (o) => (o.businessName || o.accountId).toLowerCase();
15730
15978
  nonHouseOptions.sort((x, y) => {
@@ -15858,7 +16106,7 @@ var accounts_default = app13;
15858
16106
 
15859
16107
  // server/routes/admin/logs.ts
15860
16108
  import { existsSync as existsSync27, readdirSync as readdirSync20, readFileSync as readFileSync31, statSync as statSync13 } from "fs";
15861
- import { resolve as resolve20, basename as basename9 } from "path";
16109
+ import { resolve as resolve21, basename as basename9 } from "path";
15862
16110
 
15863
16111
  // app/lib/logs-read-resolve.ts
15864
16112
  import { existsSync as existsSync26 } from "fs";
@@ -15885,7 +16133,7 @@ app14.get("/", async (c) => {
15885
16133
  const cacheKeyParam = c.req.query("cacheKey");
15886
16134
  const download = c.req.query("download") === "1";
15887
16135
  const account = resolveAccount();
15888
- const accountLogDir = account ? resolve20(account.accountDir, "logs") : null;
16136
+ const accountLogDir = account ? resolve21(account.accountDir, "logs") : null;
15889
16137
  const logDirs = [];
15890
16138
  if (accountLogDir) logDirs.push(accountLogDir);
15891
16139
  logDirs.push(LOG_DIR);
@@ -15893,7 +16141,7 @@ app14.get("/", async (c) => {
15893
16141
  const safe = basename9(fileParam);
15894
16142
  const searched = [];
15895
16143
  for (const dir of logDirs) {
15896
- const filePath = resolve20(dir, safe);
16144
+ const filePath = resolve21(dir, safe);
15897
16145
  searched.push(filePath);
15898
16146
  try {
15899
16147
  const buffer = readFileSync31(filePath);
@@ -16005,10 +16253,10 @@ app14.get("/", async (c) => {
16005
16253
  console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
16006
16254
  continue;
16007
16255
  }
16008
- files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync13(resolve20(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
16256
+ files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync13(resolve21(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
16009
16257
  seen.add(name);
16010
16258
  try {
16011
- const content = readFileSync31(resolve20(dir, name));
16259
+ const content = readFileSync31(resolve21(dir, name));
16012
16260
  const tail = content.length > TAIL_BYTES ? content.subarray(content.length - TAIL_BYTES).toString("utf-8") : content.toString("utf-8");
16013
16261
  logs[name] = tail.trim() || "(empty)";
16014
16262
  } catch (err) {
@@ -16049,11 +16297,11 @@ var claude_info_default = app15;
16049
16297
  // server/routes/admin/attachment.ts
16050
16298
  import { readFile as readFile4, readdir as readdir2 } from "fs/promises";
16051
16299
  import { existsSync as existsSync28 } from "fs";
16052
- import { resolve as resolve21 } from "path";
16300
+ import { resolve as resolve22 } from "path";
16053
16301
  var app16 = new Hono();
16054
16302
  var ATTACHMENT_ID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
16055
16303
  function uploadsDirFor2(accountId, attachmentId) {
16056
- return resolve21(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
16304
+ return resolve22(DATA_ROOT, "accounts", accountId, "uploads", attachmentId);
16057
16305
  }
16058
16306
  app16.get("/:attachmentId", requireAdminSession, async (c) => {
16059
16307
  const attachmentId = c.req.param("attachmentId");
@@ -16090,7 +16338,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
16090
16338
  if (!found) {
16091
16339
  return new Response("Not found", { status: 404 });
16092
16340
  }
16093
- const metaPath = resolve21(dir, `${attachmentId}.meta.json`);
16341
+ const metaPath = resolve22(dir, `${attachmentId}.meta.json`);
16094
16342
  if (!existsSync28(metaPath)) {
16095
16343
  return new Response("Not found", { status: 404 });
16096
16344
  }
@@ -16100,12 +16348,12 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
16100
16348
  } catch {
16101
16349
  return new Response("Not found", { status: 404 });
16102
16350
  }
16103
- const entries = await readdir2(dir);
16104
- const dataFile = entries.find((f) => !f.endsWith(".meta.json") && !f.endsWith(EXTRACTED_TEXT_SUFFIX));
16351
+ const entries2 = await readdir2(dir);
16352
+ const dataFile = entries2.find((f) => !f.endsWith(".meta.json") && !f.endsWith(EXTRACTED_TEXT_SUFFIX));
16105
16353
  if (!dataFile) {
16106
16354
  return new Response("Not found", { status: 404 });
16107
16355
  }
16108
- const filePath = resolve21(dir, dataFile);
16356
+ const filePath = resolve22(dir, dataFile);
16109
16357
  const buffer = await readFile4(filePath);
16110
16358
  const inlineSafe = isInlineSafeMime(meta.mimeType);
16111
16359
  const safeName = meta.filename.replace(/["\\\r\n]/g, "_");
@@ -16167,8 +16415,35 @@ app17.get("/", requireAdminSession, async (c) => {
16167
16415
  var session_upload_default = app17;
16168
16416
 
16169
16417
  // server/routes/admin/agents.ts
16170
- import { resolve as resolve22 } from "path";
16418
+ import { resolve as resolve23 } from "path";
16171
16419
  import { readdirSync as readdirSync21, readFileSync as readFileSync32, existsSync as existsSync30, rmSync as rmSync2 } from "fs";
16420
+
16421
+ // server/routes/admin/_account-scope.ts
16422
+ function accountDirForSession(cacheKey) {
16423
+ const accountId = getAccountIdForSession(cacheKey);
16424
+ if (!accountId) return null;
16425
+ const match = listValidAccounts().find((a) => a.accountId === accountId);
16426
+ return match ? { accountId, accountDir: match.accountDir } : null;
16427
+ }
16428
+ function validateAccountId2(accountId) {
16429
+ if (!accountId) return null;
16430
+ const match = listValidAccounts().find((a) => a.accountId === accountId);
16431
+ return match ? { accountId, accountDir: match.accountDir } : null;
16432
+ }
16433
+ async function authorizeAccountWrite(c, accountId) {
16434
+ const remote = c.env?.incoming?.socket?.remoteAddress ?? "";
16435
+ const peerIsLoopback = remote === "127.0.0.1" || remote === "::1" || remote === "::ffff:127.0.0.1";
16436
+ if (peerIsLoopback && !c.req.header("x-forwarded-for")) return { ok: true, via: "on-device" };
16437
+ const { fingerprint, signedSessionToken } = await resolveCacheKey(c);
16438
+ if (!fingerprint || !validateSession(fingerprint, "admin", signedSessionToken).ok) {
16439
+ return { ok: false, reason: "no-session" };
16440
+ }
16441
+ const acct = accountDirForSession(fingerprint);
16442
+ if (!acct || acct.accountId !== accountId) return { ok: false, reason: "account-mismatch" };
16443
+ return { ok: true, via: "session" };
16444
+ }
16445
+
16446
+ // server/routes/admin/agents.ts
16172
16447
  var SLUG_UNSAFE = (s) => s.includes("/") || s.includes("..") || s.includes("\\");
16173
16448
  function subdirs(dir) {
16174
16449
  if (!existsSync30(dir)) return [];
@@ -16189,22 +16464,22 @@ function splitFrontmatter(text) {
16189
16464
  return { fm, body: text.slice(m[0].length) };
16190
16465
  }
16191
16466
  function listSpecialists(accountDir) {
16192
- const pluginsDir = resolve22(accountDir, "plugins");
16467
+ const pluginsDir = resolve23(accountDir, "plugins");
16193
16468
  const specialists = [];
16194
16469
  let specialistsSkipped = 0;
16195
16470
  for (const plugin of subdirs(pluginsDir).sort()) {
16196
- const agentsDirP = resolve22(pluginsDir, plugin, "agents");
16471
+ const agentsDirP = resolve23(pluginsDir, plugin, "agents");
16197
16472
  if (!existsSync30(agentsDirP)) continue;
16198
- let entries;
16473
+ let entries2;
16199
16474
  try {
16200
- entries = readdirSync21(agentsDirP, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
16475
+ entries2 = readdirSync21(agentsDirP, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
16201
16476
  } catch {
16202
16477
  continue;
16203
16478
  }
16204
- for (const entry of entries) {
16479
+ for (const entry of entries2) {
16205
16480
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
16206
16481
  try {
16207
- const { fm } = splitFrontmatter(readFileSync32(resolve22(agentsDirP, entry.name), "utf-8"));
16482
+ const { fm } = splitFrontmatter(readFileSync32(resolve23(agentsDirP, entry.name), "utf-8"));
16208
16483
  if (!fm.name) {
16209
16484
  specialistsSkipped++;
16210
16485
  console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry.name}`);
@@ -16232,19 +16507,22 @@ var OWNED_DOCS = [
16232
16507
  { file: "KNOWLEDGE-SUMMARY.md", key: "knowledgeSummary" }
16233
16508
  ];
16234
16509
  var app18 = new Hono();
16235
- app18.get("/", (c) => {
16236
- const account = resolveAccount();
16237
- if (!account) return c.json({ agents: [], skipped: 0, specialistsSkipped: 0 });
16510
+ app18.get("/", requireAdminSession, (c) => {
16511
+ const account = accountDirForSession(c.var.cacheKey);
16512
+ if (!account) {
16513
+ console.error("[admin/agents] op=list auth-rejected reason=no-account-for-session");
16514
+ return c.json({ error: "Account not found for session" }, 401);
16515
+ }
16238
16516
  const agents = [];
16239
16517
  let skipped = 0;
16240
- const agentsDir = resolve22(account.accountDir, "agents");
16518
+ const agentsDir = resolve23(account.accountDir, "agents");
16241
16519
  if (existsSync30(agentsDir)) {
16242
16520
  try {
16243
- const entries = readdirSync21(agentsDir, { withFileTypes: true });
16244
- for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
16521
+ const entries2 = readdirSync21(agentsDir, { withFileTypes: true });
16522
+ for (const entry of entries2.sort((a, b) => a.name.localeCompare(b.name))) {
16245
16523
  if (!entry.isDirectory()) continue;
16246
16524
  if (entry.name === "admin") continue;
16247
- const configPath2 = resolve22(agentsDir, entry.name, "config.json");
16525
+ const configPath2 = resolve23(agentsDir, entry.name, "config.json");
16248
16526
  if (!existsSync30(configPath2)) continue;
16249
16527
  try {
16250
16528
  const config = JSON.parse(readFileSync32(configPath2, "utf-8"));
@@ -16264,22 +16542,25 @@ app18.get("/", (c) => {
16264
16542
  }
16265
16543
  }
16266
16544
  const { specialists, specialistsSkipped } = listSpecialists(account.accountDir);
16267
- console.log(`[admin/agents] op=list agents=${agents.length} specialists=${specialists.length} skipped=${skipped} specialistsSkipped=${specialistsSkipped}`);
16268
- return c.json({ agents: [...agents, ...specialists], skipped, specialistsSkipped });
16545
+ console.log(`[admin/agents] op=list accountId=${account.accountId.slice(0, 8)} agents=${agents.length} specialists=${specialists.length} skipped=${skipped} specialistsSkipped=${specialistsSkipped}`);
16546
+ return c.json({ agents: [...agents, ...specialists], accountId: account.accountId, skipped, specialistsSkipped });
16269
16547
  });
16270
- app18.get("/:slug", (c) => {
16548
+ app18.get("/:slug", requireAdminSession, (c) => {
16271
16549
  const slug = c.req.param("slug");
16272
- const account = resolveAccount();
16273
- if (!account) return c.json({ error: "No account resolved" }, 400);
16550
+ const account = accountDirForSession(c.var.cacheKey);
16551
+ if (!account) {
16552
+ console.error("[admin/agents] op=detail auth-rejected reason=no-account-for-session");
16553
+ return c.json({ error: "Account not found for session" }, 401);
16554
+ }
16274
16555
  if (SLUG_UNSAFE(slug)) return c.json({ error: "Invalid agent slug" }, 400);
16275
16556
  const pluginParam = c.req.query("plugin");
16276
16557
  if (pluginParam) {
16277
16558
  if (SLUG_UNSAFE(pluginParam)) return c.json({ error: "Invalid plugin" }, 400);
16278
- const file = resolve22(account.accountDir, "plugins", pluginParam, "agents", `${slug}.md`);
16559
+ const file = resolve23(account.accountDir, "plugins", pluginParam, "agents", `${slug}.md`);
16279
16560
  if (!existsSync30(file)) return c.json({ error: "Agent not found" }, 404);
16280
16561
  const { fm, body } = splitFrontmatter(readFileSync32(file, "utf-8"));
16281
- const skills = subdirs(resolve22(account.accountDir, "plugins", pluginParam, "skills"));
16282
- console.log(`[admin/agents] op=detail slug=${slug} kind=specialist plugin=${pluginParam}`);
16562
+ const skills = subdirs(resolve23(account.accountDir, "plugins", pluginParam, "skills"));
16563
+ console.log(`[admin/agents] op=detail accountId=${account.accountId.slice(0, 8)} slug=${slug} kind=specialist plugin=${pluginParam}`);
16283
16564
  return c.json({
16284
16565
  agent: {
16285
16566
  kind: "specialist",
@@ -16294,8 +16575,8 @@ app18.get("/:slug", (c) => {
16294
16575
  }
16295
16576
  });
16296
16577
  }
16297
- const agentDir = resolve22(account.accountDir, "agents", slug);
16298
- const configPath2 = resolve22(agentDir, "config.json");
16578
+ const agentDir = resolve23(account.accountDir, "agents", slug);
16579
+ const configPath2 = resolve23(agentDir, "config.json");
16299
16580
  if (!existsSync30(configPath2)) return c.json({ error: "Agent not found" }, 404);
16300
16581
  let config;
16301
16582
  try {
@@ -16307,7 +16588,7 @@ app18.get("/:slug", (c) => {
16307
16588
  const docs = {};
16308
16589
  const present = {};
16309
16590
  for (const { file, key } of OWNED_DOCS) {
16310
- const p = resolve22(agentDir, file);
16591
+ const p = resolve23(agentDir, file);
16311
16592
  try {
16312
16593
  if (existsSync30(p)) {
16313
16594
  docs[key] = readFileSync32(p, "utf-8");
@@ -16323,7 +16604,7 @@ app18.get("/:slug", (c) => {
16323
16604
  }
16324
16605
  }
16325
16606
  const found = Object.keys(present).filter((k) => present[k]);
16326
- console.log(`[admin/agents] op=detail slug=${slug} present=${found.join(",") || "none"}`);
16607
+ console.log(`[admin/agents] op=detail accountId=${account.accountId.slice(0, 8)} slug=${slug} kind=public present=${found.join(",") || "none"}`);
16327
16608
  return c.json({
16328
16609
  agent: {
16329
16610
  slug,
@@ -16341,15 +16622,28 @@ app18.get("/:slug", (c) => {
16341
16622
  });
16342
16623
  app18.delete("/:slug", async (c) => {
16343
16624
  const slug = c.req.param("slug");
16344
- const account = resolveAccount();
16345
- if (!account) return c.json({ error: "No account resolved" }, 400);
16346
16625
  if (slug === "admin") {
16347
16626
  return c.json({ error: "Cannot delete the admin agent" }, 403);
16348
16627
  }
16349
16628
  if (SLUG_UNSAFE(slug)) {
16350
16629
  return c.json({ error: "Invalid agent slug" }, 400);
16351
16630
  }
16352
- const agentDir = resolve22(account.accountDir, "agents", slug);
16631
+ const accountIdParam = c.req.query("accountId") ?? "";
16632
+ if (!accountIdParam) {
16633
+ console.error(`[admin/agents] op=delete rejected reason=missing-accountId slug=${slug}`);
16634
+ return c.json({ error: "accountId is required" }, 400);
16635
+ }
16636
+ const account = validateAccountId2(accountIdParam);
16637
+ if (!account) {
16638
+ console.error(`[admin/agents] op=delete rejected reason=unknown-accountId accountId=${accountIdParam.slice(0, 8)} slug=${slug}`);
16639
+ return c.json({ error: "Unknown accountId" }, 400);
16640
+ }
16641
+ const authz = await authorizeAccountWrite(c, account.accountId);
16642
+ if (!authz.ok) {
16643
+ console.error(`[admin/agents] op=delete rejected reason=${authz.reason} accountId=${account.accountId.slice(0, 8)} slug=${slug}`);
16644
+ return c.json({ error: "Not authorized for this account" }, 403);
16645
+ }
16646
+ const agentDir = resolve23(account.accountDir, "agents", slug);
16353
16647
  if (!existsSync30(agentDir)) {
16354
16648
  return c.json({ error: "Agent not found" }, 404);
16355
16649
  }
@@ -16357,29 +16651,42 @@ app18.delete("/:slug", async (c) => {
16357
16651
  await deleteAgentProjection(account.accountId, slug);
16358
16652
  } catch (err) {
16359
16653
  const msg = err instanceof Error ? err.message : String(err);
16360
- console.error(`[admin/agents] graph cleanup failed for agent "${slug}", aborting file removal: ${msg}`);
16654
+ console.error(`[admin/agents] op=delete accountId=${account.accountId.slice(0, 8)} slug=${slug} outcome=failed reason=graph-cleanup-failed error="${msg}" \u2014 files preserved`);
16361
16655
  return c.json({ error: `Graph cleanup failed: ${msg}` }, 500);
16362
16656
  }
16363
16657
  try {
16364
16658
  rmSync2(agentDir, { recursive: true, force: true });
16365
- console.log(`[admin/agents] deleted agent "${slug}"`);
16659
+ console.log(`[admin/agents] op=delete accountId=${account.accountId.slice(0, 8)} slug=${slug} outcome=ok`);
16366
16660
  return c.json({ ok: true });
16367
16661
  } catch (err) {
16368
- console.error(`[admin/agents] failed to delete agent "${slug}": ${err}`);
16662
+ console.error(`[admin/agents] op=delete accountId=${account.accountId.slice(0, 8)} slug=${slug} outcome=failed reason=rm-error error="${err}"`);
16369
16663
  return c.json({ error: "Failed to delete agent" }, 500);
16370
16664
  }
16371
16665
  });
16372
16666
  app18.post("/:slug/project", async (c) => {
16373
16667
  const slug = c.req.param("slug");
16374
- const account = resolveAccount();
16375
- if (!account) return c.json({ error: "No account resolved" }, 400);
16376
16668
  if (slug === "admin") {
16377
16669
  return c.json({ error: "Cannot project the admin agent" }, 403);
16378
16670
  }
16379
16671
  if (SLUG_UNSAFE(slug)) {
16380
16672
  return c.json({ error: "Invalid agent slug" }, 400);
16381
16673
  }
16382
- const agentDir = resolve22(account.accountDir, "agents", slug);
16674
+ const accountIdParam = c.req.query("accountId") ?? "";
16675
+ if (!accountIdParam) {
16676
+ console.error(`[admin/agents] op=project rejected reason=missing-accountId slug=${slug}`);
16677
+ return c.json({ error: "accountId is required" }, 400);
16678
+ }
16679
+ const account = validateAccountId2(accountIdParam);
16680
+ if (!account) {
16681
+ console.error(`[admin/agents] op=project rejected reason=unknown-accountId accountId=${accountIdParam.slice(0, 8)} slug=${slug}`);
16682
+ return c.json({ error: "Unknown accountId" }, 400);
16683
+ }
16684
+ const authz = await authorizeAccountWrite(c, account.accountId);
16685
+ if (!authz.ok) {
16686
+ console.error(`[admin/agents] op=project rejected reason=${authz.reason} accountId=${account.accountId.slice(0, 8)} slug=${slug}`);
16687
+ return c.json({ error: "Not authorized for this account" }, 403);
16688
+ }
16689
+ const agentDir = resolve23(account.accountDir, "agents", slug);
16383
16690
  if (!existsSync30(agentDir)) {
16384
16691
  return c.json({ error: "Agent not found on disk" }, 404);
16385
16692
  }
@@ -17083,7 +17390,7 @@ var sessions_default = app19;
17083
17390
 
17084
17391
  // app/lib/claude-agent/spawn-context.ts
17085
17392
  import { existsSync as existsSync32, readFileSync as readFileSync33, readdirSync as readdirSync22, statSync as statSync15 } from "fs";
17086
- import { dirname as dirname12, resolve as resolve23, join as join33 } from "path";
17393
+ import { dirname as dirname12, resolve as resolve24, join as join33 } from "path";
17087
17394
  async function resolveOwnerProfileBlock(accountId, userId) {
17088
17395
  if (!userId) return { ok: false, reason: "missing-user-id" };
17089
17396
  try {
@@ -17180,7 +17487,7 @@ function parseSkillPathsFromFrontmatter(fm) {
17180
17487
  }
17181
17488
  function listPluginDirs(accountPluginsDir) {
17182
17489
  const out = /* @__PURE__ */ new Map();
17183
- const platformPlugins = resolve23(PLATFORM_ROOT, "plugins");
17490
+ const platformPlugins = resolve24(PLATFORM_ROOT, "plugins");
17184
17491
  if (existsSync32(platformPlugins)) {
17185
17492
  for (const name of readdirSync22(platformPlugins)) {
17186
17493
  const dir = join33(platformPlugins, name);
@@ -17190,7 +17497,7 @@ function listPluginDirs(accountPluginsDir) {
17190
17497
  }
17191
17498
  }
17192
17499
  }
17193
- const premiumRoot = resolve23(dirname12(PLATFORM_ROOT), "premium-plugins");
17500
+ const premiumRoot = resolve24(dirname12(PLATFORM_ROOT), "premium-plugins");
17194
17501
  if (existsSync32(premiumRoot)) {
17195
17502
  for (const bundle of readdirSync22(premiumRoot)) {
17196
17503
  const bundlePlugins = join33(premiumRoot, bundle, "plugins");
@@ -17223,7 +17530,7 @@ function listPluginDirs(accountPluginsDir) {
17223
17530
  return out;
17224
17531
  }
17225
17532
  function accountPluginsDirFor(accountId) {
17226
- return resolve23(PLATFORM_ROOT, "..", "data/accounts", accountId, "plugins");
17533
+ return resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "plugins");
17227
17534
  }
17228
17535
  function listAccountPluginNames(accountPluginsDir) {
17229
17536
  if (!existsSync32(accountPluginsDir)) return [];
@@ -17240,7 +17547,7 @@ function listAccountPluginNames(accountPluginsDir) {
17240
17547
  }
17241
17548
  }
17242
17549
  function readEnabledPlugins(accountId) {
17243
- const accountFile = resolve23(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17550
+ const accountFile = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17244
17551
  if (!existsSync32(accountFile)) return /* @__PURE__ */ new Set();
17245
17552
  try {
17246
17553
  const parsed = JSON.parse(readFileSync33(accountFile, "utf-8"));
@@ -17316,11 +17623,11 @@ ${skillFm}
17316
17623
  return out;
17317
17624
  }
17318
17625
  function computeSpecialistDomains(accountId) {
17319
- const specialistsDir = resolve23(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
17626
+ const specialistsDir = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
17320
17627
  if (!existsSync32(specialistsDir)) return [];
17321
- let entries;
17628
+ let entries2;
17322
17629
  try {
17323
- entries = readdirSync22(specialistsDir);
17630
+ entries2 = readdirSync22(specialistsDir);
17324
17631
  } catch {
17325
17632
  return [];
17326
17633
  }
@@ -17342,7 +17649,7 @@ function computeSpecialistDomains(accountId) {
17342
17649
  return map.get(tool);
17343
17650
  };
17344
17651
  const out = [];
17345
- for (const file of entries.sort()) {
17652
+ for (const file of entries2.sort()) {
17346
17653
  if (!file.endsWith(".md")) continue;
17347
17654
  const fm = readFrontmatter(join33(specialistsDir, file));
17348
17655
  if (!fm) continue;
@@ -17362,7 +17669,7 @@ ${fm}
17362
17669
  return out;
17363
17670
  }
17364
17671
  function computeDormantPlugins(accountId) {
17365
- const accountFile = resolve23(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17672
+ const accountFile = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17366
17673
  if (!existsSync32(accountFile)) return [];
17367
17674
  let enabled;
17368
17675
  try {
@@ -17377,18 +17684,18 @@ function computeDormantPlugins(accountId) {
17377
17684
  );
17378
17685
  return [];
17379
17686
  }
17380
- const pluginsDir = resolve23(PLATFORM_ROOT, "plugins");
17687
+ const pluginsDir = resolve24(PLATFORM_ROOT, "plugins");
17381
17688
  if (!existsSync32(pluginsDir)) return [];
17382
- let entries;
17689
+ let entries2;
17383
17690
  try {
17384
- entries = readdirSync22(pluginsDir);
17691
+ entries2 = readdirSync22(pluginsDir);
17385
17692
  } catch {
17386
17693
  return [];
17387
17694
  }
17388
17695
  const out = [];
17389
- for (const name of entries) {
17696
+ for (const name of entries2) {
17390
17697
  if (enabled.has(name)) continue;
17391
- const manifestPath = resolve23(pluginsDir, name, "PLUGIN.md");
17698
+ const manifestPath = resolve24(pluginsDir, name, "PLUGIN.md");
17392
17699
  if (!existsSync32(manifestPath)) continue;
17393
17700
  let manifest;
17394
17701
  try {
@@ -17407,7 +17714,7 @@ function computeDormantPlugins(accountId) {
17407
17714
 
17408
17715
  // server/routes/admin/claude-sessions.ts
17409
17716
  import { existsSync as existsSync33, readFileSync as readFileSync34 } from "fs";
17410
- import { resolve as resolve24 } from "path";
17717
+ import { resolve as resolve25 } from "path";
17411
17718
  function readTunnelState(brandConfigDir) {
17412
17719
  const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
17413
17720
  if (!existsSync33(statePath)) return null;
@@ -17423,10 +17730,10 @@ function readTunnelState(brandConfigDir) {
17423
17730
  }
17424
17731
  }
17425
17732
  function resolveTunnelUrl() {
17426
- const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve24(process.cwd(), "..");
17733
+ const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
17427
17734
  let brand;
17428
17735
  try {
17429
- brand = JSON.parse(readFileSync34(resolve24(platformRoot5, "config", "brand.json"), "utf-8"));
17736
+ brand = JSON.parse(readFileSync34(resolve25(platformRoot5, "config", "brand.json"), "utf-8"));
17430
17737
  } catch {
17431
17738
  return null;
17432
17739
  }
@@ -17665,6 +17972,77 @@ app22.post("/", async (c) => {
17665
17972
  console.error(`[${event}] ${formatted}`);
17666
17973
  return c.json({ ok: true });
17667
17974
  });
17975
+ function formatEvent(resource, accountId) {
17976
+ return `data: ${JSON.stringify({ resource, accountId })}
17977
+
17978
+ `;
17979
+ }
17980
+ function shouldDeliver(eventAccountId, subscriberAccountId) {
17981
+ return eventAccountId === null || eventAccountId === subscriberAccountId;
17982
+ }
17983
+ app22.get("/", requireAdminSession, async (c) => {
17984
+ const accountId = getAccountIdForSession(c.var.cacheKey);
17985
+ if (!accountId) return c.json({ error: "Account not found for session" }, 401);
17986
+ const encoder = new TextEncoder();
17987
+ let unsubscribe = () => {
17988
+ };
17989
+ let heartbeat = null;
17990
+ let closed = false;
17991
+ const teardown = (reason) => {
17992
+ if (closed) return;
17993
+ closed = true;
17994
+ unsubscribe();
17995
+ if (heartbeat) clearInterval(heartbeat);
17996
+ console.log(`[admin-events] op=drop resource=all accountId=${accountId.slice(0, 8)} reason=${reason}`);
17997
+ };
17998
+ const stream2 = new ReadableStream({
17999
+ start(controller) {
18000
+ console.log(`[admin-events] op=subscribe resource=all accountId=${accountId.slice(0, 8)}`);
18001
+ unsubscribe = onInvalidate((resource, eventAccountId) => {
18002
+ if (closed) return;
18003
+ if (!shouldDeliver(eventAccountId, accountId)) return;
18004
+ try {
18005
+ controller.enqueue(encoder.encode(formatEvent(resource, eventAccountId)));
18006
+ console.log(`[admin-events] op=emit resource=${resource} accountId=${accountId.slice(0, 8)}`);
18007
+ } catch (err) {
18008
+ teardown(`enqueue-failed:${String(err)}`);
18009
+ try {
18010
+ controller.close();
18011
+ } catch {
18012
+ }
18013
+ }
18014
+ });
18015
+ heartbeat = setInterval(() => {
18016
+ try {
18017
+ controller.enqueue(encoder.encode(": ping\n\n"));
18018
+ } catch {
18019
+ teardown("heartbeat-enqueue-failed");
18020
+ try {
18021
+ controller.close();
18022
+ } catch {
18023
+ }
18024
+ }
18025
+ }, 2e4);
18026
+ c.req.raw.signal.addEventListener("abort", () => {
18027
+ teardown("client-aborted");
18028
+ try {
18029
+ controller.close();
18030
+ } catch {
18031
+ }
18032
+ });
18033
+ },
18034
+ cancel() {
18035
+ teardown("client-closed");
18036
+ }
18037
+ });
18038
+ return new Response(stream2, {
18039
+ headers: {
18040
+ "Content-Type": "text/event-stream",
18041
+ "Cache-Control": "no-cache",
18042
+ Connection: "keep-alive"
18043
+ }
18044
+ });
18045
+ });
17668
18046
  var events_default = app22;
17669
18047
 
17670
18048
  // server/routes/admin/files.ts
@@ -17672,7 +18050,7 @@ import { createReadStream as createReadStream2, createWriteStream as createWrite
17672
18050
  import { readdir as readdir4, readFile as readFile7, stat as stat6, mkdir as mkdir4, unlink as unlink3, rename as rename2, rmdir } from "fs/promises";
17673
18051
  import { realpathSync as realpathSync7 } from "fs";
17674
18052
  import { randomUUID as randomUUID10 } from "crypto";
17675
- import { basename as basename11, dirname as dirname13, join as join35, relative as relative5, resolve as resolve26, sep as sep8 } from "path";
18053
+ import { basename as basename11, dirname as dirname13, join as join35, relative as relative5, resolve as resolve27, sep as sep8 } from "path";
17676
18054
  import { Readable as Readable2 } from "stream";
17677
18055
 
17678
18056
  // ../lib/graph-trash/src/index.ts
@@ -17990,7 +18368,7 @@ async function cascadeDeleteDocument(params) {
17990
18368
 
17991
18369
  // app/lib/file-index.ts
17992
18370
  import * as fsp from "fs/promises";
17993
- import { resolve as resolve25, relative as relative4, join as join34, basename as basename10, extname as extname2, sep as sep7 } from "path";
18371
+ import { resolve as resolve26, relative as relative4, join as join34, basename as basename10, extname as extname2, sep as sep7 } from "path";
17994
18372
  import { tmpdir as tmpdir2 } from "os";
17995
18373
  import { execFile as execFile2 } from "child_process";
17996
18374
  import { promisify as promisify2 } from "util";
@@ -18143,16 +18521,16 @@ async function readDisplayName(absolute) {
18143
18521
  }
18144
18522
  }
18145
18523
  async function walkSubtree(root, dataRoot, out) {
18146
- let entries;
18524
+ let entries2;
18147
18525
  try {
18148
- entries = await fsp.readdir(root, { withFileTypes: true });
18526
+ entries2 = await fsp.readdir(root, { withFileTypes: true });
18149
18527
  } catch (err) {
18150
18528
  if (err.code === "ENOENT") return { clean: true };
18151
18529
  console.error(`[file-index] walk-error dir="${relative4(dataRoot, root)}" err="${err.message}"`);
18152
18530
  return { clean: false };
18153
18531
  }
18154
18532
  let clean = true;
18155
- for (const entry of entries) {
18533
+ for (const entry of entries2) {
18156
18534
  if (entry.isSymbolicLink()) continue;
18157
18535
  if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
18158
18536
  const abs = join34(root, entry.name);
@@ -18310,7 +18688,7 @@ async function reconcileFileIndex(accountId, opts) {
18310
18688
  return withSession(opts, async (session) => {
18311
18689
  const walked = [];
18312
18690
  const subtreeRoots = [
18313
- resolve25(dataRoot, "accounts", accountId)
18691
+ resolve26(dataRoot, "accounts", accountId)
18314
18692
  ];
18315
18693
  let clean = true;
18316
18694
  for (const root of subtreeRoots) {
@@ -18393,7 +18771,7 @@ async function reconcileFileIndexDebounced(accountId, opts) {
18393
18771
  async function indexFile(accountId, relativePath, opts) {
18394
18772
  const dataRoot = opts?.dataRoot ?? DATA_ROOT;
18395
18773
  const embed2 = opts?.embed ?? embed;
18396
- const absolute = resolve25(dataRoot, relativePath);
18774
+ const absolute = resolve26(dataRoot, relativePath);
18397
18775
  await withSession(opts, async (session) => {
18398
18776
  const st = await fsp.stat(absolute);
18399
18777
  const wf = {
@@ -18444,11 +18822,11 @@ function crc32(buf) {
18444
18822
  for (let i = 0; i < buf.length; i++) crc = crcTable[(crc ^ buf[i]) & 255] ^ crc >>> 8;
18445
18823
  return (crc ^ 4294967295) >>> 0;
18446
18824
  }
18447
- function buildZip(entries) {
18825
+ function buildZip(entries2) {
18448
18826
  const localChunks = [];
18449
18827
  const centralChunks = [];
18450
18828
  let offset = 0;
18451
- for (const entry of entries) {
18829
+ for (const entry of entries2) {
18452
18830
  const nameBytes = Buffer.from(entry.name, "utf8");
18453
18831
  const crc = crc32(entry.data);
18454
18832
  const uncompressedSize = entry.data.length;
@@ -18498,14 +18876,31 @@ function buildZip(entries) {
18498
18876
  eocd.writeUInt32LE(EOCD_SIG, 0);
18499
18877
  eocd.writeUInt16LE(0, 4);
18500
18878
  eocd.writeUInt16LE(0, 6);
18501
- eocd.writeUInt16LE(entries.length, 8);
18502
- eocd.writeUInt16LE(entries.length, 10);
18879
+ eocd.writeUInt16LE(entries2.length, 8);
18880
+ eocd.writeUInt16LE(entries2.length, 10);
18503
18881
  eocd.writeUInt32LE(centralSize, 12);
18504
18882
  eocd.writeUInt32LE(centralOffset, 16);
18505
18883
  eocd.writeUInt16LE(0, 20);
18506
18884
  return Buffer.concat([...localChunks, centralDir, eocd]);
18507
18885
  }
18508
18886
 
18887
+ // server/lib/account-root-groups.ts
18888
+ var import_dist = __toESM(require_dist2(), 1);
18889
+ function classifyAccountRoot(schemaMd, rootEntries) {
18890
+ const regions = (0, import_dist.parseSchemaRegions)(schemaMd);
18891
+ if (!regions.parsed) {
18892
+ return { home: [], system: [...rootEntries], unknown: [], parsed: false, reason: regions.reason };
18893
+ }
18894
+ const homeOrder = [...regions.ontologyRoots, ...import_dist.HOME_FIXED].filter((d, i, a) => a.indexOf(d) === i);
18895
+ const homeSet = new Set(homeOrder);
18896
+ const present = new Set(rootEntries);
18897
+ const home = homeOrder.filter((d) => present.has(d));
18898
+ const system = rootEntries.filter((n) => !homeSet.has(n));
18899
+ const declared = /* @__PURE__ */ new Set([...regions.allowedTopLevel, ...regions.pluginOwned, ...homeSet]);
18900
+ const unknown = rootEntries.filter((n) => !declared.has(n));
18901
+ return { home, system, unknown, parsed: true, reason: "ok" };
18902
+ }
18903
+
18509
18904
  // server/routes/admin/files.ts
18510
18905
  var UPLOAD_TMP_DIR = ".uploads-tmp";
18511
18906
  var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -18522,7 +18917,7 @@ async function readMeta(absDir, baseName) {
18522
18917
  }
18523
18918
  async function readAccountNames() {
18524
18919
  const map = /* @__PURE__ */ new Map();
18525
- const accountsDir = resolve26(DATA_ROOT, "accounts");
18920
+ const accountsDir = resolve27(DATA_ROOT, "accounts");
18526
18921
  let names;
18527
18922
  try {
18528
18923
  names = await readdir4(accountsDir);
@@ -18531,7 +18926,7 @@ async function readAccountNames() {
18531
18926
  }
18532
18927
  for (const name of names) {
18533
18928
  if (!UUID_RE4.test(name)) continue;
18534
- const configPath2 = resolve26(accountsDir, name, "account.json");
18929
+ const configPath2 = resolve27(accountsDir, name, "account.json");
18535
18930
  try {
18536
18931
  const raw = await readFile7(configPath2, "utf8");
18537
18932
  const parsed = JSON.parse(raw);
@@ -18617,8 +19012,24 @@ function buildDisplayPath(relPath, accountNames) {
18617
19012
  return dn ? { name: seg, displayName: dn } : { name: seg };
18618
19013
  });
18619
19014
  }
18620
- function sortDirEntries(entries) {
18621
- entries.sort((a, b) => {
19015
+ var HOME_CHILD_PREVIEW = 20;
19016
+ function parseGroupPath(raw, sessionAccountId) {
19017
+ const trimmed = raw.replace(/^\.?\/*/, "");
19018
+ if (trimmed === "@home" || trimmed === "@system") {
19019
+ return { view: trimmed.slice(1), accountRel: `accounts/${sessionAccountId}` };
19020
+ }
19021
+ const segs = trimmed.split("/").filter(Boolean);
19022
+ if (segs.length !== 3) return null;
19023
+ if (segs[0] !== "accounts" || !UUID_RE4.test(segs[1])) return null;
19024
+ if (segs[2] !== "@home" && segs[2] !== "@system") return null;
19025
+ return { view: segs[2].slice(1), accountRel: `accounts/${segs[1]}` };
19026
+ }
19027
+ function isAccountRoot(relPath) {
19028
+ const segs = relPath.split("/").filter(Boolean);
19029
+ return segs.length === 2 && segs[0] === "accounts" && UUID_RE4.test(segs[1]);
19030
+ }
19031
+ function sortDirEntries(entries2) {
19032
+ entries2.sort((a, b) => {
18622
19033
  if (a.kind !== b.kind) return a.kind === "directory" ? -1 : 1;
18623
19034
  if (a.kind === "file" && b.kind === "file") {
18624
19035
  const byTime = b.modifiedAt.localeCompare(a.modifiedAt);
@@ -18675,6 +19086,7 @@ function isProtectedFromRename(relPath) {
18675
19086
  function isValidEntryName(name) {
18676
19087
  if (typeof name !== "string" || name.length === 0) return false;
18677
19088
  if (name === "." || name === "..") return false;
19089
+ if (name.startsWith("@")) return false;
18678
19090
  return !/[\\/\0]/.test(name);
18679
19091
  }
18680
19092
  function resolveOwnAccountWrite(rawPath, accountId, endpoint) {
@@ -18719,7 +19131,8 @@ app23.get("/", requireAdminSession, async (c) => {
18719
19131
  return c.json({ error: "Account not found for session" }, 401);
18720
19132
  }
18721
19133
  const rawPath = c.req.query("path") ?? "";
18722
- const resolution = resolveDataPath(rawPath);
19134
+ const groupReq = parseGroupPath(rawPath, accountId);
19135
+ const resolution = resolveDataPath(groupReq ? groupReq.accountRel : rawPath);
18723
19136
  if (!resolution.ok) {
18724
19137
  if (resolution.status === 403) {
18725
19138
  console.error(`[data] path-traversal-blocked requested="${rawPath}" resolved="${resolution.resolved ?? "n/a"}"`);
@@ -18739,7 +19152,7 @@ app23.get("/", requireAdminSession, async (c) => {
18739
19152
  const names = await readdir4(absolute);
18740
19153
  const segs = relPath.split("/").filter(Boolean);
18741
19154
  const isAccountParent = segs.length === 1 && segs[0] === "accounts";
18742
- const entries = [];
19155
+ const entries2 = [];
18743
19156
  for (const name of names) {
18744
19157
  if (UUID_RE4.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
18745
19158
  continue;
@@ -18752,7 +19165,7 @@ app23.get("/", requireAdminSession, async (c) => {
18752
19165
  try {
18753
19166
  const entryPath = join35(absolute, name);
18754
19167
  const s = await stat6(entryPath);
18755
- entries.push({
19168
+ entries2.push({
18756
19169
  name,
18757
19170
  kind: s.isDirectory() ? "directory" : s.isFile() ? "file" : "other",
18758
19171
  sizeBytes: s.isDirectory() ? null : s.size,
@@ -18760,12 +19173,12 @@ app23.get("/", requireAdminSession, async (c) => {
18760
19173
  protected: protectedEntry
18761
19174
  });
18762
19175
  } catch {
18763
- entries.push({ name, kind: "other", sizeBytes: null, modifiedAt: (/* @__PURE__ */ new Date(0)).toISOString(), protected: protectedEntry });
19176
+ entries2.push({ name, kind: "other", sizeBytes: null, modifiedAt: (/* @__PURE__ */ new Date(0)).toISOString(), protected: protectedEntry });
18764
19177
  }
18765
19178
  }
18766
19179
  const accountNames = await readAccountNames();
18767
- const classes = await Promise.all(entries.map((e) => enrich(absolute, e, accountNames)));
18768
- sortDirEntries(entries);
19180
+ const classes = await Promise.all(entries2.map((e) => enrich(absolute, e, accountNames)));
19181
+ sortDirEntries(entries2);
18769
19182
  let flattened = 0;
18770
19183
  let keptAsDir = 0;
18771
19184
  for (const cls of classes) {
@@ -18777,8 +19190,77 @@ app23.get("/", requireAdminSession, async (c) => {
18777
19190
  console.error(`[data] op=uploads-flatten containers=${containers} flattened=${flattened} kept-as-dir=${keptAsDir}`);
18778
19191
  }
18779
19192
  const displayPath = buildDisplayPath(relPath, accountNames);
18780
- console.error(`[data] file-list path="${relPath}" entries=${entries.length}`);
18781
- return c.json({ path: relPath, displayPath, entries });
19193
+ if (groupReq || isAccountRoot(relPath)) {
19194
+ const acctId = relPath.split("/")[1] ?? accountId;
19195
+ const schemaMd = await readFile7(join35(absolute, "SCHEMA.md"), "utf8").catch(() => null);
19196
+ const groups = classifyAccountRoot(schemaMd, entries2.map((e) => e.name));
19197
+ console.error(
19198
+ `[data-schema] op=classify account=${acctId} status=${groups.parsed ? "ok" : "parse-failed"} reason=${groups.reason} entries=${entries2.length} home=${groups.home.join(",") || "none"} system=${groups.system.length} unknown=${groups.unknown.join(",") || "none"}`
19199
+ );
19200
+ if (groupReq && !groups.parsed) {
19201
+ return c.json({ path: relPath, displayPath, entries: entries2 });
19202
+ }
19203
+ if (!groupReq) {
19204
+ const homeSet = new Set(groups.home);
19205
+ for (const e of entries2) e.group = homeSet.has(e.name) ? "home" : "system";
19206
+ return c.json({ path: relPath, displayPath, entries: entries2 });
19207
+ }
19208
+ const groupPath = `${groupReq.accountRel}/@${groupReq.view}`;
19209
+ const groupDisplay = [...displayPath, { name: `@${groupReq.view}`, displayName: groupReq.view }];
19210
+ if (groupReq.view === "system") {
19211
+ const systemSet = new Set(groups.system);
19212
+ return c.json({
19213
+ path: groupPath,
19214
+ displayPath: groupDisplay,
19215
+ view: "system",
19216
+ entries: entries2.filter((e) => systemSet.has(e.name))
19217
+ });
19218
+ }
19219
+ const byName = new Map(entries2.map((e) => [e.name, e]));
19220
+ const homeDirs = [];
19221
+ const homeFiles = [];
19222
+ for (const name of groups.home) {
19223
+ if (byName.get(name)?.kind === "directory") homeDirs.push(name);
19224
+ else homeFiles.push(name);
19225
+ }
19226
+ if (homeFiles.length > 0) {
19227
+ console.error(`[data-schema] op=home-files account=${acctId} count=${homeFiles.length} names=${homeFiles.join(",")}`);
19228
+ }
19229
+ const cards = [];
19230
+ for (const name of homeDirs) {
19231
+ const base = byName.get(name);
19232
+ try {
19233
+ const dirents = await readdir4(join35(absolute, name), { withFileTypes: true });
19234
+ const visible = dirents.filter((d) => !d.name.startsWith("."));
19235
+ visible.sort((a, b) => {
19236
+ const ad = a.isDirectory() ? 0 : 1;
19237
+ const bd = b.isDirectory() ? 0 : 1;
19238
+ return ad !== bd ? ad - bd : a.name.localeCompare(b.name);
19239
+ });
19240
+ cards.push({
19241
+ ...base,
19242
+ childCount: visible.length,
19243
+ children: visible.slice(0, HOME_CHILD_PREVIEW).map((d) => ({
19244
+ name: d.name,
19245
+ kind: d.isDirectory() ? "directory" : "file"
19246
+ }))
19247
+ });
19248
+ } catch (err) {
19249
+ const message = err instanceof Error ? err.message : String(err);
19250
+ console.error(`[data-schema] op=card-children account=${acctId} bucket=${name} status=error reason="${message}"`);
19251
+ cards.push({ ...base, childCount: null, children: [] });
19252
+ }
19253
+ }
19254
+ return c.json({
19255
+ path: groupPath,
19256
+ displayPath: groupDisplay,
19257
+ view: "home",
19258
+ entries: cards,
19259
+ systemCount: groups.system.length + homeFiles.length
19260
+ });
19261
+ }
19262
+ console.error(`[data] file-list path="${relPath}" entries=${entries2.length}`);
19263
+ return c.json({ path: relPath, displayPath, entries: entries2 });
18782
19264
  } catch (err) {
18783
19265
  const code = err.code;
18784
19266
  if (code === "ENOENT") {
@@ -18930,14 +19412,14 @@ app23.get("/download-zip", requireAdminSession, async (c) => {
18930
19412
  if (rawPaths.length > maxFiles) {
18931
19413
  return c.json({ error: `Too many files (max ${maxFiles})` }, 413);
18932
19414
  }
18933
- const entries = [];
19415
+ const entries2 = [];
18934
19416
  let total = 0;
18935
19417
  let dirsWalked = 0;
18936
19418
  const addFile = async (absolute, size, member) => {
18937
- if (entries.length >= maxFiles) return c.json({ error: `Too many files (max ${maxFiles})` }, 413);
19419
+ if (entries2.length >= maxFiles) return c.json({ error: `Too many files (max ${maxFiles})` }, 413);
18938
19420
  total += size;
18939
19421
  if (total > maxTotalBytes) return c.json({ error: "Selection too large to zip" }, 413);
18940
- entries.push({ name: member, data: await readFile7(absolute) });
19422
+ entries2.push({ name: member, data: await readFile7(absolute) });
18941
19423
  return null;
18942
19424
  };
18943
19425
  for (const rawPath of rawPaths) {
@@ -18985,8 +19467,8 @@ app23.get("/download-zip", requireAdminSession, async (c) => {
18985
19467
  throw err;
18986
19468
  }
18987
19469
  }
18988
- const archive = buildZip(entries);
18989
- console.error(`[data] file-download-zip dirs=${dirsWalked} files=${entries.length} bytes=${archive.length}`);
19470
+ const archive = buildZip(entries2);
19471
+ console.error(`[data] file-download-zip dirs=${dirsWalked} files=${entries2.length} bytes=${archive.length}`);
18990
19472
  return new Response(new Uint8Array(archive), {
18991
19473
  status: 200,
18992
19474
  headers: {
@@ -19027,8 +19509,8 @@ async function resolveUploadTarget(c, accountId, uid) {
19027
19509
  console.error(`[data] write-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
19028
19510
  return { ok: false, status: 403, error: "Path is outside your account folder" };
19029
19511
  }
19030
- const destDir = relDir === "." ? base.absolute : resolve26(base.absolute, relDir);
19031
- const destPath = resolve26(destDir, finalName);
19512
+ const destDir = relDir === "." ? base.absolute : resolve27(base.absolute, relDir);
19513
+ const destPath = resolve27(destDir, finalName);
19032
19514
  if (relpath) {
19033
19515
  const firstCreated = await mkdir4(destDir, { recursive: true });
19034
19516
  if (firstCreated) console.error(`[data-upload] op=mkdir uid=${uid} token=${token} dir="${destRel}"`);
@@ -19045,7 +19527,7 @@ async function resolveUploadTarget(c, accountId, uid) {
19045
19527
  return { ok: true, destDir, destPath, destRel, finalName, mimeType, relpath, token };
19046
19528
  }
19047
19529
  async function logUploadsTmpCensus(accountId) {
19048
- const tmpDir = resolve26(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
19530
+ const tmpDir = resolve27(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
19049
19531
  let live = 0;
19050
19532
  try {
19051
19533
  live = (await readdir4(tmpDir)).length;
@@ -19072,9 +19554,9 @@ app23.post("/upload", requireAdminSession, async (c) => {
19072
19554
  if (!body) return c.json({ error: "Empty request body" }, 400);
19073
19555
  console.error(`[data-upload] op=request uid=${uid} account=${accountId} dir="${destRel}" token=${token} rel="${relpath ?? ""}" declaredBytes=${declaredBytes}`);
19074
19556
  const ceiling = dataUploadCeiling();
19075
- const tmpDir = resolve26(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
19557
+ const tmpDir = resolve27(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
19076
19558
  await mkdir4(tmpDir, { recursive: true });
19077
- const tmpPath = resolve26(tmpDir, `${uid}.part`);
19559
+ const tmpPath = resolve27(tmpDir, `${uid}.part`);
19078
19560
  const out = createWriteStream2(tmpPath);
19079
19561
  const t0 = Date.now();
19080
19562
  let received = 0;
@@ -19221,9 +19703,9 @@ async function handleChunkUpload(c, accountId) {
19221
19703
  }
19222
19704
  const target = await resolveUploadTarget(c, accountId, uploadId);
19223
19705
  if (!target.ok) return c.json({ error: target.error }, target.status);
19224
- const tmpDir = resolve26(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
19706
+ const tmpDir = resolve27(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
19225
19707
  await mkdir4(tmpDir, { recursive: true });
19226
- const tmpPath = resolve26(tmpDir, `${uploadId}.part`);
19708
+ const tmpPath = resolve27(tmpDir, `${uploadId}.part`);
19227
19709
  const out = createWriteStream2(tmpPath);
19228
19710
  const state2 = {
19229
19711
  accountId,
@@ -19329,7 +19811,7 @@ async function evictStaleChunkUploads(ttlMs) {
19329
19811
  return evicted;
19330
19812
  }
19331
19813
  async function sweepStaleUploadTemps() {
19332
- const accountsRoot = resolve26(DATA_ROOT, "accounts");
19814
+ const accountsRoot = resolve27(DATA_ROOT, "accounts");
19333
19815
  let accounts;
19334
19816
  try {
19335
19817
  accounts = await readdir4(accountsRoot, { withFileTypes: true });
@@ -19339,16 +19821,16 @@ async function sweepStaleUploadTemps() {
19339
19821
  let removed = 0;
19340
19822
  for (const acc of accounts) {
19341
19823
  if (!acc.isDirectory()) continue;
19342
- const tmpDir = resolve26(accountsRoot, acc.name, UPLOAD_TMP_DIR);
19343
- let entries;
19824
+ const tmpDir = resolve27(accountsRoot, acc.name, UPLOAD_TMP_DIR);
19825
+ let entries2;
19344
19826
  try {
19345
- entries = await readdir4(tmpDir);
19827
+ entries2 = await readdir4(tmpDir);
19346
19828
  } catch {
19347
19829
  continue;
19348
19830
  }
19349
- for (const name of entries) {
19831
+ for (const name of entries2) {
19350
19832
  try {
19351
- await unlink3(resolve26(tmpDir, name));
19833
+ await unlink3(resolve27(tmpDir, name));
19352
19834
  removed++;
19353
19835
  } catch {
19354
19836
  }
@@ -19459,7 +19941,7 @@ app23.post("/folder", requireAdminSession, async (c) => {
19459
19941
  if (!isValidEntryName(name)) return c.json({ error: "Invalid folder name" }, 400);
19460
19942
  const parent = resolveOwnAccountWrite(rawPath, accountId, "POST /api/admin/files/folder");
19461
19943
  if (!parent.ok) return c.json({ error: parent.error }, parent.status);
19462
- const newAbs = resolve26(parent.absolute, name);
19944
+ const newAbs = resolve27(parent.absolute, name);
19463
19945
  const newRel = `${parent.relative}/${name}`;
19464
19946
  try {
19465
19947
  const info = await stat6(parent.absolute);
@@ -19498,7 +19980,7 @@ app23.post("/rename", requireAdminSession, async (c) => {
19498
19980
  console.error(`[data] file-rename blocked path="${src.relative}" reason="protected"`);
19499
19981
  return c.json({ error: "Protected entry \u2014 refusing to rename" }, 403);
19500
19982
  }
19501
- const destAbs = resolve26(dirname13(src.absolute), newName);
19983
+ const destAbs = resolve27(dirname13(src.absolute), newName);
19502
19984
  const newRel = `${dirname13(src.relative)}/${newName}`.replace(/^\.\//, "");
19503
19985
  if (isProtectedFromRename(newRel)) {
19504
19986
  console.error(`[data] file-rename blocked path="${newRel}" reason="protected-target"`);
@@ -19529,7 +20011,7 @@ app23.post("/rename", requireAdminSession, async (c) => {
19529
20011
  var files_default = app23;
19530
20012
 
19531
20013
  // ../lib/graph-search/src/index.ts
19532
- var import_dist = __toESM(require_dist2());
20014
+ var import_dist2 = __toESM(require_dist3());
19533
20015
  import { int } from "neo4j-driver";
19534
20016
 
19535
20017
  // ../lib/graph-search/src/rrf-fusion.ts
@@ -19779,7 +20261,7 @@ async function bm25Only(session, params) {
19779
20261
  ${scopeClause}
19780
20262
  ${agentClause}
19781
20263
  ${labelClause}
19782
- AND ${(0, import_dist.notTrashed)("node")}
20264
+ AND ${(0, import_dist2.notTrashed)("node")}
19783
20265
  ${kwClause}
19784
20266
  RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
19785
20267
  ORDER BY score DESC
@@ -19941,7 +20423,7 @@ async function hybrid(session, embed2, params) {
19941
20423
  WHERE node.accountId = $accountId
19942
20424
  ${scopeClause}
19943
20425
  ${agentClause}
19944
- AND ${(0, import_dist.notTrashed)("node")}
20426
+ AND ${(0, import_dist2.notTrashed)("node")}
19945
20427
  ${keywordClause}
19946
20428
  RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
19947
20429
  ORDER BY score DESC
@@ -20040,7 +20522,7 @@ async function hybrid(session, embed2, params) {
20040
20522
  const propResult = await session.run(
20041
20523
  `MATCH (node)
20042
20524
  WHERE node.accountId = $accountId
20043
- AND ${(0, import_dist.notTrashed)("node")}
20525
+ AND ${(0, import_dist2.notTrashed)("node")}
20044
20526
  AND node.keywords IS NOT NULL
20045
20527
  AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
20046
20528
  ${propScope.clause}
@@ -20092,7 +20574,7 @@ async function hybrid(session, embed2, params) {
20092
20574
  const propResult = await session.run(
20093
20575
  `MATCH (node)
20094
20576
  WHERE node.accountId = $accountId
20095
- AND ${(0, import_dist.notTrashed)("node")}
20577
+ AND ${(0, import_dist2.notTrashed)("node")}
20096
20578
  AND node.keywords IS NOT NULL
20097
20579
  AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
20098
20580
  ${propScope.clause}
@@ -20199,7 +20681,7 @@ async function hybrid(session, embed2, params) {
20199
20681
  `UNWIND $nodeIds AS nid
20200
20682
  MATCH (n)-[r]-(related)
20201
20683
  WHERE elementId(n) = nid
20202
- AND ${(0, import_dist.notTrashed)("related")}
20684
+ AND ${(0, import_dist2.notTrashed)("related")}
20203
20685
  ${expandScopeClause}
20204
20686
  ${expandAgentClause}
20205
20687
  WITH nid, n, r, related
@@ -20427,8 +20909,8 @@ var graph_search_default = app24;
20427
20909
  import neo4j2 from "neo4j-driver";
20428
20910
 
20429
20911
  // app/lib/graph-labels.ts
20430
- var import_dist2 = __toESM(require_dist3(), 1);
20431
- var import_dist3 = __toESM(require_dist3(), 1);
20912
+ var import_dist3 = __toESM(require_dist4(), 1);
20913
+ var import_dist4 = __toESM(require_dist4(), 1);
20432
20914
  var HIDDEN_BY_DEFAULT_LABELS = Object.freeze(
20433
20915
  /* @__PURE__ */ new Set(["Chunk", "GraphPreference"])
20434
20916
  );
@@ -20506,16 +20988,16 @@ var EXCLUDED_EDGE_TYPES = Object.freeze(
20506
20988
  ])
20507
20989
  );
20508
20990
  function isKnownLabel(label) {
20509
- return Object.prototype.hasOwnProperty.call(import_dist3.GRAPH_LABEL_COLOURS, label);
20991
+ return Object.prototype.hasOwnProperty.call(import_dist4.GRAPH_LABEL_COLOURS, label);
20510
20992
  }
20511
20993
  function isHiddenByDefault(label) {
20512
20994
  return HIDDEN_BY_DEFAULT_LABELS.has(label);
20513
20995
  }
20514
20996
 
20515
20997
  // server/lib/top-level-labels.ts
20516
- var import_dist4 = __toESM(require_dist3(), 1);
20998
+ var import_dist5 = __toESM(require_dist4(), 1);
20517
20999
  import { readdirSync as readdirSync23, readFileSync as readFileSync35 } from "fs";
20518
- import { join as join36, resolve as resolve27 } from "path";
21000
+ import { join as join36, resolve as resolve28 } from "path";
20519
21001
  var STATIC_TOP_LEVEL_LABELS = Object.freeze(
20520
21002
  /* @__PURE__ */ new Set([
20521
21003
  // Base-schema infra (schema-base.md has no top-level section).
@@ -20621,7 +21103,7 @@ function resolveReferencesDir() {
20621
21103
  if (process.env.MAXY_PLATFORM_ROOT) {
20622
21104
  return join36(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
20623
21105
  }
20624
- return resolve27(import.meta.dirname, "../../../plugins/memory/references");
21106
+ return resolve28(import.meta.dirname, "../../../plugins/memory/references");
20625
21107
  }
20626
21108
  function parseTableTopLevelLabels(referencesDir) {
20627
21109
  const labels = /* @__PURE__ */ new Set();
@@ -20650,7 +21132,7 @@ function getTopLevelLabelAllowlist(opts = {}) {
20650
21132
  const referencesDir = opts.referencesDir ?? resolveReferencesDir();
20651
21133
  const { labels: derived, contributingFiles } = parseTableTopLevelLabels(referencesDir);
20652
21134
  const excluded = [];
20653
- for (const label of import_dist4.ADDITIONAL_BASE_LABELS) {
21135
+ for (const label of import_dist5.ADDITIONAL_BASE_LABELS) {
20654
21136
  if (derived.delete(label)) excluded.push(label);
20655
21137
  }
20656
21138
  const derivedCount = derived.size;
@@ -21786,7 +22268,7 @@ var graph_default_view_default = app29;
21786
22268
 
21787
22269
  // server/routes/admin/sidebar-artefacts.ts
21788
22270
  import { readdir as readdir5, stat as stat7 } from "fs/promises";
21789
- import { resolve as resolve28, relative as relative6, isAbsolute as isAbsolute2, sep as sep9, basename as basename12 } from "path";
22271
+ import { resolve as resolve29, relative as relative6, isAbsolute as isAbsolute2, sep as sep9, basename as basename12 } from "path";
21790
22272
  import { existsSync as existsSync35 } from "fs";
21791
22273
  var LIMIT = 50;
21792
22274
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
@@ -21802,20 +22284,25 @@ app30.get("/", requireAdminSession, async (c) => {
21802
22284
  return c.json({ error: "Account not found for session" }, 401);
21803
22285
  }
21804
22286
  const start = Date.now();
21805
- const accountFiles = await fetchAccountFileArtefacts(accountId);
21806
- if (accountFiles === null) {
22287
+ ensureAccountWatchers(accountId, resolve29(ACCOUNTS_DIR, accountId));
22288
+ const { value, state } = await getOrCompute("sidebar-artefacts", accountId, async () => {
22289
+ const accountFiles = await fetchAccountFileArtefacts(accountId);
22290
+ if (accountFiles === null) return null;
22291
+ const accountDir = resolve29(ACCOUNTS_DIR, accountId);
22292
+ const agents = await fetchAgentTemplateRows(accountDir);
22293
+ const artefacts = [...accountFiles, ...agents].sort(
22294
+ (a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
22295
+ ).slice(0, LIMIT);
22296
+ return { artefacts, accountFileCount: accountFiles.length, agentCount: agents.length };
22297
+ });
22298
+ if (value === null) {
21807
22299
  return c.json({ error: "Failed to load artefacts" }, 500);
21808
22300
  }
21809
- const accountDir = resolve28(ACCOUNTS_DIR, accountId);
21810
- const agents = await fetchAgentTemplateRows(accountDir);
21811
- const artefacts = [...accountFiles, ...agents].sort(
21812
- (a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
21813
- ).slice(0, LIMIT);
21814
22301
  const ms = Date.now() - start;
21815
22302
  console.log(
21816
- `[admin/sidebar-artefacts] account=${accountId} count=${artefacts.length} accountFiles=${accountFiles.length} agents=${agents.length} ms=${ms}`
22303
+ `[admin/sidebar-artefacts] account=${accountId} count=${value.artefacts.length} accountFiles=${value.accountFileCount} agents=${value.agentCount} cache=${state} ms=${ms}`
21817
22304
  );
21818
- return c.json({ artefacts });
22305
+ return c.json({ artefacts: value.artefacts });
21819
22306
  });
21820
22307
  async function fetchAccountFileArtefacts(accountId) {
21821
22308
  const session = getSession();
@@ -21858,8 +22345,8 @@ async function fetchAccountFileArtefacts(accountId) {
21858
22345
  async function fetchAgentTemplateRows(accountDir) {
21859
22346
  const rows = [];
21860
22347
  for (const filename of ADMIN_AGENT_FILES) {
21861
- const overridePath = resolve28(accountDir, "agents", "admin", filename);
21862
- const bundledPath = resolve28(PLATFORM_ROOT, "templates", "agents", "admin", filename);
22348
+ const overridePath = resolve29(accountDir, "agents", "admin", filename);
22349
+ const bundledPath = resolve29(PLATFORM_ROOT, "templates", "agents", "admin", filename);
21863
22350
  const labelStem = filename.replace(/\.md$/, "");
21864
22351
  const row = await readAgentTemplateRow({
21865
22352
  id: `agent-template:admin:${filename}`,
@@ -21872,12 +22359,12 @@ async function fetchAgentTemplateRows(accountDir) {
21872
22359
  });
21873
22360
  if (row) rows.push(row);
21874
22361
  }
21875
- const overrideDir = resolve28(accountDir, "specialists", "agents");
21876
- const bundledDir = resolve28(PLATFORM_ROOT, "templates", "specialists", "agents");
22362
+ const overrideDir = resolve29(accountDir, "specialists", "agents");
22363
+ const bundledDir = resolve29(PLATFORM_ROOT, "templates", "specialists", "agents");
21877
22364
  const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
21878
22365
  for (const filename of specialistNames) {
21879
- const overridePath = resolve28(overrideDir, filename);
21880
- const bundledPath = resolve28(bundledDir, filename);
22366
+ const overridePath = resolve29(overrideDir, filename);
22367
+ const bundledPath = resolve29(bundledDir, filename);
21881
22368
  const row = await readAgentTemplateRow({
21882
22369
  id: `agent-template:specialist:${filename}`,
21883
22370
  displayName: filename.replace(/\.md$/, ""),
@@ -21896,8 +22383,8 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
21896
22383
  for (const dir of [overrideDir, bundledDir]) {
21897
22384
  if (!existsSync35(dir)) continue;
21898
22385
  try {
21899
- const entries = await readdir5(dir);
21900
- for (const entry of entries) {
22386
+ const entries2 = await readdir5(dir);
22387
+ for (const entry of entries2) {
21901
22388
  if (entry.endsWith(".md")) names.add(entry);
21902
22389
  }
21903
22390
  } catch (err) {
@@ -22363,24 +22850,24 @@ var session_rc_spawn_default = app36;
22363
22850
  import { randomUUID as randomUUID12 } from "crypto";
22364
22851
 
22365
22852
  // server/wa-descriptor.ts
22366
- import { resolve as resolve29, join as join38 } from "path";
22853
+ import { resolve as resolve30, join as join38 } from "path";
22367
22854
  function waGatewayUrl() {
22368
22855
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
22369
22856
  }
22370
22857
  function waServerPath() {
22371
- return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve29(process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
22858
+ return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
22372
22859
  }
22373
22860
  function waChannelDescriptor(senderId) {
22374
22861
  return { senderId, gatewayUrl: waGatewayUrl(), serverPath: waServerPath() };
22375
22862
  }
22376
22863
 
22377
22864
  // server/telegram-descriptor.ts
22378
- import { resolve as resolve30, join as join39 } from "path";
22865
+ import { resolve as resolve31, join as join39 } from "path";
22379
22866
  function telegramGatewayUrl() {
22380
22867
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
22381
22868
  }
22382
22869
  function telegramServerPath() {
22383
- return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, ".."), "services/telegram-channel/dist/server.js");
22870
+ return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, ".."), "services/telegram-channel/dist/server.js");
22384
22871
  }
22385
22872
  function telegramChannelDescriptor(senderId) {
22386
22873
  return { senderId, gatewayUrl: telegramGatewayUrl(), serverPath: telegramServerPath() };
@@ -22665,8 +23152,8 @@ var system_stats_default = app38;
22665
23152
 
22666
23153
  // server/routes/admin/health.ts
22667
23154
  import { existsSync as existsSync36, readFileSync as readFileSync37 } from "fs";
22668
- import { resolve as resolve31, join as join40 } from "path";
22669
- var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve31(process.cwd(), "..");
23155
+ import { resolve as resolve32, join as join40 } from "path";
23156
+ var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve32(process.cwd(), "..");
22670
23157
  var brandHostname = "maxy";
22671
23158
  var brandJsonPath = join40(PLATFORM_ROOT6, "config", "brand.json");
22672
23159
  if (existsSync36(brandJsonPath)) {
@@ -22676,7 +23163,7 @@ if (existsSync36(brandJsonPath)) {
22676
23163
  } catch {
22677
23164
  }
22678
23165
  }
22679
- var VERSION_FILE = resolve31(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
23166
+ var VERSION_FILE = resolve32(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
22680
23167
  var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
22681
23168
  var PROBE_TIMEOUT_MS = 1e3;
22682
23169
  function readVersion() {
@@ -24132,7 +24619,7 @@ var routines_default = app48;
24132
24619
 
24133
24620
  // server/routes/admin/skills.ts
24134
24621
  import { existsSync as existsSync38, readdirSync as readdirSync24, readFileSync as readFileSync39, rmSync as rmSync3 } from "fs";
24135
- import { resolve as resolve32 } from "path";
24622
+ import { resolve as resolve33 } from "path";
24136
24623
  var app49 = new Hono();
24137
24624
  var NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
24138
24625
  function splitSkillMd(text) {
@@ -24154,12 +24641,6 @@ function stripQuotes(s) {
24154
24641
  if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) return s.slice(1, -1);
24155
24642
  return s;
24156
24643
  }
24157
- function accountDirForSession(cacheKey) {
24158
- const accountId = getAccountIdForSession(cacheKey);
24159
- if (!accountId) return null;
24160
- const match = listValidAccounts().find((a) => a.accountId === accountId);
24161
- return match ? { accountId, accountDir: match.accountDir } : null;
24162
- }
24163
24644
  function subdirs2(dir) {
24164
24645
  if (!existsSync38(dir)) return [];
24165
24646
  try {
@@ -24174,28 +24655,32 @@ app49.get("/", requireAdminSession, async (c) => {
24174
24655
  console.error('[admin:skills] op=list auth-rejected reason="no account for session"');
24175
24656
  return c.json({ error: "Account not found for session" }, 401);
24176
24657
  }
24177
- const pluginsDir = resolve32(acct.accountDir, "plugins");
24178
- const skills = [];
24179
- let pluginCount = 0;
24180
- for (const plugin of subdirs2(pluginsDir)) {
24181
- pluginCount++;
24182
- const skillsDir = resolve32(pluginsDir, plugin, "skills");
24183
- for (const skill of subdirs2(skillsDir)) {
24184
- const skillMd = resolve32(skillsDir, skill, "SKILL.md");
24185
- if (!existsSync38(skillMd)) continue;
24186
- try {
24187
- const { frontmatter } = splitSkillMd(readFileSync39(skillMd, "utf-8"));
24188
- const refsDir = resolve32(skillsDir, skill, "references");
24189
- const refCount = existsSync38(refsDir) ? readdirSync24(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).length : 0;
24190
- skills.push({ plugin, skill, description: frontmatter.description, refCount });
24191
- } catch (err) {
24192
- console.error(`[admin:skills] op=list-skip plugin=${plugin} skill=${skill} reason="${err instanceof Error ? err.message : String(err)}"`);
24658
+ ensureAccountWatchers(acct.accountId, acct.accountDir);
24659
+ const { value, state } = await getOrCompute("skills", acct.accountId, async () => {
24660
+ const pluginsDir = resolve33(acct.accountDir, "plugins");
24661
+ const skills = [];
24662
+ let pluginCount = 0;
24663
+ for (const plugin of subdirs2(pluginsDir)) {
24664
+ pluginCount++;
24665
+ const skillsDir = resolve33(pluginsDir, plugin, "skills");
24666
+ for (const skill of subdirs2(skillsDir)) {
24667
+ const skillMd = resolve33(skillsDir, skill, "SKILL.md");
24668
+ if (!existsSync38(skillMd)) continue;
24669
+ try {
24670
+ const { frontmatter } = splitSkillMd(readFileSync39(skillMd, "utf-8"));
24671
+ const refsDir = resolve33(skillsDir, skill, "references");
24672
+ const refCount = existsSync38(refsDir) ? readdirSync24(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).length : 0;
24673
+ skills.push({ plugin, skill, description: frontmatter.description, refCount });
24674
+ } catch (err) {
24675
+ console.error(`[admin:skills] op=list-skip plugin=${plugin} skill=${skill} reason="${err instanceof Error ? err.message : String(err)}"`);
24676
+ }
24193
24677
  }
24194
24678
  }
24195
- }
24196
- skills.sort((a, b) => a.plugin.localeCompare(b.plugin) || a.skill.localeCompare(b.skill));
24197
- console.log(`[admin:skills] op=list accountId=${acct.accountId.slice(0, 8)} plugins=${pluginCount} skills=${skills.length}`);
24198
- return c.json({ skills });
24679
+ skills.sort((a, b) => a.plugin.localeCompare(b.plugin) || a.skill.localeCompare(b.skill));
24680
+ return { skills, pluginCount };
24681
+ });
24682
+ console.log(`[admin:skills] op=list accountId=${acct.accountId.slice(0, 8)} plugins=${value.pluginCount} skills=${value.skills.length} cache=${state}`);
24683
+ return c.json({ skills: value.skills });
24199
24684
  });
24200
24685
  app49.get("/:plugin/:skill", requireAdminSession, async (c) => {
24201
24686
  const acct = accountDirForSession(c.var.cacheKey);
@@ -24206,14 +24691,14 @@ app49.get("/:plugin/:skill", requireAdminSession, async (c) => {
24206
24691
  console.error(`[admin:skills] op=get outcome=rejected reason=invalid-name plugin="${plugin}" skill="${skill}"`);
24207
24692
  return c.json({ error: "Invalid plugin or skill name" }, 400);
24208
24693
  }
24209
- const skillDir = resolve32(acct.accountDir, "plugins", plugin, "skills", skill);
24210
- const skillMd = resolve32(skillDir, "SKILL.md");
24694
+ const skillDir = resolve33(acct.accountDir, "plugins", plugin, "skills", skill);
24695
+ const skillMd = resolve33(skillDir, "SKILL.md");
24211
24696
  const found = existsSync38(skillMd);
24212
24697
  console.log(`[admin:skills] op=get plugin=${plugin} skill=${skill} found=${found}`);
24213
24698
  if (!found) return c.json({ error: "Skill not found" }, 404);
24214
24699
  try {
24215
24700
  const { frontmatter, body } = splitSkillMd(readFileSync39(skillMd, "utf-8"));
24216
- const refsDir = resolve32(skillDir, "references");
24701
+ const refsDir = resolve33(skillDir, "references");
24217
24702
  const references = existsSync38(refsDir) ? readdirSync24(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).sort() : [];
24218
24703
  return c.json({ skill: { plugin, skill, frontmatter, body, references } });
24219
24704
  } catch (err) {
@@ -24231,10 +24716,10 @@ app49.delete("/:plugin/:skill", requireAdminSession, async (c) => {
24231
24716
  console.error(`[admin:skills] op=delete outcome=rejected reason=invalid-name plugin="${plugin}" skill="${skill}"`);
24232
24717
  return c.json({ error: "Invalid plugin or skill name" }, 400);
24233
24718
  }
24234
- const pluginDir = resolve32(acct.accountDir, "plugins", plugin);
24235
- const skillsDir = resolve32(pluginDir, "skills");
24236
- const skillDir = resolve32(skillsDir, skill);
24237
- if (!existsSync38(resolve32(skillDir, "SKILL.md"))) {
24719
+ const pluginDir = resolve33(acct.accountDir, "plugins", plugin);
24720
+ const skillsDir = resolve33(pluginDir, "skills");
24721
+ const skillDir = resolve33(skillsDir, skill);
24722
+ if (!existsSync38(resolve33(skillDir, "SKILL.md"))) {
24238
24723
  console.error(`[admin:skills] op=delete outcome=rejected reason=not-found plugin=${plugin} skill=${skill}`);
24239
24724
  return c.json({ error: "Skill not found" }, 404);
24240
24725
  }
@@ -24286,6 +24771,15 @@ app50.get("/", requireAdminSession, async (c) => {
24286
24771
  console.error(`${TAG39} op=list auth-rejected reason="no account for session"`);
24287
24772
  return c.json({ error: "Account not found for session" }, 401);
24288
24773
  }
24774
+ const cacheStart = Date.now();
24775
+ const cached3 = await getOrCompute("tasks-list", accountId, () => computeTaskList(accountId));
24776
+ console.log(`${TAG39} op=list-cache cache=${cached3.state} account=${accountId} ms=${Date.now() - cacheStart}`);
24777
+ if (cached3.value === null) {
24778
+ return c.json({ error: "tasks-list-failed" }, 500);
24779
+ }
24780
+ return c.json(cached3.value);
24781
+ });
24782
+ async function computeTaskList(accountId) {
24289
24783
  const session = getSession();
24290
24784
  try {
24291
24785
  const result = await session.run(
@@ -24368,14 +24862,14 @@ app50.get("/", requireAdminSession, async (c) => {
24368
24862
  console.log(
24369
24863
  `${TAG39} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned}`
24370
24864
  );
24371
- return c.json({ open, completed });
24865
+ return { open, completed };
24372
24866
  } catch (err) {
24373
24867
  console.error(`${TAG39} op=list error="${err instanceof Error ? err.message : String(err)}"`);
24374
- return c.json({ error: "tasks-list-failed" }, 500);
24868
+ return null;
24375
24869
  } finally {
24376
24870
  await session.close();
24377
24871
  }
24378
- });
24872
+ }
24379
24873
  var tasks_list_default = app50;
24380
24874
 
24381
24875
  // server/routes/admin/task-timer-start.ts
@@ -24419,6 +24913,7 @@ app51.post("/", requireAdminSession, async (c) => {
24419
24913
  const priorStartedAt = open.records[0]?.get("startedAt");
24420
24914
  if (priorEntryId) {
24421
24915
  console.log(`${TAG40} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
24916
+ invalidate("tasks-list", accountId);
24422
24917
  return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
24423
24918
  }
24424
24919
  const entryId = randomUUID14();
@@ -24429,6 +24924,7 @@ app51.post("/", requireAdminSession, async (c) => {
24429
24924
  { taskId, accountId, entryId, now }
24430
24925
  );
24431
24926
  console.log(`${TAG40} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
24927
+ invalidate("tasks-list", accountId);
24432
24928
  return c.json({ ok: true, running: true, entryId, startedAt: now });
24433
24929
  } catch (err) {
24434
24930
  console.error(`${TAG40} op=start error="${err instanceof Error ? err.message : String(err)}"`);
@@ -24478,6 +24974,7 @@ app52.post("/", requireAdminSession, async (c) => {
24478
24974
  );
24479
24975
  const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
24480
24976
  console.log(`${TAG41} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
24977
+ invalidate("tasks-list", accountId);
24481
24978
  return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
24482
24979
  }
24483
24980
  const seconds = secondsBetween(startedAt, now);
@@ -24502,6 +24999,7 @@ app52.post("/", requireAdminSession, async (c) => {
24502
24999
  const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
24503
25000
  console.log(`${TAG41} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
24504
25001
  console.log(`${TAG41} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
25002
+ invalidate("tasks-list", accountId);
24505
25003
  return c.json({ ok: true, running: false, seconds, secondsLogged });
24506
25004
  } catch (err) {
24507
25005
  console.error(`${TAG41} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
@@ -24545,6 +25043,7 @@ app53.post("/", requireAdminSession, async (c) => {
24545
25043
  }
24546
25044
  const secondsLogged = toNum(result.records[0].get("secondsLogged"));
24547
25045
  console.log(`${TAG42} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
25046
+ invalidate("tasks-list", accountId);
24548
25047
  return c.json({ ok: true, status: "completed", secondsLogged });
24549
25048
  } catch (err) {
24550
25049
  console.error(`${TAG42} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
@@ -24626,6 +25125,7 @@ app54.post("/", requireAdminSession, async (c) => {
24626
25125
  );
24627
25126
  const secondsLoggedAfter = toNum(write.records[0]?.get("secondsLoggedAfter"));
24628
25127
  console.log(`${TAG43} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
25128
+ invalidate("tasks-list", accountId);
24629
25129
  return c.json({ ok: true, secondsLogged: secondsLoggedAfter });
24630
25130
  } catch (err) {
24631
25131
  console.error(`${TAG43} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
@@ -24638,16 +25138,16 @@ var task_time_adjust_default = app54;
24638
25138
 
24639
25139
  // app/lib/admin-roster.ts
24640
25140
  import { existsSync as existsSync39, readdirSync as readdirSync25, readFileSync as readFileSync40 } from "fs";
24641
- import { resolve as resolve33 } from "path";
25141
+ import { resolve as resolve34 } from "path";
24642
25142
  function readHouseAdminUserIds(accountsDir = ACCOUNTS_DIR) {
24643
- let entries;
25143
+ let entries2;
24644
25144
  try {
24645
- entries = readdirSync25(accountsDir);
25145
+ entries2 = readdirSync25(accountsDir);
24646
25146
  } catch {
24647
25147
  return [];
24648
25148
  }
24649
- for (const entry of entries) {
24650
- const cfgPath = resolve33(accountsDir, entry, "account.json");
25149
+ for (const entry of entries2) {
25150
+ const cfgPath = resolve34(accountsDir, entry, "account.json");
24651
25151
  if (!existsSync39(cfgPath)) continue;
24652
25152
  try {
24653
25153
  const cfg = JSON.parse(readFileSync40(cfgPath, "utf-8"));
@@ -24771,6 +25271,7 @@ app55.post("/", requireAdminSession, async (c) => {
24771
25271
  { taskId, accountId, now }
24772
25272
  );
24773
25273
  console.log(`${TAG44} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
25274
+ invalidate("tasks-list", accountId);
24774
25275
  return c.json({ ok: true, assigneeUserId: null, assigneeName: null });
24775
25276
  }
24776
25277
  const set = await session.run(
@@ -24795,6 +25296,7 @@ app55.post("/", requireAdminSession, async (c) => {
24795
25296
  console.log(
24796
25297
  `${TAG44} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
24797
25298
  );
25299
+ invalidate("tasks-list", accountId);
24798
25300
  return c.json({ ok: true, assigneeUserId, assigneeName });
24799
25301
  } catch (err) {
24800
25302
  console.error(`${TAG44} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
@@ -25103,9 +25605,9 @@ var verify_token_default = app59;
25103
25605
 
25104
25606
  // app/lib/access-email.ts
25105
25607
  import { spawn as spawn2 } from "child_process";
25106
- import { resolve as resolve34 } from "path";
25107
- var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve34(process.cwd(), "..");
25108
- var SEND_SCRIPT = resolve34(
25608
+ import { resolve as resolve35 } from "path";
25609
+ var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve35(process.cwd(), "..");
25610
+ var SEND_SCRIPT = resolve35(
25109
25611
  PLATFORM_ROOT7,
25110
25612
  "plugins",
25111
25613
  "email",
@@ -25248,7 +25750,7 @@ var access_default = app61;
25248
25750
 
25249
25751
  // server/routes/sites.ts
25250
25752
  import { existsSync as existsSync40, readFileSync as readFileSync41, realpathSync as realpathSync8, statSync as statSync17 } from "fs";
25251
- import { resolve as resolve35 } from "path";
25753
+ import { resolve as resolve36 } from "path";
25252
25754
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
25253
25755
  var MIME = {
25254
25756
  ".html": "text/html; charset=utf-8",
@@ -25305,8 +25807,8 @@ app62.get("/:rel{.*}", (c) => {
25305
25807
  }
25306
25808
  segments.push(seg);
25307
25809
  }
25308
- const rootDir = resolve35(account.accountDir, "sites");
25309
- let filePath = segments.length === 0 ? rootDir : resolve35(rootDir, ...segments);
25810
+ const rootDir = resolve36(account.accountDir, "sites");
25811
+ let filePath = segments.length === 0 ? rootDir : resolve36(rootDir, ...segments);
25310
25812
  if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
25311
25813
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
25312
25814
  return c.text("Forbidden", 403);
@@ -25326,7 +25828,7 @@ app62.get("/:rel{.*}", (c) => {
25326
25828
  return c.redirect(target, 301);
25327
25829
  }
25328
25830
  if (stat11?.isDirectory()) {
25329
- filePath = resolve35(filePath, "index.html");
25831
+ filePath = resolve36(filePath, "index.html");
25330
25832
  }
25331
25833
  if (!filePath.startsWith(rootDir + "/")) {
25332
25834
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
@@ -25972,14 +26474,14 @@ async function writeEvent(opts) {
25972
26474
  var visitor_event_default = app65;
25973
26475
 
25974
26476
  // server/routes/session.ts
25975
- import { resolve as resolve36 } from "path";
26477
+ import { resolve as resolve37 } from "path";
25976
26478
  import { existsSync as existsSync42, writeFileSync as writeFileSync15, mkdirSync as mkdirSync9 } from "fs";
25977
26479
  var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
25978
26480
  function writeBrandingCache(accountId, agentSlug, branding) {
25979
26481
  try {
25980
- const cacheDir = resolve36(MAXY_DIR, "branding-cache", accountId);
26482
+ const cacheDir = resolve37(MAXY_DIR, "branding-cache", accountId);
25981
26483
  mkdirSync9(cacheDir, { recursive: true });
25982
- writeFileSync15(resolve36(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
26484
+ writeFileSync15(resolve37(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
25983
26485
  } catch (err) {
25984
26486
  console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
25985
26487
  }
@@ -26056,8 +26558,8 @@ app66.post("/", async (c) => {
26056
26558
  }
26057
26559
  let agentConfig = null;
26058
26560
  if (account) {
26059
- const agentDir = resolve36(account.accountDir, "agents", agentSlug);
26060
- if (!existsSync42(agentDir) || !existsSync42(resolve36(agentDir, "config.json"))) {
26561
+ const agentDir = resolve37(account.accountDir, "agents", agentSlug);
26562
+ if (!existsSync42(agentDir) || !existsSync42(resolve37(agentDir, "config.json"))) {
26061
26563
  return c.json({ error: "Agent not found" }, 404);
26062
26564
  }
26063
26565
  agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
@@ -26317,7 +26819,7 @@ var calendar_public_default = app67;
26317
26819
  // server/routes/portal-fetch.ts
26318
26820
  import { createReadStream as createReadStream3 } from "fs";
26319
26821
  import { stat as stat8, readFile as readFile9, realpath } from "fs/promises";
26320
- import { join as join44, resolve as resolve37, sep as sep10 } from "path";
26822
+ import { join as join44, resolve as resolve38, sep as sep10 } from "path";
26321
26823
  import { Readable as Readable3 } from "stream";
26322
26824
  var app68 = new Hono();
26323
26825
  var TAG49 = "[portal-fetch]";
@@ -26370,7 +26872,7 @@ ${expiresAtMs}`)
26370
26872
  return diff === 0;
26371
26873
  }
26372
26874
  async function readAccountSecret(accountId) {
26373
- const path3 = resolve37(DATA_ROOT, "accounts", accountId, "secrets", "data-portal.env");
26875
+ const path3 = resolve38(DATA_ROOT, "accounts", accountId, "secrets", "data-portal.env");
26374
26876
  let text;
26375
26877
  try {
26376
26878
  text = await readFile9(path3, "utf8");
@@ -26406,7 +26908,7 @@ async function resolveFetchTarget(accountDir, relPath, ownerId) {
26406
26908
  const exposeFolders = await readExposeFolders2(accountDir);
26407
26909
  const { exposed } = resolveExposedDirs(schemaText, exposeFolders);
26408
26910
  if (exposed.length === 0 && !ownerId) return { ok: false, reason: "not-exposed" };
26409
- const lexical = resolve37(accountDir, relPath);
26911
+ const lexical = resolve38(accountDir, relPath);
26410
26912
  let root;
26411
26913
  let absolute;
26412
26914
  try {
@@ -26455,7 +26957,7 @@ async function handle(c, headOnly) {
26455
26957
  return c.json({ ok: false, error: "denied" }, 401);
26456
26958
  }
26457
26959
  const target = await resolveFetchTarget(
26458
- resolve37(DATA_ROOT, "accounts", accountId),
26960
+ resolve38(DATA_ROOT, "accounts", accountId),
26459
26961
  relPath,
26460
26962
  owner || void 0
26461
26963
  );
@@ -26616,14 +27118,14 @@ function formatCensusLine(f) {
26616
27118
  var TAG51 = "[ledger-census]";
26617
27119
  var DAY_MS = 864e5;
26618
27120
  function countWriteRejects24h(logDir, now) {
26619
- let entries;
27121
+ let entries2;
26620
27122
  try {
26621
- entries = readdirSync27(logDir).filter((f) => f.startsWith("mcp-ledger-") && f.endsWith(".log"));
27123
+ entries2 = readdirSync27(logDir).filter((f) => f.startsWith("mcp-ledger-") && f.endsWith(".log"));
26622
27124
  } catch {
26623
27125
  return 0;
26624
27126
  }
26625
27127
  let total = 0;
26626
- for (const name of entries) {
27128
+ for (const name of entries2) {
26627
27129
  const path3 = join45(logDir, name);
26628
27130
  try {
26629
27131
  if (now - statSync18(path3).mtimeMs > DAY_MS) continue;
@@ -26778,7 +27280,7 @@ async function runConversationAudit() {
26778
27280
  }
26779
27281
 
26780
27282
  // app/lib/graph-health.ts
26781
- var import_dist6 = __toESM(require_dist4(), 1);
27283
+ var import_dist7 = __toESM(require_dist5(), 1);
26782
27284
  var HOUR_MS = 60 * 60 * 1e3;
26783
27285
  function renderLabelTop(rows) {
26784
27286
  return rows.map((b) => {
@@ -26823,7 +27325,7 @@ async function runGraphHealthTick() {
26823
27325
  console.error(
26824
27326
  `[graph-health] userprofile-multi accounts=${upAccounts} top=${upTop.length > 0 ? upTop.join(",") : "none"}`
26825
27327
  );
26826
- const indexed = [...import_dist6.VECTOR_INDEXED_LABELS];
27328
+ const indexed = [...import_dist7.VECTOR_INDEXED_LABELS];
26827
27329
  const embCount = await session.run(
26828
27330
  `MATCH (n) WHERE n.embedding IS NULL AND any(l IN labels(n) WHERE l IN $indexed)
26829
27331
  RETURN count(n) AS total`,
@@ -26896,7 +27398,7 @@ function startGraphHealthTimer() {
26896
27398
 
26897
27399
  // app/lib/file-watcher.ts
26898
27400
  import * as fsp2 from "fs/promises";
26899
- import { resolve as resolve38, sep as sep11 } from "path";
27401
+ import { resolve as resolve39, sep as sep11 } from "path";
26900
27402
  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;
26901
27403
  var DEFAULT_COALESCE_MS = 500;
26902
27404
  var ROOTS = ["accounts"];
@@ -26915,7 +27417,7 @@ async function startFileWatcher(opts = {}) {
26915
27417
  const dropFn = opts.drop ?? dropFileIndex;
26916
27418
  for (const r of ROOTS) {
26917
27419
  try {
26918
- await fsp2.mkdir(resolve38(dataRoot, r), { recursive: true });
27420
+ await fsp2.mkdir(resolve39(dataRoot, r), { recursive: true });
26919
27421
  } catch (err) {
26920
27422
  console.error(
26921
27423
  `[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
@@ -26936,7 +27438,7 @@ async function startFileWatcher(opts = {}) {
26936
27438
  timers.set(relativePath, t);
26937
27439
  }
26938
27440
  async function runHook(relativePath, accountId) {
26939
- const absolute = resolve38(dataRoot, relativePath);
27441
+ const absolute = resolve39(dataRoot, relativePath);
26940
27442
  let exists = false;
26941
27443
  try {
26942
27444
  const st = await fsp2.stat(absolute);
@@ -26960,7 +27462,7 @@ async function startFileWatcher(opts = {}) {
26960
27462
  }
26961
27463
  }
26962
27464
  async function watchRoot(rootName) {
26963
- const absRoot = resolve38(dataRoot, rootName);
27465
+ const absRoot = resolve39(dataRoot, rootName);
26964
27466
  try {
26965
27467
  const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
26966
27468
  for await (const event of iter) {
@@ -26999,18 +27501,18 @@ async function startFileWatcher(opts = {}) {
26999
27501
 
27000
27502
  // app/lib/migrate-uploads.ts
27001
27503
  import { mkdir as mkdir6, readdir as readdir6, rename as rename3, rm as rm3 } from "fs/promises";
27002
- import { dirname as dirname15, relative as relative7, resolve as resolve39 } from "path";
27504
+ import { dirname as dirname15, relative as relative7, resolve as resolve40 } from "path";
27003
27505
  var ACCOUNT_UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
27004
27506
  async function walkFiles(dir) {
27005
27507
  const out = [];
27006
- let entries;
27508
+ let entries2;
27007
27509
  try {
27008
- entries = await readdir6(dir, { withFileTypes: true });
27510
+ entries2 = await readdir6(dir, { withFileTypes: true });
27009
27511
  } catch {
27010
27512
  return out;
27011
27513
  }
27012
- for (const e of entries) {
27013
- const abs = resolve39(dir, e.name);
27514
+ for (const e of entries2) {
27515
+ const abs = resolve40(dir, e.name);
27014
27516
  if (e.isDirectory()) {
27015
27517
  out.push(...await walkFiles(abs));
27016
27518
  } else if (e.isFile()) {
@@ -27030,7 +27532,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
27030
27532
  let moved = 0;
27031
27533
  for (const oldAbs of files) {
27032
27534
  const suffix = relative7(srcDir, oldAbs);
27033
- const newAbs = resolve39(destDir, suffix);
27535
+ const newAbs = resolve40(destDir, suffix);
27034
27536
  await mkdir6(dirname15(newAbs), { recursive: true });
27035
27537
  await rename3(oldAbs, newAbs);
27036
27538
  moved++;
@@ -27057,7 +27559,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
27057
27559
  }
27058
27560
  async function migrateUploads(opts = {}) {
27059
27561
  const dataRoot = opts.dataRoot ?? DATA_ROOT;
27060
- const oldRoot = resolve39(dataRoot, "uploads");
27562
+ const oldRoot = resolve40(dataRoot, "uploads");
27061
27563
  let topEntries;
27062
27564
  try {
27063
27565
  topEntries = await readdir6(oldRoot, { withFileTypes: true });
@@ -27078,8 +27580,8 @@ async function migrateUploads(opts = {}) {
27078
27580
  const name = entry.name;
27079
27581
  if (ACCOUNT_UUID_RE5.test(name)) {
27080
27582
  moved += await relocateTree(
27081
- resolve39(oldRoot, name),
27082
- resolve39(dataRoot, "accounts", name, "uploads"),
27583
+ resolve40(oldRoot, name),
27584
+ resolve40(dataRoot, "accounts", name, "uploads"),
27083
27585
  dataRoot,
27084
27586
  name,
27085
27587
  session
@@ -27091,8 +27593,8 @@ async function migrateUploads(opts = {}) {
27091
27593
  continue;
27092
27594
  }
27093
27595
  moved += await relocateTree(
27094
- resolve39(oldRoot, "public"),
27095
- resolve39(dataRoot, "accounts", installAccountId, "uploads", "public"),
27596
+ resolve40(oldRoot, "public"),
27597
+ resolve40(dataRoot, "accounts", installAccountId, "uploads", "public"),
27096
27598
  dataRoot,
27097
27599
  null,
27098
27600
  // public uploads carry no graph nodes
@@ -27169,13 +27671,13 @@ async function collectLiveSidecars(projectsRoot) {
27169
27671
  for (const slug of slugs) {
27170
27672
  if (!slug.isDirectory()) continue;
27171
27673
  const slugDir = join46(projectsRoot, slug.name);
27172
- let entries;
27674
+ let entries2;
27173
27675
  try {
27174
- entries = await readdir7(slugDir, { withFileTypes: true });
27676
+ entries2 = await readdir7(slugDir, { withFileTypes: true });
27175
27677
  } catch {
27176
27678
  continue;
27177
27679
  }
27178
- for (const entry of entries) {
27680
+ for (const entry of entries2) {
27179
27681
  if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
27180
27682
  out.push(join46(slugDir, entry.name));
27181
27683
  } else if (entry.isDirectory() && entry.name === "subagents") {
@@ -28234,16 +28736,16 @@ var WebchatGateway = class _WebchatGateway {
28234
28736
  * The public /api/chat route awaits this to return the reply on the same SSE
28235
28737
  * response, preserving the pre-756 POST→single-blob browser contract. */
28236
28738
  awaitReply(key, timeoutMs) {
28237
- return new Promise((resolve45) => {
28739
+ return new Promise((resolve46) => {
28238
28740
  const timer = setTimeout(() => {
28239
28741
  this.replyAwaiters.delete(key);
28240
- resolve45({ timeout: true });
28742
+ resolve46({ timeout: true });
28241
28743
  }, timeoutMs);
28242
28744
  if (timer.unref) timer.unref();
28243
28745
  this.replyAwaiters.set(key, (r) => {
28244
28746
  clearTimeout(timer);
28245
28747
  this.replyAwaiters.delete(key);
28246
- resolve45(r);
28748
+ resolve46(r);
28247
28749
  });
28248
28750
  });
28249
28751
  }
@@ -28254,11 +28756,11 @@ var WebchatGateway = class _WebchatGateway {
28254
28756
  * terminal dialog stays answerable). */
28255
28757
  awaitPermissionVerdict(p, timeoutMs) {
28256
28758
  const k = _WebchatGateway.promptKey(p.key, p.requestId);
28257
- return new Promise((resolve45) => {
28759
+ return new Promise((resolve46) => {
28258
28760
  this.pendingPrompts.get(k)?.resolve({ timeout: true });
28259
28761
  const timer = setTimeout(() => {
28260
28762
  this.pendingPrompts.delete(k);
28261
- resolve45({ timeout: true });
28763
+ resolve46({ timeout: true });
28262
28764
  }, timeoutMs);
28263
28765
  if (timer.unref) timer.unref();
28264
28766
  this.pendingPrompts.set(k, {
@@ -28267,7 +28769,7 @@ var WebchatGateway = class _WebchatGateway {
28267
28769
  resolve: (r) => {
28268
28770
  clearTimeout(timer);
28269
28771
  this.pendingPrompts.delete(k);
28270
- resolve45(r);
28772
+ resolve46(r);
28271
28773
  }
28272
28774
  });
28273
28775
  console.error(`[webchat:perm] op=open key=${keyDisplay(p.key)} id=${p.requestId} tool=${p.toolName}`);
@@ -28832,7 +29334,7 @@ async function fanOut(subscribers, text, onError, tag) {
28832
29334
 
28833
29335
  // app/lib/webchat/file-delivery.ts
28834
29336
  import { realpathSync as realpathSync9 } from "fs";
28835
- import { resolve as resolve40 } from "path";
29337
+ import { resolve as resolve41 } from "path";
28836
29338
 
28837
29339
  // app/lib/channel-pty-bridge/file-delivery.ts
28838
29340
  var SEND_USER_FILE = "SendUserFile";
@@ -28933,7 +29435,7 @@ function makeWebchatSendFile(entry) {
28933
29435
  console.error(`${TAG53} file-delivery reject reason=no-account sender=${entry.senderId}`);
28934
29436
  return { ok: false, error: "no-account" };
28935
29437
  }
28936
- const accountDir = resolve40(platformRoot2(), "..", "data/accounts", entry.accountId);
29438
+ const accountDir = resolve41(platformRoot2(), "..", "data/accounts", entry.accountId);
28937
29439
  try {
28938
29440
  const resolved = realpathSync9(filePath);
28939
29441
  const accountResolved = realpathSync9(accountDir);
@@ -29497,7 +29999,7 @@ function buildTelegramSpawnRequest(input) {
29497
29999
  // app/lib/telegram/outbound/send-document.ts
29498
30000
  import { realpathSync as realpathSync10 } from "fs";
29499
30001
  import { readFile as readFile11, stat as stat10 } from "fs/promises";
29500
- import { resolve as resolve41, basename as basename13 } from "path";
30002
+ import { resolve as resolve42, basename as basename13 } from "path";
29501
30003
  var TAG55 = "[telegram:outbound]";
29502
30004
  var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
29503
30005
  async function sendTelegramDocument(input) {
@@ -29508,7 +30010,7 @@ async function sendTelegramDocument(input) {
29508
30010
  if (!maxyAccountId || !platformRoot5) {
29509
30011
  return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
29510
30012
  }
29511
- const accountDir = resolve41(platformRoot5, "..", "data/accounts", maxyAccountId);
30013
+ const accountDir = resolve42(platformRoot5, "..", "data/accounts", maxyAccountId);
29512
30014
  let accountResolved;
29513
30015
  try {
29514
30016
  accountResolved = realpathSync10(accountDir);
@@ -29800,11 +30302,11 @@ async function firePublicSessionEndReview(input) {
29800
30302
  }
29801
30303
 
29802
30304
  // app/lib/whatsapp/inbound/resolve-client-graph-owner.ts
29803
- var import_dist7 = __toESM(require_dist(), 1);
30305
+ var import_dist8 = __toESM(require_dist(), 1);
29804
30306
  async function resolveClientOwnerUserId(accountId, deps = {}) {
29805
30307
  const listAccounts = deps.listAccounts ?? listValidAccounts;
29806
30308
  const getSession4 = deps.getSession ?? getSession;
29807
- const resolveOwner2 = deps.resolveOwner ?? import_dist7.resolveOwnerUserId;
30309
+ const resolveOwner2 = deps.resolveOwner ?? import_dist8.resolveOwnerUserId;
29808
30310
  const role = listAccounts().find((a) => a.accountId === accountId)?.config.role;
29809
30311
  if (role !== "client") return null;
29810
30312
  const session = getSession4();
@@ -29901,10 +30403,10 @@ function warnOnChannelAdminBindingDrift() {
29901
30403
 
29902
30404
  // server/lib/booking-site-accounts.ts
29903
30405
  import { existsSync as existsSync44, readFileSync as readFileSync45 } from "fs";
29904
- import { resolve as resolve42 } from "path";
30406
+ import { resolve as resolve43 } from "path";
29905
30407
  function listBookingSiteAccounts(accounts) {
29906
30408
  return accounts.filter((a) => {
29907
- const availPath = resolve42(a.accountDir, "calendar-availability.json");
30409
+ const availPath = resolve43(a.accountDir, "calendar-availability.json");
29908
30410
  if (!existsSync44(availPath)) return false;
29909
30411
  try {
29910
30412
  const cfg = JSON.parse(readFileSync45(availPath, "utf-8"));
@@ -29946,7 +30448,7 @@ function broadcastAdminShutdown(reason) {
29946
30448
  // ../lib/entitlement/src/index.ts
29947
30449
  import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
29948
30450
  import { existsSync as existsSync45, readFileSync as readFileSync46, statSync as statSync19 } from "fs";
29949
- import { resolve as resolve43 } from "path";
30451
+ import { resolve as resolve44 } from "path";
29950
30452
 
29951
30453
  // ../lib/entitlement/src/canonicalize.ts
29952
30454
  function canonicalize(value) {
@@ -29981,7 +30483,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
29981
30483
  var GRACE_DAYS = 7;
29982
30484
  var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
29983
30485
  function pubkeyPath(brand) {
29984
- return resolve43(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
30486
+ return resolve44(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
29985
30487
  }
29986
30488
  var memo = null;
29987
30489
  function memoKey(mtimeMs, account) {
@@ -29993,7 +30495,7 @@ function resolveEntitlement(brand, account) {
29993
30495
  if (brand.commercialMode !== true) {
29994
30496
  return logResolved(implicitTrust(account), null);
29995
30497
  }
29996
- const entitlementPath = resolve43(brand.configDir, "entitlement.json");
30498
+ const entitlementPath = resolve44(brand.configDir, "entitlement.json");
29997
30499
  if (!existsSync45(entitlementPath)) {
29998
30500
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
29999
30501
  }
@@ -30249,6 +30751,7 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
30249
30751
  aliasDomains = updated;
30250
30752
  console.log(`[alias-domains] reloaded ${updated.size} alias domain(s): ${[...updated].join(", ")}`);
30251
30753
  });
30754
+ attachRouteCacheWatchers();
30252
30755
  function isPublicHost(host) {
30253
30756
  return host.startsWith("public.") || aliasDomains.has(host);
30254
30757
  }
@@ -30266,8 +30769,8 @@ var webchatFileFollowers = /* @__PURE__ */ new Map();
30266
30769
  async function fetchAccountStandingRules(accountId) {
30267
30770
  const session = getSession();
30268
30771
  try {
30269
- const res = await (0, import_dist8.resolveActiveRules)(session, accountId);
30270
- return { block: (0, import_dist8.formatStandingRulesBlock)(res.rules), ownerUserId: res.ownerUserId, source: res.source };
30772
+ const res = await (0, import_dist9.resolveActiveRules)(session, accountId);
30773
+ return { block: (0, import_dist9.formatStandingRulesBlock)(res.rules), ownerUserId: res.ownerUserId, source: res.source };
30271
30774
  } catch (err) {
30272
30775
  console.error(
30273
30776
  `[preference-inject] op=fetch-failed accountId=${accountId} error=${err instanceof Error ? err.message : String(err)}`
@@ -30301,7 +30804,7 @@ var waGateway = new WaGateway({
30301
30804
  fetchStandingRules: fetchAccountStandingRules,
30302
30805
  resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
30303
30806
  gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
30304
- serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve44(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
30807
+ serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
30305
30808
  // Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
30306
30809
  // path-validation scope) is the sender's effective SESSION account, resolved
30307
30810
  // once at the inbound gate and threaded here via the gateway's per-sender doc
@@ -30316,7 +30819,7 @@ var waGateway = new WaGateway({
30316
30819
  caption,
30317
30820
  accountId,
30318
30821
  maxyAccountId,
30319
- platformRoot: resolve44(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."))
30822
+ platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."))
30320
30823
  });
30321
30824
  return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
30322
30825
  },
@@ -30996,8 +31499,8 @@ app69.get("/agent-assets/:slug/:filename", (c) => {
30996
31499
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
30997
31500
  return c.text("Not found", 404);
30998
31501
  }
30999
- const filePath = resolve44(account.accountDir, "agents", slug, "assets", filename);
31000
- const expectedDir = resolve44(account.accountDir, "agents", slug, "assets");
31502
+ const filePath = resolve45(account.accountDir, "agents", slug, "assets", filename);
31503
+ const expectedDir = resolve45(account.accountDir, "agents", slug, "assets");
31001
31504
  if (!filePath.startsWith(expectedDir + "/")) {
31002
31505
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
31003
31506
  return c.text("Forbidden", 403);
@@ -31026,8 +31529,8 @@ app69.get("/generated/:filename", (c) => {
31026
31529
  console.error(`[generated] serve file=${filename} status=404`);
31027
31530
  return c.text("Not found", 404);
31028
31531
  }
31029
- const filePath = resolve44(account.accountDir, "generated", filename);
31030
- const expectedDir = resolve44(account.accountDir, "generated");
31532
+ const filePath = resolve45(account.accountDir, "generated", filename);
31533
+ const expectedDir = resolve45(account.accountDir, "generated");
31031
31534
  if (!filePath.startsWith(expectedDir + "/")) {
31032
31535
  console.error(`[generated] serve file=${filename} status=403`);
31033
31536
  return c.text("Forbidden", 403);
@@ -31081,11 +31584,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
31081
31584
  var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
31082
31585
  var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
31083
31586
  var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
31084
- (p) => existsSync46(resolve44(process.cwd(), "public", p.replace(/^\//, "")))
31587
+ (p) => existsSync46(resolve45(process.cwd(), "public", p.replace(/^\//, "")))
31085
31588
  );
31086
31589
  var SW_SOURCE = (() => {
31087
31590
  try {
31088
- return readFileSync47(resolve44(process.cwd(), "public", "sw.js"), "utf-8");
31591
+ return readFileSync47(resolve45(process.cwd(), "public", "sw.js"), "utf-8");
31089
31592
  } catch {
31090
31593
  return null;
31091
31594
  }
@@ -31136,7 +31639,7 @@ var clientErrorReporterScript = `<script>
31136
31639
  function cachedHtml(file) {
31137
31640
  let html = htmlCache.get(file);
31138
31641
  if (!html) {
31139
- html = readFileSync47(resolve44(process.cwd(), "public", file), "utf-8");
31642
+ html = readFileSync47(resolve45(process.cwd(), "public", file), "utf-8");
31140
31643
  const productNameEsc = escapeHtml(BRAND.productName);
31141
31644
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
31142
31645
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -31254,7 +31757,7 @@ app69.use("/vnc-popout.html", logViewerFetch);
31254
31757
  app69.get("/vnc-popout.html", (c) => {
31255
31758
  let html = htmlCache.get("vnc-popout.html");
31256
31759
  if (!html) {
31257
- html = readFileSync47(resolve44(process.cwd(), "public", "vnc-popout.html"), "utf-8");
31760
+ html = readFileSync47(resolve45(process.cwd(), "public", "vnc-popout.html"), "utf-8");
31258
31761
  const name = escapeHtml(BRAND.productName);
31259
31762
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
31260
31763
  html = html.replace("</head>", ` ${brandScript}
@@ -31407,7 +31910,7 @@ var httpServer = serve({ fetch: app69.fetch, port, hostname });
31407
31910
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31408
31911
  {
31409
31912
  const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31410
- const reconcileScript = resolve44(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
31913
+ const reconcileScript = resolve45(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
31411
31914
  const runReconcile = (ctx) => {
31412
31915
  if (!existsSync46(reconcileScript)) return;
31413
31916
  try {
@@ -31448,7 +31951,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31448
31951
  {
31449
31952
  const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
31450
31953
  const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31451
- const dreamSweepScript = resolve44(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
31954
+ const dreamSweepScript = resolve45(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
31452
31955
  registerLoop({
31453
31956
  name: "dream-cycle-sweep",
31454
31957
  intervalMs: DREAM_CYCLE_SWEEP_INTERVAL_MS,
@@ -31472,7 +31975,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31472
31975
  }
31473
31976
  {
31474
31977
  const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31475
- const outlookScript = resolve44(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
31978
+ const outlookScript = resolve45(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
31476
31979
  const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
31477
31980
  const runOutlookComplete = (ctx) => {
31478
31981
  if (!existsSync46(outlookScript)) return;
@@ -31498,7 +32001,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31498
32001
  }
31499
32002
  {
31500
32003
  const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31501
- const strandedAccountsDir = resolve44(auditRoot, "..", "data/accounts");
32004
+ const strandedAccountsDir = resolve45(auditRoot, "..", "data/accounts");
31502
32005
  const STRANDED_AUDIT_INTERVAL_MS = 3e5;
31503
32006
  const STRANDED_AGE_MS = 16 * 6e4;
31504
32007
  const STRANDED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
@@ -31508,7 +32011,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31508
32011
  const now = Date.now();
31509
32012
  for (const name of readdirSync28(strandedAccountsDir)) {
31510
32013
  if (!STRANDED_UUID_RE.test(name)) continue;
31511
- const pendingPath2 = resolve44(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
32014
+ const pendingPath2 = resolve45(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
31512
32015
  if (!existsSync46(pendingPath2)) continue;
31513
32016
  const ageMs2 = now - statSync20(pendingPath2).mtimeMs;
31514
32017
  if (ageMs2 > STRANDED_AGE_MS) {
@@ -31528,7 +32031,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31528
32031
  }
31529
32032
  {
31530
32033
  const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31531
- const googleAccountsDir = resolve44(googleRoot, "..", "data/accounts");
32034
+ const googleAccountsDir = resolve45(googleRoot, "..", "data/accounts");
31532
32035
  const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
31533
32036
  const runGooglePendingAuditSafe = () => {
31534
32037
  try {
@@ -31543,7 +32046,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31543
32046
  firstRunDelayMs: 27e3,
31544
32047
  run: runGooglePendingAuditSafe
31545
32048
  });
31546
- const googleAuditScript = resolve44(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
32049
+ const googleAuditScript = resolve45(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
31547
32050
  const GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS = 36e5;
31548
32051
  const runGoogleAccountAudit = (ctx) => {
31549
32052
  if (!existsSync46(googleAuditScript)) return;
@@ -31618,7 +32121,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31618
32121
  }
31619
32122
  {
31620
32123
  const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31621
- const publishScript = resolve44(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
32124
+ const publishScript = resolve45(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
31622
32125
  const PUBLISH_INTERVAL_MS = 3e5;
31623
32126
  const bookingAccounts = () => {
31624
32127
  try {
@@ -31648,7 +32151,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31648
32151
  }
31649
32152
  };
31650
32153
  const auditSnapshotAge = (account) => {
31651
- const availPath = resolve44(account.accountDir, "calendar-availability.json");
32154
+ const availPath = resolve45(account.accountDir, "calendar-availability.json");
31652
32155
  let hasBookingSite = false;
31653
32156
  try {
31654
32157
  if (existsSync46(availPath)) {
@@ -31658,7 +32161,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31658
32161
  } catch {
31659
32162
  }
31660
32163
  if (!hasBookingSite) return;
31661
- const statePath = resolve44(account.accountDir, "state", "booking-availability", "last-publish.json");
32164
+ const statePath = resolve45(account.accountDir, "state", "booking-availability", "last-publish.json");
31662
32165
  let lastSuccessAt = null;
31663
32166
  if (existsSync46(statePath)) {
31664
32167
  try {
@@ -31695,7 +32198,7 @@ startTimeEntryCensus(() => getSession());
31695
32198
  startLedgerCensus(() => getSession());
31696
32199
  {
31697
32200
  const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31698
- const auditScript = resolve44(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
32201
+ const auditScript = resolve45(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
31699
32202
  const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
31700
32203
  const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
31701
32204
  const runConnectorAudit = (ctx) => {
@@ -32004,7 +32507,7 @@ if (bootAccountConfig?.whatsapp) {
32004
32507
  }
32005
32508
  init({
32006
32509
  configDir: configDirForWhatsApp,
32007
- platformRoot: resolve44(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..")),
32510
+ platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..")),
32008
32511
  accountConfig: bootAccountConfig,
32009
32512
  onMessage: async (msg) => {
32010
32513
  if (isObserveAccount(msg.accountId)) {