@rubytech/create-maxy-code 0.1.504 → 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 (105) 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/lib/models/dist/index.d.ts +5 -5
  10. package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
  11. package/payload/platform/lib/models/dist/index.js +7 -7
  12. package/payload/platform/lib/models/dist/index.js.map +1 -1
  13. package/payload/platform/lib/models/src/index.ts +7 -7
  14. package/payload/platform/package.json +3 -3
  15. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +83 -28
  16. package/payload/platform/plugins/admin/skills/public-agent-manager/SKILL.md +5 -5
  17. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +12 -0
  18. package/payload/platform/plugins/docs/references/admin-session.md +1 -1
  19. package/payload/platform/plugins/docs/references/admin-ui.md +82 -27
  20. package/payload/platform/plugins/work/mcp/dist/__tests__/session-metering.test.js +2 -2
  21. package/payload/platform/plugins/work/mcp/dist/__tests__/session-metering.test.js.map +1 -1
  22. package/payload/platform/plugins/work/mcp/dist/index.js +1 -1
  23. package/payload/platform/plugins/work/mcp/dist/index.js.map +1 -1
  24. package/payload/platform/plugins/work/mcp/dist/tools/session-metering.js +2 -2
  25. package/payload/platform/plugins/work/mcp/dist/tools/session-metering.js.map +1 -1
  26. package/payload/platform/scripts/check-no-esm-require.mjs +5 -0
  27. package/payload/platform/scripts/logs-read-jsonl.test.sh +1 -1
  28. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts +1 -1
  29. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
  30. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +50 -3
  31. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
  32. package/payload/platform/services/claude-session-manager/dist/http-server.js +2 -2
  33. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  34. package/payload/platform/services/claude-session-manager/dist/pricing.d.ts +19 -11
  35. package/payload/platform/services/claude-session-manager/dist/pricing.d.ts.map +1 -1
  36. package/payload/platform/services/claude-session-manager/dist/pricing.js +18 -15
  37. package/payload/platform/services/claude-session-manager/dist/pricing.js.map +1 -1
  38. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +1 -1
  39. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  40. package/payload/platform/services/claude-session-manager/dist/session-metering.js +3 -3
  41. package/payload/platform/services/claude-session-manager/dist/session-metering.js.map +1 -1
  42. package/payload/platform/templates/account.json +1 -1
  43. package/payload/platform/templates/specialists/agents/coding-assistant.md +1 -1
  44. package/payload/platform/templates/specialists/agents/content-producer.md +1 -1
  45. package/payload/platform/templates/specialists/agents/librarian.md +1 -1
  46. package/payload/platform/templates/specialists/agents/research-assistant.md +1 -1
  47. package/payload/server/{chunk-HN4HFTXE.js → chunk-5ADBNEJA.js} +1410 -1409
  48. package/payload/server/maxy-edge.js +1 -1
  49. package/payload/server/public/activity.html +5 -5
  50. package/payload/server/public/agents.html +4 -4
  51. package/payload/server/public/assets/{AdminLoginScreens-DWMR4KtI.js → AdminLoginScreens-D5KOQA8S.js} +1 -1
  52. package/payload/server/public/assets/AdminShell-C8wazpnz.js +2 -0
  53. package/payload/server/public/assets/{activity-DH3z4cv3.js → activity-CFqkDhTs.js} +1 -1
  54. package/payload/server/public/assets/admin-B-EGUWS4.js +1 -0
  55. package/payload/server/public/assets/agents-DPulfmrd.js +1 -0
  56. package/payload/server/public/assets/{browser-C_MJYN5k.js → browser-T_5xbnJh.js} +1 -1
  57. package/payload/server/public/assets/{calendar-DA0h7dqW.js → calendar-CKjuiG8c.js} +1 -1
  58. package/payload/server/public/assets/chat-DWLYAA70.js +1 -0
  59. package/payload/server/public/assets/chevron-left-DBMCTKlT.js +1 -0
  60. package/payload/server/public/assets/chevron-right-SBAr6zzc.js +1 -0
  61. package/payload/server/public/assets/clock-kkzt7Scf.js +1 -0
  62. package/payload/server/public/assets/data-CV8N9qcy.js +1 -0
  63. package/payload/server/public/assets/{file-text-RCoSeOpD.js → file-text-c6cA4Evd.js} +1 -1
  64. package/payload/server/public/assets/graph-DIk-o45J.js +51 -0
  65. package/payload/server/public/assets/{graph-labels-DJV0aIG5.js → graph-labels-5bjxhC_p.js} +1 -1
  66. package/payload/server/public/assets/{maximize-2-DcESsKbu.js → maximize-2-BCQkFb1_.js} +1 -1
  67. package/payload/server/public/assets/{operator-Dlkw1sXJ.js → operator-0UnNo2ms.js} +1 -1
  68. package/payload/server/public/assets/page-HVtUfub2.js +32 -0
  69. package/payload/server/public/assets/page-JJa2xdzf.js +1 -0
  70. package/payload/server/public/assets/{public-C-UHWk_S.js → public-CKEYyIPn.js} +1 -1
  71. package/payload/server/public/assets/{rotate-ccw-C1nRSAzP.js → rotate-ccw-dTpO5dhL.js} +1 -1
  72. package/payload/server/public/assets/{routines-qdAZ0sA4.js → routines-C6P1-Dto.js} +1 -1
  73. package/payload/server/public/assets/{skills-B78wr822.js → skills-ClrpVqlz.js} +1 -1
  74. package/payload/server/public/assets/tasks-C8SNhSFC.js +1 -0
  75. package/payload/server/public/assets/{time-entry-format-BhlltPP8.js → time-entry-format-CCO6N6XZ.js} +1 -1
  76. package/payload/server/public/assets/{triangle-alert-rEVGyIhi.js → triangle-alert-CHjdKpag.js} +1 -1
  77. package/payload/server/public/assets/{useCopyFeedback-DzpXjm9d.js → useCopyFeedback-BTUu3-l8.js} +1 -1
  78. package/payload/server/public/assets/{useSubAccountSwitcher-DVmWZxar.js → useSubAccountSwitcher-DSW9vDi2.js} +1 -1
  79. package/payload/server/public/assets/{useSubAccountSwitcher-wP8cOzPj.css → useSubAccountSwitcher-DyrH8DA8.css} +1 -1
  80. package/payload/server/public/assets/{useVoiceRecorder-CRRmPjYr.js → useVoiceRecorder-BeNqxmm2.js} +1 -1
  81. package/payload/server/public/assets/{wrench-oeLti270.js → wrench-CeNnc7oO.js} +1 -1
  82. package/payload/server/public/browser.html +4 -4
  83. package/payload/server/public/calendar.html +7 -7
  84. package/payload/server/public/chat.html +13 -13
  85. package/payload/server/public/data.html +11 -11
  86. package/payload/server/public/graph.html +9 -9
  87. package/payload/server/public/index.html +14 -14
  88. package/payload/server/public/operator.html +14 -14
  89. package/payload/server/public/public.html +13 -13
  90. package/payload/server/public/routines.html +6 -6
  91. package/payload/server/public/skills.html +5 -5
  92. package/payload/server/public/tasks.html +6 -6
  93. package/payload/server/server.js +1395 -812
  94. package/payload/server/public/assets/AdminShell-C8hBpL9K.js +0 -2
  95. package/payload/server/public/assets/admin-aaGhd2Yh.js +0 -1
  96. package/payload/server/public/assets/agents-SPu-clsf.js +0 -1
  97. package/payload/server/public/assets/chat-Bg7dlM0I.js +0 -1
  98. package/payload/server/public/assets/chevron-left-BoDA12H8.js +0 -1
  99. package/payload/server/public/assets/chevron-right-DXjrO6qA.js +0 -1
  100. package/payload/server/public/assets/clock-BceBgZP1.js +0 -1
  101. package/payload/server/public/assets/data-rNLaurgY.js +0 -1
  102. package/payload/server/public/assets/graph-Dm-YZeNP.js +0 -51
  103. package/payload/server/public/assets/page-Dl-mgQUu.js +0 -32
  104. package/payload/server/public/assets/page-DoyJrk8E.js +0 -1
  105. package/payload/server/public/assets/tasks-DbIsS-vW.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);
@@ -4518,95 +4821,23 @@ async function ensureWhatsAppConversation(input) {
4518
4821
  );
4519
4822
  return null;
4520
4823
  }
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
- );
4584
- }
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");
4593
- }
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 };
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 });
@@ -13578,7 +13826,7 @@ function writeCanonicalOverrideId(accountDir, userId, sessionId) {
13578
13826
  }
13579
13827
 
13580
13828
  // ../lib/models/src/index.ts
13581
- var OPUS_MODEL = "claude-opus-4-8[1m]";
13829
+ var OPUS_MODEL = "claude-opus-5[1m]";
13582
13830
  var SONNET_MODEL = "claude-sonnet-5";
13583
13831
  var HAIKU_MODEL = "claude-haiku-4-5";
13584
13832
  var MODEL_CONTEXT_WINDOW = {
@@ -13590,7 +13838,7 @@ function contextWindow(model) {
13590
13838
  return MODEL_CONTEXT_WINDOW[model] ?? 2e5;
13591
13839
  }
13592
13840
  var MODEL_DISPLAY_NAMES = {
13593
- [OPUS_MODEL]: "Opus 4.8 (1M context)",
13841
+ [OPUS_MODEL]: "Opus 5 (1M context)",
13594
13842
  [SONNET_MODEL]: "Sonnet 5",
13595
13843
  [HAIKU_MODEL]: "Haiku 4.5"
13596
13844
  };
@@ -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,9 +16415,91 @@ 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("\\");
16448
+ function subdirs(dir) {
16449
+ if (!existsSync30(dir)) return [];
16450
+ try {
16451
+ return readdirSync21(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
16452
+ } catch {
16453
+ return [];
16454
+ }
16455
+ }
16456
+ function splitFrontmatter(text) {
16457
+ const m = text.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/);
16458
+ const fm = {};
16459
+ if (!m) return { fm, body: text };
16460
+ for (const line of m[1].split(/\r?\n/)) {
16461
+ const kv = line.match(/^([A-Za-z][\w-]*):[ \t]*(.*)$/);
16462
+ if (kv) fm[kv[1]] = kv[2].trim().replace(/^["']|["']$/g, "").trim();
16463
+ }
16464
+ return { fm, body: text.slice(m[0].length) };
16465
+ }
16466
+ function listSpecialists(accountDir) {
16467
+ const pluginsDir = resolve23(accountDir, "plugins");
16468
+ const specialists = [];
16469
+ let specialistsSkipped = 0;
16470
+ for (const plugin of subdirs(pluginsDir).sort()) {
16471
+ const agentsDirP = resolve23(pluginsDir, plugin, "agents");
16472
+ if (!existsSync30(agentsDirP)) continue;
16473
+ let entries2;
16474
+ try {
16475
+ entries2 = readdirSync21(agentsDirP, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
16476
+ } catch {
16477
+ continue;
16478
+ }
16479
+ for (const entry of entries2) {
16480
+ if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
16481
+ try {
16482
+ const { fm } = splitFrontmatter(readFileSync32(resolve23(agentsDirP, entry.name), "utf-8"));
16483
+ if (!fm.name) {
16484
+ specialistsSkipped++;
16485
+ console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry.name}`);
16486
+ continue;
16487
+ }
16488
+ specialists.push({
16489
+ slug: entry.name.replace(/\.md$/, ""),
16490
+ displayName: fm.name,
16491
+ kind: "specialist",
16492
+ plugin,
16493
+ description: fm.description ?? ""
16494
+ });
16495
+ } catch {
16496
+ specialistsSkipped++;
16497
+ console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry.name}`);
16498
+ }
16499
+ }
16500
+ }
16501
+ return { specialists, specialistsSkipped };
16502
+ }
16173
16503
  var OWNED_DOCS = [
16174
16504
  { file: "IDENTITY.md", key: "identity" },
16175
16505
  { file: "SOUL.md", key: "soul" },
@@ -16177,46 +16507,76 @@ var OWNED_DOCS = [
16177
16507
  { file: "KNOWLEDGE-SUMMARY.md", key: "knowledgeSummary" }
16178
16508
  ];
16179
16509
  var app18 = new Hono();
16180
- app18.get("/", (c) => {
16181
- const account = resolveAccount();
16182
- if (!account) return c.json({ agents: [], skipped: 0 });
16183
- const agentsDir = resolve22(account.accountDir, "agents");
16184
- if (!existsSync30(agentsDir)) return c.json({ agents: [], skipped: 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
+ }
16185
16516
  const agents = [];
16186
16517
  let skipped = 0;
16187
- try {
16188
- const entries = readdirSync21(agentsDir, { withFileTypes: true });
16189
- for (const entry of entries.sort((a, b) => a.name.localeCompare(b.name))) {
16190
- if (!entry.isDirectory()) continue;
16191
- if (entry.name === "admin") continue;
16192
- const configPath2 = resolve22(agentsDir, entry.name, "config.json");
16193
- if (!existsSync30(configPath2)) continue;
16194
- try {
16195
- const config = JSON.parse(readFileSync32(configPath2, "utf-8"));
16196
- agents.push({
16197
- slug: entry.name,
16198
- displayName: config.displayName ?? entry.name,
16199
- status: config.status ?? "unknown"
16200
- });
16201
- } catch {
16202
- skipped++;
16203
- console.error(`[admin/agents] failed to parse config.json for agent "${entry.name}" \u2014 skipping`);
16518
+ const agentsDir = resolve23(account.accountDir, "agents");
16519
+ if (existsSync30(agentsDir)) {
16520
+ try {
16521
+ const entries2 = readdirSync21(agentsDir, { withFileTypes: true });
16522
+ for (const entry of entries2.sort((a, b) => a.name.localeCompare(b.name))) {
16523
+ if (!entry.isDirectory()) continue;
16524
+ if (entry.name === "admin") continue;
16525
+ const configPath2 = resolve23(agentsDir, entry.name, "config.json");
16526
+ if (!existsSync30(configPath2)) continue;
16527
+ try {
16528
+ const config = JSON.parse(readFileSync32(configPath2, "utf-8"));
16529
+ agents.push({
16530
+ slug: entry.name,
16531
+ displayName: config.displayName ?? entry.name,
16532
+ status: config.status ?? "unknown",
16533
+ kind: "public"
16534
+ });
16535
+ } catch {
16536
+ skipped++;
16537
+ console.error(`[admin/agents] failed to parse config.json for agent "${entry.name}" \u2014 skipping`);
16538
+ }
16204
16539
  }
16540
+ } catch (err) {
16541
+ console.error(`[admin/agents] failed to scan agents directory: ${err}`);
16205
16542
  }
16206
- } catch (err) {
16207
- console.error(`[admin/agents] failed to scan agents directory: ${err}`);
16208
- return c.json({ agents: [], skipped: 0 });
16209
16543
  }
16210
- console.log(`[admin/agents] op=list agents=${agents.length} skipped=${skipped}`);
16211
- return c.json({ agents, skipped });
16544
+ const { specialists, specialistsSkipped } = listSpecialists(account.accountDir);
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 });
16212
16547
  });
16213
- app18.get("/:slug", (c) => {
16548
+ app18.get("/:slug", requireAdminSession, (c) => {
16214
16549
  const slug = c.req.param("slug");
16215
- const account = resolveAccount();
16216
- 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
+ }
16217
16555
  if (SLUG_UNSAFE(slug)) return c.json({ error: "Invalid agent slug" }, 400);
16218
- const agentDir = resolve22(account.accountDir, "agents", slug);
16219
- const configPath2 = resolve22(agentDir, "config.json");
16556
+ const pluginParam = c.req.query("plugin");
16557
+ if (pluginParam) {
16558
+ if (SLUG_UNSAFE(pluginParam)) return c.json({ error: "Invalid plugin" }, 400);
16559
+ const file = resolve23(account.accountDir, "plugins", pluginParam, "agents", `${slug}.md`);
16560
+ if (!existsSync30(file)) return c.json({ error: "Agent not found" }, 404);
16561
+ const { fm, body } = splitFrontmatter(readFileSync32(file, "utf-8"));
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}`);
16564
+ return c.json({
16565
+ agent: {
16566
+ kind: "specialist",
16567
+ slug,
16568
+ displayName: fm.name ?? slug,
16569
+ description: fm.description ?? "",
16570
+ summary: fm.summary ?? "",
16571
+ model: fm.model ?? null,
16572
+ tools: fm.tools ? fm.tools.split(",").map((t) => t.trim()).filter(Boolean) : [],
16573
+ systemPrompt: body.trim(),
16574
+ skills
16575
+ }
16576
+ });
16577
+ }
16578
+ const agentDir = resolve23(account.accountDir, "agents", slug);
16579
+ const configPath2 = resolve23(agentDir, "config.json");
16220
16580
  if (!existsSync30(configPath2)) return c.json({ error: "Agent not found" }, 404);
16221
16581
  let config;
16222
16582
  try {
@@ -16228,7 +16588,7 @@ app18.get("/:slug", (c) => {
16228
16588
  const docs = {};
16229
16589
  const present = {};
16230
16590
  for (const { file, key } of OWNED_DOCS) {
16231
- const p = resolve22(agentDir, file);
16591
+ const p = resolve23(agentDir, file);
16232
16592
  try {
16233
16593
  if (existsSync30(p)) {
16234
16594
  docs[key] = readFileSync32(p, "utf-8");
@@ -16244,7 +16604,7 @@ app18.get("/:slug", (c) => {
16244
16604
  }
16245
16605
  }
16246
16606
  const found = Object.keys(present).filter((k) => present[k]);
16247
- 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"}`);
16248
16608
  return c.json({
16249
16609
  agent: {
16250
16610
  slug,
@@ -16262,15 +16622,28 @@ app18.get("/:slug", (c) => {
16262
16622
  });
16263
16623
  app18.delete("/:slug", async (c) => {
16264
16624
  const slug = c.req.param("slug");
16265
- const account = resolveAccount();
16266
- if (!account) return c.json({ error: "No account resolved" }, 400);
16267
16625
  if (slug === "admin") {
16268
16626
  return c.json({ error: "Cannot delete the admin agent" }, 403);
16269
16627
  }
16270
16628
  if (SLUG_UNSAFE(slug)) {
16271
16629
  return c.json({ error: "Invalid agent slug" }, 400);
16272
16630
  }
16273
- 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);
16274
16647
  if (!existsSync30(agentDir)) {
16275
16648
  return c.json({ error: "Agent not found" }, 404);
16276
16649
  }
@@ -16278,29 +16651,42 @@ app18.delete("/:slug", async (c) => {
16278
16651
  await deleteAgentProjection(account.accountId, slug);
16279
16652
  } catch (err) {
16280
16653
  const msg = err instanceof Error ? err.message : String(err);
16281
- 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`);
16282
16655
  return c.json({ error: `Graph cleanup failed: ${msg}` }, 500);
16283
16656
  }
16284
16657
  try {
16285
16658
  rmSync2(agentDir, { recursive: true, force: true });
16286
- console.log(`[admin/agents] deleted agent "${slug}"`);
16659
+ console.log(`[admin/agents] op=delete accountId=${account.accountId.slice(0, 8)} slug=${slug} outcome=ok`);
16287
16660
  return c.json({ ok: true });
16288
16661
  } catch (err) {
16289
- 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}"`);
16290
16663
  return c.json({ error: "Failed to delete agent" }, 500);
16291
16664
  }
16292
16665
  });
16293
16666
  app18.post("/:slug/project", async (c) => {
16294
16667
  const slug = c.req.param("slug");
16295
- const account = resolveAccount();
16296
- if (!account) return c.json({ error: "No account resolved" }, 400);
16297
16668
  if (slug === "admin") {
16298
16669
  return c.json({ error: "Cannot project the admin agent" }, 403);
16299
16670
  }
16300
16671
  if (SLUG_UNSAFE(slug)) {
16301
16672
  return c.json({ error: "Invalid agent slug" }, 400);
16302
16673
  }
16303
- 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);
16304
16690
  if (!existsSync30(agentDir)) {
16305
16691
  return c.json({ error: "Agent not found on disk" }, 404);
16306
16692
  }
@@ -17004,7 +17390,7 @@ var sessions_default = app19;
17004
17390
 
17005
17391
  // app/lib/claude-agent/spawn-context.ts
17006
17392
  import { existsSync as existsSync32, readFileSync as readFileSync33, readdirSync as readdirSync22, statSync as statSync15 } from "fs";
17007
- 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";
17008
17394
  async function resolveOwnerProfileBlock(accountId, userId) {
17009
17395
  if (!userId) return { ok: false, reason: "missing-user-id" };
17010
17396
  try {
@@ -17101,7 +17487,7 @@ function parseSkillPathsFromFrontmatter(fm) {
17101
17487
  }
17102
17488
  function listPluginDirs(accountPluginsDir) {
17103
17489
  const out = /* @__PURE__ */ new Map();
17104
- const platformPlugins = resolve23(PLATFORM_ROOT, "plugins");
17490
+ const platformPlugins = resolve24(PLATFORM_ROOT, "plugins");
17105
17491
  if (existsSync32(platformPlugins)) {
17106
17492
  for (const name of readdirSync22(platformPlugins)) {
17107
17493
  const dir = join33(platformPlugins, name);
@@ -17111,7 +17497,7 @@ function listPluginDirs(accountPluginsDir) {
17111
17497
  }
17112
17498
  }
17113
17499
  }
17114
- const premiumRoot = resolve23(dirname12(PLATFORM_ROOT), "premium-plugins");
17500
+ const premiumRoot = resolve24(dirname12(PLATFORM_ROOT), "premium-plugins");
17115
17501
  if (existsSync32(premiumRoot)) {
17116
17502
  for (const bundle of readdirSync22(premiumRoot)) {
17117
17503
  const bundlePlugins = join33(premiumRoot, bundle, "plugins");
@@ -17144,7 +17530,7 @@ function listPluginDirs(accountPluginsDir) {
17144
17530
  return out;
17145
17531
  }
17146
17532
  function accountPluginsDirFor(accountId) {
17147
- return resolve23(PLATFORM_ROOT, "..", "data/accounts", accountId, "plugins");
17533
+ return resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "plugins");
17148
17534
  }
17149
17535
  function listAccountPluginNames(accountPluginsDir) {
17150
17536
  if (!existsSync32(accountPluginsDir)) return [];
@@ -17161,7 +17547,7 @@ function listAccountPluginNames(accountPluginsDir) {
17161
17547
  }
17162
17548
  }
17163
17549
  function readEnabledPlugins(accountId) {
17164
- const accountFile = resolve23(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17550
+ const accountFile = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17165
17551
  if (!existsSync32(accountFile)) return /* @__PURE__ */ new Set();
17166
17552
  try {
17167
17553
  const parsed = JSON.parse(readFileSync33(accountFile, "utf-8"));
@@ -17237,11 +17623,11 @@ ${skillFm}
17237
17623
  return out;
17238
17624
  }
17239
17625
  function computeSpecialistDomains(accountId) {
17240
- const specialistsDir = resolve23(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
17626
+ const specialistsDir = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
17241
17627
  if (!existsSync32(specialistsDir)) return [];
17242
- let entries;
17628
+ let entries2;
17243
17629
  try {
17244
- entries = readdirSync22(specialistsDir);
17630
+ entries2 = readdirSync22(specialistsDir);
17245
17631
  } catch {
17246
17632
  return [];
17247
17633
  }
@@ -17263,7 +17649,7 @@ function computeSpecialistDomains(accountId) {
17263
17649
  return map.get(tool);
17264
17650
  };
17265
17651
  const out = [];
17266
- for (const file of entries.sort()) {
17652
+ for (const file of entries2.sort()) {
17267
17653
  if (!file.endsWith(".md")) continue;
17268
17654
  const fm = readFrontmatter(join33(specialistsDir, file));
17269
17655
  if (!fm) continue;
@@ -17283,7 +17669,7 @@ ${fm}
17283
17669
  return out;
17284
17670
  }
17285
17671
  function computeDormantPlugins(accountId) {
17286
- const accountFile = resolve23(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17672
+ const accountFile = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17287
17673
  if (!existsSync32(accountFile)) return [];
17288
17674
  let enabled;
17289
17675
  try {
@@ -17298,18 +17684,18 @@ function computeDormantPlugins(accountId) {
17298
17684
  );
17299
17685
  return [];
17300
17686
  }
17301
- const pluginsDir = resolve23(PLATFORM_ROOT, "plugins");
17687
+ const pluginsDir = resolve24(PLATFORM_ROOT, "plugins");
17302
17688
  if (!existsSync32(pluginsDir)) return [];
17303
- let entries;
17689
+ let entries2;
17304
17690
  try {
17305
- entries = readdirSync22(pluginsDir);
17691
+ entries2 = readdirSync22(pluginsDir);
17306
17692
  } catch {
17307
17693
  return [];
17308
17694
  }
17309
17695
  const out = [];
17310
- for (const name of entries) {
17696
+ for (const name of entries2) {
17311
17697
  if (enabled.has(name)) continue;
17312
- const manifestPath = resolve23(pluginsDir, name, "PLUGIN.md");
17698
+ const manifestPath = resolve24(pluginsDir, name, "PLUGIN.md");
17313
17699
  if (!existsSync32(manifestPath)) continue;
17314
17700
  let manifest;
17315
17701
  try {
@@ -17328,7 +17714,7 @@ function computeDormantPlugins(accountId) {
17328
17714
 
17329
17715
  // server/routes/admin/claude-sessions.ts
17330
17716
  import { existsSync as existsSync33, readFileSync as readFileSync34 } from "fs";
17331
- import { resolve as resolve24 } from "path";
17717
+ import { resolve as resolve25 } from "path";
17332
17718
  function readTunnelState(brandConfigDir) {
17333
17719
  const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
17334
17720
  if (!existsSync33(statePath)) return null;
@@ -17344,10 +17730,10 @@ function readTunnelState(brandConfigDir) {
17344
17730
  }
17345
17731
  }
17346
17732
  function resolveTunnelUrl() {
17347
- 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(), "..");
17348
17734
  let brand;
17349
17735
  try {
17350
- brand = JSON.parse(readFileSync34(resolve24(platformRoot5, "config", "brand.json"), "utf-8"));
17736
+ brand = JSON.parse(readFileSync34(resolve25(platformRoot5, "config", "brand.json"), "utf-8"));
17351
17737
  } catch {
17352
17738
  return null;
17353
17739
  }
@@ -17586,6 +17972,77 @@ app22.post("/", async (c) => {
17586
17972
  console.error(`[${event}] ${formatted}`);
17587
17973
  return c.json({ ok: true });
17588
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
+ });
17589
18046
  var events_default = app22;
17590
18047
 
17591
18048
  // server/routes/admin/files.ts
@@ -17593,7 +18050,7 @@ import { createReadStream as createReadStream2, createWriteStream as createWrite
17593
18050
  import { readdir as readdir4, readFile as readFile7, stat as stat6, mkdir as mkdir4, unlink as unlink3, rename as rename2, rmdir } from "fs/promises";
17594
18051
  import { realpathSync as realpathSync7 } from "fs";
17595
18052
  import { randomUUID as randomUUID10 } from "crypto";
17596
- 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";
17597
18054
  import { Readable as Readable2 } from "stream";
17598
18055
 
17599
18056
  // ../lib/graph-trash/src/index.ts
@@ -17911,7 +18368,7 @@ async function cascadeDeleteDocument(params) {
17911
18368
 
17912
18369
  // app/lib/file-index.ts
17913
18370
  import * as fsp from "fs/promises";
17914
- 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";
17915
18372
  import { tmpdir as tmpdir2 } from "os";
17916
18373
  import { execFile as execFile2 } from "child_process";
17917
18374
  import { promisify as promisify2 } from "util";
@@ -18064,16 +18521,16 @@ async function readDisplayName(absolute) {
18064
18521
  }
18065
18522
  }
18066
18523
  async function walkSubtree(root, dataRoot, out) {
18067
- let entries;
18524
+ let entries2;
18068
18525
  try {
18069
- entries = await fsp.readdir(root, { withFileTypes: true });
18526
+ entries2 = await fsp.readdir(root, { withFileTypes: true });
18070
18527
  } catch (err) {
18071
18528
  if (err.code === "ENOENT") return { clean: true };
18072
18529
  console.error(`[file-index] walk-error dir="${relative4(dataRoot, root)}" err="${err.message}"`);
18073
18530
  return { clean: false };
18074
18531
  }
18075
18532
  let clean = true;
18076
- for (const entry of entries) {
18533
+ for (const entry of entries2) {
18077
18534
  if (entry.isSymbolicLink()) continue;
18078
18535
  if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
18079
18536
  const abs = join34(root, entry.name);
@@ -18231,7 +18688,7 @@ async function reconcileFileIndex(accountId, opts) {
18231
18688
  return withSession(opts, async (session) => {
18232
18689
  const walked = [];
18233
18690
  const subtreeRoots = [
18234
- resolve25(dataRoot, "accounts", accountId)
18691
+ resolve26(dataRoot, "accounts", accountId)
18235
18692
  ];
18236
18693
  let clean = true;
18237
18694
  for (const root of subtreeRoots) {
@@ -18314,7 +18771,7 @@ async function reconcileFileIndexDebounced(accountId, opts) {
18314
18771
  async function indexFile(accountId, relativePath, opts) {
18315
18772
  const dataRoot = opts?.dataRoot ?? DATA_ROOT;
18316
18773
  const embed2 = opts?.embed ?? embed;
18317
- const absolute = resolve25(dataRoot, relativePath);
18774
+ const absolute = resolve26(dataRoot, relativePath);
18318
18775
  await withSession(opts, async (session) => {
18319
18776
  const st = await fsp.stat(absolute);
18320
18777
  const wf = {
@@ -18365,11 +18822,11 @@ function crc32(buf) {
18365
18822
  for (let i = 0; i < buf.length; i++) crc = crcTable[(crc ^ buf[i]) & 255] ^ crc >>> 8;
18366
18823
  return (crc ^ 4294967295) >>> 0;
18367
18824
  }
18368
- function buildZip(entries) {
18825
+ function buildZip(entries2) {
18369
18826
  const localChunks = [];
18370
18827
  const centralChunks = [];
18371
18828
  let offset = 0;
18372
- for (const entry of entries) {
18829
+ for (const entry of entries2) {
18373
18830
  const nameBytes = Buffer.from(entry.name, "utf8");
18374
18831
  const crc = crc32(entry.data);
18375
18832
  const uncompressedSize = entry.data.length;
@@ -18419,14 +18876,31 @@ function buildZip(entries) {
18419
18876
  eocd.writeUInt32LE(EOCD_SIG, 0);
18420
18877
  eocd.writeUInt16LE(0, 4);
18421
18878
  eocd.writeUInt16LE(0, 6);
18422
- eocd.writeUInt16LE(entries.length, 8);
18423
- eocd.writeUInt16LE(entries.length, 10);
18879
+ eocd.writeUInt16LE(entries2.length, 8);
18880
+ eocd.writeUInt16LE(entries2.length, 10);
18424
18881
  eocd.writeUInt32LE(centralSize, 12);
18425
18882
  eocd.writeUInt32LE(centralOffset, 16);
18426
18883
  eocd.writeUInt16LE(0, 20);
18427
18884
  return Buffer.concat([...localChunks, centralDir, eocd]);
18428
18885
  }
18429
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
+
18430
18904
  // server/routes/admin/files.ts
18431
18905
  var UPLOAD_TMP_DIR = ".uploads-tmp";
18432
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;
@@ -18443,7 +18917,7 @@ async function readMeta(absDir, baseName) {
18443
18917
  }
18444
18918
  async function readAccountNames() {
18445
18919
  const map = /* @__PURE__ */ new Map();
18446
- const accountsDir = resolve26(DATA_ROOT, "accounts");
18920
+ const accountsDir = resolve27(DATA_ROOT, "accounts");
18447
18921
  let names;
18448
18922
  try {
18449
18923
  names = await readdir4(accountsDir);
@@ -18452,7 +18926,7 @@ async function readAccountNames() {
18452
18926
  }
18453
18927
  for (const name of names) {
18454
18928
  if (!UUID_RE4.test(name)) continue;
18455
- const configPath2 = resolve26(accountsDir, name, "account.json");
18929
+ const configPath2 = resolve27(accountsDir, name, "account.json");
18456
18930
  try {
18457
18931
  const raw = await readFile7(configPath2, "utf8");
18458
18932
  const parsed = JSON.parse(raw);
@@ -18538,8 +19012,24 @@ function buildDisplayPath(relPath, accountNames) {
18538
19012
  return dn ? { name: seg, displayName: dn } : { name: seg };
18539
19013
  });
18540
19014
  }
18541
- function sortDirEntries(entries) {
18542
- 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) => {
18543
19033
  if (a.kind !== b.kind) return a.kind === "directory" ? -1 : 1;
18544
19034
  if (a.kind === "file" && b.kind === "file") {
18545
19035
  const byTime = b.modifiedAt.localeCompare(a.modifiedAt);
@@ -18596,6 +19086,7 @@ function isProtectedFromRename(relPath) {
18596
19086
  function isValidEntryName(name) {
18597
19087
  if (typeof name !== "string" || name.length === 0) return false;
18598
19088
  if (name === "." || name === "..") return false;
19089
+ if (name.startsWith("@")) return false;
18599
19090
  return !/[\\/\0]/.test(name);
18600
19091
  }
18601
19092
  function resolveOwnAccountWrite(rawPath, accountId, endpoint) {
@@ -18640,7 +19131,8 @@ app23.get("/", requireAdminSession, async (c) => {
18640
19131
  return c.json({ error: "Account not found for session" }, 401);
18641
19132
  }
18642
19133
  const rawPath = c.req.query("path") ?? "";
18643
- const resolution = resolveDataPath(rawPath);
19134
+ const groupReq = parseGroupPath(rawPath, accountId);
19135
+ const resolution = resolveDataPath(groupReq ? groupReq.accountRel : rawPath);
18644
19136
  if (!resolution.ok) {
18645
19137
  if (resolution.status === 403) {
18646
19138
  console.error(`[data] path-traversal-blocked requested="${rawPath}" resolved="${resolution.resolved ?? "n/a"}"`);
@@ -18660,7 +19152,7 @@ app23.get("/", requireAdminSession, async (c) => {
18660
19152
  const names = await readdir4(absolute);
18661
19153
  const segs = relPath.split("/").filter(Boolean);
18662
19154
  const isAccountParent = segs.length === 1 && segs[0] === "accounts";
18663
- const entries = [];
19155
+ const entries2 = [];
18664
19156
  for (const name of names) {
18665
19157
  if (UUID_RE4.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
18666
19158
  continue;
@@ -18673,7 +19165,7 @@ app23.get("/", requireAdminSession, async (c) => {
18673
19165
  try {
18674
19166
  const entryPath = join35(absolute, name);
18675
19167
  const s = await stat6(entryPath);
18676
- entries.push({
19168
+ entries2.push({
18677
19169
  name,
18678
19170
  kind: s.isDirectory() ? "directory" : s.isFile() ? "file" : "other",
18679
19171
  sizeBytes: s.isDirectory() ? null : s.size,
@@ -18681,12 +19173,12 @@ app23.get("/", requireAdminSession, async (c) => {
18681
19173
  protected: protectedEntry
18682
19174
  });
18683
19175
  } catch {
18684
- 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 });
18685
19177
  }
18686
19178
  }
18687
19179
  const accountNames = await readAccountNames();
18688
- const classes = await Promise.all(entries.map((e) => enrich(absolute, e, accountNames)));
18689
- sortDirEntries(entries);
19180
+ const classes = await Promise.all(entries2.map((e) => enrich(absolute, e, accountNames)));
19181
+ sortDirEntries(entries2);
18690
19182
  let flattened = 0;
18691
19183
  let keptAsDir = 0;
18692
19184
  for (const cls of classes) {
@@ -18698,8 +19190,77 @@ app23.get("/", requireAdminSession, async (c) => {
18698
19190
  console.error(`[data] op=uploads-flatten containers=${containers} flattened=${flattened} kept-as-dir=${keptAsDir}`);
18699
19191
  }
18700
19192
  const displayPath = buildDisplayPath(relPath, accountNames);
18701
- console.error(`[data] file-list path="${relPath}" entries=${entries.length}`);
18702
- 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 });
18703
19264
  } catch (err) {
18704
19265
  const code = err.code;
18705
19266
  if (code === "ENOENT") {
@@ -18851,14 +19412,14 @@ app23.get("/download-zip", requireAdminSession, async (c) => {
18851
19412
  if (rawPaths.length > maxFiles) {
18852
19413
  return c.json({ error: `Too many files (max ${maxFiles})` }, 413);
18853
19414
  }
18854
- const entries = [];
19415
+ const entries2 = [];
18855
19416
  let total = 0;
18856
19417
  let dirsWalked = 0;
18857
19418
  const addFile = async (absolute, size, member) => {
18858
- 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);
18859
19420
  total += size;
18860
19421
  if (total > maxTotalBytes) return c.json({ error: "Selection too large to zip" }, 413);
18861
- entries.push({ name: member, data: await readFile7(absolute) });
19422
+ entries2.push({ name: member, data: await readFile7(absolute) });
18862
19423
  return null;
18863
19424
  };
18864
19425
  for (const rawPath of rawPaths) {
@@ -18906,8 +19467,8 @@ app23.get("/download-zip", requireAdminSession, async (c) => {
18906
19467
  throw err;
18907
19468
  }
18908
19469
  }
18909
- const archive = buildZip(entries);
18910
- 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}`);
18911
19472
  return new Response(new Uint8Array(archive), {
18912
19473
  status: 200,
18913
19474
  headers: {
@@ -18948,8 +19509,8 @@ async function resolveUploadTarget(c, accountId, uid) {
18948
19509
  console.error(`[data] write-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
18949
19510
  return { ok: false, status: 403, error: "Path is outside your account folder" };
18950
19511
  }
18951
- const destDir = relDir === "." ? base.absolute : resolve26(base.absolute, relDir);
18952
- const destPath = resolve26(destDir, finalName);
19512
+ const destDir = relDir === "." ? base.absolute : resolve27(base.absolute, relDir);
19513
+ const destPath = resolve27(destDir, finalName);
18953
19514
  if (relpath) {
18954
19515
  const firstCreated = await mkdir4(destDir, { recursive: true });
18955
19516
  if (firstCreated) console.error(`[data-upload] op=mkdir uid=${uid} token=${token} dir="${destRel}"`);
@@ -18966,7 +19527,7 @@ async function resolveUploadTarget(c, accountId, uid) {
18966
19527
  return { ok: true, destDir, destPath, destRel, finalName, mimeType, relpath, token };
18967
19528
  }
18968
19529
  async function logUploadsTmpCensus(accountId) {
18969
- const tmpDir = resolve26(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
19530
+ const tmpDir = resolve27(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
18970
19531
  let live = 0;
18971
19532
  try {
18972
19533
  live = (await readdir4(tmpDir)).length;
@@ -18993,9 +19554,9 @@ app23.post("/upload", requireAdminSession, async (c) => {
18993
19554
  if (!body) return c.json({ error: "Empty request body" }, 400);
18994
19555
  console.error(`[data-upload] op=request uid=${uid} account=${accountId} dir="${destRel}" token=${token} rel="${relpath ?? ""}" declaredBytes=${declaredBytes}`);
18995
19556
  const ceiling = dataUploadCeiling();
18996
- const tmpDir = resolve26(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
19557
+ const tmpDir = resolve27(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
18997
19558
  await mkdir4(tmpDir, { recursive: true });
18998
- const tmpPath = resolve26(tmpDir, `${uid}.part`);
19559
+ const tmpPath = resolve27(tmpDir, `${uid}.part`);
18999
19560
  const out = createWriteStream2(tmpPath);
19000
19561
  const t0 = Date.now();
19001
19562
  let received = 0;
@@ -19142,9 +19703,9 @@ async function handleChunkUpload(c, accountId) {
19142
19703
  }
19143
19704
  const target = await resolveUploadTarget(c, accountId, uploadId);
19144
19705
  if (!target.ok) return c.json({ error: target.error }, target.status);
19145
- const tmpDir = resolve26(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
19706
+ const tmpDir = resolve27(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
19146
19707
  await mkdir4(tmpDir, { recursive: true });
19147
- const tmpPath = resolve26(tmpDir, `${uploadId}.part`);
19708
+ const tmpPath = resolve27(tmpDir, `${uploadId}.part`);
19148
19709
  const out = createWriteStream2(tmpPath);
19149
19710
  const state2 = {
19150
19711
  accountId,
@@ -19250,7 +19811,7 @@ async function evictStaleChunkUploads(ttlMs) {
19250
19811
  return evicted;
19251
19812
  }
19252
19813
  async function sweepStaleUploadTemps() {
19253
- const accountsRoot = resolve26(DATA_ROOT, "accounts");
19814
+ const accountsRoot = resolve27(DATA_ROOT, "accounts");
19254
19815
  let accounts;
19255
19816
  try {
19256
19817
  accounts = await readdir4(accountsRoot, { withFileTypes: true });
@@ -19260,16 +19821,16 @@ async function sweepStaleUploadTemps() {
19260
19821
  let removed = 0;
19261
19822
  for (const acc of accounts) {
19262
19823
  if (!acc.isDirectory()) continue;
19263
- const tmpDir = resolve26(accountsRoot, acc.name, UPLOAD_TMP_DIR);
19264
- let entries;
19824
+ const tmpDir = resolve27(accountsRoot, acc.name, UPLOAD_TMP_DIR);
19825
+ let entries2;
19265
19826
  try {
19266
- entries = await readdir4(tmpDir);
19827
+ entries2 = await readdir4(tmpDir);
19267
19828
  } catch {
19268
19829
  continue;
19269
19830
  }
19270
- for (const name of entries) {
19831
+ for (const name of entries2) {
19271
19832
  try {
19272
- await unlink3(resolve26(tmpDir, name));
19833
+ await unlink3(resolve27(tmpDir, name));
19273
19834
  removed++;
19274
19835
  } catch {
19275
19836
  }
@@ -19380,7 +19941,7 @@ app23.post("/folder", requireAdminSession, async (c) => {
19380
19941
  if (!isValidEntryName(name)) return c.json({ error: "Invalid folder name" }, 400);
19381
19942
  const parent = resolveOwnAccountWrite(rawPath, accountId, "POST /api/admin/files/folder");
19382
19943
  if (!parent.ok) return c.json({ error: parent.error }, parent.status);
19383
- const newAbs = resolve26(parent.absolute, name);
19944
+ const newAbs = resolve27(parent.absolute, name);
19384
19945
  const newRel = `${parent.relative}/${name}`;
19385
19946
  try {
19386
19947
  const info = await stat6(parent.absolute);
@@ -19419,7 +19980,7 @@ app23.post("/rename", requireAdminSession, async (c) => {
19419
19980
  console.error(`[data] file-rename blocked path="${src.relative}" reason="protected"`);
19420
19981
  return c.json({ error: "Protected entry \u2014 refusing to rename" }, 403);
19421
19982
  }
19422
- const destAbs = resolve26(dirname13(src.absolute), newName);
19983
+ const destAbs = resolve27(dirname13(src.absolute), newName);
19423
19984
  const newRel = `${dirname13(src.relative)}/${newName}`.replace(/^\.\//, "");
19424
19985
  if (isProtectedFromRename(newRel)) {
19425
19986
  console.error(`[data] file-rename blocked path="${newRel}" reason="protected-target"`);
@@ -19450,7 +20011,7 @@ app23.post("/rename", requireAdminSession, async (c) => {
19450
20011
  var files_default = app23;
19451
20012
 
19452
20013
  // ../lib/graph-search/src/index.ts
19453
- var import_dist = __toESM(require_dist2());
20014
+ var import_dist2 = __toESM(require_dist3());
19454
20015
  import { int } from "neo4j-driver";
19455
20016
 
19456
20017
  // ../lib/graph-search/src/rrf-fusion.ts
@@ -19700,7 +20261,7 @@ async function bm25Only(session, params) {
19700
20261
  ${scopeClause}
19701
20262
  ${agentClause}
19702
20263
  ${labelClause}
19703
- AND ${(0, import_dist.notTrashed)("node")}
20264
+ AND ${(0, import_dist2.notTrashed)("node")}
19704
20265
  ${kwClause}
19705
20266
  RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
19706
20267
  ORDER BY score DESC
@@ -19862,7 +20423,7 @@ async function hybrid(session, embed2, params) {
19862
20423
  WHERE node.accountId = $accountId
19863
20424
  ${scopeClause}
19864
20425
  ${agentClause}
19865
- AND ${(0, import_dist.notTrashed)("node")}
20426
+ AND ${(0, import_dist2.notTrashed)("node")}
19866
20427
  ${keywordClause}
19867
20428
  RETURN node, score, labels(node) AS nodeLabels, elementId(node) AS nodeId
19868
20429
  ORDER BY score DESC
@@ -19961,7 +20522,7 @@ async function hybrid(session, embed2, params) {
19961
20522
  const propResult = await session.run(
19962
20523
  `MATCH (node)
19963
20524
  WHERE node.accountId = $accountId
19964
- AND ${(0, import_dist.notTrashed)("node")}
20525
+ AND ${(0, import_dist2.notTrashed)("node")}
19965
20526
  AND node.keywords IS NOT NULL
19966
20527
  AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
19967
20528
  ${propScope.clause}
@@ -20013,7 +20574,7 @@ async function hybrid(session, embed2, params) {
20013
20574
  const propResult = await session.run(
20014
20575
  `MATCH (node)
20015
20576
  WHERE node.accountId = $accountId
20016
- AND ${(0, import_dist.notTrashed)("node")}
20577
+ AND ${(0, import_dist2.notTrashed)("node")}
20017
20578
  AND node.keywords IS NOT NULL
20018
20579
  AND ANY(kw IN $kwSubs WHERE ANY(nk IN node.keywords WHERE toLower(nk) = kw))
20019
20580
  ${propScope.clause}
@@ -20120,7 +20681,7 @@ async function hybrid(session, embed2, params) {
20120
20681
  `UNWIND $nodeIds AS nid
20121
20682
  MATCH (n)-[r]-(related)
20122
20683
  WHERE elementId(n) = nid
20123
- AND ${(0, import_dist.notTrashed)("related")}
20684
+ AND ${(0, import_dist2.notTrashed)("related")}
20124
20685
  ${expandScopeClause}
20125
20686
  ${expandAgentClause}
20126
20687
  WITH nid, n, r, related
@@ -20348,8 +20909,8 @@ var graph_search_default = app24;
20348
20909
  import neo4j2 from "neo4j-driver";
20349
20910
 
20350
20911
  // app/lib/graph-labels.ts
20351
- var import_dist2 = __toESM(require_dist3(), 1);
20352
- var import_dist3 = __toESM(require_dist3(), 1);
20912
+ var import_dist3 = __toESM(require_dist4(), 1);
20913
+ var import_dist4 = __toESM(require_dist4(), 1);
20353
20914
  var HIDDEN_BY_DEFAULT_LABELS = Object.freeze(
20354
20915
  /* @__PURE__ */ new Set(["Chunk", "GraphPreference"])
20355
20916
  );
@@ -20427,16 +20988,16 @@ var EXCLUDED_EDGE_TYPES = Object.freeze(
20427
20988
  ])
20428
20989
  );
20429
20990
  function isKnownLabel(label) {
20430
- return Object.prototype.hasOwnProperty.call(import_dist3.GRAPH_LABEL_COLOURS, label);
20991
+ return Object.prototype.hasOwnProperty.call(import_dist4.GRAPH_LABEL_COLOURS, label);
20431
20992
  }
20432
20993
  function isHiddenByDefault(label) {
20433
20994
  return HIDDEN_BY_DEFAULT_LABELS.has(label);
20434
20995
  }
20435
20996
 
20436
20997
  // server/lib/top-level-labels.ts
20437
- var import_dist4 = __toESM(require_dist3(), 1);
20998
+ var import_dist5 = __toESM(require_dist4(), 1);
20438
20999
  import { readdirSync as readdirSync23, readFileSync as readFileSync35 } from "fs";
20439
- import { join as join36, resolve as resolve27 } from "path";
21000
+ import { join as join36, resolve as resolve28 } from "path";
20440
21001
  var STATIC_TOP_LEVEL_LABELS = Object.freeze(
20441
21002
  /* @__PURE__ */ new Set([
20442
21003
  // Base-schema infra (schema-base.md has no top-level section).
@@ -20542,7 +21103,7 @@ function resolveReferencesDir() {
20542
21103
  if (process.env.MAXY_PLATFORM_ROOT) {
20543
21104
  return join36(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
20544
21105
  }
20545
- return resolve27(import.meta.dirname, "../../../plugins/memory/references");
21106
+ return resolve28(import.meta.dirname, "../../../plugins/memory/references");
20546
21107
  }
20547
21108
  function parseTableTopLevelLabels(referencesDir) {
20548
21109
  const labels = /* @__PURE__ */ new Set();
@@ -20571,7 +21132,7 @@ function getTopLevelLabelAllowlist(opts = {}) {
20571
21132
  const referencesDir = opts.referencesDir ?? resolveReferencesDir();
20572
21133
  const { labels: derived, contributingFiles } = parseTableTopLevelLabels(referencesDir);
20573
21134
  const excluded = [];
20574
- for (const label of import_dist4.ADDITIONAL_BASE_LABELS) {
21135
+ for (const label of import_dist5.ADDITIONAL_BASE_LABELS) {
20575
21136
  if (derived.delete(label)) excluded.push(label);
20576
21137
  }
20577
21138
  const derivedCount = derived.size;
@@ -21707,7 +22268,7 @@ var graph_default_view_default = app29;
21707
22268
 
21708
22269
  // server/routes/admin/sidebar-artefacts.ts
21709
22270
  import { readdir as readdir5, stat as stat7 } from "fs/promises";
21710
- 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";
21711
22272
  import { existsSync as existsSync35 } from "fs";
21712
22273
  var LIMIT = 50;
21713
22274
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
@@ -21723,20 +22284,25 @@ app30.get("/", requireAdminSession, async (c) => {
21723
22284
  return c.json({ error: "Account not found for session" }, 401);
21724
22285
  }
21725
22286
  const start = Date.now();
21726
- const accountFiles = await fetchAccountFileArtefacts(accountId);
21727
- 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) {
21728
22299
  return c.json({ error: "Failed to load artefacts" }, 500);
21729
22300
  }
21730
- const accountDir = resolve28(ACCOUNTS_DIR, accountId);
21731
- const agents = await fetchAgentTemplateRows(accountDir);
21732
- const artefacts = [...accountFiles, ...agents].sort(
21733
- (a, b) => (b.updatedAt ?? "").localeCompare(a.updatedAt ?? "")
21734
- ).slice(0, LIMIT);
21735
22301
  const ms = Date.now() - start;
21736
22302
  console.log(
21737
- `[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}`
21738
22304
  );
21739
- return c.json({ artefacts });
22305
+ return c.json({ artefacts: value.artefacts });
21740
22306
  });
21741
22307
  async function fetchAccountFileArtefacts(accountId) {
21742
22308
  const session = getSession();
@@ -21779,8 +22345,8 @@ async function fetchAccountFileArtefacts(accountId) {
21779
22345
  async function fetchAgentTemplateRows(accountDir) {
21780
22346
  const rows = [];
21781
22347
  for (const filename of ADMIN_AGENT_FILES) {
21782
- const overridePath = resolve28(accountDir, "agents", "admin", filename);
21783
- 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);
21784
22350
  const labelStem = filename.replace(/\.md$/, "");
21785
22351
  const row = await readAgentTemplateRow({
21786
22352
  id: `agent-template:admin:${filename}`,
@@ -21793,12 +22359,12 @@ async function fetchAgentTemplateRows(accountDir) {
21793
22359
  });
21794
22360
  if (row) rows.push(row);
21795
22361
  }
21796
- const overrideDir = resolve28(accountDir, "specialists", "agents");
21797
- const bundledDir = resolve28(PLATFORM_ROOT, "templates", "specialists", "agents");
22362
+ const overrideDir = resolve29(accountDir, "specialists", "agents");
22363
+ const bundledDir = resolve29(PLATFORM_ROOT, "templates", "specialists", "agents");
21798
22364
  const specialistNames = await unionSpecialistFilenames(overrideDir, bundledDir);
21799
22365
  for (const filename of specialistNames) {
21800
- const overridePath = resolve28(overrideDir, filename);
21801
- const bundledPath = resolve28(bundledDir, filename);
22366
+ const overridePath = resolve29(overrideDir, filename);
22367
+ const bundledPath = resolve29(bundledDir, filename);
21802
22368
  const row = await readAgentTemplateRow({
21803
22369
  id: `agent-template:specialist:${filename}`,
21804
22370
  displayName: filename.replace(/\.md$/, ""),
@@ -21817,8 +22383,8 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
21817
22383
  for (const dir of [overrideDir, bundledDir]) {
21818
22384
  if (!existsSync35(dir)) continue;
21819
22385
  try {
21820
- const entries = await readdir5(dir);
21821
- for (const entry of entries) {
22386
+ const entries2 = await readdir5(dir);
22387
+ for (const entry of entries2) {
21822
22388
  if (entry.endsWith(".md")) names.add(entry);
21823
22389
  }
21824
22390
  } catch (err) {
@@ -22284,24 +22850,24 @@ var session_rc_spawn_default = app36;
22284
22850
  import { randomUUID as randomUUID12 } from "crypto";
22285
22851
 
22286
22852
  // server/wa-descriptor.ts
22287
- import { resolve as resolve29, join as join38 } from "path";
22853
+ import { resolve as resolve30, join as join38 } from "path";
22288
22854
  function waGatewayUrl() {
22289
22855
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
22290
22856
  }
22291
22857
  function waServerPath() {
22292
- 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");
22293
22859
  }
22294
22860
  function waChannelDescriptor(senderId) {
22295
22861
  return { senderId, gatewayUrl: waGatewayUrl(), serverPath: waServerPath() };
22296
22862
  }
22297
22863
 
22298
22864
  // server/telegram-descriptor.ts
22299
- import { resolve as resolve30, join as join39 } from "path";
22865
+ import { resolve as resolve31, join as join39 } from "path";
22300
22866
  function telegramGatewayUrl() {
22301
22867
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
22302
22868
  }
22303
22869
  function telegramServerPath() {
22304
- 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");
22305
22871
  }
22306
22872
  function telegramChannelDescriptor(senderId) {
22307
22873
  return { senderId, gatewayUrl: telegramGatewayUrl(), serverPath: telegramServerPath() };
@@ -22586,8 +23152,8 @@ var system_stats_default = app38;
22586
23152
 
22587
23153
  // server/routes/admin/health.ts
22588
23154
  import { existsSync as existsSync36, readFileSync as readFileSync37 } from "fs";
22589
- import { resolve as resolve31, join as join40 } from "path";
22590
- 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(), "..");
22591
23157
  var brandHostname = "maxy";
22592
23158
  var brandJsonPath = join40(PLATFORM_ROOT6, "config", "brand.json");
22593
23159
  if (existsSync36(brandJsonPath)) {
@@ -22597,7 +23163,7 @@ if (existsSync36(brandJsonPath)) {
22597
23163
  } catch {
22598
23164
  }
22599
23165
  }
22600
- var VERSION_FILE = resolve31(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
23166
+ var VERSION_FILE = resolve32(PLATFORM_ROOT6, `config/.${brandHostname}-version`);
22601
23167
  var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
22602
23168
  var PROBE_TIMEOUT_MS = 1e3;
22603
23169
  function readVersion() {
@@ -24053,7 +24619,7 @@ var routines_default = app48;
24053
24619
 
24054
24620
  // server/routes/admin/skills.ts
24055
24621
  import { existsSync as existsSync38, readdirSync as readdirSync24, readFileSync as readFileSync39, rmSync as rmSync3 } from "fs";
24056
- import { resolve as resolve32 } from "path";
24622
+ import { resolve as resolve33 } from "path";
24057
24623
  var app49 = new Hono();
24058
24624
  var NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
24059
24625
  function splitSkillMd(text) {
@@ -24075,13 +24641,7 @@ function stripQuotes(s) {
24075
24641
  if (s.startsWith('"') && s.endsWith('"') || s.startsWith("'") && s.endsWith("'")) return s.slice(1, -1);
24076
24642
  return s;
24077
24643
  }
24078
- function accountDirForSession(cacheKey) {
24079
- const accountId = getAccountIdForSession(cacheKey);
24080
- if (!accountId) return null;
24081
- const match = listValidAccounts().find((a) => a.accountId === accountId);
24082
- return match ? { accountId, accountDir: match.accountDir } : null;
24083
- }
24084
- function subdirs(dir) {
24644
+ function subdirs2(dir) {
24085
24645
  if (!existsSync38(dir)) return [];
24086
24646
  try {
24087
24647
  return readdirSync24(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
@@ -24095,28 +24655,32 @@ app49.get("/", requireAdminSession, async (c) => {
24095
24655
  console.error('[admin:skills] op=list auth-rejected reason="no account for session"');
24096
24656
  return c.json({ error: "Account not found for session" }, 401);
24097
24657
  }
24098
- const pluginsDir = resolve32(acct.accountDir, "plugins");
24099
- const skills = [];
24100
- let pluginCount = 0;
24101
- for (const plugin of subdirs(pluginsDir)) {
24102
- pluginCount++;
24103
- const skillsDir = resolve32(pluginsDir, plugin, "skills");
24104
- for (const skill of subdirs(skillsDir)) {
24105
- const skillMd = resolve32(skillsDir, skill, "SKILL.md");
24106
- if (!existsSync38(skillMd)) continue;
24107
- try {
24108
- const { frontmatter } = splitSkillMd(readFileSync39(skillMd, "utf-8"));
24109
- const refsDir = resolve32(skillsDir, skill, "references");
24110
- const refCount = existsSync38(refsDir) ? readdirSync24(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).length : 0;
24111
- skills.push({ plugin, skill, description: frontmatter.description, refCount });
24112
- } catch (err) {
24113
- 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
+ }
24114
24677
  }
24115
24678
  }
24116
- }
24117
- skills.sort((a, b) => a.plugin.localeCompare(b.plugin) || a.skill.localeCompare(b.skill));
24118
- console.log(`[admin:skills] op=list accountId=${acct.accountId.slice(0, 8)} plugins=${pluginCount} skills=${skills.length}`);
24119
- 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 });
24120
24684
  });
24121
24685
  app49.get("/:plugin/:skill", requireAdminSession, async (c) => {
24122
24686
  const acct = accountDirForSession(c.var.cacheKey);
@@ -24127,14 +24691,14 @@ app49.get("/:plugin/:skill", requireAdminSession, async (c) => {
24127
24691
  console.error(`[admin:skills] op=get outcome=rejected reason=invalid-name plugin="${plugin}" skill="${skill}"`);
24128
24692
  return c.json({ error: "Invalid plugin or skill name" }, 400);
24129
24693
  }
24130
- const skillDir = resolve32(acct.accountDir, "plugins", plugin, "skills", skill);
24131
- const skillMd = resolve32(skillDir, "SKILL.md");
24694
+ const skillDir = resolve33(acct.accountDir, "plugins", plugin, "skills", skill);
24695
+ const skillMd = resolve33(skillDir, "SKILL.md");
24132
24696
  const found = existsSync38(skillMd);
24133
24697
  console.log(`[admin:skills] op=get plugin=${plugin} skill=${skill} found=${found}`);
24134
24698
  if (!found) return c.json({ error: "Skill not found" }, 404);
24135
24699
  try {
24136
24700
  const { frontmatter, body } = splitSkillMd(readFileSync39(skillMd, "utf-8"));
24137
- const refsDir = resolve32(skillDir, "references");
24701
+ const refsDir = resolve33(skillDir, "references");
24138
24702
  const references = existsSync38(refsDir) ? readdirSync24(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).sort() : [];
24139
24703
  return c.json({ skill: { plugin, skill, frontmatter, body, references } });
24140
24704
  } catch (err) {
@@ -24152,16 +24716,16 @@ app49.delete("/:plugin/:skill", requireAdminSession, async (c) => {
24152
24716
  console.error(`[admin:skills] op=delete outcome=rejected reason=invalid-name plugin="${plugin}" skill="${skill}"`);
24153
24717
  return c.json({ error: "Invalid plugin or skill name" }, 400);
24154
24718
  }
24155
- const pluginDir = resolve32(acct.accountDir, "plugins", plugin);
24156
- const skillsDir = resolve32(pluginDir, "skills");
24157
- const skillDir = resolve32(skillsDir, skill);
24158
- 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"))) {
24159
24723
  console.error(`[admin:skills] op=delete outcome=rejected reason=not-found plugin=${plugin} skill=${skill}`);
24160
24724
  return c.json({ error: "Skill not found" }, 404);
24161
24725
  }
24162
24726
  try {
24163
24727
  rmSync3(skillDir, { recursive: true, force: true });
24164
- const pluginDirRemoved = subdirs(skillsDir).length === 0;
24728
+ const pluginDirRemoved = subdirs2(skillsDir).length === 0;
24165
24729
  if (pluginDirRemoved) rmSync3(pluginDir, { recursive: true, force: true });
24166
24730
  const skillDirGone = !existsSync38(skillDir);
24167
24731
  if (!skillDirGone) {
@@ -24207,6 +24771,15 @@ app50.get("/", requireAdminSession, async (c) => {
24207
24771
  console.error(`${TAG39} op=list auth-rejected reason="no account for session"`);
24208
24772
  return c.json({ error: "Account not found for session" }, 401);
24209
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) {
24210
24783
  const session = getSession();
24211
24784
  try {
24212
24785
  const result = await session.run(
@@ -24289,14 +24862,14 @@ app50.get("/", requireAdminSession, async (c) => {
24289
24862
  console.log(
24290
24863
  `${TAG39} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned}`
24291
24864
  );
24292
- return c.json({ open, completed });
24865
+ return { open, completed };
24293
24866
  } catch (err) {
24294
24867
  console.error(`${TAG39} op=list error="${err instanceof Error ? err.message : String(err)}"`);
24295
- return c.json({ error: "tasks-list-failed" }, 500);
24868
+ return null;
24296
24869
  } finally {
24297
24870
  await session.close();
24298
24871
  }
24299
- });
24872
+ }
24300
24873
  var tasks_list_default = app50;
24301
24874
 
24302
24875
  // server/routes/admin/task-timer-start.ts
@@ -24340,6 +24913,7 @@ app51.post("/", requireAdminSession, async (c) => {
24340
24913
  const priorStartedAt = open.records[0]?.get("startedAt");
24341
24914
  if (priorEntryId) {
24342
24915
  console.log(`${TAG40} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
24916
+ invalidate("tasks-list", accountId);
24343
24917
  return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
24344
24918
  }
24345
24919
  const entryId = randomUUID14();
@@ -24350,6 +24924,7 @@ app51.post("/", requireAdminSession, async (c) => {
24350
24924
  { taskId, accountId, entryId, now }
24351
24925
  );
24352
24926
  console.log(`${TAG40} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
24927
+ invalidate("tasks-list", accountId);
24353
24928
  return c.json({ ok: true, running: true, entryId, startedAt: now });
24354
24929
  } catch (err) {
24355
24930
  console.error(`${TAG40} op=start error="${err instanceof Error ? err.message : String(err)}"`);
@@ -24399,6 +24974,7 @@ app52.post("/", requireAdminSession, async (c) => {
24399
24974
  );
24400
24975
  const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
24401
24976
  console.log(`${TAG41} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
24977
+ invalidate("tasks-list", accountId);
24402
24978
  return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
24403
24979
  }
24404
24980
  const seconds = secondsBetween(startedAt, now);
@@ -24423,6 +24999,7 @@ app52.post("/", requireAdminSession, async (c) => {
24423
24999
  const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
24424
25000
  console.log(`${TAG41} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
24425
25001
  console.log(`${TAG41} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
25002
+ invalidate("tasks-list", accountId);
24426
25003
  return c.json({ ok: true, running: false, seconds, secondsLogged });
24427
25004
  } catch (err) {
24428
25005
  console.error(`${TAG41} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
@@ -24466,6 +25043,7 @@ app53.post("/", requireAdminSession, async (c) => {
24466
25043
  }
24467
25044
  const secondsLogged = toNum(result.records[0].get("secondsLogged"));
24468
25045
  console.log(`${TAG42} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
25046
+ invalidate("tasks-list", accountId);
24469
25047
  return c.json({ ok: true, status: "completed", secondsLogged });
24470
25048
  } catch (err) {
24471
25049
  console.error(`${TAG42} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
@@ -24547,6 +25125,7 @@ app54.post("/", requireAdminSession, async (c) => {
24547
25125
  );
24548
25126
  const secondsLoggedAfter = toNum(write.records[0]?.get("secondsLoggedAfter"));
24549
25127
  console.log(`${TAG43} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
25128
+ invalidate("tasks-list", accountId);
24550
25129
  return c.json({ ok: true, secondsLogged: secondsLoggedAfter });
24551
25130
  } catch (err) {
24552
25131
  console.error(`${TAG43} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
@@ -24559,16 +25138,16 @@ var task_time_adjust_default = app54;
24559
25138
 
24560
25139
  // app/lib/admin-roster.ts
24561
25140
  import { existsSync as existsSync39, readdirSync as readdirSync25, readFileSync as readFileSync40 } from "fs";
24562
- import { resolve as resolve33 } from "path";
25141
+ import { resolve as resolve34 } from "path";
24563
25142
  function readHouseAdminUserIds(accountsDir = ACCOUNTS_DIR) {
24564
- let entries;
25143
+ let entries2;
24565
25144
  try {
24566
- entries = readdirSync25(accountsDir);
25145
+ entries2 = readdirSync25(accountsDir);
24567
25146
  } catch {
24568
25147
  return [];
24569
25148
  }
24570
- for (const entry of entries) {
24571
- const cfgPath = resolve33(accountsDir, entry, "account.json");
25149
+ for (const entry of entries2) {
25150
+ const cfgPath = resolve34(accountsDir, entry, "account.json");
24572
25151
  if (!existsSync39(cfgPath)) continue;
24573
25152
  try {
24574
25153
  const cfg = JSON.parse(readFileSync40(cfgPath, "utf-8"));
@@ -24692,6 +25271,7 @@ app55.post("/", requireAdminSession, async (c) => {
24692
25271
  { taskId, accountId, now }
24693
25272
  );
24694
25273
  console.log(`${TAG44} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
25274
+ invalidate("tasks-list", accountId);
24695
25275
  return c.json({ ok: true, assigneeUserId: null, assigneeName: null });
24696
25276
  }
24697
25277
  const set = await session.run(
@@ -24699,6 +25279,7 @@ app55.post("/", requireAdminSession, async (c) => {
24699
25279
  MATCH (au:AdminUser {userId: $assigneeUserId})
24700
25280
  MERGE (t)-[:ASSIGNED_TO]->(au)
24701
25281
  SET t.updatedAt = $now
25282
+ WITH t, au
24702
25283
  OPTIONAL MATCH (au)-[:OWNS]->(p:Person) WHERE p.accountId = au.accountId
24703
25284
  RETURN au.userId AS userId, p.givenName AS givenName, p.familyName AS familyName`,
24704
25285
  { taskId, accountId, assigneeUserId, now }
@@ -24715,6 +25296,7 @@ app55.post("/", requireAdminSession, async (c) => {
24715
25296
  console.log(
24716
25297
  `${TAG44} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
24717
25298
  );
25299
+ invalidate("tasks-list", accountId);
24718
25300
  return c.json({ ok: true, assigneeUserId, assigneeName });
24719
25301
  } catch (err) {
24720
25302
  console.error(`${TAG44} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
@@ -25023,9 +25605,9 @@ var verify_token_default = app59;
25023
25605
 
25024
25606
  // app/lib/access-email.ts
25025
25607
  import { spawn as spawn2 } from "child_process";
25026
- import { resolve as resolve34 } from "path";
25027
- var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT ?? resolve34(process.cwd(), "..");
25028
- 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(
25029
25611
  PLATFORM_ROOT7,
25030
25612
  "plugins",
25031
25613
  "email",
@@ -25168,7 +25750,7 @@ var access_default = app61;
25168
25750
 
25169
25751
  // server/routes/sites.ts
25170
25752
  import { existsSync as existsSync40, readFileSync as readFileSync41, realpathSync as realpathSync8, statSync as statSync17 } from "fs";
25171
- import { resolve as resolve35 } from "path";
25753
+ import { resolve as resolve36 } from "path";
25172
25754
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
25173
25755
  var MIME = {
25174
25756
  ".html": "text/html; charset=utf-8",
@@ -25225,8 +25807,8 @@ app62.get("/:rel{.*}", (c) => {
25225
25807
  }
25226
25808
  segments.push(seg);
25227
25809
  }
25228
- const rootDir = resolve35(account.accountDir, "sites");
25229
- 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);
25230
25812
  if (filePath !== rootDir && !filePath.startsWith(rootDir + "/")) {
25231
25813
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
25232
25814
  return c.text("Forbidden", 403);
@@ -25246,7 +25828,7 @@ app62.get("/:rel{.*}", (c) => {
25246
25828
  return c.redirect(target, 301);
25247
25829
  }
25248
25830
  if (stat11?.isDirectory()) {
25249
- filePath = resolve35(filePath, "index.html");
25831
+ filePath = resolve36(filePath, "index.html");
25250
25832
  }
25251
25833
  if (!filePath.startsWith(rootDir + "/")) {
25252
25834
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
@@ -25892,14 +26474,14 @@ async function writeEvent(opts) {
25892
26474
  var visitor_event_default = app65;
25893
26475
 
25894
26476
  // server/routes/session.ts
25895
- import { resolve as resolve36 } from "path";
26477
+ import { resolve as resolve37 } from "path";
25896
26478
  import { existsSync as existsSync42, writeFileSync as writeFileSync15, mkdirSync as mkdirSync9 } from "fs";
25897
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;
25898
26480
  function writeBrandingCache(accountId, agentSlug, branding) {
25899
26481
  try {
25900
- const cacheDir = resolve36(MAXY_DIR, "branding-cache", accountId);
26482
+ const cacheDir = resolve37(MAXY_DIR, "branding-cache", accountId);
25901
26483
  mkdirSync9(cacheDir, { recursive: true });
25902
- writeFileSync15(resolve36(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
26484
+ writeFileSync15(resolve37(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
25903
26485
  } catch (err) {
25904
26486
  console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
25905
26487
  }
@@ -25976,8 +26558,8 @@ app66.post("/", async (c) => {
25976
26558
  }
25977
26559
  let agentConfig = null;
25978
26560
  if (account) {
25979
- const agentDir = resolve36(account.accountDir, "agents", agentSlug);
25980
- 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"))) {
25981
26563
  return c.json({ error: "Agent not found" }, 404);
25982
26564
  }
25983
26565
  agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
@@ -26237,7 +26819,7 @@ var calendar_public_default = app67;
26237
26819
  // server/routes/portal-fetch.ts
26238
26820
  import { createReadStream as createReadStream3 } from "fs";
26239
26821
  import { stat as stat8, readFile as readFile9, realpath } from "fs/promises";
26240
- 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";
26241
26823
  import { Readable as Readable3 } from "stream";
26242
26824
  var app68 = new Hono();
26243
26825
  var TAG49 = "[portal-fetch]";
@@ -26290,7 +26872,7 @@ ${expiresAtMs}`)
26290
26872
  return diff === 0;
26291
26873
  }
26292
26874
  async function readAccountSecret(accountId) {
26293
- const path3 = resolve37(DATA_ROOT, "accounts", accountId, "secrets", "data-portal.env");
26875
+ const path3 = resolve38(DATA_ROOT, "accounts", accountId, "secrets", "data-portal.env");
26294
26876
  let text;
26295
26877
  try {
26296
26878
  text = await readFile9(path3, "utf8");
@@ -26326,7 +26908,7 @@ async function resolveFetchTarget(accountDir, relPath, ownerId) {
26326
26908
  const exposeFolders = await readExposeFolders2(accountDir);
26327
26909
  const { exposed } = resolveExposedDirs(schemaText, exposeFolders);
26328
26910
  if (exposed.length === 0 && !ownerId) return { ok: false, reason: "not-exposed" };
26329
- const lexical = resolve37(accountDir, relPath);
26911
+ const lexical = resolve38(accountDir, relPath);
26330
26912
  let root;
26331
26913
  let absolute;
26332
26914
  try {
@@ -26375,7 +26957,7 @@ async function handle(c, headOnly) {
26375
26957
  return c.json({ ok: false, error: "denied" }, 401);
26376
26958
  }
26377
26959
  const target = await resolveFetchTarget(
26378
- resolve37(DATA_ROOT, "accounts", accountId),
26960
+ resolve38(DATA_ROOT, "accounts", accountId),
26379
26961
  relPath,
26380
26962
  owner || void 0
26381
26963
  );
@@ -26536,14 +27118,14 @@ function formatCensusLine(f) {
26536
27118
  var TAG51 = "[ledger-census]";
26537
27119
  var DAY_MS = 864e5;
26538
27120
  function countWriteRejects24h(logDir, now) {
26539
- let entries;
27121
+ let entries2;
26540
27122
  try {
26541
- 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"));
26542
27124
  } catch {
26543
27125
  return 0;
26544
27126
  }
26545
27127
  let total = 0;
26546
- for (const name of entries) {
27128
+ for (const name of entries2) {
26547
27129
  const path3 = join45(logDir, name);
26548
27130
  try {
26549
27131
  if (now - statSync18(path3).mtimeMs > DAY_MS) continue;
@@ -26698,7 +27280,7 @@ async function runConversationAudit() {
26698
27280
  }
26699
27281
 
26700
27282
  // app/lib/graph-health.ts
26701
- var import_dist6 = __toESM(require_dist4(), 1);
27283
+ var import_dist7 = __toESM(require_dist5(), 1);
26702
27284
  var HOUR_MS = 60 * 60 * 1e3;
26703
27285
  function renderLabelTop(rows) {
26704
27286
  return rows.map((b) => {
@@ -26743,7 +27325,7 @@ async function runGraphHealthTick() {
26743
27325
  console.error(
26744
27326
  `[graph-health] userprofile-multi accounts=${upAccounts} top=${upTop.length > 0 ? upTop.join(",") : "none"}`
26745
27327
  );
26746
- const indexed = [...import_dist6.VECTOR_INDEXED_LABELS];
27328
+ const indexed = [...import_dist7.VECTOR_INDEXED_LABELS];
26747
27329
  const embCount = await session.run(
26748
27330
  `MATCH (n) WHERE n.embedding IS NULL AND any(l IN labels(n) WHERE l IN $indexed)
26749
27331
  RETURN count(n) AS total`,
@@ -26816,7 +27398,7 @@ function startGraphHealthTimer() {
26816
27398
 
26817
27399
  // app/lib/file-watcher.ts
26818
27400
  import * as fsp2 from "fs/promises";
26819
- import { resolve as resolve38, sep as sep11 } from "path";
27401
+ import { resolve as resolve39, sep as sep11 } from "path";
26820
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;
26821
27403
  var DEFAULT_COALESCE_MS = 500;
26822
27404
  var ROOTS = ["accounts"];
@@ -26835,7 +27417,7 @@ async function startFileWatcher(opts = {}) {
26835
27417
  const dropFn = opts.drop ?? dropFileIndex;
26836
27418
  for (const r of ROOTS) {
26837
27419
  try {
26838
- await fsp2.mkdir(resolve38(dataRoot, r), { recursive: true });
27420
+ await fsp2.mkdir(resolve39(dataRoot, r), { recursive: true });
26839
27421
  } catch (err) {
26840
27422
  console.error(
26841
27423
  `[file-watcher] start-failed root="${r}" err="${err.message}" \u2014 index will be maintained by the 5-min reconcile backstop only`
@@ -26856,7 +27438,7 @@ async function startFileWatcher(opts = {}) {
26856
27438
  timers.set(relativePath, t);
26857
27439
  }
26858
27440
  async function runHook(relativePath, accountId) {
26859
- const absolute = resolve38(dataRoot, relativePath);
27441
+ const absolute = resolve39(dataRoot, relativePath);
26860
27442
  let exists = false;
26861
27443
  try {
26862
27444
  const st = await fsp2.stat(absolute);
@@ -26880,7 +27462,7 @@ async function startFileWatcher(opts = {}) {
26880
27462
  }
26881
27463
  }
26882
27464
  async function watchRoot(rootName) {
26883
- const absRoot = resolve38(dataRoot, rootName);
27465
+ const absRoot = resolve39(dataRoot, rootName);
26884
27466
  try {
26885
27467
  const iter = fsp2.watch(absRoot, { recursive: true, signal: controller.signal });
26886
27468
  for await (const event of iter) {
@@ -26919,18 +27501,18 @@ async function startFileWatcher(opts = {}) {
26919
27501
 
26920
27502
  // app/lib/migrate-uploads.ts
26921
27503
  import { mkdir as mkdir6, readdir as readdir6, rename as rename3, rm as rm3 } from "fs/promises";
26922
- 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";
26923
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;
26924
27506
  async function walkFiles(dir) {
26925
27507
  const out = [];
26926
- let entries;
27508
+ let entries2;
26927
27509
  try {
26928
- entries = await readdir6(dir, { withFileTypes: true });
27510
+ entries2 = await readdir6(dir, { withFileTypes: true });
26929
27511
  } catch {
26930
27512
  return out;
26931
27513
  }
26932
- for (const e of entries) {
26933
- const abs = resolve39(dir, e.name);
27514
+ for (const e of entries2) {
27515
+ const abs = resolve40(dir, e.name);
26934
27516
  if (e.isDirectory()) {
26935
27517
  out.push(...await walkFiles(abs));
26936
27518
  } else if (e.isFile()) {
@@ -26950,7 +27532,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
26950
27532
  let moved = 0;
26951
27533
  for (const oldAbs of files) {
26952
27534
  const suffix = relative7(srcDir, oldAbs);
26953
- const newAbs = resolve39(destDir, suffix);
27535
+ const newAbs = resolve40(destDir, suffix);
26954
27536
  await mkdir6(dirname15(newAbs), { recursive: true });
26955
27537
  await rename3(oldAbs, newAbs);
26956
27538
  moved++;
@@ -26977,7 +27559,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
26977
27559
  }
26978
27560
  async function migrateUploads(opts = {}) {
26979
27561
  const dataRoot = opts.dataRoot ?? DATA_ROOT;
26980
- const oldRoot = resolve39(dataRoot, "uploads");
27562
+ const oldRoot = resolve40(dataRoot, "uploads");
26981
27563
  let topEntries;
26982
27564
  try {
26983
27565
  topEntries = await readdir6(oldRoot, { withFileTypes: true });
@@ -26998,8 +27580,8 @@ async function migrateUploads(opts = {}) {
26998
27580
  const name = entry.name;
26999
27581
  if (ACCOUNT_UUID_RE5.test(name)) {
27000
27582
  moved += await relocateTree(
27001
- resolve39(oldRoot, name),
27002
- resolve39(dataRoot, "accounts", name, "uploads"),
27583
+ resolve40(oldRoot, name),
27584
+ resolve40(dataRoot, "accounts", name, "uploads"),
27003
27585
  dataRoot,
27004
27586
  name,
27005
27587
  session
@@ -27011,8 +27593,8 @@ async function migrateUploads(opts = {}) {
27011
27593
  continue;
27012
27594
  }
27013
27595
  moved += await relocateTree(
27014
- resolve39(oldRoot, "public"),
27015
- resolve39(dataRoot, "accounts", installAccountId, "uploads", "public"),
27596
+ resolve40(oldRoot, "public"),
27597
+ resolve40(dataRoot, "accounts", installAccountId, "uploads", "public"),
27016
27598
  dataRoot,
27017
27599
  null,
27018
27600
  // public uploads carry no graph nodes
@@ -27089,13 +27671,13 @@ async function collectLiveSidecars(projectsRoot) {
27089
27671
  for (const slug of slugs) {
27090
27672
  if (!slug.isDirectory()) continue;
27091
27673
  const slugDir = join46(projectsRoot, slug.name);
27092
- let entries;
27674
+ let entries2;
27093
27675
  try {
27094
- entries = await readdir7(slugDir, { withFileTypes: true });
27676
+ entries2 = await readdir7(slugDir, { withFileTypes: true });
27095
27677
  } catch {
27096
27678
  continue;
27097
27679
  }
27098
- for (const entry of entries) {
27680
+ for (const entry of entries2) {
27099
27681
  if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
27100
27682
  out.push(join46(slugDir, entry.name));
27101
27683
  } else if (entry.isDirectory() && entry.name === "subagents") {
@@ -28154,16 +28736,16 @@ var WebchatGateway = class _WebchatGateway {
28154
28736
  * The public /api/chat route awaits this to return the reply on the same SSE
28155
28737
  * response, preserving the pre-756 POST→single-blob browser contract. */
28156
28738
  awaitReply(key, timeoutMs) {
28157
- return new Promise((resolve45) => {
28739
+ return new Promise((resolve46) => {
28158
28740
  const timer = setTimeout(() => {
28159
28741
  this.replyAwaiters.delete(key);
28160
- resolve45({ timeout: true });
28742
+ resolve46({ timeout: true });
28161
28743
  }, timeoutMs);
28162
28744
  if (timer.unref) timer.unref();
28163
28745
  this.replyAwaiters.set(key, (r) => {
28164
28746
  clearTimeout(timer);
28165
28747
  this.replyAwaiters.delete(key);
28166
- resolve45(r);
28748
+ resolve46(r);
28167
28749
  });
28168
28750
  });
28169
28751
  }
@@ -28174,11 +28756,11 @@ var WebchatGateway = class _WebchatGateway {
28174
28756
  * terminal dialog stays answerable). */
28175
28757
  awaitPermissionVerdict(p, timeoutMs) {
28176
28758
  const k = _WebchatGateway.promptKey(p.key, p.requestId);
28177
- return new Promise((resolve45) => {
28759
+ return new Promise((resolve46) => {
28178
28760
  this.pendingPrompts.get(k)?.resolve({ timeout: true });
28179
28761
  const timer = setTimeout(() => {
28180
28762
  this.pendingPrompts.delete(k);
28181
- resolve45({ timeout: true });
28763
+ resolve46({ timeout: true });
28182
28764
  }, timeoutMs);
28183
28765
  if (timer.unref) timer.unref();
28184
28766
  this.pendingPrompts.set(k, {
@@ -28187,7 +28769,7 @@ var WebchatGateway = class _WebchatGateway {
28187
28769
  resolve: (r) => {
28188
28770
  clearTimeout(timer);
28189
28771
  this.pendingPrompts.delete(k);
28190
- resolve45(r);
28772
+ resolve46(r);
28191
28773
  }
28192
28774
  });
28193
28775
  console.error(`[webchat:perm] op=open key=${keyDisplay(p.key)} id=${p.requestId} tool=${p.toolName}`);
@@ -28752,7 +29334,7 @@ async function fanOut(subscribers, text, onError, tag) {
28752
29334
 
28753
29335
  // app/lib/webchat/file-delivery.ts
28754
29336
  import { realpathSync as realpathSync9 } from "fs";
28755
- import { resolve as resolve40 } from "path";
29337
+ import { resolve as resolve41 } from "path";
28756
29338
 
28757
29339
  // app/lib/channel-pty-bridge/file-delivery.ts
28758
29340
  var SEND_USER_FILE = "SendUserFile";
@@ -28853,7 +29435,7 @@ function makeWebchatSendFile(entry) {
28853
29435
  console.error(`${TAG53} file-delivery reject reason=no-account sender=${entry.senderId}`);
28854
29436
  return { ok: false, error: "no-account" };
28855
29437
  }
28856
- const accountDir = resolve40(platformRoot2(), "..", "data/accounts", entry.accountId);
29438
+ const accountDir = resolve41(platformRoot2(), "..", "data/accounts", entry.accountId);
28857
29439
  try {
28858
29440
  const resolved = realpathSync9(filePath);
28859
29441
  const accountResolved = realpathSync9(accountDir);
@@ -29417,7 +29999,7 @@ function buildTelegramSpawnRequest(input) {
29417
29999
  // app/lib/telegram/outbound/send-document.ts
29418
30000
  import { realpathSync as realpathSync10 } from "fs";
29419
30001
  import { readFile as readFile11, stat as stat10 } from "fs/promises";
29420
- import { resolve as resolve41, basename as basename13 } from "path";
30002
+ import { resolve as resolve42, basename as basename13 } from "path";
29421
30003
  var TAG55 = "[telegram:outbound]";
29422
30004
  var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
29423
30005
  async function sendTelegramDocument(input) {
@@ -29428,7 +30010,7 @@ async function sendTelegramDocument(input) {
29428
30010
  if (!maxyAccountId || !platformRoot5) {
29429
30011
  return { ok: false, status: 400, error: "Cannot validate file path: missing account or platform context" };
29430
30012
  }
29431
- const accountDir = resolve41(platformRoot5, "..", "data/accounts", maxyAccountId);
30013
+ const accountDir = resolve42(platformRoot5, "..", "data/accounts", maxyAccountId);
29432
30014
  let accountResolved;
29433
30015
  try {
29434
30016
  accountResolved = realpathSync10(accountDir);
@@ -29720,11 +30302,11 @@ async function firePublicSessionEndReview(input) {
29720
30302
  }
29721
30303
 
29722
30304
  // app/lib/whatsapp/inbound/resolve-client-graph-owner.ts
29723
- var import_dist7 = __toESM(require_dist(), 1);
30305
+ var import_dist8 = __toESM(require_dist(), 1);
29724
30306
  async function resolveClientOwnerUserId(accountId, deps = {}) {
29725
30307
  const listAccounts = deps.listAccounts ?? listValidAccounts;
29726
30308
  const getSession4 = deps.getSession ?? getSession;
29727
- const resolveOwner2 = deps.resolveOwner ?? import_dist7.resolveOwnerUserId;
30309
+ const resolveOwner2 = deps.resolveOwner ?? import_dist8.resolveOwnerUserId;
29728
30310
  const role = listAccounts().find((a) => a.accountId === accountId)?.config.role;
29729
30311
  if (role !== "client") return null;
29730
30312
  const session = getSession4();
@@ -29821,10 +30403,10 @@ function warnOnChannelAdminBindingDrift() {
29821
30403
 
29822
30404
  // server/lib/booking-site-accounts.ts
29823
30405
  import { existsSync as existsSync44, readFileSync as readFileSync45 } from "fs";
29824
- import { resolve as resolve42 } from "path";
30406
+ import { resolve as resolve43 } from "path";
29825
30407
  function listBookingSiteAccounts(accounts) {
29826
30408
  return accounts.filter((a) => {
29827
- const availPath = resolve42(a.accountDir, "calendar-availability.json");
30409
+ const availPath = resolve43(a.accountDir, "calendar-availability.json");
29828
30410
  if (!existsSync44(availPath)) return false;
29829
30411
  try {
29830
30412
  const cfg = JSON.parse(readFileSync45(availPath, "utf-8"));
@@ -29866,7 +30448,7 @@ function broadcastAdminShutdown(reason) {
29866
30448
  // ../lib/entitlement/src/index.ts
29867
30449
  import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
29868
30450
  import { existsSync as existsSync45, readFileSync as readFileSync46, statSync as statSync19 } from "fs";
29869
- import { resolve as resolve43 } from "path";
30451
+ import { resolve as resolve44 } from "path";
29870
30452
 
29871
30453
  // ../lib/entitlement/src/canonicalize.ts
29872
30454
  function canonicalize(value) {
@@ -29901,7 +30483,7 @@ var PUBKEY_SHA256 = "8eee6bcb33545fd13b16d3199a5735ca5db5062834c7b49dfe4f23801d9
29901
30483
  var GRACE_DAYS = 7;
29902
30484
  var GRACE_MS = GRACE_DAYS * 24 * 60 * 60 * 1e3;
29903
30485
  function pubkeyPath(brand) {
29904
- return resolve43(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
30486
+ return resolve44(brand.platformRoot, "lib", "entitlement", "rubytech-pubkey.pem");
29905
30487
  }
29906
30488
  var memo = null;
29907
30489
  function memoKey(mtimeMs, account) {
@@ -29913,7 +30495,7 @@ function resolveEntitlement(brand, account) {
29913
30495
  if (brand.commercialMode !== true) {
29914
30496
  return logResolved(implicitTrust(account), null);
29915
30497
  }
29916
- const entitlementPath = resolve43(brand.configDir, "entitlement.json");
30498
+ const entitlementPath = resolve44(brand.configDir, "entitlement.json");
29917
30499
  if (!existsSync45(entitlementPath)) {
29918
30500
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
29919
30501
  }
@@ -30169,6 +30751,7 @@ watchFile(ALIAS_DOMAINS_PATH, { interval: 2e3 }, () => {
30169
30751
  aliasDomains = updated;
30170
30752
  console.log(`[alias-domains] reloaded ${updated.size} alias domain(s): ${[...updated].join(", ")}`);
30171
30753
  });
30754
+ attachRouteCacheWatchers();
30172
30755
  function isPublicHost(host) {
30173
30756
  return host.startsWith("public.") || aliasDomains.has(host);
30174
30757
  }
@@ -30186,8 +30769,8 @@ var webchatFileFollowers = /* @__PURE__ */ new Map();
30186
30769
  async function fetchAccountStandingRules(accountId) {
30187
30770
  const session = getSession();
30188
30771
  try {
30189
- const res = await (0, import_dist8.resolveActiveRules)(session, accountId);
30190
- 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 };
30191
30774
  } catch (err) {
30192
30775
  console.error(
30193
30776
  `[preference-inject] op=fetch-failed accountId=${accountId} error=${err instanceof Error ? err.message : String(err)}`
@@ -30221,7 +30804,7 @@ var waGateway = new WaGateway({
30221
30804
  fetchStandingRules: fetchAccountStandingRules,
30222
30805
  resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
30223
30806
  gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
30224
- 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"),
30225
30808
  // Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
30226
30809
  // path-validation scope) is the sender's effective SESSION account, resolved
30227
30810
  // once at the inbound gate and threaded here via the gateway's per-sender doc
@@ -30236,7 +30819,7 @@ var waGateway = new WaGateway({
30236
30819
  caption,
30237
30820
  accountId,
30238
30821
  maxyAccountId,
30239
- platformRoot: resolve44(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."))
30822
+ platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."))
30240
30823
  });
30241
30824
  return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
30242
30825
  },
@@ -30916,8 +31499,8 @@ app69.get("/agent-assets/:slug/:filename", (c) => {
30916
31499
  console.error(`[agent-assets] no-account slug=${slug} file=${filename}`);
30917
31500
  return c.text("Not found", 404);
30918
31501
  }
30919
- const filePath = resolve44(account.accountDir, "agents", slug, "assets", filename);
30920
- 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");
30921
31504
  if (!filePath.startsWith(expectedDir + "/")) {
30922
31505
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
30923
31506
  return c.text("Forbidden", 403);
@@ -30946,8 +31529,8 @@ app69.get("/generated/:filename", (c) => {
30946
31529
  console.error(`[generated] serve file=${filename} status=404`);
30947
31530
  return c.text("Not found", 404);
30948
31531
  }
30949
- const filePath = resolve44(account.accountDir, "generated", filename);
30950
- const expectedDir = resolve44(account.accountDir, "generated");
31532
+ const filePath = resolve45(account.accountDir, "generated", filename);
31533
+ const expectedDir = resolve45(account.accountDir, "generated");
30951
31534
  if (!filePath.startsWith(expectedDir + "/")) {
30952
31535
  console.error(`[generated] serve file=${filename} status=403`);
30953
31536
  return c.text("Forbidden", 403);
@@ -31001,11 +31584,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
31001
31584
  var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
31002
31585
  var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
31003
31586
  var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
31004
- (p) => existsSync46(resolve44(process.cwd(), "public", p.replace(/^\//, "")))
31587
+ (p) => existsSync46(resolve45(process.cwd(), "public", p.replace(/^\//, "")))
31005
31588
  );
31006
31589
  var SW_SOURCE = (() => {
31007
31590
  try {
31008
- return readFileSync47(resolve44(process.cwd(), "public", "sw.js"), "utf-8");
31591
+ return readFileSync47(resolve45(process.cwd(), "public", "sw.js"), "utf-8");
31009
31592
  } catch {
31010
31593
  return null;
31011
31594
  }
@@ -31056,7 +31639,7 @@ var clientErrorReporterScript = `<script>
31056
31639
  function cachedHtml(file) {
31057
31640
  let html = htmlCache.get(file);
31058
31641
  if (!html) {
31059
- html = readFileSync47(resolve44(process.cwd(), "public", file), "utf-8");
31642
+ html = readFileSync47(resolve45(process.cwd(), "public", file), "utf-8");
31060
31643
  const productNameEsc = escapeHtml(BRAND.productName);
31061
31644
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
31062
31645
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -31174,7 +31757,7 @@ app69.use("/vnc-popout.html", logViewerFetch);
31174
31757
  app69.get("/vnc-popout.html", (c) => {
31175
31758
  let html = htmlCache.get("vnc-popout.html");
31176
31759
  if (!html) {
31177
- html = readFileSync47(resolve44(process.cwd(), "public", "vnc-popout.html"), "utf-8");
31760
+ html = readFileSync47(resolve45(process.cwd(), "public", "vnc-popout.html"), "utf-8");
31178
31761
  const name = escapeHtml(BRAND.productName);
31179
31762
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
31180
31763
  html = html.replace("</head>", ` ${brandScript}
@@ -31327,7 +31910,7 @@ var httpServer = serve({ fetch: app69.fetch, port, hostname });
31327
31910
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31328
31911
  {
31329
31912
  const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31330
- 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");
31331
31914
  const runReconcile = (ctx) => {
31332
31915
  if (!existsSync46(reconcileScript)) return;
31333
31916
  try {
@@ -31368,7 +31951,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31368
31951
  {
31369
31952
  const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
31370
31953
  const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31371
- 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");
31372
31955
  registerLoop({
31373
31956
  name: "dream-cycle-sweep",
31374
31957
  intervalMs: DREAM_CYCLE_SWEEP_INTERVAL_MS,
@@ -31392,7 +31975,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31392
31975
  }
31393
31976
  {
31394
31977
  const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31395
- 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");
31396
31979
  const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
31397
31980
  const runOutlookComplete = (ctx) => {
31398
31981
  if (!existsSync46(outlookScript)) return;
@@ -31418,7 +32001,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31418
32001
  }
31419
32002
  {
31420
32003
  const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31421
- const strandedAccountsDir = resolve44(auditRoot, "..", "data/accounts");
32004
+ const strandedAccountsDir = resolve45(auditRoot, "..", "data/accounts");
31422
32005
  const STRANDED_AUDIT_INTERVAL_MS = 3e5;
31423
32006
  const STRANDED_AGE_MS = 16 * 6e4;
31424
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;
@@ -31428,7 +32011,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31428
32011
  const now = Date.now();
31429
32012
  for (const name of readdirSync28(strandedAccountsDir)) {
31430
32013
  if (!STRANDED_UUID_RE.test(name)) continue;
31431
- const pendingPath2 = resolve44(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
32014
+ const pendingPath2 = resolve45(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
31432
32015
  if (!existsSync46(pendingPath2)) continue;
31433
32016
  const ageMs2 = now - statSync20(pendingPath2).mtimeMs;
31434
32017
  if (ageMs2 > STRANDED_AGE_MS) {
@@ -31448,7 +32031,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31448
32031
  }
31449
32032
  {
31450
32033
  const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31451
- const googleAccountsDir = resolve44(googleRoot, "..", "data/accounts");
32034
+ const googleAccountsDir = resolve45(googleRoot, "..", "data/accounts");
31452
32035
  const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
31453
32036
  const runGooglePendingAuditSafe = () => {
31454
32037
  try {
@@ -31463,7 +32046,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31463
32046
  firstRunDelayMs: 27e3,
31464
32047
  run: runGooglePendingAuditSafe
31465
32048
  });
31466
- 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");
31467
32050
  const GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS = 36e5;
31468
32051
  const runGoogleAccountAudit = (ctx) => {
31469
32052
  if (!existsSync46(googleAuditScript)) return;
@@ -31538,7 +32121,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31538
32121
  }
31539
32122
  {
31540
32123
  const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31541
- 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");
31542
32125
  const PUBLISH_INTERVAL_MS = 3e5;
31543
32126
  const bookingAccounts = () => {
31544
32127
  try {
@@ -31568,7 +32151,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31568
32151
  }
31569
32152
  };
31570
32153
  const auditSnapshotAge = (account) => {
31571
- const availPath = resolve44(account.accountDir, "calendar-availability.json");
32154
+ const availPath = resolve45(account.accountDir, "calendar-availability.json");
31572
32155
  let hasBookingSite = false;
31573
32156
  try {
31574
32157
  if (existsSync46(availPath)) {
@@ -31578,7 +32161,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
31578
32161
  } catch {
31579
32162
  }
31580
32163
  if (!hasBookingSite) return;
31581
- const statePath = resolve44(account.accountDir, "state", "booking-availability", "last-publish.json");
32164
+ const statePath = resolve45(account.accountDir, "state", "booking-availability", "last-publish.json");
31582
32165
  let lastSuccessAt = null;
31583
32166
  if (existsSync46(statePath)) {
31584
32167
  try {
@@ -31615,7 +32198,7 @@ startTimeEntryCensus(() => getSession());
31615
32198
  startLedgerCensus(() => getSession());
31616
32199
  {
31617
32200
  const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
31618
- 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");
31619
32202
  const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
31620
32203
  const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
31621
32204
  const runConnectorAudit = (ctx) => {
@@ -31924,7 +32507,7 @@ if (bootAccountConfig?.whatsapp) {
31924
32507
  }
31925
32508
  init({
31926
32509
  configDir: configDirForWhatsApp,
31927
- platformRoot: resolve44(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..")),
32510
+ platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..")),
31928
32511
  accountConfig: bootAccountConfig,
31929
32512
  onMessage: async (msg) => {
31930
32513
  if (isObserveAccount(msg.accountId)) {