@rubytech/create-maxy-code 0.1.570 → 0.1.571

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 (174) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +6 -0
  3. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +1 -1
  4. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  5. package/payload/platform/services/claude-session-manager/dist/http-server.js +38 -13
  6. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  7. package/payload/platform/services/telegram-channel/dist/notification.d.ts +20 -7
  8. package/payload/platform/services/telegram-channel/dist/notification.d.ts.map +1 -1
  9. package/payload/platform/services/telegram-channel/dist/notification.js +38 -4
  10. package/payload/platform/services/telegram-channel/dist/notification.js.map +1 -1
  11. package/payload/server/public/activity.html +5 -5
  12. package/payload/server/public/agents.html +4 -4
  13. package/payload/server/public/assets/{AdminLoginScreens-5gI137xF.js → AdminLoginScreens-CKyVm5aW.js} +1 -1
  14. package/payload/server/public/assets/AdminLoginScreens-CKyVm5aW.js.br +0 -0
  15. package/payload/server/public/assets/AdminLoginScreens-CKyVm5aW.js.gz +0 -0
  16. package/payload/server/public/assets/{AdminShell-Bfapavlp.js → AdminShell-slZzNEDR.js} +1 -1
  17. package/payload/server/public/assets/AdminShell-slZzNEDR.js.br +0 -0
  18. package/payload/server/public/assets/AdminShell-slZzNEDR.js.gz +0 -0
  19. package/payload/server/public/assets/{activity-DnbsmUgn.js → activity-6DhWjVwg.js} +1 -1
  20. package/payload/server/public/assets/activity-6DhWjVwg.js.br +0 -0
  21. package/payload/server/public/assets/activity-6DhWjVwg.js.gz +0 -0
  22. package/payload/server/public/assets/{admin-BXIv0_oj.js → admin-BB8DoIb_.js} +1 -1
  23. package/payload/server/public/assets/admin-BB8DoIb_.js.br +0 -0
  24. package/payload/server/public/assets/admin-BB8DoIb_.js.gz +0 -0
  25. package/payload/server/public/assets/{agents-Dl2wOcpj.js → agents-D-28pUk7.js} +1 -1
  26. package/payload/server/public/assets/agents-D-28pUk7.js.br +0 -0
  27. package/payload/server/public/assets/agents-D-28pUk7.js.gz +0 -0
  28. package/payload/server/public/assets/{browser-D-Uc9ewO.js → browser-BGJPx931.js} +1 -1
  29. package/payload/server/public/assets/browser-BGJPx931.js.br +0 -0
  30. package/payload/server/public/assets/browser-BGJPx931.js.gz +0 -0
  31. package/payload/server/public/assets/{calendar-Cu3O6Bay.js → calendar-CP7u15G9.js} +1 -1
  32. package/payload/server/public/assets/calendar-CP7u15G9.js.br +0 -0
  33. package/payload/server/public/assets/calendar-CP7u15G9.js.gz +0 -0
  34. package/payload/server/public/assets/chat-C0wgXTz3.js +1 -0
  35. package/payload/server/public/assets/chat-C0wgXTz3.js.br +0 -0
  36. package/payload/server/public/assets/chat-C0wgXTz3.js.gz +0 -0
  37. package/payload/server/public/assets/chevron-left-CKe1u6eC.js +1 -0
  38. package/payload/server/public/assets/chevron-left-CKe1u6eC.js.br +0 -0
  39. package/payload/server/public/assets/clock-D8MegkDy.js +1 -0
  40. package/payload/server/public/assets/clock-D8MegkDy.js.br +0 -0
  41. package/payload/server/public/assets/{copy-DPBVV8KZ.js → copy-Cu819JFC.js} +1 -1
  42. package/payload/server/public/assets/copy-Cu819JFC.js.br +0 -0
  43. package/payload/server/public/assets/copy-Cu819JFC.js.gz +0 -0
  44. package/payload/server/public/assets/data-B7W5Ocvt.js +1 -0
  45. package/payload/server/public/assets/data-B7W5Ocvt.js.br +0 -0
  46. package/payload/server/public/assets/data-B7W5Ocvt.js.gz +0 -0
  47. package/payload/server/public/assets/{file-text-Dn82O6ke.js → file-text-BoiZDy84.js} +1 -1
  48. package/payload/server/public/assets/file-text-BoiZDy84.js.br +0 -0
  49. package/payload/server/public/assets/file-text-BoiZDy84.js.gz +0 -0
  50. package/payload/server/public/assets/{graph-D2J7a7Ll.js → graph-Dr6uIMgA.js} +1 -1
  51. package/payload/server/public/assets/graph-Dr6uIMgA.js.br +0 -0
  52. package/payload/server/public/assets/graph-Dr6uIMgA.js.gz +0 -0
  53. package/payload/server/public/assets/{graph-labels-D3gkY2IH.js → graph-labels-9y5-8Rc_.js} +1 -1
  54. package/payload/server/public/assets/graph-labels-9y5-8Rc_.js.br +0 -0
  55. package/payload/server/public/assets/graph-labels-9y5-8Rc_.js.gz +0 -0
  56. package/payload/server/public/assets/{operator-Bz_yj1im.js → operator-Cn5P5yqu.js} +1 -1
  57. package/payload/server/public/assets/operator-Cn5P5yqu.js.br +0 -0
  58. package/payload/server/public/assets/operator-Cn5P5yqu.js.gz +0 -0
  59. package/payload/server/public/assets/{page-D6u2xYh7.js → page-DqnWu9Aj.js} +1 -1
  60. package/payload/server/public/assets/page-DqnWu9Aj.js.br +0 -0
  61. package/payload/server/public/assets/page-DqnWu9Aj.js.gz +0 -0
  62. package/payload/server/public/assets/{page-mH4nyQ75.js → page-VTcDQ8qS.js} +1 -1
  63. package/payload/server/public/assets/page-VTcDQ8qS.js.br +0 -0
  64. package/payload/server/public/assets/page-VTcDQ8qS.js.gz +0 -0
  65. package/payload/server/public/assets/play-Dp6K3szP.js +1 -0
  66. package/payload/server/public/assets/play-Dp6K3szP.js.br +0 -0
  67. package/payload/server/public/assets/play-Dp6K3szP.js.gz +0 -0
  68. package/payload/server/public/assets/{public-CtoYVjPR.js → public-HlWIQCkl.js} +1 -1
  69. package/payload/server/public/assets/public-HlWIQCkl.js.br +0 -0
  70. package/payload/server/public/assets/public-HlWIQCkl.js.gz +0 -0
  71. package/payload/server/public/assets/{rotate-ccw-BXoIghE3.js → rotate-ccw-kpEqIj4T.js} +1 -1
  72. package/payload/server/public/assets/rotate-ccw-kpEqIj4T.js.br +0 -0
  73. package/payload/server/public/assets/rotate-ccw-kpEqIj4T.js.gz +0 -0
  74. package/payload/server/public/assets/{routines-DXleYpDv.js → routines-CvDzjwtZ.js} +1 -1
  75. package/payload/server/public/assets/routines-CvDzjwtZ.js.br +0 -0
  76. package/payload/server/public/assets/routines-CvDzjwtZ.js.gz +0 -0
  77. package/payload/server/public/assets/{skills-CMl38MKH.js → skills-Bom76JQv.js} +1 -1
  78. package/payload/server/public/assets/skills-Bom76JQv.js.br +0 -0
  79. package/payload/server/public/assets/skills-Bom76JQv.js.gz +0 -0
  80. package/payload/server/public/assets/{tasks-Cshaf0Md.js → tasks-DCiTDQ-r.js} +1 -1
  81. package/payload/server/public/assets/tasks-DCiTDQ-r.js.br +0 -0
  82. package/payload/server/public/assets/tasks-DCiTDQ-r.js.gz +0 -0
  83. package/payload/server/public/assets/{triangle-alert-CS-NXr_9.js → triangle-alert-DBSoNN4T.js} +1 -1
  84. package/payload/server/public/assets/triangle-alert-DBSoNN4T.js.br +0 -0
  85. package/payload/server/public/assets/triangle-alert-DBSoNN4T.js.gz +0 -0
  86. package/payload/server/public/assets/{useCopyFeedback-pKLfQJNG.js → useCopyFeedback-Do4uNxoZ.js} +1 -1
  87. package/payload/server/public/assets/useCopyFeedback-Do4uNxoZ.js.br +0 -0
  88. package/payload/server/public/assets/useCopyFeedback-Do4uNxoZ.js.gz +0 -0
  89. package/payload/server/public/assets/{useMediaQuery-BHFn0-S9.css → useMediaQuery-BbG7Ar0P.css} +1 -1
  90. package/payload/server/public/assets/useMediaQuery-BbG7Ar0P.css.br +0 -0
  91. package/payload/server/public/assets/{useMediaQuery-BHFn0-S9.css.gz → useMediaQuery-BbG7Ar0P.css.gz} +0 -0
  92. package/payload/server/public/assets/useVoiceRecorder-BzezRxgT.js +2 -0
  93. package/payload/server/public/assets/useVoiceRecorder-BzezRxgT.js.br +0 -0
  94. package/payload/server/public/assets/useVoiceRecorder-BzezRxgT.js.gz +0 -0
  95. package/payload/server/public/assets/{wrench-czES9Rdy.js → wrench-BmLFQPJb.js} +1 -1
  96. package/payload/server/public/assets/wrench-BmLFQPJb.js.br +0 -0
  97. package/payload/server/public/assets/wrench-BmLFQPJb.js.gz +0 -0
  98. package/payload/server/public/browser.html +4 -4
  99. package/payload/server/public/calendar.html +7 -7
  100. package/payload/server/public/chat.html +13 -13
  101. package/payload/server/public/data.html +11 -11
  102. package/payload/server/public/graph.html +9 -9
  103. package/payload/server/public/index.html +13 -13
  104. package/payload/server/public/operator.html +14 -14
  105. package/payload/server/public/public.html +13 -13
  106. package/payload/server/public/routines.html +7 -7
  107. package/payload/server/public/skills.html +5 -5
  108. package/payload/server/public/tasks.html +6 -6
  109. package/payload/server/server.js +739 -469
  110. package/payload/server/public/assets/AdminLoginScreens-5gI137xF.js.br +0 -0
  111. package/payload/server/public/assets/AdminLoginScreens-5gI137xF.js.gz +0 -0
  112. package/payload/server/public/assets/AdminShell-Bfapavlp.js.br +0 -0
  113. package/payload/server/public/assets/AdminShell-Bfapavlp.js.gz +0 -0
  114. package/payload/server/public/assets/activity-DnbsmUgn.js.br +0 -0
  115. package/payload/server/public/assets/activity-DnbsmUgn.js.gz +0 -0
  116. package/payload/server/public/assets/admin-BXIv0_oj.js.br +0 -0
  117. package/payload/server/public/assets/admin-BXIv0_oj.js.gz +0 -0
  118. package/payload/server/public/assets/agents-Dl2wOcpj.js.br +0 -0
  119. package/payload/server/public/assets/agents-Dl2wOcpj.js.gz +0 -0
  120. package/payload/server/public/assets/browser-D-Uc9ewO.js.br +0 -0
  121. package/payload/server/public/assets/browser-D-Uc9ewO.js.gz +0 -0
  122. package/payload/server/public/assets/calendar-Cu3O6Bay.js.br +0 -0
  123. package/payload/server/public/assets/calendar-Cu3O6Bay.js.gz +0 -0
  124. package/payload/server/public/assets/chat-Bso94e-f.js +0 -1
  125. package/payload/server/public/assets/chat-Bso94e-f.js.br +0 -0
  126. package/payload/server/public/assets/chat-Bso94e-f.js.gz +0 -0
  127. package/payload/server/public/assets/chevron-left-CDwfR9V-.js +0 -1
  128. package/payload/server/public/assets/chevron-left-CDwfR9V-.js.br +0 -0
  129. package/payload/server/public/assets/clock-DDVrNLt9.js +0 -1
  130. package/payload/server/public/assets/clock-DDVrNLt9.js.br +0 -0
  131. package/payload/server/public/assets/clock-DDVrNLt9.js.gz +0 -0
  132. package/payload/server/public/assets/copy-DPBVV8KZ.js.br +0 -0
  133. package/payload/server/public/assets/copy-DPBVV8KZ.js.gz +0 -0
  134. package/payload/server/public/assets/data-Dei8n2EX.js +0 -1
  135. package/payload/server/public/assets/data-Dei8n2EX.js.br +0 -0
  136. package/payload/server/public/assets/data-Dei8n2EX.js.gz +0 -0
  137. package/payload/server/public/assets/file-text-Dn82O6ke.js.br +0 -0
  138. package/payload/server/public/assets/file-text-Dn82O6ke.js.gz +0 -0
  139. package/payload/server/public/assets/graph-D2J7a7Ll.js.br +0 -0
  140. package/payload/server/public/assets/graph-D2J7a7Ll.js.gz +0 -0
  141. package/payload/server/public/assets/graph-labels-D3gkY2IH.js.br +0 -0
  142. package/payload/server/public/assets/graph-labels-D3gkY2IH.js.gz +0 -0
  143. package/payload/server/public/assets/operator-Bz_yj1im.js.br +0 -0
  144. package/payload/server/public/assets/operator-Bz_yj1im.js.gz +0 -0
  145. package/payload/server/public/assets/page-D6u2xYh7.js.br +0 -0
  146. package/payload/server/public/assets/page-D6u2xYh7.js.gz +0 -0
  147. package/payload/server/public/assets/page-mH4nyQ75.js.br +0 -0
  148. package/payload/server/public/assets/page-mH4nyQ75.js.gz +0 -0
  149. package/payload/server/public/assets/play-ByuChQJJ.js +0 -1
  150. package/payload/server/public/assets/play-ByuChQJJ.js.br +0 -0
  151. package/payload/server/public/assets/play-ByuChQJJ.js.gz +0 -0
  152. package/payload/server/public/assets/public-CtoYVjPR.js.br +0 -0
  153. package/payload/server/public/assets/public-CtoYVjPR.js.gz +0 -0
  154. package/payload/server/public/assets/rotate-ccw-BXoIghE3.js.br +0 -0
  155. package/payload/server/public/assets/rotate-ccw-BXoIghE3.js.gz +0 -0
  156. package/payload/server/public/assets/routines-DXleYpDv.js.br +0 -0
  157. package/payload/server/public/assets/routines-DXleYpDv.js.gz +0 -0
  158. package/payload/server/public/assets/skills-CMl38MKH.js.br +0 -0
  159. package/payload/server/public/assets/skills-CMl38MKH.js.gz +0 -0
  160. package/payload/server/public/assets/tasks-Cshaf0Md.js.br +0 -0
  161. package/payload/server/public/assets/tasks-Cshaf0Md.js.gz +0 -0
  162. package/payload/server/public/assets/triangle-alert-CS-NXr_9.js.br +0 -3
  163. package/payload/server/public/assets/triangle-alert-CS-NXr_9.js.gz +0 -0
  164. package/payload/server/public/assets/useCopyFeedback-pKLfQJNG.js.br +0 -0
  165. package/payload/server/public/assets/useCopyFeedback-pKLfQJNG.js.gz +0 -0
  166. package/payload/server/public/assets/useMediaQuery-BHFn0-S9.css.br +0 -0
  167. package/payload/server/public/assets/useVoiceRecorder-EgO1GmIg.js +0 -2
  168. package/payload/server/public/assets/useVoiceRecorder-EgO1GmIg.js.br +0 -0
  169. package/payload/server/public/assets/useVoiceRecorder-EgO1GmIg.js.gz +0 -0
  170. package/payload/server/public/assets/wrench-czES9Rdy.js.br +0 -0
  171. package/payload/server/public/assets/wrench-czES9Rdy.js.gz +0 -0
  172. /package/payload/server/public/assets/{useMediaQuery-oDCasnxD.js → useMediaQuery-6vKHR1CS.js} +0 -0
  173. /package/payload/server/public/assets/{useMediaQuery-oDCasnxD.js.br → useMediaQuery-6vKHR1CS.js.br} +0 -0
  174. /package/payload/server/public/assets/{useMediaQuery-oDCasnxD.js.gz → useMediaQuery-6vKHR1CS.js.gz} +0 -0
@@ -4367,7 +4367,7 @@ init_dist();
4367
4367
  import { readFileSync as readFileSync51, existsSync as existsSync54, watchFile, readdirSync as readdirSync32, statSync as statSync30 } from "fs";
4368
4368
  import { spawn as spawn3 } from "child_process";
4369
4369
  import { createHash as createHash8 } from "crypto";
4370
- import { resolve as resolve49, join as join60, basename as basename17 } from "path";
4370
+ import { resolve as resolve49, join as join61, basename as basename17 } from "path";
4371
4371
  import { homedir as homedir5 } from "os";
4372
4372
 
4373
4373
  // server/lib/route-cache-watchers.ts
@@ -6788,6 +6788,9 @@ function createScheduleInjectRoutes(deps) {
6788
6788
  role: "admin",
6789
6789
  personId: null,
6790
6790
  text: prompt,
6791
+ // Task 2489 — a scheduled inject carries no inbound file by
6792
+ // construction: there is no message to have attached one.
6793
+ media: [],
6791
6794
  source: "schedule",
6792
6795
  scheduleProvenance,
6793
6796
  reply
@@ -14961,7 +14964,7 @@ var webchat_greeting_default = app10;
14961
14964
  init_dist();
14962
14965
  init_claude_agent();
14963
14966
  import { homedir as homedir3 } from "os";
14964
- import { resolve as resolve21, join as join32 } from "path";
14967
+ import { resolve as resolve21, join as join33 } from "path";
14965
14968
  import { existsSync as existsSync22, readFileSync as readFileSync27 } from "fs";
14966
14969
 
14967
14970
  // app/lib/telegram/gateway/instance.ts
@@ -15002,6 +15005,20 @@ function checkTelegramAccess(params) {
15002
15005
  }
15003
15006
 
15004
15007
  // app/lib/telegram/route-inbound.ts
15008
+ var CONTENT_KEYS = [
15009
+ "photo",
15010
+ "video",
15011
+ "video_note",
15012
+ "voice",
15013
+ "audio",
15014
+ "document",
15015
+ "sticker",
15016
+ "venue",
15017
+ "location",
15018
+ "text",
15019
+ "caption"
15020
+ ];
15021
+ var ENVELOPE_KEYS = /* @__PURE__ */ new Set(["message_id", "from", "chat", "date", "edit_date"]);
15005
15022
  function telegramSenderDisplay(from) {
15006
15023
  const first = from.first_name?.trim() ?? "";
15007
15024
  if (first.length > 0) {
@@ -15012,13 +15029,97 @@ function telegramSenderDisplay(from) {
15012
15029
  if (handle2.length > 0) return `@${handle2}`;
15013
15030
  return String(from.id ?? "");
15014
15031
  }
15032
+ function describeTelegramUpdate(update) {
15033
+ const isEdit = update.message == null && update.edited_message != null;
15034
+ const m = update.message ?? update.edited_message;
15035
+ const envelope = update.message != null ? "message" : update.edited_message != null ? "edited_message" : "other";
15036
+ if (!m) return { envelope, contentKeys: [], content: "none", primaryKind: "none", isEdit };
15037
+ let contentKeys = CONTENT_KEYS.filter((k) => m[k] != null);
15038
+ if (contentKeys.length === 0) {
15039
+ contentKeys = Object.keys(m).filter((k) => !ENVELOPE_KEYS.has(k)).sort();
15040
+ }
15041
+ return {
15042
+ envelope,
15043
+ contentKeys,
15044
+ content: contentKeys.length > 0 ? contentKeys.join(",") : "none",
15045
+ primaryKind: contentKeys[0] ?? "none",
15046
+ isEdit
15047
+ };
15048
+ }
15049
+ function fileIds(f) {
15050
+ if (!f || typeof f.file_id !== "string" || typeof f.file_unique_id !== "string") return null;
15051
+ return { fileId: f.file_id, fileUniqueId: f.file_unique_id };
15052
+ }
15053
+ function extractContent(m) {
15054
+ const media = [];
15055
+ let placeholder = null;
15056
+ const note = (s) => {
15057
+ if (placeholder === null) placeholder = s;
15058
+ };
15059
+ const photo = Array.isArray(m.photo) && m.photo.length > 0 ? m.photo[m.photo.length - 1] : void 0;
15060
+ const photoIds = fileIds(photo);
15061
+ if (photoIds) {
15062
+ media.push({ type: "image", ...photoIds, mimetype: "image/jpeg" });
15063
+ note("[photo]");
15064
+ }
15065
+ const videoIds = fileIds(m.video);
15066
+ if (videoIds) {
15067
+ media.push({ type: "video", ...videoIds, ...m.video?.mime_type ? { mimetype: m.video.mime_type } : {} });
15068
+ note("[video]");
15069
+ }
15070
+ const videoNoteIds = fileIds(m.video_note);
15071
+ if (videoNoteIds) {
15072
+ media.push({
15073
+ type: "video",
15074
+ ...videoNoteIds,
15075
+ ...m.video_note?.mime_type ? { mimetype: m.video_note.mime_type } : {}
15076
+ });
15077
+ note("[video]");
15078
+ }
15079
+ const voiceIds = fileIds(m.voice);
15080
+ if (voiceIds) {
15081
+ media.push({ type: "audio", ...voiceIds, ...m.voice?.mime_type ? { mimetype: m.voice.mime_type } : {} });
15082
+ note("[voice]");
15083
+ }
15084
+ const audioIds = fileIds(m.audio);
15085
+ if (audioIds) {
15086
+ media.push({ type: "audio", ...audioIds, ...m.audio?.mime_type ? { mimetype: m.audio.mime_type } : {} });
15087
+ note("[audio]");
15088
+ }
15089
+ const docIds = fileIds(m.document);
15090
+ if (docIds) {
15091
+ media.push({
15092
+ type: "document",
15093
+ ...docIds,
15094
+ ...m.document?.mime_type ? { mimetype: m.document.mime_type } : {},
15095
+ ...m.document?.file_name ? { fileName: m.document.file_name } : {}
15096
+ });
15097
+ note(`[document: ${m.document?.file_name ?? "file"}]`);
15098
+ }
15099
+ if (m.sticker) note("[sticker]");
15100
+ if (m.venue) {
15101
+ const v = m.venue;
15102
+ const parts = [v.title, v.address, `${v.location?.latitude},${v.location?.longitude}`].filter(Boolean);
15103
+ note(`[location: ${parts.join(" \u2014 ")}]`);
15104
+ }
15105
+ if (m.location) {
15106
+ const coords = `${m.location.latitude},${m.location.longitude}`;
15107
+ note(m.location.live_period != null ? `[live location: ${coords}]` : `[location: ${coords}]`);
15108
+ }
15109
+ return { placeholder, media };
15110
+ }
15015
15111
  function routeTelegramUpdate(input) {
15016
- const m = input.update.message;
15112
+ const isEdit = input.update.message == null && input.update.edited_message != null;
15113
+ const m = input.update.message ?? input.update.edited_message;
15017
15114
  if (!m || typeof m.from?.id !== "number" || typeof m.chat?.id !== "number") {
15018
15115
  return { kind: "ignore", reason: "no-message" };
15019
15116
  }
15020
- if (typeof m.text !== "string" || m.text.length === 0) {
15021
- return { kind: "ignore", reason: "no-text" };
15117
+ const { placeholder, media } = extractContent(m);
15118
+ const typed = typeof m.text === "string" && m.text.length > 0 ? m.text : null;
15119
+ const captioned = typeof m.caption === "string" && m.caption.length > 0 ? m.caption : null;
15120
+ const text = typed ?? captioned ?? placeholder ?? "";
15121
+ if (text.length === 0 && media.length === 0) {
15122
+ return { kind: "ignore", reason: "unsupported-content" };
15022
15123
  }
15023
15124
  const access = checkTelegramAccess({ senderId: m.from.id, entry: input.entry });
15024
15125
  if (!access.allowed) {
@@ -15028,25 +15129,211 @@ function routeTelegramUpdate(input) {
15028
15129
  kind: "dispatch",
15029
15130
  senderId: String(m.from.id),
15030
15131
  chatId: m.chat.id,
15031
- text: m.text,
15132
+ text,
15032
15133
  agentType: access.agentType,
15033
15134
  reason: access.reason,
15034
15135
  messageId: Number.isInteger(m.message_id) ? m.message_id : null,
15035
- senderDisplay: telegramSenderDisplay(m.from)
15136
+ senderDisplay: telegramSenderDisplay(m.from),
15137
+ media,
15138
+ isEdit,
15139
+ editDate: Number.isInteger(m.edit_date) ? m.edit_date : null,
15140
+ textIsPlaceholder: typed === null && captioned === null && placeholder !== null
15036
15141
  };
15037
15142
  }
15038
15143
 
15144
+ // app/lib/telegram/inbound/media.ts
15145
+ import { mkdir as mkdir2, writeFile as writeFile4 } from "fs/promises";
15146
+ import { join as join31 } from "path";
15147
+ var TAG24 = "[telegram-inbound]";
15148
+ var TELEGRAM_MEDIA_DIR = "/tmp/maxy-media";
15149
+ var DOWNLOAD_TIMEOUT_MS = 45e3;
15150
+ function extensionFor(filePath, mimetype) {
15151
+ const fromPath = filePath.split("/").pop()?.split(".").slice(1).pop();
15152
+ if (fromPath && /^[a-z0-9]+$/i.test(fromPath)) return fromPath;
15153
+ const sub = mimetype?.split("/").pop()?.split(";")[0]?.trim();
15154
+ if (sub && /^[a-z0-9]+$/i.test(sub)) return sub;
15155
+ return "bin";
15156
+ }
15157
+ function pathSafe(s) {
15158
+ return s.replace(/[^A-Za-z0-9_-]/g, "_");
15159
+ }
15160
+ function refusalReason(body, status) {
15161
+ const b = body;
15162
+ if (typeof b?.description === "string" && b.description.length > 0) return b.description;
15163
+ return `telegram returned ${status}`;
15164
+ }
15165
+ async function downloadTelegramMedia(input) {
15166
+ if (input.items.length === 0) return [];
15167
+ const doFetch = input.fetchImpl ?? fetch;
15168
+ const dir = input.dir ?? TELEGRAM_MEDIA_DIR;
15169
+ const timeoutMs = input.timeoutMs ?? DOWNLOAD_TIMEOUT_MS;
15170
+ const out = [];
15171
+ for (const item of input.items) {
15172
+ const base = {
15173
+ type: item.type,
15174
+ ...item.mimetype ? { mimetype: item.mimetype } : {}
15175
+ };
15176
+ let result;
15177
+ let bytes = 0;
15178
+ try {
15179
+ const signal = AbortSignal.timeout(timeoutMs);
15180
+ const metaRes = await doFetch(
15181
+ `https://api.telegram.org/bot${input.token}/getFile?file_id=${encodeURIComponent(item.fileId)}`,
15182
+ { signal }
15183
+ );
15184
+ const meta = await metaRes.json();
15185
+ const filePath = meta?.result?.file_path;
15186
+ if (!metaRes.ok || meta?.ok !== true || typeof filePath !== "string" || filePath.length === 0) {
15187
+ result = { ...base, failure: refusalReason(meta, metaRes.status) };
15188
+ } else {
15189
+ const fileRes = await doFetch(`https://api.telegram.org/file/bot${input.token}/${filePath}`, { signal });
15190
+ if (!fileRes.ok) {
15191
+ result = { ...base, failure: `telegram returned ${fileRes.status}` };
15192
+ } else {
15193
+ const body = Buffer.from(await fileRes.arrayBuffer());
15194
+ await mkdir2(dir, { recursive: true });
15195
+ const path = join31(
15196
+ dir,
15197
+ `tg-${pathSafe(input.botId)}-${pathSafe(item.fileUniqueId)}.${extensionFor(filePath, item.mimetype)}`
15198
+ );
15199
+ await writeFile4(path, body);
15200
+ bytes = body.length;
15201
+ result = { ...base, path };
15202
+ }
15203
+ }
15204
+ } catch (err) {
15205
+ result = { ...base, failure: err instanceof Error ? err.message : String(err) };
15206
+ }
15207
+ console.error(
15208
+ `${TAG24} op=media-download botId=${input.botId} type=${item.type} ok=${result.path ? "yes" : "no"} bytes=${bytes} path=${result.path ?? "-"} reason=${result.failure ?? "-"}`
15209
+ );
15210
+ out.push(result);
15211
+ }
15212
+ return out;
15213
+ }
15214
+
15215
+ // app/lib/telegram/inbound/transcribe.ts
15216
+ init_stt();
15217
+ var TAG25 = "[telegram-inbound]";
15218
+ async function transcribeTelegramAudio(input) {
15219
+ const doTranscribe = input.transcribeImpl ?? transcribe;
15220
+ const out = [];
15221
+ const transcripts = [];
15222
+ for (const m of input.media) {
15223
+ if (m.type !== "audio") {
15224
+ out.push(m);
15225
+ continue;
15226
+ }
15227
+ if (!m.path) {
15228
+ console.error(
15229
+ `${TAG25} op=transcribe botId=${input.botId} ok=no chars=0 ms=0 reason=${m.failure ?? "no local file"}`
15230
+ );
15231
+ out.push(m);
15232
+ continue;
15233
+ }
15234
+ const startedMs = Date.now();
15235
+ let heard;
15236
+ let reason = "-";
15237
+ try {
15238
+ const r = await doTranscribe(m.path, m.mimetype ?? "");
15239
+ const t = r?.text.trim();
15240
+ heard = t ? t : void 0;
15241
+ if (!heard) reason = "no transcript returned";
15242
+ } catch (err) {
15243
+ reason = err instanceof Error ? err.message : String(err);
15244
+ }
15245
+ console.error(
15246
+ `${TAG25} op=transcribe botId=${input.botId} ok=${heard ? "yes" : "no"} chars=${heard?.length ?? 0} ms=${Date.now() - startedMs} reason=${reason}`
15247
+ );
15248
+ if (heard) {
15249
+ transcripts.push(heard);
15250
+ out.push({ ...m, transcribed: true });
15251
+ } else {
15252
+ out.push(m);
15253
+ }
15254
+ }
15255
+ if (transcripts.length === 0) return { text: input.text, media: out };
15256
+ const body = transcripts.join("\n\n");
15257
+ const caption = input.textIsPlaceholder ? "" : input.text.trim();
15258
+ return { text: caption ? `${caption}
15259
+
15260
+ ${body}` : body, media: out };
15261
+ }
15262
+
15263
+ // app/lib/telegram/gateway/telegram-inbound-census.ts
15264
+ var ANSWER_THRESHOLD_MS = 3e4;
15265
+ var GAP_NAME_LIMIT = 10;
15266
+ var received = 0;
15267
+ var answered = 0;
15268
+ var outstanding = /* @__PURE__ */ new Map();
15269
+ var kindDispatched = 0;
15270
+ var kindIgnored = 0;
15271
+ var kindCounts = /* @__PURE__ */ new Map();
15272
+ function noteInboundKind(kind, dispatched) {
15273
+ if (dispatched) kindDispatched += 1;
15274
+ else kindIgnored += 1;
15275
+ kindCounts.set(kind, (kindCounts.get(kind) ?? 0) + 1);
15276
+ }
15277
+ function readTelegramKindCensus() {
15278
+ const kinds = [...kindCounts.entries()].map(([kind, count]) => ({ kind, count })).sort((a, b) => b.count - a.count || a.kind.localeCompare(b.kind));
15279
+ return { dispatched: kindDispatched, ignored: kindIgnored, kinds };
15280
+ }
15281
+ function buildTelegramKindCensusLine(c) {
15282
+ const kinds = c.kinds.length > 0 ? c.kinds.map((k) => `${k.kind}:${k.count}`).join(",") : "none";
15283
+ return `[telegram-native] op=inbound-kind-census dispatched=${c.dispatched} ignored=${c.ignored} kinds=${kinds}`;
15284
+ }
15285
+ function noteReceived(key2, botId, messageId, now) {
15286
+ received += 1;
15287
+ const list = outstanding.get(key2);
15288
+ if (list) list.push({ messageId, botId, receivedAt: now });
15289
+ else outstanding.set(key2, [{ messageId, botId, receivedAt: now }]);
15290
+ }
15291
+ function noteAnswered(key2) {
15292
+ const list = outstanding.get(key2);
15293
+ if (!list || list.length === 0) return;
15294
+ list.shift();
15295
+ if (list.length === 0) outstanding.delete(key2);
15296
+ answered += 1;
15297
+ }
15298
+ function readTelegramInboundCensus(now) {
15299
+ const gaps = [];
15300
+ for (const [key2, list] of outstanding) {
15301
+ for (const o of list) {
15302
+ const ageMs2 = now - o.receivedAt;
15303
+ if (ageMs2 > ANSWER_THRESHOLD_MS) gaps.push({ messageId: o.messageId, botId: o.botId, key: key2, ageMs: ageMs2 });
15304
+ }
15305
+ }
15306
+ gaps.sort((a, b) => b.ageMs - a.ageMs);
15307
+ return { received, answered, gaps };
15308
+ }
15309
+ function buildTelegramNotifyReconcileLines(input) {
15310
+ const named = input.gaps.slice(0, GAP_NAME_LIMIT);
15311
+ const lines = [
15312
+ `[telegram-native] op=telegram-notify-reconcile received=${input.received} answered=${input.answered} answerGap=${input.gaps.length} named=${named.length}`
15313
+ ];
15314
+ for (const g of named) {
15315
+ lines.push(
15316
+ `[telegram-native] op=telegram-answer-gap messageId=${g.messageId} botId=${g.botId} key=${g.key} ageMs=${g.ageMs}`
15317
+ );
15318
+ }
15319
+ return lines;
15320
+ }
15321
+ function runTelegramNotifyReconcile(now) {
15322
+ for (const line of buildTelegramNotifyReconcileLines(readTelegramInboundCensus(now))) console.error(line);
15323
+ console.error(buildTelegramKindCensusLine(readTelegramKindCensus()));
15324
+ }
15325
+
15039
15326
  // server/routes/telegram.ts
15040
15327
  init_channel_key();
15041
15328
  init_admin_session_id();
15042
15329
 
15043
15330
  // server/channel-session-override.ts
15044
15331
  import { readFileSync as readFileSync26, writeFileSync as writeFileSync11, renameSync as renameSync5 } from "fs";
15045
- import { join as join31 } from "path";
15332
+ import { join as join32 } from "path";
15046
15333
  var FILE2 = "channel-session-override.json";
15047
15334
  var UUID3 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
15048
15335
  function channelOverridePath(accountDir) {
15049
- return join31(accountDir, FILE2);
15336
+ return join32(accountDir, FILE2);
15050
15337
  }
15051
15338
  function senderKey(channel, senderId) {
15052
15339
  return `${channel}:${senderId}`;
@@ -15152,8 +15439,9 @@ function decideTelegramNotify(input) {
15152
15439
  if (input.isDuplicate()) return { emit: false, reason: "duplicate" };
15153
15440
  return { emit: true, senderType: input.agentType };
15154
15441
  }
15155
- function telegramNotifyId(botId, chatId, messageId) {
15156
- return `tg:${botId}:${chatId}:${messageId}`;
15442
+ function telegramNotifyId(botId, chatId, messageId, editDate) {
15443
+ const suffix = editDate === void 0 ? "" : `:edit:${editDate}`;
15444
+ return `tg:${botId}:${chatId}:${messageId}${suffix}`;
15157
15445
  }
15158
15446
 
15159
15447
  // app/lib/telegram/inbound/notify-dedupe.ts
@@ -15182,21 +15470,21 @@ function isTelegramNotifyDuplicate(notifyId) {
15182
15470
 
15183
15471
  // app/lib/telegram/gateway/telegram-notify-census.ts
15184
15472
  var PUBLISH_THRESHOLD_MS = 3e4;
15185
- var GAP_NAME_LIMIT = 10;
15473
+ var GAP_NAME_LIMIT2 = 10;
15186
15474
  var eligible = 0;
15187
15475
  var published = 0;
15188
- var outstanding = /* @__PURE__ */ new Map();
15476
+ var outstanding2 = /* @__PURE__ */ new Map();
15189
15477
  function noteNotifyEligible(notifyId, botId, now) {
15190
15478
  eligible += 1;
15191
- outstanding.set(notifyId, { botId, at: now });
15479
+ outstanding2.set(notifyId, { botId, at: now });
15192
15480
  }
15193
15481
  function noteNotifyPublished(notifyId) {
15194
- if (!outstanding.delete(notifyId)) return;
15482
+ if (!outstanding2.delete(notifyId)) return;
15195
15483
  published += 1;
15196
15484
  }
15197
15485
  function readTelegramNotifyCensus(now) {
15198
15486
  const missing = [];
15199
- for (const [notifyId, o] of outstanding) {
15487
+ for (const [notifyId, o] of outstanding2) {
15200
15488
  const ageMs2 = now - o.at;
15201
15489
  if (ageMs2 > PUBLISH_THRESHOLD_MS) missing.push({ notifyId, botId: o.botId, ageMs: ageMs2 });
15202
15490
  }
@@ -15204,7 +15492,7 @@ function readTelegramNotifyCensus(now) {
15204
15492
  return { eligible, published, missing };
15205
15493
  }
15206
15494
  function buildTelegramNotifyCensusLines(input) {
15207
- const named = input.missing.slice(0, GAP_NAME_LIMIT);
15495
+ const named = input.missing.slice(0, GAP_NAME_LIMIT2);
15208
15496
  const lines = [
15209
15497
  `[telegram-native] op=notify-publish-census eligible=${input.eligible} published=${input.published} missing=${input.missing.length} named=${named.length}`
15210
15498
  ];
@@ -15224,10 +15512,10 @@ function runTelegramNotifyPublishCensus(now) {
15224
15512
  // server/routes/telegram.ts
15225
15513
  init_neo4j_store();
15226
15514
  var telegramAdoptionSeen = /* @__PURE__ */ new Set();
15227
- var TAG24 = "[telegram-inbound]";
15515
+ var TAG26 = "[telegram-inbound]";
15228
15516
  function configDirName2() {
15229
15517
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve21(process.cwd(), "..");
15230
- const brandPath = join32(platformRoot5, "config", "brand.json");
15518
+ const brandPath = join33(platformRoot5, "config", "brand.json");
15231
15519
  if (existsSync22(brandPath)) {
15232
15520
  try {
15233
15521
  return JSON.parse(readFileSync27(brandPath, "utf-8")).configDir ?? ".maxy";
@@ -15246,61 +15534,67 @@ var app11 = new Hono();
15246
15534
  app11.post("/", async (c) => {
15247
15535
  const botId = c.req.query("bot");
15248
15536
  if (!botId) {
15249
- console.error(`${TAG24} op=reject reason=missing-bot-param`);
15537
+ console.error(`${TAG26} op=reject reason=missing-bot-param`);
15250
15538
  return c.json({ ok: false }, 400);
15251
15539
  }
15252
- console.error(`${TAG24} op=received botId=${botId} path=/api/telegram/`);
15540
+ console.error(`${TAG26} op=received botId=${botId} path=/api/telegram/`);
15253
15541
  const resolved = resolveBotEntry(listValidAccounts(), botId);
15254
15542
  if (resolved.kind === "none") {
15255
- console.error(`${TAG24} op=reject reason=unknown-bot botId=${botId}`);
15543
+ console.error(`${TAG26} op=reject reason=unknown-bot botId=${botId}`);
15256
15544
  return c.json({ ok: false }, 401);
15257
15545
  }
15258
15546
  if (resolved.kind === "duplicate") {
15259
- console.error(`${TAG24} op=reject reason=duplicate-bot-id botId=${botId} accounts=${resolved.count}`);
15547
+ console.error(`${TAG26} op=reject reason=duplicate-bot-id botId=${botId} accounts=${resolved.count}`);
15260
15548
  return c.json({ ok: false }, 401);
15261
15549
  }
15262
15550
  const { accountId, accountDir, entry } = resolved;
15263
15551
  const agentSlug = entry.role === "admin" ? "admin" : entry.agent;
15264
- console.error(`${TAG24} op=entry botId=${botId} accountId=${accountId} role=${entry.role} agent=${agentSlug}`);
15552
+ console.error(`${TAG26} op=entry botId=${botId} accountId=${accountId} role=${entry.role} agent=${agentSlug}`);
15265
15553
  const sp = secretPath(botId);
15266
15554
  if (!existsSync22(sp)) {
15267
- console.error(`${TAG24} op=secret botId=${botId} result=missing-file`);
15555
+ console.error(`${TAG26} op=secret botId=${botId} result=missing-file`);
15268
15556
  return c.json({ ok: false }, 401);
15269
15557
  }
15270
15558
  const expected = readFileSync27(sp, "utf-8").trim();
15271
15559
  const got = c.req.header("x-telegram-bot-api-secret-token") ?? "";
15272
15560
  if (got !== expected) {
15273
- console.error(`${TAG24} op=secret botId=${botId} result=mismatch`);
15561
+ console.error(`${TAG26} op=secret botId=${botId} result=mismatch`);
15274
15562
  return c.json({ ok: false }, 401);
15275
15563
  }
15276
- console.error(`${TAG24} op=secret botId=${botId} result=ok`);
15564
+ console.error(`${TAG26} op=secret botId=${botId} result=ok`);
15277
15565
  let update;
15278
15566
  try {
15279
15567
  update = await c.req.json();
15280
15568
  } catch {
15281
15569
  return c.json({ ok: true }, 200);
15282
15570
  }
15571
+ const shape = describeTelegramUpdate(update);
15572
+ console.error(
15573
+ `${TAG26} op=inbound-kind botId=${botId} update=${shape.envelope} content=${shape.content} isEdit=${shape.isEdit ? "yes" : "no"}`
15574
+ );
15283
15575
  const decision = routeTelegramUpdate({ update, entry });
15576
+ noteInboundKind(shape.primaryKind, decision.kind === "dispatch");
15284
15577
  if (decision.kind === "ignore") {
15285
- console.error(`${TAG24} op=ignore botId=${botId} reason=${decision.reason}`);
15578
+ console.error(`${TAG26} op=ignore botId=${botId} reason=${decision.reason}`);
15286
15579
  return c.json({ ok: true }, 200);
15287
15580
  }
15288
15581
  if (decision.kind === "denied") {
15289
- console.error(`${TAG24} op=access botId=${botId} senderId=- allowed=false reason=${decision.reason}`);
15582
+ console.error(`${TAG26} op=access botId=${botId} senderId=- allowed=false reason=${decision.reason}`);
15290
15583
  return c.json({ ok: true }, 200);
15291
15584
  }
15292
15585
  const { senderId, chatId, text } = decision;
15293
- console.error(`${TAG24} op=access botId=${botId} senderId=${senderId} allowed=true reason=${decision.reason}`);
15586
+ console.error(`${TAG26} op=access botId=${botId} senderId=${senderId} allowed=true reason=${decision.reason}`);
15294
15587
  const channelKey = telegramChannelKey(botId, senderId);
15295
15588
  const scope = entry.role === "admin" ? "admin" : "public";
15296
15589
  const adminUserId = entry.role === "admin" ? resolveTelegramAdminUserId({ accountId, chatId: senderId }) : null;
15297
15590
  const sessionId = adminUserId ? adminSessionIdFor(accountId, senderId, adminUserId) : adminSessionIdFor(accountId, senderId, void 0, botId);
15298
15591
  const inboundAt = (/* @__PURE__ */ new Date()).toISOString();
15592
+ const editSuffix = decision.isEdit ? `:edit:${decision.editDate}` : "";
15299
15593
  appendMessage2(accountId, {
15300
15594
  // Telegram's own per-chat message number, so a redelivered update dedupes.
15301
15595
  // Task 2437 parses it once, in routeTelegramUpdate; reading the raw update
15302
15596
  // again here would be a second authority for the same fact.
15303
- messageId: `telegram:${accountId}:${channelKey}:in:${decision.messageId ?? inboundAt}`,
15597
+ messageId: `telegram:${accountId}:${channelKey}:in:${decision.messageId ?? inboundAt}${editSuffix}`,
15304
15598
  sessionId,
15305
15599
  dateSent: inboundAt,
15306
15600
  body: text,
@@ -15319,14 +15613,26 @@ app11.post("/", async (c) => {
15319
15613
  const gate = decideTelegramNotify({
15320
15614
  messageId: decision.messageId,
15321
15615
  agentType: decision.agentType,
15322
- isDuplicate: () => decision.messageId === null ? false : isTelegramNotifyDuplicate(telegramNotifyId(botId, String(chatId), decision.messageId))
15616
+ isDuplicate: () => decision.messageId === null ? false : isTelegramNotifyDuplicate(
15617
+ telegramNotifyId(
15618
+ botId,
15619
+ String(chatId),
15620
+ decision.messageId,
15621
+ decision.isEdit ? decision.editDate : void 0
15622
+ )
15623
+ )
15323
15624
  });
15324
15625
  if (!gate.emit) {
15325
15626
  console.error(
15326
15627
  `[channel-notify] op=skip channel=telegram botId=${botId} reason=${gate.reason}`
15327
15628
  );
15328
15629
  } else {
15329
- const notifyId = telegramNotifyId(botId, String(chatId), decision.messageId);
15630
+ const notifyId = telegramNotifyId(
15631
+ botId,
15632
+ String(chatId),
15633
+ decision.messageId,
15634
+ decision.isEdit ? decision.editDate : void 0
15635
+ );
15330
15636
  const { body, truncated } = formatNotifyBody(text);
15331
15637
  noteNotifyEligible(notifyId, botId, Date.now());
15332
15638
  console.error(
@@ -15357,14 +15663,14 @@ app11.post("/", async (c) => {
15357
15663
  }
15358
15664
  }
15359
15665
  const active = entry.role === "admin" ? true : isActiveAgentSlug(accountDir, entry.agent);
15360
- console.error(`${TAG24} op=agent botId=${botId} slug=${agentSlug} active=${active}`);
15666
+ console.error(`${TAG26} op=agent botId=${botId} slug=${agentSlug} active=${active}`);
15361
15667
  if (!active) {
15362
- console.error(`${TAG24} op=reject reason=agent-inactive botId=${botId} agent=${agentSlug}`);
15668
+ console.error(`${TAG26} op=reject reason=agent-inactive botId=${botId} agent=${agentSlug}`);
15363
15669
  return c.json({ ok: true }, 200);
15364
15670
  }
15365
15671
  const gateway = getTelegramGateway();
15366
15672
  if (!gateway) {
15367
- console.error(`${TAG24} op=reply-dropped botId=${botId} reason=gateway-not-ready`);
15673
+ console.error(`${TAG26} op=reply-dropped botId=${botId} reason=gateway-not-ready`);
15368
15674
  return c.json({ ok: true }, 200);
15369
15675
  }
15370
15676
  const reply = async (replyText) => {
@@ -15385,8 +15691,8 @@ app11.post("/", async (c) => {
15385
15691
  origin: "agent",
15386
15692
  createdAt: at
15387
15693
  });
15388
- console.error(`${TAG24} op=reply-sent botId=${botId} ok=true`);
15389
- } else console.error(`${TAG24} op=reply-dropped botId=${botId} reason=${sent.error}`);
15694
+ console.error(`${TAG26} op=reply-sent botId=${botId} ok=true`);
15695
+ } else console.error(`${TAG26} op=reply-dropped botId=${botId} reason=${sent.error}`);
15390
15696
  };
15391
15697
  if (adminUserId) {
15392
15698
  const line = runAdminSessionAdoption({
@@ -15412,25 +15718,35 @@ app11.post("/", async (c) => {
15412
15718
  });
15413
15719
  if (line) console.error(line);
15414
15720
  }
15415
- void gateway.handleInbound({
15416
- accountId,
15417
- accountDir,
15418
- botId,
15419
- botToken: entry.token,
15420
- agentSlug,
15421
- senderId,
15422
- role: entry.role,
15423
- personId: null,
15424
- // Task 2078 — the admin person this chat is bound to (the users.json
15425
- // telegram binding). It is the SUBJECT of the session id, so one admin's
15426
- // Telegram, WhatsApp and webchat resolve to one conversation. Resolved
15427
- // above, alongside the store row's own session id, so the row and the spawn
15428
- // can never name different sessions for one message.
15429
- adminUserId,
15430
- chatId: String(chatId),
15431
- text,
15432
- reply
15433
- });
15721
+ const media = await downloadTelegramMedia({ token: entry.token, botId, items: decision.media });
15722
+ void (async () => {
15723
+ const heard = await transcribeTelegramAudio({
15724
+ botId,
15725
+ text,
15726
+ textIsPlaceholder: decision.textIsPlaceholder,
15727
+ media
15728
+ });
15729
+ void gateway.handleInbound({
15730
+ accountId,
15731
+ accountDir,
15732
+ botId,
15733
+ botToken: entry.token,
15734
+ agentSlug,
15735
+ senderId,
15736
+ role: entry.role,
15737
+ personId: null,
15738
+ // Task 2078 — the admin person this chat is bound to (the users.json
15739
+ // telegram binding). It is the SUBJECT of the session id, so one admin's
15740
+ // Telegram, WhatsApp and webchat resolve to one conversation. Resolved
15741
+ // above, alongside the store row's own session id, so the row and the spawn
15742
+ // can never name different sessions for one message.
15743
+ adminUserId,
15744
+ chatId: String(chatId),
15745
+ text: heard.text,
15746
+ media: heard.media,
15747
+ reply
15748
+ });
15749
+ })();
15434
15750
  return c.json({ ok: true }, 200);
15435
15751
  });
15436
15752
  var telegram_default = app11;
@@ -15444,29 +15760,29 @@ function mountTelegramRoutes(app79, telegramRoutes) {
15444
15760
  // server/routes/quickbooks.ts
15445
15761
  init_dist();
15446
15762
  init_claude_agent();
15447
- import { join as join33 } from "path";
15763
+ import { join as join34 } from "path";
15448
15764
  import { existsSync as existsSync23, readFileSync as readFileSync28, writeFileSync as writeFileSync12, mkdirSync as mkdirSync5, rmSync as rmSync4, renameSync as renameSync6 } from "fs";
15449
- var TAG25 = "[quickbooks]";
15765
+ var TAG27 = "[quickbooks]";
15450
15766
  var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
15451
15767
  var STATE_RE = /^[A-Za-z0-9_-]+$/;
15452
15768
  function pendingPath(accountDir, state) {
15453
- return join33(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
15769
+ return join34(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
15454
15770
  }
15455
15771
  function storePath(accountDir) {
15456
- return join33(accountDir, "secrets", "quickbooks.json");
15772
+ return join34(accountDir, "secrets", "quickbooks.json");
15457
15773
  }
15458
15774
  async function completeConsent(args) {
15459
15775
  const { accountDir, code, realmId } = args;
15460
15776
  const state = args.state;
15461
15777
  if (!state || !STATE_RE.test(state) || !existsSync23(pendingPath(accountDir, state))) {
15462
- console.error(`${TAG25} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
15778
+ console.error(`${TAG27} op=callback state=${state ?? ""} stateValid=false realmId=${realmId ?? ""}`);
15463
15779
  return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
15464
15780
  }
15465
15781
  const claimFile = `${pendingPath(accountDir, state)}.claimed`;
15466
15782
  try {
15467
15783
  renameSync6(pendingPath(accountDir, state), claimFile);
15468
15784
  } catch {
15469
- console.error(`${TAG25} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
15785
+ console.error(`${TAG27} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
15470
15786
  return { ok: false, status: 400, message: "Invalid or unknown authorization state.", stateValid: false };
15471
15787
  }
15472
15788
  try {
@@ -15474,14 +15790,14 @@ async function completeConsent(args) {
15474
15790
  try {
15475
15791
  pending = JSON.parse(readFileSync28(claimFile, "utf-8"));
15476
15792
  } catch {
15477
- console.error(`${TAG25} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
15793
+ console.error(`${TAG27} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
15478
15794
  return { ok: false, status: 400, message: "Authorization state could not be read.", stateValid: false };
15479
15795
  }
15480
15796
  if (Date.now() > pending.expiresAt) {
15481
- console.error(`${TAG25} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
15797
+ console.error(`${TAG27} op=callback state=${state} stateValid=false realmId=${realmId ?? ""}`);
15482
15798
  return { ok: false, status: 400, message: "Authorization request expired. Generate a new consent link.", stateValid: false };
15483
15799
  }
15484
- console.error(`${TAG25} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
15800
+ console.error(`${TAG27} op=callback state=${state} stateValid=true realmId=${realmId ?? ""}`);
15485
15801
  if (!code || !realmId) {
15486
15802
  return { ok: false, status: 400, message: "Missing code or realmId in the callback.", stateValid: true };
15487
15803
  }
@@ -15505,12 +15821,12 @@ async function completeConsent(args) {
15505
15821
  });
15506
15822
  const text = await res.text();
15507
15823
  if (!res.ok) {
15508
- console.error(`${TAG25} op=token-exchange realmId=${realmId} persisted=false`);
15824
+ console.error(`${TAG27} op=token-exchange realmId=${realmId} persisted=false`);
15509
15825
  return { ok: false, status: 502, message: `Token exchange failed (${res.status}). Generate a new consent link to retry.`, stateValid: true };
15510
15826
  }
15511
15827
  const body = JSON.parse(text);
15512
15828
  if (!body.refresh_token) {
15513
- console.error(`${TAG25} op=token-exchange realmId=${realmId} persisted=false`);
15829
+ console.error(`${TAG27} op=token-exchange realmId=${realmId} persisted=false`);
15514
15830
  return { ok: false, status: 502, message: "Token exchange returned no refresh token.", stateValid: true };
15515
15831
  }
15516
15832
  const now = Date.now();
@@ -15520,10 +15836,10 @@ async function completeConsent(args) {
15520
15836
  refreshTokenExpiry: now + (body.x_refresh_token_expires_in ?? 864e4) * 1e3,
15521
15837
  lastRefresh: now
15522
15838
  };
15523
- mkdirSync5(join33(accountDir, "secrets"), { recursive: true });
15839
+ mkdirSync5(join34(accountDir, "secrets"), { recursive: true });
15524
15840
  writeFileSync12(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
15525
15841
  const persisted = JSON.parse(readFileSync28(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
15526
- console.error(`${TAG25} op=token-exchange realmId=${realmId} persisted=${persisted}`);
15842
+ console.error(`${TAG27} op=token-exchange realmId=${realmId} persisted=${persisted}`);
15527
15843
  return { ok: persisted, status: persisted ? 200 : 500, message: persisted ? `Connected company ${realmId}.` : "Failed to persist the connection.", stateValid: true };
15528
15844
  } finally {
15529
15845
  rmSync4(claimFile, { force: true });
@@ -15536,7 +15852,7 @@ var app12 = new Hono();
15536
15852
  app12.get("/callback", async (c) => {
15537
15853
  const account = resolveAccount();
15538
15854
  if (!account) {
15539
- console.error(`${TAG25} op=callback stateValid=false realmId= reason=no-account`);
15855
+ console.error(`${TAG27} op=callback stateValid=false realmId= reason=no-account`);
15540
15856
  return c.html(page("QuickBooks", "This install has no account configured."), 500);
15541
15857
  }
15542
15858
  const result = await completeConsent({
@@ -15566,7 +15882,7 @@ function claudeBin() {
15566
15882
  }
15567
15883
 
15568
15884
  // server/routes/onboarding.ts
15569
- import { dirname as dirname13, join as join35 } from "path";
15885
+ import { dirname as dirname13, join as join36 } from "path";
15570
15886
 
15571
15887
  // app/lib/claude-keychain.ts
15572
15888
  import { execFileSync as execFileSync3 } from "child_process";
@@ -15696,7 +16012,7 @@ function readHostCredsBlob(service) {
15696
16012
 
15697
16013
  // ../lib/admins-write/src/index.ts
15698
16014
  import { existsSync as existsSync24, readFileSync as readFileSync29, writeFileSync as writeFileSync13, renameSync as renameSync7, mkdirSync as mkdirSync6, readdirSync as readdirSync19, statSync as statSync18, appendFileSync as appendFileSync2 } from "fs";
15699
- import { dirname as dirname12, join as join34 } from "path";
16015
+ import { dirname as dirname12, join as join35 } from "path";
15700
16016
  function id8(value) {
15701
16017
  return value.slice(0, 8);
15702
16018
  }
@@ -15769,7 +16085,7 @@ function writeAdminEntry(input) {
15769
16085
  return result;
15770
16086
  }
15771
16087
  try {
15772
- const accountJsonPath = join34(input.accountDir, "account.json");
16088
+ const accountJsonPath = join35(input.accountDir, "account.json");
15773
16089
  if (!existsSync24(accountJsonPath)) {
15774
16090
  throw new Error(`account.json not found at ${accountJsonPath}`);
15775
16091
  }
@@ -15817,13 +16133,13 @@ function computeAdminStoreDivergence(input) {
15817
16133
  }
15818
16134
  for (const entry of entries2) {
15819
16135
  if (entry.startsWith(".")) continue;
15820
- const accountDir = join34(input.accountsDir, entry);
16136
+ const accountDir = join35(input.accountsDir, entry);
15821
16137
  try {
15822
16138
  if (!statSync18(accountDir).isDirectory()) continue;
15823
16139
  } catch {
15824
16140
  continue;
15825
16141
  }
15826
- const accountJsonPath = join34(accountDir, "account.json");
16142
+ const accountJsonPath = join35(accountDir, "account.json");
15827
16143
  if (!existsSync24(accountJsonPath)) continue;
15828
16144
  let admins = [];
15829
16145
  try {
@@ -16002,7 +16318,7 @@ app13.post("/claude-auth", async (c) => {
16002
16318
  });
16003
16319
  persistKeychainService(
16004
16320
  writebackResult,
16005
- (service) => writeFileSync14(join35(dirname13(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
16321
+ (service) => writeFileSync14(join36(dirname13(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
16006
16322
  (line) => console.log(line)
16007
16323
  );
16008
16324
  if (darwinAuthChild === claudeProc2) darwinAuthChild = null;
@@ -16272,8 +16588,8 @@ init_paths();
16272
16588
  init_remote_auth();
16273
16589
  init_loop_registry();
16274
16590
  import { appendFileSync as appendFileSync3, existsSync as existsSync26, renameSync as renameSync9, statSync as statSync19 } from "fs";
16275
- import { join as join36 } from "path";
16276
- var CLIENT_ERRORS_LOG = join36(LOG_DIR, "client-errors.log");
16591
+ import { join as join37 } from "path";
16592
+ var CLIENT_ERRORS_LOG = join37(LOG_DIR, "client-errors.log");
16277
16593
  var MAX_LOG_SIZE = 10 * 1024 * 1024;
16278
16594
  var MAX_BODY_SIZE = 8 * 1024;
16279
16595
  var MAX_STACK_LEN = 2e3;
@@ -16701,12 +17017,12 @@ import { resolve as resolve22, basename as basename11 } from "path";
16701
17017
 
16702
17018
  // app/lib/logs-read-resolve.ts
16703
17019
  import { existsSync as existsSync27 } from "fs";
16704
- import { join as join37 } from "path";
17020
+ import { join as join38 } from "path";
16705
17021
  function resolveSessionLogPaths(filename, logDirs) {
16706
17022
  const tried = [filename];
16707
17023
  const hits = [];
16708
17024
  for (const dir of logDirs) {
16709
- const fullPath = join37(dir, filename);
17025
+ const fullPath = join38(dir, filename);
16710
17026
  if (existsSync27(fullPath)) {
16711
17027
  hits.push({ path: fullPath, dir });
16712
17028
  }
@@ -17036,7 +17352,7 @@ import { execFileSync as execFileSync6 } from "child_process";
17036
17352
  // ../services/claude-session-manager/src/tool-surface.ts
17037
17353
  import { readFileSync as readFileSync32, readdirSync as readdirSync21, statSync as statSync22, existsSync as existsSync31 } from "fs";
17038
17354
  import { createHash as createHash5 } from "crypto";
17039
- import { join as join38 } from "path";
17355
+ import { join as join39 } from "path";
17040
17356
 
17041
17357
  // ../services/claude-session-manager/src/canonical-tool-names.ts
17042
17358
  function canonicalToolName(plugin, tool) {
@@ -17289,13 +17605,13 @@ function loadToolSurface(pluginsRoots) {
17289
17605
  const riskByTool = /* @__PURE__ */ new Map();
17290
17606
  const manifestPaths = /* @__PURE__ */ new Map();
17291
17607
  const loadOne = (pluginsRoot, plugin) => {
17292
- const pluginDir = join38(pluginsRoot, plugin);
17608
+ const pluginDir = join39(pluginsRoot, plugin);
17293
17609
  try {
17294
17610
  if (!statSync22(pluginDir).isDirectory()) return;
17295
17611
  } catch {
17296
17612
  return;
17297
17613
  }
17298
- const manifestPath = join38(pluginDir, "PLUGIN.md");
17614
+ const manifestPath = join39(pluginDir, "PLUGIN.md");
17299
17615
  if (!existsSync31(manifestPath)) return;
17300
17616
  const raw = readFileSync32(manifestPath, "utf-8");
17301
17617
  const frontmatter = extractFrontmatter(raw, plugin);
@@ -17341,9 +17657,9 @@ function loadToolSurface(pluginsRoots) {
17341
17657
  for (const root of roots) {
17342
17658
  const entries2 = readdirSync21(root).sort();
17343
17659
  for (const plugin of entries2) {
17344
- const pluginDir = join38(root, plugin);
17660
+ const pluginDir = join39(root, plugin);
17345
17661
  loadOne(root, plugin);
17346
- const subRoot = join38(pluginDir, "plugins");
17662
+ const subRoot = join39(pluginDir, "plugins");
17347
17663
  let subEntries;
17348
17664
  try {
17349
17665
  if (!statSync22(subRoot).isDirectory()) continue;
@@ -18804,7 +19120,7 @@ init_claude_agent();
18804
19120
  init_account();
18805
19121
  init_neo4j_store();
18806
19122
  import { existsSync as existsSync34, readFileSync as readFileSync34, readdirSync as readdirSync23, statSync as statSync23 } from "fs";
18807
- import { dirname as dirname14, resolve as resolve25, join as join39 } from "path";
19123
+ import { dirname as dirname14, resolve as resolve25, join as join40 } from "path";
18808
19124
  async function resolveOwnerProfileBlock(accountId, userId) {
18809
19125
  if (!userId) return { ok: false, reason: "missing-user-id" };
18810
19126
  try {
@@ -18845,8 +19161,8 @@ function frontmatterField(manifest, field2) {
18845
19161
  function extractPluginToolDescriptions(pluginDir) {
18846
19162
  const out = /* @__PURE__ */ new Map();
18847
19163
  const candidates = [
18848
- join39(pluginDir, "mcp/dist/index.js"),
18849
- join39(pluginDir, "mcp/src/index.ts")
19164
+ join40(pluginDir, "mcp/dist/index.js"),
19165
+ join40(pluginDir, "mcp/src/index.ts")
18850
19166
  ];
18851
19167
  let raw = null;
18852
19168
  for (const path of candidates) {
@@ -18904,7 +19220,7 @@ function listPluginDirs(accountPluginsDir) {
18904
19220
  const platformPlugins = resolve25(PLATFORM_ROOT, "plugins");
18905
19221
  if (existsSync34(platformPlugins)) {
18906
19222
  for (const name of readdirSync23(platformPlugins)) {
18907
- const dir = join39(platformPlugins, name);
19223
+ const dir = join40(platformPlugins, name);
18908
19224
  try {
18909
19225
  if (statSync23(dir).isDirectory()) out.set(name, dir);
18910
19226
  } catch {
@@ -18914,11 +19230,11 @@ function listPluginDirs(accountPluginsDir) {
18914
19230
  const premiumRoot = resolve25(dirname14(PLATFORM_ROOT), "premium-plugins");
18915
19231
  if (existsSync34(premiumRoot)) {
18916
19232
  for (const bundle of readdirSync23(premiumRoot)) {
18917
- const bundlePlugins = join39(premiumRoot, bundle, "plugins");
19233
+ const bundlePlugins = join40(premiumRoot, bundle, "plugins");
18918
19234
  if (!existsSync34(bundlePlugins)) continue;
18919
19235
  try {
18920
19236
  for (const name of readdirSync23(bundlePlugins)) {
18921
- const dir = join39(bundlePlugins, name);
19237
+ const dir = join40(bundlePlugins, name);
18922
19238
  try {
18923
19239
  if (statSync23(dir).isDirectory()) out.set(name, dir);
18924
19240
  } catch {
@@ -18932,7 +19248,7 @@ function listPluginDirs(accountPluginsDir) {
18932
19248
  try {
18933
19249
  for (const name of readdirSync23(accountPluginsDir)) {
18934
19250
  if (out.has(name)) continue;
18935
- const dir = join39(accountPluginsDir, name);
19251
+ const dir = join40(accountPluginsDir, name);
18936
19252
  try {
18937
19253
  if (statSync23(dir).isDirectory()) out.set(name, dir);
18938
19254
  } catch {
@@ -18951,7 +19267,7 @@ function listAccountPluginNames(accountPluginsDir) {
18951
19267
  try {
18952
19268
  return readdirSync23(accountPluginsDir).filter((name) => {
18953
19269
  try {
18954
- return statSync23(join39(accountPluginsDir, name)).isDirectory();
19270
+ return statSync23(join40(accountPluginsDir, name)).isDirectory();
18955
19271
  } catch {
18956
19272
  return false;
18957
19273
  }
@@ -18994,7 +19310,7 @@ function computeActivePlugins(accountId) {
18994
19310
  for (const name of emitNames) {
18995
19311
  const dir = pluginDirs.get(name);
18996
19312
  if (!dir) continue;
18997
- const fm = readFrontmatter(join39(dir, "PLUGIN.md"));
19313
+ const fm = readFrontmatter(join40(dir, "PLUGIN.md"));
18998
19314
  if (!fm) continue;
18999
19315
  const description = frontmatterField(`---
19000
19316
  ${fm}
@@ -19011,7 +19327,7 @@ ${fm}
19011
19327
  `plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
19012
19328
  );
19013
19329
  if (toolNames.length > 0 && descMap.size === 0) {
19014
- const hasSource = existsSync34(join39(dir, "mcp/dist/index.js")) || existsSync34(join39(dir, "mcp/src/index.ts"));
19330
+ const hasSource = existsSync34(join40(dir, "mcp/dist/index.js")) || existsSync34(join40(dir, "mcp/src/index.ts"));
19015
19331
  if (hasSource) {
19016
19332
  console.warn(
19017
19333
  `[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
@@ -19021,7 +19337,7 @@ ${fm}
19021
19337
  const skillPaths = parseSkillPathsFromFrontmatter(fm);
19022
19338
  const skills = [];
19023
19339
  for (const relPath of skillPaths) {
19024
- const skillPath = join39(dir, relPath);
19340
+ const skillPath = join40(dir, relPath);
19025
19341
  const skillFm = readFrontmatter(skillPath);
19026
19342
  if (!skillFm) continue;
19027
19343
  const skillName = frontmatterField(`---
@@ -19065,7 +19381,7 @@ function computeSpecialistDomains(accountId) {
19065
19381
  const out = [];
19066
19382
  for (const file of entries2.sort()) {
19067
19383
  if (!file.endsWith(".md")) continue;
19068
- const fm = readFrontmatter(join39(specialistsDir, file));
19384
+ const fm = readFrontmatter(join40(specialistsDir, file));
19069
19385
  if (!fm) continue;
19070
19386
  const wrapped = `---
19071
19387
  ${fm}
@@ -19159,7 +19475,7 @@ function resolveTunnelUrl() {
19159
19475
  if (!state) return null;
19160
19476
  return `https://${hostname2}.${state.domain}`;
19161
19477
  }
19162
- var TAG26 = "[claude-session-manager:wrapper]";
19478
+ var TAG28 = "[claude-session-manager:wrapper]";
19163
19479
  async function refuseIfClaudeAuthDead(c, route, sessionId) {
19164
19480
  const auth = await ensureAuth();
19165
19481
  if (auth.status !== "dead" && auth.status !== "missing") return null;
@@ -19177,12 +19493,12 @@ async function performSpawnWithInitialMessage(args) {
19177
19493
  const aboutOwner = await resolveOwnerProfileBlock(args.senderId, args.userId);
19178
19494
  const ownerMs = Date.now() - ownerStart;
19179
19495
  const aboutOwnerStatus = aboutOwner == null ? "absent" : "ok" in aboutOwner && aboutOwner.ok === false ? `unresolved:${aboutOwner.reason}` : "ok";
19180
- console.log(`${TAG26} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
19496
+ console.log(`${TAG28} about-owner-resolved status=${aboutOwnerStatus} ms=${ownerMs}`);
19181
19497
  const dormantPlugins = computeDormantPlugins(args.senderId);
19182
19498
  const activePlugins = computeActivePlugins(args.senderId);
19183
19499
  const specialistDomains = computeSpecialistDomains(args.senderId);
19184
19500
  const tunnelUrl = resolveTunnelUrl();
19185
- console.log(`${TAG26} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
19501
+ console.log(`${TAG28} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
19186
19502
  const upstreamPayload = JSON.stringify({
19187
19503
  senderId: args.senderId,
19188
19504
  // Task 205 — pass userId through to the manager so it lands as
@@ -19209,24 +19525,24 @@ async function performSpawnWithInitialMessage(args) {
19209
19525
  // unshapely values.
19210
19526
  conversationNodeId: args.conversationNodeId
19211
19527
  });
19212
- console.log(`${TAG26} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
19528
+ console.log(`${TAG28} forward-spawn-start managerBase=${managerBase("claude-session-manager:wrapper")} bytes=${upstreamPayload.length} hidden=${args.hidden} specialist=${args.specialist ?? "none"}`);
19213
19529
  const forwardStart = Date.now();
19214
19530
  const upstream = await fetch(`${managerBase("claude-session-manager:wrapper")}/public-spawn`, {
19215
19531
  method: "POST",
19216
19532
  headers: { "content-type": "application/json" },
19217
19533
  body: upstreamPayload
19218
19534
  }).catch((err) => {
19219
- console.error(`${TAG26} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
19535
+ console.error(`${TAG28} fetch-failed op=spawn message=${err instanceof Error ? err.message : String(err)} ms=${Date.now() - forwardStart}`);
19220
19536
  return null;
19221
19537
  });
19222
19538
  if (!upstream) return {
19223
19539
  response: new Response(JSON.stringify({ error: "manager-unreachable" }), { status: 503, headers: { "content-type": "application/json" } }),
19224
19540
  claudeSessionId: null
19225
19541
  };
19226
- console.log(`${TAG26} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
19542
+ console.log(`${TAG28} forward-spawn-done status=${upstream.status} ms=${Date.now() - forwardStart}`);
19227
19543
  if (args.initialMessage) {
19228
19544
  const inputBytes = Buffer.byteLength(args.initialMessage, "utf8");
19229
- console.log(`${TAG26} initial-message-inlined bytes=${inputBytes}`);
19545
+ console.log(`${TAG28} initial-message-inlined bytes=${inputBytes}`);
19230
19546
  }
19231
19547
  const bodyText = await upstream.text().catch(() => "");
19232
19548
  let claudeSessionId = null;
@@ -19261,7 +19577,7 @@ app23.post("/", async (c) => {
19261
19577
  if (refusal) return refusal;
19262
19578
  const senderId = getAccountIdForSession(cacheKey) ?? "";
19263
19579
  if (!senderId) {
19264
- console.error(`${TAG26} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
19580
+ console.error(`${TAG28} reject reason=no-account-id cacheKey-prefix=${cacheKey.slice(0, 8)}`);
19265
19581
  return c.json({ error: "admin-account-not-resolved" }, 500);
19266
19582
  }
19267
19583
  const userId = getUserIdForSession(cacheKey) ?? void 0;
@@ -19270,7 +19586,7 @@ app23.post("/", async (c) => {
19270
19586
  const permissionMode = typeof body.permissionMode === "string" ? body.permissionMode : void 0;
19271
19587
  const specialist = typeof body.specialist === "string" && /^[A-Za-z0-9_-]{1,64}$/.test(body.specialist) ? body.specialist : void 0;
19272
19588
  const model = typeof body.model === "string" && /^[A-Za-z0-9._-]{1,64}$/.test(body.model) ? body.model : void 0;
19273
- console.log(`${TAG26} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
19589
+ console.log(`${TAG28} spawn-request-in surface=cookie accountId=${senderId.slice(0, 8)} userId=${userId ? userId.slice(0, 8) : "absent"} channel=${channel} permissionMode=${permissionMode ?? "default"} specialist=${specialist ?? "none"} model=${model ?? "default"} initialMessage=${initialMessage ? "yes" : "no"}`);
19274
19590
  const conversationNodeId = cacheKey ? getSessionIdForSession(cacheKey) : void 0;
19275
19591
  const { response, claudeSessionId } = await performSpawnWithInitialMessage({
19276
19592
  senderId,
@@ -19289,14 +19605,14 @@ app23.post("/", async (c) => {
19289
19605
  claudeSessionId,
19290
19606
  senderId
19291
19607
  );
19292
- console.log(`${TAG26} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
19608
+ console.log(`${TAG28} route-done surface=cookie status=${response.status} route-ms=${Date.now() - routeStart}`);
19293
19609
  return response;
19294
19610
  });
19295
19611
  var claude_sessions_default = app23;
19296
19612
 
19297
19613
  // server/routes/admin/log-ingest.ts
19298
19614
  init_dist();
19299
- var TAG27 = "[log-ingest]";
19615
+ var TAG29 = "[log-ingest]";
19300
19616
  var TAG_PATTERN = /^[A-Za-z0-9_:-]{1,32}$/;
19301
19617
  var LEVELS = /* @__PURE__ */ new Set(["debug", "info", "warn", "error"]);
19302
19618
  var MAX_LINE_BYTES = 4096;
@@ -19307,7 +19623,7 @@ function isLoopbackAddr2(addr) {
19307
19623
  app24.post("/", async (c) => {
19308
19624
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
19309
19625
  if (!isLoopbackAddr2(remoteAddr)) {
19310
- console.error(`${TAG27} reject reason=non-loopback remoteAddr=${remoteAddr}`);
19626
+ console.error(`${TAG29} reject reason=non-loopback remoteAddr=${remoteAddr}`);
19311
19627
  return c.json({ error: "log-ingest-loopback-only" }, 403);
19312
19628
  }
19313
19629
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -19316,7 +19632,7 @@ app24.post("/", async (c) => {
19316
19632
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
19317
19633
  const offender = tokens.find((t) => !isLoopbackAddr2(t));
19318
19634
  if (offender !== void 0) {
19319
- console.error(`${TAG27} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
19635
+ console.error(`${TAG29} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
19320
19636
  return c.json({ error: "log-ingest-loopback-only" }, 403);
19321
19637
  }
19322
19638
  }
@@ -19354,9 +19670,9 @@ init_dist();
19354
19670
  init_sidebar_sessions();
19355
19671
  init_claude_agent();
19356
19672
  init_account_scope();
19357
- import { join as join40 } from "path";
19673
+ import { join as join41 } from "path";
19358
19674
  init_channel_key();
19359
- var TAG28 = "[blocked-tool-notify]";
19675
+ var TAG30 = "[blocked-tool-notify]";
19360
19676
  function isLoopbackAddr3(addr) {
19361
19677
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
19362
19678
  }
@@ -19374,18 +19690,18 @@ Answer the permission card in the session's PTY or in Claude Desktop. Some check
19374
19690
  async function sendWhatsApp(account, to, text) {
19375
19691
  const res = resolveSocket(account.accountId);
19376
19692
  if (!res.ok) {
19377
- console.error(`${TAG28} op=socket-unavailable accountId=${account.accountId} reason=${res.reason}`);
19693
+ console.error(`${TAG30} op=socket-unavailable accountId=${account.accountId} reason=${res.reason}`);
19378
19694
  return false;
19379
19695
  }
19380
19696
  const sent = await sendTextMessage(res.sock, to, text, { accountId: res.accountId });
19381
- if (!sent.success) console.error(`${TAG28} op=send-failed to=${to} error=${sent.error ?? "unknown"}`);
19697
+ if (!sent.success) console.error(`${TAG30} op=send-failed to=${to} error=${sent.error ?? "unknown"}`);
19382
19698
  return sent.success === true;
19383
19699
  }
19384
19700
  var app25 = new Hono();
19385
19701
  app25.post("/", async (c) => {
19386
19702
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
19387
19703
  if (!isLoopbackAddr3(remoteAddr)) {
19388
- console.error(`${TAG28} op=reject reason=non-loopback remoteAddr=${remoteAddr}`);
19704
+ console.error(`${TAG30} op=reject reason=non-loopback remoteAddr=${remoteAddr}`);
19389
19705
  return c.json({ error: "session-blocked-loopback-only" }, 403);
19390
19706
  }
19391
19707
  let body = {};
@@ -19402,17 +19718,17 @@ app25.post("/", async (c) => {
19402
19718
  if (!tool) return c.json({ error: "tool-required" }, 400);
19403
19719
  const text = blockedNotificationText({ sessionId, agentId, tool, blockedForMs });
19404
19720
  const projectDir = findSessionProjectDir(sessionId);
19405
- const meta = projectDir ? readSidecarMeta(join40(projectDir, `${sessionId}.meta.json`)) : { role: null, channel: null, senderId: null, accountId: null };
19721
+ const meta = projectDir ? readSidecarMeta(join41(projectDir, `${sessionId}.meta.json`)) : { role: null, channel: null, senderId: null, accountId: null };
19406
19722
  const account = validateAccountId2(meta.accountId ?? "");
19407
19723
  if (!account) {
19408
19724
  console.error(
19409
- `${TAG28} op=account-unresolved sessionId=${sessionId.slice(0, 8)} sidecarAccountId=${meta.accountId ?? "none"}`
19725
+ `${TAG30} op=account-unresolved sessionId=${sessionId.slice(0, 8)} sidecarAccountId=${meta.accountId ?? "none"}`
19410
19726
  );
19411
19727
  return c.json({ delivered: false, channel: "none" }, 200);
19412
19728
  }
19413
19729
  if (meta.role === "admin" && meta.channel === "whatsapp" && meta.senderId) {
19414
19730
  const delivered2 = await sendWhatsApp(account, meta.senderId, text);
19415
- console.error(`${TAG28} op=notify sessionId=${sessionId.slice(0, 8)} channel=whatsapp delivered=${delivered2}`);
19731
+ console.error(`${TAG30} op=notify sessionId=${sessionId.slice(0, 8)} channel=whatsapp delivered=${delivered2}`);
19416
19732
  return c.json({ delivered: delivered2, channel: "whatsapp" }, 200);
19417
19733
  }
19418
19734
  if (meta.role === "admin" && meta.channel === "telegram" && meta.senderId) {
@@ -19422,11 +19738,11 @@ app25.post("/", async (c) => {
19422
19738
  const chatId = Number(parsed.senderId);
19423
19739
  if (resolved.kind === "one" && Number.isFinite(chatId)) {
19424
19740
  const res = await sendTelegramText(resolved.entry.token, chatId, text);
19425
- console.error(`${TAG28} op=notify sessionId=${sessionId.slice(0, 8)} channel=telegram delivered=${res.ok}`);
19741
+ console.error(`${TAG30} op=notify sessionId=${sessionId.slice(0, 8)} channel=telegram delivered=${res.ok}`);
19426
19742
  return c.json({ delivered: res.ok, channel: "telegram" }, 200);
19427
19743
  }
19428
19744
  console.error(
19429
- `${TAG28} op=telegram-unresolved sessionId=${sessionId.slice(0, 8)} botId=${parsed.botId} kind=${resolved.kind}`
19745
+ `${TAG30} op=telegram-unresolved sessionId=${sessionId.slice(0, 8)} botId=${parsed.botId} kind=${resolved.kind}`
19430
19746
  );
19431
19747
  }
19432
19748
  }
@@ -19436,7 +19752,7 @@ app25.post("/", async (c) => {
19436
19752
  if (await sendWhatsApp(account, phone, text)) delivered = true;
19437
19753
  }
19438
19754
  console.error(
19439
- `${TAG28} op=notify sessionId=${sessionId.slice(0, 8)} channel=house-admin phones=${phones.length} delivered=${delivered}`
19755
+ `${TAG30} op=notify sessionId=${sessionId.slice(0, 8)} channel=house-admin phones=${phones.length} delivered=${delivered}`
19440
19756
  );
19441
19757
  return c.json({ delivered, channel: "house-admin" }, 200);
19442
19758
  });
@@ -19475,18 +19791,18 @@ var ALLOWED_EVENTS = /* @__PURE__ */ new Set([
19475
19791
  ]);
19476
19792
  var app26 = new Hono();
19477
19793
  app26.post("/", async (c) => {
19478
- const TAG60 = "[admin:events]";
19794
+ const TAG62 = "[admin:events]";
19479
19795
  let body;
19480
19796
  try {
19481
19797
  body = await c.req.json();
19482
19798
  } catch (err) {
19483
19799
  const detail = err instanceof Error ? err.message : String(err);
19484
- console.error(`${TAG60} reject reason=body-not-json detail=${detail}`);
19800
+ console.error(`${TAG62} reject reason=body-not-json detail=${detail}`);
19485
19801
  return c.json({ ok: false, detail: "Request body was not valid JSON" }, 400);
19486
19802
  }
19487
19803
  const event = typeof body.event === "string" ? body.event : "";
19488
19804
  if (!ALLOWED_EVENTS.has(event)) {
19489
- console.error(`${TAG60} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
19805
+ console.error(`${TAG62} reject reason=event-not-allowed event=${JSON.stringify(event)}`);
19490
19806
  return c.json({ ok: false, detail: `Event "${event}" is not allowed` }, 400);
19491
19807
  }
19492
19808
  const rawFields = body.fields && typeof body.fields === "object" ? body.fields : {};
@@ -19609,10 +19925,10 @@ init_claude_agent();
19609
19925
  init_data_path();
19610
19926
  init_sidebar_sessions();
19611
19927
  import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync36 } from "fs";
19612
- import { readdir as readdir4, readFile as readFile9, stat as stat6, mkdir as mkdir2, unlink as unlink3, rename as rename3, rmdir } from "fs/promises";
19928
+ import { readdir as readdir4, readFile as readFile9, stat as stat6, mkdir as mkdir3, unlink as unlink3, rename as rename3, rmdir } from "fs/promises";
19613
19929
  import { realpathSync as realpathSync7 } from "fs";
19614
19930
  import { randomUUID as randomUUID6 } from "crypto";
19615
- import { basename as basename13, dirname as dirname15, join as join42, relative as relative6, resolve as resolve28, sep as sep9 } from "path";
19931
+ import { basename as basename13, dirname as dirname15, join as join43, relative as relative6, resolve as resolve28, sep as sep9 } from "path";
19616
19932
  import { Readable as Readable2 } from "stream";
19617
19933
  init_attachments();
19618
19934
 
@@ -19936,7 +20252,7 @@ async function cascadeDeleteDocument(params) {
19936
20252
  init_data_path();
19937
20253
  init_neo4j_store();
19938
20254
  import * as fsp from "fs/promises";
19939
- import { resolve as resolve27, relative as relative5, join as join41, basename as basename12, extname, sep as sep8 } from "path";
20255
+ import { resolve as resolve27, relative as relative5, join as join42, basename as basename12, extname, sep as sep8 } from "path";
19940
20256
  import { tmpdir as tmpdir3 } from "os";
19941
20257
  import { execFile } from "child_process";
19942
20258
  import { promisify } from "util";
@@ -20018,7 +20334,7 @@ async function extractPdf(absolute) {
20018
20334
  return stdout.trim();
20019
20335
  }
20020
20336
  async function ocrPdf(absolute) {
20021
- const outPdf = join41(tmpdir3(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
20337
+ const outPdf = join42(tmpdir3(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
20022
20338
  try {
20023
20339
  await execFileAsync(
20024
20340
  "ocrmypdf",
@@ -20080,7 +20396,7 @@ async function readDisplayName(absolute) {
20080
20396
  const stem = dot === -1 ? base : base.slice(0, dot);
20081
20397
  if (base === `${stem}.meta.json`) return null;
20082
20398
  try {
20083
- const raw = await fsp.readFile(join41(dir, `${stem}.meta.json`), "utf-8");
20399
+ const raw = await fsp.readFile(join42(dir, `${stem}.meta.json`), "utf-8");
20084
20400
  const meta = JSON.parse(raw);
20085
20401
  const dn = meta.displayName ?? meta.filename;
20086
20402
  return typeof dn === "string" && dn.length > 0 ? dn : null;
@@ -20101,7 +20417,7 @@ async function walkSubtree(root, dataRoot, out) {
20101
20417
  for (const entry of entries2) {
20102
20418
  if (entry.isSymbolicLink()) continue;
20103
20419
  if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
20104
- const abs = join41(root, entry.name);
20420
+ const abs = join42(root, entry.name);
20105
20421
  if (entry.isDirectory()) {
20106
20422
  const sub = await walkSubtree(abs, dataRoot, out);
20107
20423
  if (!sub.clean) clean = false;
@@ -20477,7 +20793,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
20477
20793
  var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
20478
20794
  async function readMeta2(absDir, baseName) {
20479
20795
  try {
20480
- const raw = await readFile9(join42(absDir, `${baseName}.meta.json`), "utf8");
20796
+ const raw = await readFile9(join43(absDir, `${baseName}.meta.json`), "utf8");
20481
20797
  const parsed = JSON.parse(raw);
20482
20798
  if (typeof parsed?.filename === "string") {
20483
20799
  return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
@@ -20532,7 +20848,7 @@ async function servableFilesIn(dirAbs, uuid) {
20532
20848
  }
20533
20849
  async function enrich(absolute, entry, accountNames) {
20534
20850
  if (entry.kind === "directory" && UUID_RE3.test(entry.name)) {
20535
- const dirAbs = join42(absolute, entry.name);
20851
+ const dirAbs = join43(absolute, entry.name);
20536
20852
  const meta = await readMeta2(dirAbs, entry.name);
20537
20853
  if (meta?.filename) {
20538
20854
  const servable = await servableFilesIn(dirAbs, entry.name);
@@ -20541,7 +20857,7 @@ async function enrich(absolute, entry, accountNames) {
20541
20857
  let size = null;
20542
20858
  let modifiedAt = entry.modifiedAt;
20543
20859
  try {
20544
- const st = await stat6(join42(dirAbs, innerName));
20860
+ const st = await stat6(join43(dirAbs, innerName));
20545
20861
  size = st.size;
20546
20862
  modifiedAt = st.mtime.toISOString();
20547
20863
  } catch {
@@ -20750,7 +21066,7 @@ app27.get("/", requireAdminSession, async (c) => {
20750
21066
  const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
20751
21067
  const protectedEntry = isProtectedFromDeletion(childRel).protected;
20752
21068
  try {
20753
- const entryPath = join42(absolute, name);
21069
+ const entryPath = join43(absolute, name);
20754
21070
  const s = await stat6(entryPath);
20755
21071
  entries2.push({
20756
21072
  name,
@@ -20779,7 +21095,7 @@ app27.get("/", requireAdminSession, async (c) => {
20779
21095
  const displayPath = buildDisplayPath(relPath, accountNames);
20780
21096
  if (groupReq || isAccountRoot(relPath)) {
20781
21097
  const acctId = relPath.split("/")[1] ?? accountId;
20782
- const schemaMd = await readFile9(join42(absolute, "SCHEMA.md"), "utf8").catch(() => null);
21098
+ const schemaMd = await readFile9(join43(absolute, "SCHEMA.md"), "utf8").catch(() => null);
20783
21099
  const groups = classifyAccountRoot(schemaMd, entries2.map((e) => e.name));
20784
21100
  console.error(
20785
21101
  `[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"}`
@@ -20817,7 +21133,7 @@ app27.get("/", requireAdminSession, async (c) => {
20817
21133
  for (const name of homeDirs) {
20818
21134
  const base = byName.get(name);
20819
21135
  try {
20820
- const dirents = await readdir4(join42(absolute, name), { withFileTypes: true });
21136
+ const dirents = await readdir4(join43(absolute, name), { withFileTypes: true });
20821
21137
  const visible = dirents.filter((d) => !d.name.startsWith("."));
20822
21138
  visible.sort((a, b) => {
20823
21139
  const ad = a.isDirectory() ? 0 : 1;
@@ -20882,7 +21198,7 @@ app27.get("/download", requireAdminSession, async (c) => {
20882
21198
  console.error(`[data] op=scratchpad-no-session sessionId="${sessionId.slice(0, 8)}\u2026"`);
20883
21199
  return c.json({ error: "Not found" }, 404);
20884
21200
  }
20885
- const meta = readSidecarMeta(join42(projectDir, `${sessionId}.meta.json`));
21201
+ const meta = readSidecarMeta(join43(projectDir, `${sessionId}.meta.json`));
20886
21202
  if (!meta.accountId || meta.accountId !== accountId) {
20887
21203
  console.error(`[data] account-scope-blocked root="scratchpad" sessionId="${sessionId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
20888
21204
  return c.json({ error: "Not found" }, 404);
@@ -20977,7 +21293,7 @@ async function* walkRegularFiles(dirAbsolute) {
20977
21293
  const dirents = await readdir4(dirAbsolute, { withFileTypes: true });
20978
21294
  for (const d of dirents) {
20979
21295
  if (d.isSymbolicLink()) continue;
20980
- const child = join42(dirAbsolute, d.name);
21296
+ const child = join43(dirAbsolute, d.name);
20981
21297
  if (d.isDirectory()) {
20982
21298
  yield* walkRegularFiles(child);
20983
21299
  continue;
@@ -21087,7 +21403,7 @@ async function resolveUploadTarget(c, accountId, uid) {
21087
21403
  const base = resolveSharedOrOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
21088
21404
  if (!base.ok) return { ok: false, status: base.status, error: base.error };
21089
21405
  const relDir = relpath ? dirname15(relpath) : ".";
21090
- const destRel = relDir === "." ? base.relative : join42(base.relative, relDir);
21406
+ const destRel = relDir === "." ? base.relative : join43(base.relative, relDir);
21091
21407
  if ((0, import_dist.isSharedPath)(destRel)) {
21092
21408
  const gate = gateSharedWrite(base.absolute, destRel, accountId, "POST /api/admin/files/upload");
21093
21409
  if (!gate.ok) return { ok: false, status: gate.status, error: gate.error };
@@ -21104,7 +21420,7 @@ async function resolveUploadTarget(c, accountId, uid) {
21104
21420
  const destDir = relDir === "." ? base.absolute : resolve28(base.absolute, relDir);
21105
21421
  const destPath = resolve28(destDir, finalName);
21106
21422
  if (relpath) {
21107
- const firstCreated = await mkdir2(destDir, { recursive: true });
21423
+ const firstCreated = await mkdir3(destDir, { recursive: true });
21108
21424
  if (firstCreated) console.error(`[data-upload] op=mkdir uid=${uid} token=${token} dir="${destRel}"`);
21109
21425
  } else {
21110
21426
  const info = await stat6(destDir).catch(() => null);
@@ -21147,7 +21463,7 @@ app27.post("/upload", requireAdminSession, async (c) => {
21147
21463
  console.error(`[data-upload] op=request uid=${uid} account=${accountId} dir="${destRel}" token=${token} rel="${relpath ?? ""}" declaredBytes=${declaredBytes}`);
21148
21464
  const ceiling = dataUploadCeiling();
21149
21465
  const tmpDir = resolve28(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
21150
- await mkdir2(tmpDir, { recursive: true });
21466
+ await mkdir3(tmpDir, { recursive: true });
21151
21467
  const tmpPath = resolve28(tmpDir, `${uid}.part`);
21152
21468
  const out = createWriteStream2(tmpPath);
21153
21469
  const t0 = Date.now();
@@ -21296,7 +21612,7 @@ async function handleChunkUpload(c, accountId) {
21296
21612
  const target = await resolveUploadTarget(c, accountId, uploadId);
21297
21613
  if (!target.ok) return c.json({ error: target.error }, target.status);
21298
21614
  const tmpDir = resolve28(DATA_ROOT, "accounts", accountId, UPLOAD_TMP_DIR);
21299
- await mkdir2(tmpDir, { recursive: true });
21615
+ await mkdir3(tmpDir, { recursive: true });
21300
21616
  const tmpPath = resolve28(tmpDir, `${uploadId}.part`);
21301
21617
  const out = createWriteStream2(tmpPath);
21302
21618
  const state2 = {
@@ -21473,7 +21789,7 @@ app27.delete("/", requireAdminSession, async (c) => {
21473
21789
  const dot = base.lastIndexOf(".");
21474
21790
  const stem = dot === -1 ? base : base.slice(0, dot);
21475
21791
  const containerDir = dirname15(absolute);
21476
- const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join42(containerDir, `${stem}.meta.json`) : null;
21792
+ const sidecarPath = UUID_RE3.test(stem) && base !== `${stem}.meta.json` ? join43(containerDir, `${stem}.meta.json`) : null;
21477
21793
  const isAttachmentContainer = UUID_RE3.test(stem) && basename13(containerDir) === stem;
21478
21794
  await unlink3(absolute);
21479
21795
  if (sidecarPath) {
@@ -21483,7 +21799,7 @@ app27.delete("/", requireAdminSession, async (c) => {
21483
21799
  }
21484
21800
  }
21485
21801
  if (isAttachmentContainer) {
21486
- await unlink3(join42(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
21802
+ await unlink3(join43(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
21487
21803
  });
21488
21804
  await rmdir(containerDir).catch(() => {
21489
21805
  });
@@ -21542,7 +21858,7 @@ app27.post("/folder", requireAdminSession, async (c) => {
21542
21858
  try {
21543
21859
  const info = await stat6(parent.absolute);
21544
21860
  if (!info.isDirectory()) return c.json({ error: "Parent is not a directory" }, 400);
21545
- await mkdir2(newAbs, { recursive: false });
21861
+ await mkdir3(newAbs, { recursive: false });
21546
21862
  } catch (err) {
21547
21863
  const code = err.code;
21548
21864
  if (code === "EEXIST") return c.json({ error: "A file or folder with that name already exists" }, 409);
@@ -22609,7 +22925,7 @@ function isHiddenByDefault(label) {
22609
22925
  // server/lib/top-level-labels.ts
22610
22926
  var import_dist6 = __toESM(require_dist5(), 1);
22611
22927
  import { readdirSync as readdirSync24, readFileSync as readFileSync36 } from "fs";
22612
- import { join as join43, resolve as resolve29 } from "path";
22928
+ import { join as join44, resolve as resolve29 } from "path";
22613
22929
  var STATIC_TOP_LEVEL_LABELS = Object.freeze(
22614
22930
  /* @__PURE__ */ new Set([
22615
22931
  // Base-schema infra (schema-base.md has no top-level section).
@@ -22713,7 +23029,7 @@ function parseTopLevelLabels(content) {
22713
23029
  }
22714
23030
  function resolveReferencesDir() {
22715
23031
  if (process.env.MAXY_PLATFORM_ROOT) {
22716
- return join43(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
23032
+ return join44(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
22717
23033
  }
22718
23034
  return resolve29(import.meta.dirname, "../../../plugins/memory/references");
22719
23035
  }
@@ -22723,7 +23039,7 @@ function parseTableTopLevelLabels(referencesDir) {
22723
23039
  try {
22724
23040
  const fileNames = readdirSync24(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
22725
23041
  for (const fileName of fileNames) {
22726
- const content = readFileSync36(join43(referencesDir, fileName), "utf-8");
23042
+ const content = readFileSync36(join44(referencesDir, fileName), "utf-8");
22727
23043
  const parsed = parseTopLevelLabels(content);
22728
23044
  if (parsed.length > 0) contributingFiles.push(fileName);
22729
23045
  for (const label of parsed) labels.add(label);
@@ -24503,24 +24819,24 @@ init_session_store();
24503
24819
  import { randomUUID as randomUUID8 } from "crypto";
24504
24820
 
24505
24821
  // server/wa-descriptor.ts
24506
- import { resolve as resolve31, join as join44 } from "path";
24822
+ import { resolve as resolve31, join as join45 } from "path";
24507
24823
  function waGatewayUrl() {
24508
24824
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
24509
24825
  }
24510
24826
  function waServerPath() {
24511
- return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join44(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
24827
+ return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
24512
24828
  }
24513
24829
  function waChannelDescriptor(senderId) {
24514
24830
  return { senderId, gatewayUrl: waGatewayUrl(), serverPath: waServerPath() };
24515
24831
  }
24516
24832
 
24517
24833
  // server/telegram-descriptor.ts
24518
- import { resolve as resolve32, join as join45 } from "path";
24834
+ import { resolve as resolve32, join as join46 } from "path";
24519
24835
  function telegramGatewayUrl() {
24520
24836
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
24521
24837
  }
24522
24838
  function telegramServerPath() {
24523
- return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve32(process.env.MAXY_PLATFORM_ROOT ?? join45(__dirname, ".."), "services/telegram-channel/dist/server.js");
24839
+ return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve32(process.env.MAXY_PLATFORM_ROOT ?? join46(__dirname, ".."), "services/telegram-channel/dist/server.js");
24524
24840
  }
24525
24841
  function telegramChannelDescriptor(senderId) {
24526
24842
  return { senderId, gatewayUrl: telegramGatewayUrl(), serverPath: telegramServerPath() };
@@ -24817,10 +25133,10 @@ var system_stats_default = app42;
24817
25133
  init_dist();
24818
25134
  init_neo4j_store();
24819
25135
  import { existsSync as existsSync38, readFileSync as readFileSync37 } from "fs";
24820
- import { resolve as resolve33, join as join46 } from "path";
25136
+ import { resolve as resolve33, join as join47 } from "path";
24821
25137
  var PLATFORM_ROOT4 = process.env.MAXY_PLATFORM_ROOT ?? resolve33(process.cwd(), "..");
24822
25138
  var brandHostname = "maxy";
24823
- var brandJsonPath = join46(PLATFORM_ROOT4, "config", "brand.json");
25139
+ var brandJsonPath = join47(PLATFORM_ROOT4, "config", "brand.json");
24824
25140
  if (existsSync38(brandJsonPath)) {
24825
25141
  try {
24826
25142
  const brand = JSON.parse(readFileSync37(brandJsonPath, "utf-8"));
@@ -25082,7 +25398,7 @@ function managerLogFollowUrl(sessionId, opts) {
25082
25398
  }
25083
25399
 
25084
25400
  // server/routes/admin/linkedin-ingest.ts
25085
- var TAG29 = "[linkedin-ingest-route]";
25401
+ var TAG31 = "[linkedin-ingest-route]";
25086
25402
  var UUID4 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
25087
25403
  var ISO = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?(?:Z|[+-]\d{2}:\d{2})$/;
25088
25404
  var LINKEDIN_URL = /^https:\/\/www\.linkedin\.com\//;
@@ -25207,28 +25523,28 @@ app44.post("/", requireIngestToken, async (c) => {
25207
25523
  try {
25208
25524
  body = await c.req.json();
25209
25525
  } catch {
25210
- console.error(TAG29 + " rejected status=400 reason=schema:body-not-json");
25526
+ console.error(TAG31 + " rejected status=400 reason=schema:body-not-json");
25211
25527
  return c.json({ ok: false, error: "schema", reason: "body-not-json" }, 400);
25212
25528
  }
25213
25529
  const v = validate2(body);
25214
25530
  if (!v.ok) {
25215
- console.error(TAG29 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
25531
+ console.error(TAG31 + " rejected status=" + v.status + " reason=" + v.reason + " missing=" + v.missing.join(","));
25216
25532
  return c.json({ ok: false, error: v.error, reason: v.reason, missing: v.missing }, v.status);
25217
25533
  }
25218
25534
  const envelope = v.envelope;
25219
25535
  const senderId = c.var.ingestAccountId ?? "";
25220
25536
  if (!senderId) {
25221
- console.error(TAG29 + " rejected status=500 reason=admin-account-not-resolved");
25537
+ console.error(TAG31 + " rejected status=500 reason=admin-account-not-resolved");
25222
25538
  return c.json({ ok: false, error: "admin-account-not-resolved" }, 500);
25223
25539
  }
25224
25540
  const payloadBytes = JSON.stringify(envelope).length;
25225
25541
  console.log(
25226
- TAG29 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
25542
+ TAG31 + " received kind=" + envelope.kind + " account=" + senderId.slice(0, 8) + " pageUrl=" + envelope.pageUrl + " dispatchId=" + envelope.dispatchId + " payloadBytes=" + payloadBytes
25227
25543
  );
25228
25544
  const initialMessage = buildInitialMessage(envelope);
25229
25545
  const spawnStart = Date.now();
25230
25546
  const sessionId = randomUUID9();
25231
- console.log(TAG29 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
25547
+ console.log(TAG31 + " route target=rc-spawn dispatchId=" + envelope.dispatchId + " sessionId=" + sessionId.slice(0, 8));
25232
25548
  const spawned = await managerRcSpawn({
25233
25549
  sessionId,
25234
25550
  initialMessage,
@@ -25241,12 +25557,12 @@ app44.post("/", requireIngestToken, async (c) => {
25241
25557
  });
25242
25558
  if ("error" in spawned) {
25243
25559
  console.error(
25244
- TAG29 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
25560
+ TAG31 + " dispatch-failed dispatchId=" + envelope.dispatchId + " status=" + spawned.status + " ms=" + (Date.now() - spawnStart) + " message=" + spawned.error
25245
25561
  );
25246
25562
  return c.json({ ok: false, error: "dispatch-failed", upstreamStatus: spawned.status, detail: spawned.error }, 502);
25247
25563
  }
25248
25564
  console.log(
25249
- TAG29 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
25565
+ TAG31 + " dispatched dispatchId=" + envelope.dispatchId + " taskId=" + spawned.sessionId + " ms=" + (Date.now() - spawnStart)
25250
25566
  );
25251
25567
  return c.json({ ok: true, dispatchId: envelope.dispatchId, taskId: spawned.sessionId }, 202);
25252
25568
  });
@@ -25256,7 +25572,7 @@ var linkedin_ingest_default = app44;
25256
25572
  init_dist();
25257
25573
  init_neo4j_store();
25258
25574
  import neo4j2 from "neo4j-driver";
25259
- var TAG30 = "[post-turn-context]";
25575
+ var TAG32 = "[post-turn-context]";
25260
25576
  var STRIPPED_PROPERTIES2 = /* @__PURE__ */ new Set([
25261
25577
  "embedding",
25262
25578
  "passwordHash",
@@ -25298,7 +25614,7 @@ var app45 = new Hono();
25298
25614
  app45.get("/", async (c) => {
25299
25615
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
25300
25616
  if (!isLoopbackAddr4(remoteAddr)) {
25301
- console.error(`${TAG30} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25617
+ console.error(`${TAG32} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25302
25618
  return c.json({ error: "post-turn-context-loopback-only" }, 403);
25303
25619
  }
25304
25620
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -25307,7 +25623,7 @@ app45.get("/", async (c) => {
25307
25623
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
25308
25624
  const offender = tokens.find((t) => !isLoopbackAddr4(t));
25309
25625
  if (offender !== void 0) {
25310
- console.error(`${TAG30} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25626
+ console.error(`${TAG32} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25311
25627
  return c.json({ error: "post-turn-context-loopback-only" }, 403);
25312
25628
  }
25313
25629
  }
@@ -25339,7 +25655,7 @@ app45.get("/", async (c) => {
25339
25655
  writes.sort((a, b) => a.sortKey.localeCompare(b.sortKey));
25340
25656
  const total = Date.now() - started2;
25341
25657
  console.log(
25342
- `${TAG30} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
25658
+ `${TAG32} sessionId=${sessionId} accountId=${accountId} writes=${writes.length} ms=${total}`
25343
25659
  );
25344
25660
  return c.json({
25345
25661
  writes: writes.map(({ elementId, labels, properties }) => ({ elementId, labels, properties }))
@@ -25348,7 +25664,7 @@ app45.get("/", async (c) => {
25348
25664
  const elapsed = Date.now() - started2;
25349
25665
  const message = err instanceof Error ? err.message : String(err);
25350
25666
  console.error(
25351
- `${TAG30} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
25667
+ `${TAG32} neo4j-unreachable sessionId=${sessionId} ms=${elapsed} err="${message}"`
25352
25668
  );
25353
25669
  return c.json({ error: `post-turn-context unavailable: ${message}` }, 503);
25354
25670
  } finally {
@@ -25465,7 +25781,7 @@ function formatPreviousContext(writes) {
25465
25781
  }
25466
25782
 
25467
25783
  // server/routes/admin/public-session-context.ts
25468
- var TAG31 = "[public-session-context]";
25784
+ var TAG33 = "[public-session-context]";
25469
25785
  function isLoopbackAddr5(addr) {
25470
25786
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
25471
25787
  }
@@ -25473,7 +25789,7 @@ var app46 = new Hono();
25473
25789
  app46.get("/", async (c) => {
25474
25790
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
25475
25791
  if (!isLoopbackAddr5(remoteAddr)) {
25476
- console.error(`${TAG31} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25792
+ console.error(`${TAG33} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25477
25793
  return c.json({ error: "public-session-context-loopback-only" }, 403);
25478
25794
  }
25479
25795
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -25482,7 +25798,7 @@ app46.get("/", async (c) => {
25482
25798
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
25483
25799
  const offender = tokens.find((t) => !isLoopbackAddr5(t));
25484
25800
  if (offender !== void 0) {
25485
- console.error(`${TAG31} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25801
+ console.error(`${TAG33} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25486
25802
  return c.json({ error: "public-session-context-loopback-only" }, 403);
25487
25803
  }
25488
25804
  }
@@ -25496,14 +25812,14 @@ app46.get("/", async (c) => {
25496
25812
  const writes = await fetchSliceWrites(session, sliceToken, accountId);
25497
25813
  const total = Date.now() - started2;
25498
25814
  console.log(
25499
- `${TAG31} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
25815
+ `${TAG33} sliceToken=${sliceToken.slice(0, 8)} writes=${writes.length} ms=${total}`
25500
25816
  );
25501
25817
  return c.json({ writes });
25502
25818
  } catch (err) {
25503
25819
  const elapsed = Date.now() - started2;
25504
25820
  const message = err instanceof Error ? err.message : String(err);
25505
25821
  console.error(
25506
- `${TAG31} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
25822
+ `${TAG33} neo4j-unreachable sliceToken=${sliceToken.slice(0, 8)} ms=${elapsed} err="${message}"`
25507
25823
  );
25508
25824
  return c.json({ error: `public-session-context unavailable: ${message}` }, 503);
25509
25825
  } finally {
@@ -25525,7 +25841,7 @@ function getWebchatGateway() {
25525
25841
  }
25526
25842
 
25527
25843
  // server/routes/admin/public-session-exit.ts
25528
- var TAG32 = "[public-session-exit-route]";
25844
+ var TAG34 = "[public-session-exit-route]";
25529
25845
  function isLoopbackAddr6(addr) {
25530
25846
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
25531
25847
  }
@@ -25533,7 +25849,7 @@ var app47 = new Hono();
25533
25849
  app47.post("/", async (c) => {
25534
25850
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
25535
25851
  if (!isLoopbackAddr6(remoteAddr)) {
25536
- console.error(`${TAG32} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25852
+ console.error(`${TAG34} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25537
25853
  return c.json({ error: "public-session-exit-loopback-only" }, 403);
25538
25854
  }
25539
25855
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -25542,7 +25858,7 @@ app47.post("/", async (c) => {
25542
25858
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
25543
25859
  const offender = tokens.find((t) => !isLoopbackAddr6(t));
25544
25860
  if (offender !== void 0) {
25545
- console.error(`${TAG32} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25861
+ console.error(`${TAG34} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25546
25862
  return c.json({ error: "public-session-exit-loopback-only" }, 403);
25547
25863
  }
25548
25864
  }
@@ -25556,7 +25872,7 @@ app47.post("/", async (c) => {
25556
25872
  if (!sessionId) return c.json({ error: "sessionId required" }, 400);
25557
25873
  const gateway = getWebchatGateway();
25558
25874
  if (!gateway) {
25559
- console.error(`${TAG32} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
25875
+ console.error(`${TAG34} reject reason=gateway-unset sessionId=${sessionId.slice(0, 8)}`);
25560
25876
  return c.json({ error: "webchat-gateway-unset" }, 503);
25561
25877
  }
25562
25878
  gateway.handlePublicSessionExit(sessionId);
@@ -25566,7 +25882,7 @@ var public_session_exit_default = app47;
25566
25882
 
25567
25883
  // server/routes/admin/access-session-evict.ts
25568
25884
  init_dist();
25569
- var TAG33 = "[access-session-evict]";
25885
+ var TAG35 = "[access-session-evict]";
25570
25886
  function isLoopbackAddr7(addr) {
25571
25887
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
25572
25888
  }
@@ -25574,7 +25890,7 @@ var app48 = new Hono();
25574
25890
  app48.post("/", async (c) => {
25575
25891
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
25576
25892
  if (!isLoopbackAddr7(remoteAddr)) {
25577
- console.error(`${TAG33} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25893
+ console.error(`${TAG35} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25578
25894
  return c.json({ error: "access-session-evict-loopback-only" }, 403);
25579
25895
  }
25580
25896
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -25583,7 +25899,7 @@ app48.post("/", async (c) => {
25583
25899
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
25584
25900
  const offender = tokens.find((t) => !isLoopbackAddr7(t));
25585
25901
  if (offender !== void 0) {
25586
- console.error(`${TAG33} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25902
+ console.error(`${TAG35} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25587
25903
  return c.json({ error: "access-session-evict-loopback-only" }, 403);
25588
25904
  }
25589
25905
  }
@@ -25596,7 +25912,7 @@ app48.post("/", async (c) => {
25596
25912
  const grantId = typeof body.grantId === "string" ? body.grantId.trim() : "";
25597
25913
  if (!grantId) return c.json({ error: "grantId required" }, 400);
25598
25914
  const dropped = evictAccessSessionsByGrant(grantId);
25599
- console.log(`${TAG33} grantId=${grantId} dropped=${dropped}`);
25915
+ console.log(`${TAG35} grantId=${grantId} dropped=${dropped}`);
25600
25916
  return c.json({ ok: true, dropped });
25601
25917
  });
25602
25918
  var access_session_evict_default = app48;
@@ -25604,7 +25920,7 @@ var access_session_evict_default = app48;
25604
25920
  // server/routes/admin/enrol-person.ts
25605
25921
  init_dist();
25606
25922
  init_normalize();
25607
- var TAG34 = "[enrol]";
25923
+ var TAG36 = "[enrol]";
25608
25924
  function isLoopbackAddr8(addr) {
25609
25925
  return addr === "127.0.0.1" || addr === "::1" || addr === "::ffff:127.0.0.1";
25610
25926
  }
@@ -25613,7 +25929,7 @@ var app49 = new Hono();
25613
25929
  app49.post("/", async (c) => {
25614
25930
  const remoteAddr = c.env?.incoming?.socket?.remoteAddress ?? "";
25615
25931
  if (!isLoopbackAddr8(remoteAddr)) {
25616
- console.error(`${TAG34} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25932
+ console.error(`${TAG36} reject reason=non-loopback remoteAddr=${remoteAddr}`);
25617
25933
  return c.json({ error: "enrol-person-loopback-only" }, 403);
25618
25934
  }
25619
25935
  const xffHeader = c.env?.incoming?.headers?.["x-forwarded-for"];
@@ -25622,7 +25938,7 @@ app49.post("/", async (c) => {
25622
25938
  const tokens = xffRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0);
25623
25939
  const offender = tokens.find((t) => !isLoopbackAddr8(t));
25624
25940
  if (offender !== void 0) {
25625
- console.error(`${TAG34} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25941
+ console.error(`${TAG36} reject reason=xff-non-loopback xff=${JSON.stringify(xffRaw)}`);
25626
25942
  return c.json({ error: "enrol-person-loopback-only" }, 403);
25627
25943
  }
25628
25944
  }
@@ -25647,7 +25963,7 @@ app49.post("/", async (c) => {
25647
25963
  }
25648
25964
  const accountId = process.env.ACCOUNT_ID ?? "";
25649
25965
  if (!accountId) {
25650
- console.error(`${TAG34} op=person result=no-account-id`);
25966
+ console.error(`${TAG36} op=person result=no-account-id`);
25651
25967
  return c.json({ error: "no-account-id" }, 500);
25652
25968
  }
25653
25969
  let personId;
@@ -25655,7 +25971,7 @@ app49.post("/", async (c) => {
25655
25971
  personId = await enrolPerson({ accountId, phone, email, agentSlug });
25656
25972
  } catch (err) {
25657
25973
  console.error(
25658
- `${TAG34} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
25974
+ `${TAG36} op=person result=write-failed agentSlug=${agentSlug} contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
25659
25975
  );
25660
25976
  return c.json({ error: "enrol-failed" }, 500);
25661
25977
  }
@@ -25665,11 +25981,11 @@ app49.post("/", async (c) => {
25665
25981
  if (g) grant = { grantId: g.grantId, status: g.status, contactValue: g.contactValue };
25666
25982
  } catch (err) {
25667
25983
  console.error(
25668
- `${TAG34} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
25984
+ `${TAG36} op=person result=grant-lookup-failed contact=${maskContact(email)} err="${err instanceof Error ? err.message : String(err)}"`
25669
25985
  );
25670
25986
  }
25671
25987
  console.log(
25672
- `${TAG34} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
25988
+ `${TAG36} op=person personId=${personId} account=${accountId} agentSlug=${agentSlug} contact=${maskContact(email)}`
25673
25989
  );
25674
25990
  return c.json({ personId, grant }, 200);
25675
25991
  });
@@ -25776,7 +26092,7 @@ init_account_scope();
25776
26092
  init_neo4j_store();
25777
26093
  import { existsSync as existsSync40 } from "fs";
25778
26094
  import { randomUUID as randomUUID10 } from "crypto";
25779
- import { join as join48 } from "path";
26095
+ import { join as join49 } from "path";
25780
26096
 
25781
26097
  // server/lib/calendar-ics.ts
25782
26098
  var CRLF = "\r\n";
@@ -25877,7 +26193,7 @@ function countVEvents(ics) {
25877
26193
 
25878
26194
  // server/lib/calendar-availability.ts
25879
26195
  import { readFileSync as readFileSync39 } from "fs";
25880
- import { join as join47 } from "path";
26196
+ import { join as join48 } from "path";
25881
26197
  var AVAILABILITY_FILENAME = "calendar-availability.json";
25882
26198
  var REQUIRED_KEYS = [
25883
26199
  "timezone",
@@ -25886,7 +26202,7 @@ var REQUIRED_KEYS = [
25886
26202
  "weekly"
25887
26203
  ];
25888
26204
  function readAvailabilityConfig(accountDir) {
25889
- const path = join47(accountDir, AVAILABILITY_FILENAME);
26205
+ const path = join48(accountDir, AVAILABILITY_FILENAME);
25890
26206
  let raw;
25891
26207
  try {
25892
26208
  raw = readFileSync39(path, "utf-8");
@@ -26444,7 +26760,7 @@ app51.get("/booking-link", requireAdminSession, (c) => {
26444
26760
  }
26445
26761
  const id82 = account.accountId.slice(0, 8);
26446
26762
  try {
26447
- if (!existsSync40(join48(account.accountDir, AVAILABILITY_FILENAME))) {
26763
+ if (!existsSync40(join49(account.accountDir, AVAILABILITY_FILENAME))) {
26448
26764
  console.log(`[calendar] op=booking-link accountId=${id82} bookingDomain=none source=availability-config`);
26449
26765
  return c.json({ bookingDomain: null });
26450
26766
  }
@@ -26467,7 +26783,7 @@ init_dist();
26467
26783
  init_helpers();
26468
26784
  init_account_scope();
26469
26785
  import { existsSync as existsSync41, readFileSync as readFileSync40 } from "fs";
26470
- import { join as join49 } from "path";
26786
+ import { join as join50 } from "path";
26471
26787
  var app52 = new Hono();
26472
26788
  var PORTAL_FILENAME = "data-portal.json";
26473
26789
  app52.get("/portal-link", requireAdminSession, (c) => {
@@ -26478,7 +26794,7 @@ app52.get("/portal-link", requireAdminSession, (c) => {
26478
26794
  }
26479
26795
  const id82 = account.accountId.slice(0, 8);
26480
26796
  try {
26481
- const path = join49(account.accountDir, PORTAL_FILENAME);
26797
+ const path = join50(account.accountDir, PORTAL_FILENAME);
26482
26798
  if (!existsSync41(path)) {
26483
26799
  console.log(`[data-portal] op=portal-link accountId=${id82} portalDomain=none source=data-portal-config`);
26484
26800
  return c.json({ portalDomain: null });
@@ -27608,7 +27924,7 @@ init_helpers();
27608
27924
  init_claude_agent();
27609
27925
  init_route_cache();
27610
27926
  init_neo4j_store();
27611
- import { basename as basename15, join as join50 } from "path";
27927
+ import { basename as basename15, join as join51 } from "path";
27612
27928
 
27613
27929
  // app/lib/time-entry-format.ts
27614
27930
  function secondsBetween(startIso, endIso) {
@@ -27629,7 +27945,7 @@ function toNum(v) {
27629
27945
 
27630
27946
  // server/routes/admin/tasks-list.ts
27631
27947
  init_sidebar_sessions();
27632
- var TAG35 = "[task-timer]";
27948
+ var TAG37 = "[task-timer]";
27633
27949
  var COMPLETED = /* @__PURE__ */ new Set(["completed"]);
27634
27950
  var HIDDEN_FROM_OPEN = /* @__PURE__ */ new Set(["completed", "cancelled"]);
27635
27951
  var app55 = new Hono();
@@ -27637,12 +27953,12 @@ app55.get("/", requireAdminSession, async (c) => {
27637
27953
  const cacheKey = c.var.cacheKey;
27638
27954
  const accountId = getAccountIdForSession(cacheKey);
27639
27955
  if (!accountId) {
27640
- console.error(`${TAG35} op=list auth-rejected reason="no account for session"`);
27956
+ console.error(`${TAG37} op=list auth-rejected reason="no account for session"`);
27641
27957
  return c.json({ error: "Account not found for session" }, 401);
27642
27958
  }
27643
27959
  const cacheStart = Date.now();
27644
27960
  const cached3 = await getOrCompute("tasks-list", accountId, () => computeTaskList(accountId));
27645
- console.log(`${TAG35} op=list-cache cache=${cached3.state} account=${accountId} ms=${Date.now() - cacheStart}`);
27961
+ console.log(`${TAG37} op=list-cache cache=${cached3.state} account=${accountId} ms=${Date.now() - cacheStart}`);
27646
27962
  if (cached3.value === null) {
27647
27963
  return c.json({ error: "tasks-list-failed" }, 500);
27648
27964
  }
@@ -27743,13 +28059,13 @@ async function computeTaskList(accountId) {
27743
28059
  orphans = orphanResult.records.length > 0 ? toNum(orphanResult.records[0].get("orphans")) : 0;
27744
28060
  } catch (err) {
27745
28061
  console.error(
27746
- `${TAG35} op=session-orphans-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
28062
+ `${TAG37} op=session-orphans-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
27747
28063
  );
27748
28064
  orphans = -1;
27749
28065
  }
27750
28066
  if (orphans > 0) {
27751
28067
  console.error(
27752
- `${TAG35} op=session-orphans account=${accountId} orphans=${orphans} detail="task marked for a session spawn that never linked; the spawned session is unreachable from its row"`
28068
+ `${TAG37} op=session-orphans account=${accountId} orphans=${orphans} detail="task marked for a session spawn that never linked; the spawned session is unreachable from its row"`
27753
28069
  );
27754
28070
  }
27755
28071
  let orphanEntries = 0;
@@ -27768,14 +28084,14 @@ async function computeTaskList(accountId) {
27768
28084
  orphanAdjustments = orphanTime.records.length > 0 ? toNum(orphanTime.records[0].get("orphanAdjustments")) : 0;
27769
28085
  } catch (err) {
27770
28086
  console.error(
27771
- `${TAG35} op=orphan-time-records-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
28087
+ `${TAG37} op=orphan-time-records-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
27772
28088
  );
27773
28089
  orphanEntries = -1;
27774
28090
  orphanAdjustments = -1;
27775
28091
  }
27776
28092
  if (orphanEntries > 0 || orphanAdjustments > 0) {
27777
28093
  console.error(
27778
- `${TAG35} op=orphan-time-records account=${accountId} orphanEntries=${orphanEntries} orphanAdjustments=${orphanAdjustments} detail="time records whose task no longer exists; something removed the task without its records"`
28094
+ `${TAG37} op=orphan-time-records account=${accountId} orphanEntries=${orphanEntries} orphanAdjustments=${orphanAdjustments} detail="time records whose task no longer exists; something removed the task without its records"`
27779
28095
  );
27780
28096
  }
27781
28097
  const linkedIds = [...open3, ...completed].map((r) => r.sessionId).filter((s) => s !== null);
@@ -27785,10 +28101,10 @@ async function computeTaskList(accountId) {
27785
28101
  dangling = 0;
27786
28102
  } else if (cfg !== null) {
27787
28103
  try {
27788
- const walk = enumerateJsonlsWithSkips(join50(cfg, "projects"));
28104
+ const walk = enumerateJsonlsWithSkips(join51(cfg, "projects"));
27789
28105
  if (walk.skipped > 0) {
27790
28106
  console.error(
27791
- `${TAG35} op=session-dangling-census-incomplete account=${accountId} skipped=${walk.skipped} detail="a slug the walk could not read contributes no session ids, so its links cannot be judged"`
28107
+ `${TAG37} op=session-dangling-census-incomplete account=${accountId} skipped=${walk.skipped} detail="a slug the walk could not read contributes no session ids, so its links cannot be judged"`
27792
28108
  );
27793
28109
  dangling = null;
27794
28110
  } else {
@@ -27797,28 +28113,28 @@ async function computeTaskList(accountId) {
27797
28113
  }
27798
28114
  } catch (err) {
27799
28115
  console.error(
27800
- `${TAG35} op=session-dangling-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
28116
+ `${TAG37} op=session-dangling-census-failed account=${accountId} error="${err instanceof Error ? err.message : String(err)}"`
27801
28117
  );
27802
28118
  dangling = null;
27803
28119
  }
27804
28120
  }
27805
28121
  if (dangling !== null && dangling > 0) {
27806
28122
  console.error(
27807
- `${TAG35} op=session-dangling account=${accountId} dangling=${dangling} linked=${linkedIds.length} detail="a task links a session with no JSONL on disk; clicking it will not resume"`
28123
+ `${TAG37} op=session-dangling account=${accountId} dangling=${dangling} linked=${linkedIds.length} detail="a task links a session with no JSONL on disk; clicking it will not resume"`
27808
28124
  );
27809
28125
  }
27810
28126
  const returned = result.records.length;
27811
28127
  if (returned < graphTotal) {
27812
28128
  console.error(
27813
- `${TAG35} op=list row-count-shortfall account=${accountId} returned=${returned} graphTotal=${graphTotal} missing=${graphTotal - returned}`
28129
+ `${TAG37} op=list row-count-shortfall account=${accountId} returned=${returned} graphTotal=${graphTotal} missing=${graphTotal - returned}`
27814
28130
  );
27815
28131
  }
27816
28132
  console.log(
27817
- `${TAG35} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open3.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned} sessionLinked=${sessionLinked} sessionOrphans=${orphans < 0 ? "n/a" : orphans} sessionDangling=${dangling === null ? "n/a" : dangling}`
28133
+ `${TAG37} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open3.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned} sessionLinked=${sessionLinked} sessionOrphans=${orphans < 0 ? "n/a" : orphans} sessionDangling=${dangling === null ? "n/a" : dangling}`
27818
28134
  );
27819
28135
  return { open: open3, completed };
27820
28136
  } catch (err) {
27821
- console.error(`${TAG35} op=list error="${err instanceof Error ? err.message : String(err)}"`);
28137
+ console.error(`${TAG37} op=list error="${err instanceof Error ? err.message : String(err)}"`);
27822
28138
  return null;
27823
28139
  } finally {
27824
28140
  await session.close();
@@ -27833,7 +28149,7 @@ init_claude_agent();
27833
28149
  init_route_cache();
27834
28150
  init_neo4j_store();
27835
28151
  import { randomUUID as randomUUID11 } from "crypto";
27836
- var TAG36 = "[task-timer]";
28152
+ var TAG38 = "[task-timer]";
27837
28153
  var app56 = new Hono();
27838
28154
  app56.post("/", requireAdminSession, async (c) => {
27839
28155
  const cacheKey = c.var.cacheKey;
@@ -27848,7 +28164,7 @@ app56.post("/", requireAdminSession, async (c) => {
27848
28164
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
27849
28165
  if (!taskId) {
27850
28166
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
27851
- console.error(`${TAG36} op=timer-start rejected reason=${reason} account=${accountId}`);
28167
+ console.error(`${TAG38} op=timer-start rejected reason=${reason} account=${accountId}`);
27852
28168
  return c.json({ error: "taskId required" }, 400);
27853
28169
  }
27854
28170
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -27859,7 +28175,7 @@ app56.post("/", requireAdminSession, async (c) => {
27859
28175
  { taskId, accountId }
27860
28176
  );
27861
28177
  if (target.records.length === 0) {
27862
- console.error(`${TAG36} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
28178
+ console.error(`${TAG38} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
27863
28179
  return c.json({ error: "task-not-found" }, 404);
27864
28180
  }
27865
28181
  const open3 = await session.run(
@@ -27871,7 +28187,7 @@ app56.post("/", requireAdminSession, async (c) => {
27871
28187
  const priorEntryId = open3.records[0]?.get("entryId");
27872
28188
  const priorStartedAt = open3.records[0]?.get("startedAt");
27873
28189
  if (priorEntryId) {
27874
- console.log(`${TAG36} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
28190
+ console.log(`${TAG38} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
27875
28191
  invalidate("tasks-list", accountId);
27876
28192
  return c.json({ ok: true, running: true, entryId: priorEntryId, startedAt: priorStartedAt });
27877
28193
  }
@@ -27882,11 +28198,11 @@ app56.post("/", requireAdminSession, async (c) => {
27882
28198
  CREATE (te)-[:LOGGED_AGAINST]->(t)`,
27883
28199
  { taskId, accountId, entryId, now }
27884
28200
  );
27885
- console.log(`${TAG36} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
28201
+ console.log(`${TAG38} op=opened taskId=${taskId} entryId=${entryId} startedAt=${now}`);
27886
28202
  invalidate("tasks-list", accountId);
27887
28203
  return c.json({ ok: true, running: true, entryId, startedAt: now });
27888
28204
  } catch (err) {
27889
- console.error(`${TAG36} op=start error="${err instanceof Error ? err.message : String(err)}"`);
28205
+ console.error(`${TAG38} op=start error="${err instanceof Error ? err.message : String(err)}"`);
27890
28206
  return c.json({ error: "task-timer-start-failed" }, 500);
27891
28207
  } finally {
27892
28208
  await session.close();
@@ -27901,7 +28217,7 @@ init_claude_agent();
27901
28217
  init_route_cache();
27902
28218
  init_neo4j_store();
27903
28219
  import neo4j4 from "neo4j-driver";
27904
- var TAG37 = "[task-timer]";
28220
+ var TAG39 = "[task-timer]";
27905
28221
  var app57 = new Hono();
27906
28222
  app57.post("/", requireAdminSession, async (c) => {
27907
28223
  const cacheKey = c.var.cacheKey;
@@ -27916,7 +28232,7 @@ app57.post("/", requireAdminSession, async (c) => {
27916
28232
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
27917
28233
  if (!taskId) {
27918
28234
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
27919
- console.error(`${TAG37} op=timer-stop rejected reason=${reason} account=${accountId}`);
28235
+ console.error(`${TAG39} op=timer-stop rejected reason=${reason} account=${accountId}`);
27920
28236
  return c.json({ error: "taskId required" }, 400);
27921
28237
  }
27922
28238
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -27937,7 +28253,7 @@ app57.post("/", requireAdminSession, async (c) => {
27937
28253
  { taskId, accountId }
27938
28254
  );
27939
28255
  const secondsLogged2 = toNum(cur.records[0]?.get("secondsLogged"));
27940
- console.log(`${TAG37} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
28256
+ console.log(`${TAG39} op=stop taskId=${taskId} entryId=none seconds=0 totalAfter=${secondsLogged2}`);
27941
28257
  invalidate("tasks-list", accountId);
27942
28258
  return c.json({ ok: true, running: false, seconds: 0, secondsLogged: secondsLogged2 });
27943
28259
  }
@@ -27961,12 +28277,12 @@ app57.post("/", requireAdminSession, async (c) => {
27961
28277
  const sumEntries = toNum(verify.records[0]?.get("sumEntries"));
27962
28278
  const sumAdjustments = toNum(verify.records[0]?.get("sumAdjustments"));
27963
28279
  const secondsLogged = toNum(verify.records[0]?.get("secondsLogged"));
27964
- console.log(`${TAG37} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
27965
- console.log(`${TAG37} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
28280
+ console.log(`${TAG39} op=stop taskId=${taskId} entryId=${entryId} seconds=${seconds} totalAfter=${secondsLogged}`);
28281
+ console.log(`${TAG39} op=persisted taskId=${taskId} entryId=${entryId} sumEntries=${sumEntries} sumAdjustments=${sumAdjustments} secondsLogged=${secondsLogged}`);
27966
28282
  invalidate("tasks-list", accountId);
27967
28283
  return c.json({ ok: true, running: false, seconds, secondsLogged });
27968
28284
  } catch (err) {
27969
- console.error(`${TAG37} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
28285
+ console.error(`${TAG39} op=stop error="${err instanceof Error ? err.message : String(err)}"`);
27970
28286
  return c.json({ error: "task-timer-stop-failed" }, 500);
27971
28287
  } finally {
27972
28288
  await session.close();
@@ -27980,7 +28296,7 @@ init_helpers();
27980
28296
  init_claude_agent();
27981
28297
  init_route_cache();
27982
28298
  init_neo4j_store();
27983
- var TAG38 = "[task-timer]";
28299
+ var TAG40 = "[task-timer]";
27984
28300
  var app58 = new Hono();
27985
28301
  app58.post("/", requireAdminSession, async (c) => {
27986
28302
  const cacheKey = c.var.cacheKey;
@@ -27995,7 +28311,7 @@ app58.post("/", requireAdminSession, async (c) => {
27995
28311
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
27996
28312
  if (!taskId) {
27997
28313
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
27998
- console.error(`${TAG38} op=complete rejected reason=${reason} account=${accountId}`);
28314
+ console.error(`${TAG40} op=complete rejected reason=${reason} account=${accountId}`);
27999
28315
  return c.json({ error: "taskId required" }, 400);
28000
28316
  }
28001
28317
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -28011,11 +28327,11 @@ app58.post("/", requireAdminSession, async (c) => {
28011
28327
  return c.json({ error: "task-not-found" }, 404);
28012
28328
  }
28013
28329
  const secondsLogged = toNum(result.records[0].get("secondsLogged"));
28014
- console.log(`${TAG38} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
28330
+ console.log(`${TAG40} op=complete taskId=${taskId} status=completed secondsLogged=${secondsLogged}`);
28015
28331
  invalidate("tasks-list", accountId);
28016
28332
  return c.json({ ok: true, status: "completed", secondsLogged });
28017
28333
  } catch (err) {
28018
- console.error(`${TAG38} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
28334
+ console.error(`${TAG40} op=complete error="${err instanceof Error ? err.message : String(err)}"`);
28019
28335
  return c.json({ error: "task-complete-failed" }, 500);
28020
28336
  } finally {
28021
28337
  await session.close();
@@ -28031,7 +28347,7 @@ init_route_cache();
28031
28347
  init_neo4j_store();
28032
28348
  import { randomUUID as randomUUID12 } from "crypto";
28033
28349
  import neo4j5 from "neo4j-driver";
28034
- var TAG39 = "[task-time-adjust]";
28350
+ var TAG41 = "[task-time-adjust]";
28035
28351
  var app59 = new Hono();
28036
28352
  app59.post("/", requireAdminSession, async (c) => {
28037
28353
  const cacheKey = c.var.cacheKey;
@@ -28041,23 +28357,23 @@ app59.post("/", requireAdminSession, async (c) => {
28041
28357
  try {
28042
28358
  body = await c.req.json();
28043
28359
  } catch {
28044
- console.error(`${TAG39} op=reject reason=bad-json`);
28360
+ console.error(`${TAG41} op=reject reason=bad-json`);
28045
28361
  return c.json({ error: "invalid-json" }, 400);
28046
28362
  }
28047
28363
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
28048
28364
  if (!taskId) {
28049
28365
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
28050
- console.error(`${TAG39} op=time-adjust rejected reason=${reason} account=${accountId}`);
28366
+ console.error(`${TAG41} op=time-adjust rejected reason=${reason} account=${accountId}`);
28051
28367
  return c.json({ error: "taskId required" }, 400);
28052
28368
  }
28053
28369
  const newSeconds = body.newSeconds;
28054
28370
  if (typeof newSeconds !== "number" || !Number.isInteger(newSeconds) || newSeconds < 0) {
28055
- console.error(`${TAG39} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
28371
+ console.error(`${TAG41} op=reject reason=invalid-seconds taskId=${taskId} accountId=${accountId}`);
28056
28372
  return c.json({ error: "newSeconds must be a non-negative integer" }, 400);
28057
28373
  }
28058
28374
  const adjustmentId = randomUUID12();
28059
28375
  const now = (/* @__PURE__ */ new Date()).toISOString();
28060
- console.log(`${TAG39} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
28376
+ console.log(`${TAG41} op=request adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId} newSeconds=${newSeconds}`);
28061
28377
  const session = getSession();
28062
28378
  try {
28063
28379
  const guard = await session.run(
@@ -28067,12 +28383,12 @@ app59.post("/", requireAdminSession, async (c) => {
28067
28383
  { taskId, accountId }
28068
28384
  );
28069
28385
  if (guard.records.length === 0) {
28070
- console.error(`${TAG39} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
28386
+ console.error(`${TAG41} op=reject reason=no-task adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
28071
28387
  return c.json({ error: "task-not-found" }, 404);
28072
28388
  }
28073
28389
  const openCount = toNum(guard.records[0].get("openCount"));
28074
28390
  if (openCount > 0) {
28075
- console.error(`${TAG39} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
28391
+ console.error(`${TAG41} op=reject reason=running adjustmentId=${adjustmentId} taskId=${taskId} accountId=${accountId}`);
28076
28392
  return c.json({ error: "task-timer-running" }, 409);
28077
28393
  }
28078
28394
  const previousSeconds = toNum(guard.records[0].get("previousSeconds"));
@@ -28098,11 +28414,11 @@ app59.post("/", requireAdminSession, async (c) => {
28098
28414
  }
28099
28415
  );
28100
28416
  const secondsLoggedAfter = toNum(write.records[0]?.get("secondsLoggedAfter"));
28101
- console.log(`${TAG39} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
28417
+ console.log(`${TAG41} op=persisted adjustmentId=${adjustmentId} previousSeconds=${previousSeconds} newSeconds=${newSeconds} delta=${delta} secondsLoggedAfter=${secondsLoggedAfter}`);
28102
28418
  invalidate("tasks-list", accountId);
28103
28419
  return c.json({ ok: true, secondsLogged: secondsLoggedAfter });
28104
28420
  } catch (err) {
28105
- console.error(`${TAG39} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
28421
+ console.error(`${TAG41} op=error adjustmentId=${adjustmentId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
28106
28422
  return c.json({ error: "task-time-adjust-failed" }, 500);
28107
28423
  } finally {
28108
28424
  await session.close();
@@ -28117,7 +28433,7 @@ init_claude_agent();
28117
28433
  init_route_cache();
28118
28434
  init_neo4j_store();
28119
28435
  import { randomUUID as randomUUID13 } from "crypto";
28120
- var TAG40 = "[task-delete]";
28436
+ var TAG42 = "[task-delete]";
28121
28437
  var app60 = new Hono();
28122
28438
  app60.post("/", requireAdminSession, async (c) => {
28123
28439
  const cacheKey = c.var.cacheKey;
@@ -28127,18 +28443,18 @@ app60.post("/", requireAdminSession, async (c) => {
28127
28443
  try {
28128
28444
  body = await c.req.json();
28129
28445
  } catch {
28130
- console.error(`${TAG40} op=reject reason=bad-json`);
28446
+ console.error(`${TAG42} op=reject reason=bad-json`);
28131
28447
  return c.json({ error: "invalid-json" }, 400);
28132
28448
  }
28133
28449
  const deletionId = randomUUID13();
28134
28450
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
28135
28451
  if (!taskId) {
28136
28452
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
28137
- console.error(`${TAG40} op=reject reason=${reason} deletionId=${deletionId} accountId=${accountId}`);
28453
+ console.error(`${TAG42} op=reject reason=${reason} deletionId=${deletionId} accountId=${accountId}`);
28138
28454
  return c.json({ error: "taskId required" }, 400);
28139
28455
  }
28140
28456
  console.log(
28141
- `${TAG40} op=request deletionId=${deletionId} taskId=${taskId} accountId=${accountId} confirmed=${body.confirmed === true}`
28457
+ `${TAG42} op=request deletionId=${deletionId} taskId=${taskId} accountId=${accountId} confirmed=${body.confirmed === true}`
28142
28458
  );
28143
28459
  const session = getSession();
28144
28460
  try {
@@ -28154,18 +28470,18 @@ app60.post("/", requireAdminSession, async (c) => {
28154
28470
  { taskId, accountId }
28155
28471
  );
28156
28472
  if (guard.records.length === 0) {
28157
- console.error(`${TAG40} op=reject reason=no-task deletionId=${deletionId} taskId=${taskId} accountId=${accountId}`);
28473
+ console.error(`${TAG42} op=reject reason=no-task deletionId=${deletionId} taskId=${taskId} accountId=${accountId}`);
28158
28474
  return c.json({ error: "task-not-found" }, 404);
28159
28475
  }
28160
28476
  const timeEntries = toNum(guard.records[0].get("timeEntries"));
28161
28477
  const openCount = toNum(guard.records[0].get("openCount"));
28162
28478
  const adjustments = toNum(guard.records[0].get("adjustments"));
28163
28479
  console.log(
28164
- `${TAG40} op=guard deletionId=${deletionId} taskId=${taskId} openCount=${openCount} timeEntries=${timeEntries} adjustments=${adjustments}`
28480
+ `${TAG42} op=guard deletionId=${deletionId} taskId=${taskId} openCount=${openCount} timeEntries=${timeEntries} adjustments=${adjustments}`
28165
28481
  );
28166
28482
  if (openCount > 0) {
28167
28483
  console.error(
28168
- `${TAG40} op=reject reason=running deletionId=${deletionId} taskId=${taskId} openCount=${openCount}`
28484
+ `${TAG42} op=reject reason=running deletionId=${deletionId} taskId=${taskId} openCount=${openCount}`
28169
28485
  );
28170
28486
  return c.json({ error: "task-timer-running" }, 409);
28171
28487
  }
@@ -28201,18 +28517,18 @@ app60.post("/", requireAdminSession, async (c) => {
28201
28517
  const adjustmentsLeft = toNum(after.records[0]?.get("adjustmentsLeft"));
28202
28518
  const remaining = taskLeft + entriesLeft + adjustmentsLeft;
28203
28519
  console.log(
28204
- `${TAG40} op=persisted deletionId=${deletionId} taskId=${taskId} tasksDeleted=${tasksDeleted} timeEntriesDeleted=${timeEntriesDeleted} adjustmentsDeleted=${adjustmentsDeleted} remaining=${remaining}`
28520
+ `${TAG42} op=persisted deletionId=${deletionId} taskId=${taskId} tasksDeleted=${tasksDeleted} timeEntriesDeleted=${timeEntriesDeleted} adjustmentsDeleted=${adjustmentsDeleted} remaining=${remaining}`
28205
28521
  );
28206
28522
  if (remaining > 0) {
28207
28523
  console.error(
28208
- `${TAG40} op=incomplete deletionId=${deletionId} taskId=${taskId} taskLeft=${taskLeft} entriesLeft=${entriesLeft} adjustmentsLeft=${adjustmentsLeft} detail="the delete returned but rows for this taskId survive"`
28524
+ `${TAG42} op=incomplete deletionId=${deletionId} taskId=${taskId} taskLeft=${taskLeft} entriesLeft=${entriesLeft} adjustmentsLeft=${adjustmentsLeft} detail="the delete returned but rows for this taskId survive"`
28209
28525
  );
28210
28526
  }
28211
28527
  invalidate("tasks-list", accountId);
28212
28528
  return c.json({ ok: true, tasksDeleted, timeEntriesDeleted, adjustmentsDeleted, remaining });
28213
28529
  } catch (err) {
28214
28530
  console.error(
28215
- `${TAG40} op=error deletionId=${deletionId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`
28531
+ `${TAG42} op=error deletionId=${deletionId} taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`
28216
28532
  );
28217
28533
  return c.json({ error: "task-delete-failed" }, 500);
28218
28534
  } finally {
@@ -28315,7 +28631,7 @@ async function resolveAssignableAdmins(accountId, accountsDir = ACCOUNTS_DIR) {
28315
28631
  }
28316
28632
 
28317
28633
  // server/routes/admin/task-assign.ts
28318
- var TAG41 = "[task-assign]";
28634
+ var TAG43 = "[task-assign]";
28319
28635
  var app61 = new Hono();
28320
28636
  app61.post("/", requireAdminSession, async (c) => {
28321
28637
  const cacheKey = c.var.cacheKey;
@@ -28330,7 +28646,7 @@ app61.post("/", requireAdminSession, async (c) => {
28330
28646
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
28331
28647
  if (!taskId) {
28332
28648
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
28333
- console.error(`${TAG41} op=assign rejected reason=${reason} account=${accountId}`);
28649
+ console.error(`${TAG43} op=assign rejected reason=${reason} account=${accountId}`);
28334
28650
  return c.json({ error: "taskId required" }, 400);
28335
28651
  }
28336
28652
  const rawAssignee = body.assigneeUserId;
@@ -28342,7 +28658,7 @@ app61.post("/", requireAdminSession, async (c) => {
28342
28658
  const { ids } = await resolveAllowedAssigneeIds(accountId);
28343
28659
  if (!ids.has(assigneeUserId)) {
28344
28660
  console.error(
28345
- `${TAG41} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=not-in-roster`
28661
+ `${TAG43} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=not-in-roster`
28346
28662
  );
28347
28663
  return c.json({ error: "assignee-not-in-roster" }, 403);
28348
28664
  }
@@ -28364,7 +28680,7 @@ app61.post("/", requireAdminSession, async (c) => {
28364
28680
  `MATCH (t:Task {taskId: $taskId, accountId: $accountId}) SET t.updatedAt = $now`,
28365
28681
  { taskId, accountId, now }
28366
28682
  );
28367
- console.log(`${TAG41} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
28683
+ console.log(`${TAG43} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=none assigned=false source=route`);
28368
28684
  invalidate("tasks-list", accountId);
28369
28685
  return c.json({ ok: true, assigneeUserId: null, assigneeName: null });
28370
28686
  }
@@ -28380,7 +28696,7 @@ app61.post("/", requireAdminSession, async (c) => {
28380
28696
  );
28381
28697
  if (set.records.length === 0) {
28382
28698
  console.error(
28383
- `${TAG41} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=no-adminuser-node`
28699
+ `${TAG43} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=false source=route reason=no-adminuser-node`
28384
28700
  );
28385
28701
  return c.json({ error: "assignee-no-admin-node" }, 409);
28386
28702
  }
@@ -28388,12 +28704,12 @@ app61.post("/", requireAdminSession, async (c) => {
28388
28704
  const family = set.records[0].get("familyName") ?? null;
28389
28705
  const assigneeName = given && given.trim().length > 0 ? family && family.trim().length > 0 ? `${given.trim()} ${family.trim()}` : given.trim() : null;
28390
28706
  console.log(
28391
- `${TAG41} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
28707
+ `${TAG43} op=assign taskId=${taskId.slice(0, 8)} assigneeUserId=${assigneeUserId.slice(0, 8)} assigned=true source=route`
28392
28708
  );
28393
28709
  invalidate("tasks-list", accountId);
28394
28710
  return c.json({ ok: true, assigneeUserId, assigneeName });
28395
28711
  } catch (err) {
28396
- console.error(`${TAG41} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
28712
+ console.error(`${TAG43} op=assign error="${err instanceof Error ? err.message : String(err)}"`);
28397
28713
  return c.json({ error: "task-assign-failed" }, 500);
28398
28714
  } finally {
28399
28715
  await session.close();
@@ -28406,13 +28722,13 @@ init_dist();
28406
28722
  init_helpers();
28407
28723
  init_claude_agent();
28408
28724
  init_neo4j_store();
28409
- var TAG42 = "[task-session]";
28725
+ var TAG44 = "[task-session]";
28410
28726
  var app62 = new Hono();
28411
28727
  app62.post("/", requireAdminSession, async (c) => {
28412
28728
  const cacheKey = c.var.cacheKey;
28413
28729
  const accountId = getAccountIdForSession(cacheKey);
28414
28730
  if (!accountId) {
28415
- console.error(`${TAG42} op=request auth-rejected reason="no account for session"`);
28731
+ console.error(`${TAG44} op=request auth-rejected reason="no account for session"`);
28416
28732
  return c.json({ error: "Account not found for session" }, 401);
28417
28733
  }
28418
28734
  let body;
@@ -28424,7 +28740,7 @@ app62.post("/", requireAdminSession, async (c) => {
28424
28740
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
28425
28741
  if (!taskId) {
28426
28742
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
28427
- console.error(`${TAG42} op=request rejected reason=${reason} account=${accountId}`);
28743
+ console.error(`${TAG44} op=request rejected reason=${reason} account=${accountId}`);
28428
28744
  return c.json({ error: "taskId required" }, 400);
28429
28745
  }
28430
28746
  const session = getSession();
@@ -28438,14 +28754,14 @@ app62.post("/", requireAdminSession, async (c) => {
28438
28754
  { taskId, accountId }
28439
28755
  );
28440
28756
  if (found.records.length === 0) {
28441
- console.error(`${TAG42} op=request taskId=${taskId} account=${accountId} result=task-not-found`);
28757
+ console.error(`${TAG44} op=request taskId=${taskId} account=${accountId} result=task-not-found`);
28442
28758
  return c.json({ error: "task-not-found" }, 404);
28443
28759
  }
28444
28760
  const title = found.records[0].get("name") ?? "";
28445
28761
  const sessionId = found.records[0].get("sessionId") ?? null;
28446
28762
  const description = found.records[0].get("description") ?? "";
28447
28763
  const notes = found.records[0].get("notes") ?? "";
28448
- console.log(`${TAG42} op=request taskId=${taskId} account=${accountId} linked=${sessionId ?? "none"}`);
28764
+ console.log(`${TAG44} op=request taskId=${taskId} account=${accountId} linked=${sessionId ?? "none"}`);
28449
28765
  if (sessionId !== null) return c.json({ sessionId, title, description, notes });
28450
28766
  const now = (/* @__PURE__ */ new Date()).toISOString();
28451
28767
  const stamped = await session.run(
@@ -28455,10 +28771,10 @@ app62.post("/", requireAdminSession, async (c) => {
28455
28771
  { taskId, accountId, now }
28456
28772
  );
28457
28773
  const at = stamped.records[0]?.get("at") ?? void 0;
28458
- console.log(`${TAG42} op=marker taskId=${taskId} stamped=${at !== void 0}`);
28774
+ console.log(`${TAG44} op=marker taskId=${taskId} stamped=${at !== void 0}`);
28459
28775
  return c.json({ sessionId: null, title, description, notes });
28460
28776
  } catch (err) {
28461
- console.error(`${TAG42} op=request taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
28777
+ console.error(`${TAG44} op=request taskId=${taskId} error="${err instanceof Error ? err.message : String(err)}"`);
28462
28778
  return c.json({ error: "task-session-open-failed" }, 500);
28463
28779
  } finally {
28464
28780
  await session.close();
@@ -28472,13 +28788,13 @@ init_helpers();
28472
28788
  init_claude_agent();
28473
28789
  init_neo4j_store();
28474
28790
  init_route_cache();
28475
- var TAG43 = "[task-session]";
28791
+ var TAG45 = "[task-session]";
28476
28792
  var app63 = new Hono();
28477
28793
  app63.post("/", requireAdminSession, async (c) => {
28478
28794
  const cacheKey = c.var.cacheKey;
28479
28795
  const accountId = getAccountIdForSession(cacheKey);
28480
28796
  if (!accountId) {
28481
- console.error(`${TAG43} op=link auth-rejected reason="no account for session"`);
28797
+ console.error(`${TAG45} op=link auth-rejected reason="no account for session"`);
28482
28798
  return c.json({ error: "Account not found for session" }, 401);
28483
28799
  }
28484
28800
  let body;
@@ -28490,12 +28806,12 @@ app63.post("/", requireAdminSession, async (c) => {
28490
28806
  const taskId = typeof body.taskId === "string" ? body.taskId : "";
28491
28807
  if (!taskId) {
28492
28808
  const reason = body.taskId === null ? "null-taskId" : "missing-taskId";
28493
- console.error(`${TAG43} op=link rejected reason=${reason} account=${accountId}`);
28809
+ console.error(`${TAG45} op=link rejected reason=${reason} account=${accountId}`);
28494
28810
  return c.json({ error: "taskId required" }, 400);
28495
28811
  }
28496
28812
  const sessionId = typeof body.sessionId === "string" && body.sessionId.length > 0 ? body.sessionId : "";
28497
28813
  if (!sessionId) {
28498
- console.error(`${TAG43} op=link rejected reason=missing-sessionId taskId=${taskId} account=${accountId}`);
28814
+ console.error(`${TAG45} op=link rejected reason=missing-sessionId taskId=${taskId} account=${accountId}`);
28499
28815
  return c.json({ error: "sessionId required" }, 400);
28500
28816
  }
28501
28817
  const session = getSession();
@@ -28509,13 +28825,13 @@ app63.post("/", requireAdminSession, async (c) => {
28509
28825
  { taskId, accountId, sessionId }
28510
28826
  );
28511
28827
  if (state.records.length === 0) {
28512
- console.error(`${TAG43} op=link taskId=${taskId} account=${accountId} result=task-not-found`);
28828
+ console.error(`${TAG45} op=link taskId=${taskId} account=${accountId} result=task-not-found`);
28513
28829
  return c.json({ error: "task-not-found" }, 404);
28514
28830
  }
28515
28831
  const conversationExists = state.records[0].get("conversationExists") === true;
28516
28832
  const priorSessionIds = (state.records[0].get("priorSessionIds") ?? []).filter((s) => typeof s === "string");
28517
28833
  if (!conversationExists) {
28518
- console.error(`${TAG43} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=conversation-absent`);
28834
+ console.error(`${TAG45} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=conversation-absent`);
28519
28835
  return c.json({ linked: false, created: false, repointedFrom: null });
28520
28836
  }
28521
28837
  const stale = priorSessionIds.filter((s) => s !== sessionId);
@@ -28541,18 +28857,18 @@ app63.post("/", requireAdminSession, async (c) => {
28541
28857
  const repointedFrom = stale.length > 0 ? stale[0] : null;
28542
28858
  if (!linked) {
28543
28859
  console.error(
28544
- `${TAG43} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=edge-absent-after-merge linkedTo=${linkedTo ?? "none"}`
28860
+ `${TAG45} op=link-failed taskId=${taskId} sessionId=${sessionId} reason=edge-absent-after-merge linkedTo=${linkedTo ?? "none"}`
28545
28861
  );
28546
28862
  return c.json({ linked: false, created: false, repointedFrom });
28547
28863
  }
28548
28864
  console.log(
28549
- `${TAG43} op=link taskId=${taskId} sessionId=${sessionId} created=${created} repointedFrom=${repointedFrom ?? "none"}`
28865
+ `${TAG45} op=link taskId=${taskId} sessionId=${sessionId} created=${created} repointedFrom=${repointedFrom ?? "none"}`
28550
28866
  );
28551
28867
  invalidate("tasks-list", accountId);
28552
28868
  return c.json({ linked: true, created, repointedFrom });
28553
28869
  } catch (err) {
28554
28870
  console.error(
28555
- `${TAG43} op=link-failed taskId=${taskId} sessionId=${sessionId} reason="${err instanceof Error ? err.message : String(err)}"`
28871
+ `${TAG45} op=link-failed taskId=${taskId} sessionId=${sessionId} reason="${err instanceof Error ? err.message : String(err)}"`
28556
28872
  );
28557
28873
  return c.json({ error: "task-session-link-failed" }, 500);
28558
28874
  } finally {
@@ -28565,21 +28881,21 @@ var task_session_link_default = app63;
28565
28881
  init_dist();
28566
28882
  init_helpers();
28567
28883
  init_claude_agent();
28568
- var TAG44 = "[admin-users]";
28884
+ var TAG46 = "[admin-users]";
28569
28885
  var app64 = new Hono();
28570
28886
  app64.get("/", requireAdminSession, async (c) => {
28571
28887
  const cacheKey = c.var.cacheKey;
28572
28888
  const accountId = getAccountIdForSession(cacheKey);
28573
28889
  if (!accountId) {
28574
- console.error(`${TAG44} op=list auth-rejected reason="no account for session"`);
28890
+ console.error(`${TAG46} op=list auth-rejected reason="no account for session"`);
28575
28891
  return c.json({ error: "Account not found for session" }, 401);
28576
28892
  }
28577
28893
  try {
28578
28894
  const users = await resolveAssignableAdmins(accountId);
28579
- console.log(`${TAG44} op=list account=${accountId} count=${users.length}`);
28895
+ console.log(`${TAG46} op=list account=${accountId} count=${users.length}`);
28580
28896
  return c.json({ ok: true, users });
28581
28897
  } catch (err) {
28582
- console.error(`${TAG44} op=list error="${err instanceof Error ? err.message : String(err)}"`);
28898
+ console.error(`${TAG46} op=list error="${err instanceof Error ? err.message : String(err)}"`);
28583
28899
  return c.json({ error: "admin-users-list-failed" }, 500);
28584
28900
  }
28585
28901
  });
@@ -28593,7 +28909,7 @@ init_account();
28593
28909
  init_neo4j_store();
28594
28910
  init_src2();
28595
28911
  import { resolve as resolve38 } from "path";
28596
- var TAG45 = "[admin:routines]";
28912
+ var TAG47 = "[admin:routines]";
28597
28913
  function scopeFor(d, houseDir, houseAccountId) {
28598
28914
  if (d.channel !== "whatsapp") return null;
28599
28915
  if (d.label === "Account manager") return boundSubAccountFor(houseDir, d.destination);
@@ -28611,7 +28927,7 @@ var app65 = new Hono();
28611
28927
  app65.get("/", requireAdminSession, async (c) => {
28612
28928
  const accountId = getAccountIdForSession(c.var.cacheKey);
28613
28929
  if (!accountId) {
28614
- console.error(`${TAG45} op=destinations auth-rejected reason="no account for session"`);
28930
+ console.error(`${TAG47} op=destinations auth-rejected reason="no account for session"`);
28615
28931
  return c.json({ error: "Account not found for session" }, 401);
28616
28932
  }
28617
28933
  let houseAccountId = null;
@@ -28619,7 +28935,7 @@ app65.get("/", requireAdminSession, async (c) => {
28619
28935
  houseAccountId = resolveHouseOrSoleAccountId(ACCOUNTS_DIR);
28620
28936
  } catch (err) {
28621
28937
  const message = err instanceof Error ? err.message : String(err);
28622
- console.error(`${TAG45} op=destinations account=${accountId.slice(0, 8)} outcome=house-unresolved reason="${message}"`);
28938
+ console.error(`${TAG47} op=destinations account=${accountId.slice(0, 8)} outcome=house-unresolved reason="${message}"`);
28623
28939
  }
28624
28940
  const destinations = listDispatchDestinations({ accountsDir: ACCOUNTS_DIR, houseAccountId, accountId });
28625
28941
  const houseDir = houseAccountId === null ? null : resolve38(ACCOUNTS_DIR, houseAccountId);
@@ -28670,7 +28986,7 @@ app65.get("/", requireAdminSession, async (c) => {
28670
28986
  const scopes = [...byScope.keys()];
28671
28987
  const nameScope = scopes.length === 0 ? "none" : scopes.every((s) => s === houseAccountId) ? "house" : scopes.some((s) => s === houseAccountId) ? "mixed" : "account";
28672
28988
  console.log(
28673
- `${TAG45} op=destinations account=${accountId.slice(0, 8)} count=${destinations.length} named=${named} unnamed=${destinations.length - named} nameScope=${nameScope}` + (houseAccountId === null ? " outcome=house-unresolved" : "") + (namesUnresolved === null ? "" : ` outcome=names-unresolved reason="${namesUnresolved}"`)
28989
+ `${TAG47} op=destinations account=${accountId.slice(0, 8)} count=${destinations.length} named=${named} unnamed=${destinations.length - named} nameScope=${nameScope}` + (houseAccountId === null ? " outcome=house-unresolved" : "") + (namesUnresolved === null ? "" : ` outcome=names-unresolved reason="${namesUnresolved}"`)
28674
28990
  );
28675
28991
  return c.json({ destinations });
28676
28992
  });
@@ -28685,7 +29001,7 @@ import { readdirSync as readdirSync28 } from "fs";
28685
29001
  init_neo4j_store();
28686
29002
  init_loop_registry();
28687
29003
  var app66 = new Hono();
28688
- var TAG46 = "[activity]";
29004
+ var TAG48 = "[activity]";
28689
29005
  function resolveHouseAccountId2(accounts) {
28690
29006
  const houses = accounts.filter((a) => a.config.role === "house");
28691
29007
  if (houses.length === 1) return { accountId: houses[0].accountId, reason: "house" };
@@ -28714,19 +29030,19 @@ app66.get("/", requireAdminSession, async (c) => {
28714
29030
  const house = resolveHouseAccountId2(valid);
28715
29031
  const isHouse = caller2 !== null && house.accountId !== null && caller2 === house.accountId;
28716
29032
  console.log(
28717
- `${TAG46} op=request req=${req} caller=${short(caller2)} house=${isHouse} houseVia=${house.reason}`
29033
+ `${TAG48} op=request req=${req} caller=${short(caller2)} house=${isHouse} houseVia=${house.reason}`
28718
29034
  );
28719
29035
  if (!isHouse) {
28720
29036
  const reason = house.accountId === null ? house.reason : "not-house";
28721
29037
  console.error(
28722
- `${TAG46} op=gate req=${req} decision=deny reason=${reason} caller=${short(caller2)} houseAcct=${short(house.accountId)} accounts=${valid.length}`
29038
+ `${TAG48} op=gate req=${req} decision=deny reason=${reason} caller=${short(caller2)} houseAcct=${short(house.accountId)} accounts=${valid.length}`
28723
29039
  );
28724
29040
  return c.json({ error: "house-only" }, 403);
28725
29041
  }
28726
- console.log(`${TAG46} op=gate req=${req} decision=allow caller=${short(caller2)} via=${house.reason}`);
29042
+ console.log(`${TAG48} op=gate req=${req} decision=allow caller=${short(caller2)} via=${house.reason}`);
28727
29043
  const onDisk = countAccountDirsOnDisk();
28728
29044
  console.log(
28729
- `${TAG46} op=accounts req=${req} onDisk=${onDisk ?? "unknown"} valid=${valid.length} ids=${valid.map((a) => short(a.accountId)).join(",")}`
29045
+ `${TAG48} op=accounts req=${req} onDisk=${onDisk ?? "unknown"} valid=${valid.length} ids=${valid.map((a) => short(a.accountId)).join(",")}`
28730
29046
  );
28731
29047
  const start = Date.now();
28732
29048
  let res;
@@ -28742,17 +29058,17 @@ app66.get("/", requireAdminSession, async (c) => {
28742
29058
  });
28743
29059
  } catch (err) {
28744
29060
  console.error(
28745
- `${TAG46} op=manager-fail req=${req} reason=unreachable err=${err instanceof Error ? err.message : String(err)}`
29061
+ `${TAG48} op=manager-fail req=${req} reason=unreachable err=${err instanceof Error ? err.message : String(err)}`
28746
29062
  );
28747
29063
  return c.json({ error: "manager-unreachable" }, 502);
28748
29064
  }
28749
29065
  if (res.status !== 200) {
28750
- console.error(`${TAG46} op=manager-fail req=${req} reason=status status=${res.status}`);
29066
+ console.error(`${TAG48} op=manager-fail req=${req} reason=status status=${res.status}`);
28751
29067
  return c.json({ error: `manager-status-${res.status}` }, 502);
28752
29068
  }
28753
29069
  const body = await res.json().catch(() => null);
28754
29070
  if (!body || !Array.isArray(body.rows)) {
28755
- console.error(`${TAG46} op=manager-fail req=${req} reason=bad-json`);
29071
+ console.error(`${TAG48} op=manager-fail req=${req} reason=bad-json`);
28756
29072
  return c.json({ error: "manager-bad-json" }, 502);
28757
29073
  }
28758
29074
  const rows = body.rows;
@@ -28763,10 +29079,10 @@ app66.get("/", requireAdminSession, async (c) => {
28763
29079
  const ageNull = rows.filter((r) => r.ageMs === null).length;
28764
29080
  const sidecarNull = rows.filter((r) => r.sidecarMissing).length;
28765
29081
  console.log(
28766
- `${TAG46} op=census req=${req} ageMs=${censusAgeMs ?? "none"} live=${census?.live ?? "none"} cpuNull=${census?.cpuNull ?? "none"} rows=${rows.length} ageNull=${ageNull} sidecarNull=${sidecarNull}`
29082
+ `${TAG48} op=census req=${req} ageMs=${censusAgeMs ?? "none"} live=${census?.live ?? "none"} cpuNull=${census?.cpuNull ?? "none"} rows=${rows.length} ageNull=${ageNull} sidecarNull=${sidecarNull}`
28767
29083
  );
28768
29084
  console.log(
28769
- `${TAG46} op=response req=${req} rows=${rows.length} accounts=${valid.length} untagged=${untaggedCount} meteringFailed=${meteringFailed} ms=${Date.now() - start}`
29085
+ `${TAG48} op=response req=${req} rows=${rows.length} accounts=${valid.length} untagged=${untaggedCount} meteringFailed=${meteringFailed} ms=${Date.now() - start}`
28770
29086
  );
28771
29087
  const names = {};
28772
29088
  await Promise.all(
@@ -28785,7 +29101,7 @@ app66.get("/", requireAdminSession, async (c) => {
28785
29101
  return acc;
28786
29102
  }, {});
28787
29103
  console.log(
28788
- `${TAG46} op=loops req=${req} armed=${armed2} rendered=${loopRows.length} procPct=${cpu.processPct?.toFixed(1) ?? "null"} attributedPct=${cpu.attributedPct?.toFixed(1) ?? "null"} ` + Object.entries(byState).map(([s, n]) => `${s}=${n}`).join(" ")
29104
+ `${TAG48} op=loops req=${req} armed=${armed2} rendered=${loopRows.length} procPct=${cpu.processPct?.toFixed(1) ?? "null"} attributedPct=${cpu.attributedPct?.toFixed(1) ?? "null"} ` + Object.entries(byState).map(([s, n]) => `${s}=${n}`).join(" ")
28789
29105
  );
28790
29106
  return c.json({
28791
29107
  rows,
@@ -28879,7 +29195,7 @@ init_dist();
28879
29195
 
28880
29196
  // server/routes/access/verify-token.ts
28881
29197
  init_dist();
28882
- var TAG47 = "[access-verify]";
29198
+ var TAG49 = "[access-verify]";
28883
29199
  var MINT_TAG = "[access-session-mint]";
28884
29200
  var COOKIE_NAME = "__access_session";
28885
29201
  var app68 = new Hono();
@@ -28898,39 +29214,39 @@ app68.post("/", async (c) => {
28898
29214
  }
28899
29215
  const rateMsg = checkAccessRateLimit(ip, agentSlug);
28900
29216
  if (rateMsg) {
28901
- console.error(`${TAG47} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
29217
+ console.error(`${TAG49} grantId=- agentSlug=${agentSlug} result=rate-limited ip=${ip}`);
28902
29218
  return c.json({ error: rateMsg }, 429);
28903
29219
  }
28904
29220
  const grant = await findGrantByMagicToken(token);
28905
29221
  if (!grant) {
28906
29222
  recordAccessFailedAttempt(ip, agentSlug);
28907
- console.error(`${TAG47} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
29223
+ console.error(`${TAG49} grantId=- agentSlug=${agentSlug} result=notfound ip=${ip}`);
28908
29224
  return c.json({ error: "invalid-or-expired-link" }, 401);
28909
29225
  }
28910
29226
  if (grant.agentSlug !== agentSlug) {
28911
29227
  recordAccessFailedAttempt(ip, agentSlug);
28912
29228
  console.error(
28913
- `${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
29229
+ `${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=agent-mismatch grantAgent=${grant.agentSlug} ip=${ip}`
28914
29230
  );
28915
29231
  return c.json({ error: "invalid-or-expired-link" }, 401);
28916
29232
  }
28917
29233
  if (grant.status === "expired" || grant.status === "revoked") {
28918
29234
  recordAccessFailedAttempt(ip, agentSlug);
28919
29235
  console.error(
28920
- `${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
29236
+ `${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired status=${grant.status} ip=${ip}`
28921
29237
  );
28922
29238
  return c.json({ error: "access-no-longer-valid" }, 401);
28923
29239
  }
28924
29240
  if (grant.expiresAt !== null && grant.expiresAt < Date.now()) {
28925
29241
  recordAccessFailedAttempt(ip, agentSlug);
28926
29242
  console.error(
28927
- `${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
29243
+ `${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=expired reason=expiresAt-past ip=${ip}`
28928
29244
  );
28929
29245
  return c.json({ error: "access-no-longer-valid" }, 401);
28930
29246
  }
28931
29247
  if (!grant.sliceToken) {
28932
29248
  console.error(
28933
- `${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
29249
+ `${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=no-slice-token reason=schema-violation`
28934
29250
  );
28935
29251
  return c.json({ error: "grant-misconfigured" }, 500);
28936
29252
  }
@@ -28946,12 +29262,12 @@ app68.post("/", async (c) => {
28946
29262
  await consumeMagicTokenAndActivate(grant.grantId);
28947
29263
  } catch (err) {
28948
29264
  console.error(
28949
- `${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
29265
+ `${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=consume-failed err="${err instanceof Error ? err.message : String(err)}"`
28950
29266
  );
28951
29267
  return c.json({ error: "verification-failed" }, 500);
28952
29268
  }
28953
29269
  clearAccessRateLimit(ip, agentSlug);
28954
- console.log(`${TAG47} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
29270
+ console.log(`${TAG49} grantId=${grant.grantId} agentSlug=${agentSlug} result=ok ip=${ip}`);
28955
29271
  console.log(
28956
29272
  `${MINT_TAG} grantId=${grant.grantId} sliceToken=${grant.sliceToken.slice(0, 8)} agentSlug=${agentSlug} personId=${grant.personId ?? "none"}`
28957
29273
  );
@@ -29030,7 +29346,7 @@ async function sendMagicLinkEmail(payload) {
29030
29346
  }
29031
29347
 
29032
29348
  // server/routes/access/request-magic-link.ts
29033
- var TAG48 = "[access-request-link]";
29349
+ var TAG50 = "[access-request-link]";
29034
29350
  var app69 = new Hono();
29035
29351
  var VISITOR_MESSAGE = "If that email is on the invite list, a fresh link is on the way.";
29036
29352
  app69.post("/", async (c) => {
@@ -29047,18 +29363,18 @@ app69.post("/", async (c) => {
29047
29363
  }
29048
29364
  const rateMsg = checkRequestLinkRateLimit(contactValue);
29049
29365
  if (rateMsg) {
29050
- console.error(`${TAG48} contactValue=${maskContact(contactValue)} result=rate-limited`);
29366
+ console.error(`${TAG50} contactValue=${maskContact(contactValue)} result=rate-limited`);
29051
29367
  return c.json({ error: rateMsg }, 429);
29052
29368
  }
29053
29369
  recordRequestLinkAttempt(contactValue);
29054
29370
  const accountId = process.env.ACCOUNT_ID ?? "";
29055
29371
  if (!accountId) {
29056
- console.error(`${TAG48} contactValue=${maskContact(contactValue)} result=no-account-id`);
29372
+ console.error(`${TAG50} contactValue=${maskContact(contactValue)} result=no-account-id`);
29057
29373
  return c.json({ message: VISITOR_MESSAGE }, 200);
29058
29374
  }
29059
29375
  const grant = await findActiveGrantByContact(contactValue, agentSlug, accountId);
29060
29376
  if (!grant) {
29061
- console.log(`${TAG48} contactValue=${maskContact(contactValue)} result=notfound`);
29377
+ console.log(`${TAG50} contactValue=${maskContact(contactValue)} result=notfound`);
29062
29378
  return c.json({ message: VISITOR_MESSAGE }, 200);
29063
29379
  }
29064
29380
  let token;
@@ -29066,7 +29382,7 @@ app69.post("/", async (c) => {
29066
29382
  token = await generateNewMagicToken(grant.grantId);
29067
29383
  } catch (err) {
29068
29384
  console.error(
29069
- `${TAG48} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
29385
+ `${TAG50} contactValue=${maskContact(contactValue)} result=mint-failed err="${err instanceof Error ? err.message : String(err)}"`
29070
29386
  );
29071
29387
  return c.json({ message: VISITOR_MESSAGE }, 200);
29072
29388
  }
@@ -29098,12 +29414,12 @@ app69.post("/", async (c) => {
29098
29414
  });
29099
29415
  if (!sendResult.ok) {
29100
29416
  console.error(
29101
- `${TAG48} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
29417
+ `${TAG50} contactValue=${maskContact(contactValue)} result=send-failed err="${sendResult.error}"`
29102
29418
  );
29103
29419
  return c.json({ message: VISITOR_MESSAGE }, 200);
29104
29420
  }
29105
29421
  console.log(
29106
- `${TAG48} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
29422
+ `${TAG50} contactValue=${maskContact(contactValue)} result=ok messageId=${sendResult.messageId}`
29107
29423
  );
29108
29424
  return c.json({ message: VISITOR_MESSAGE }, 200);
29109
29425
  });
@@ -29344,7 +29660,7 @@ init_dist();
29344
29660
 
29345
29661
  // app/lib/brand-config.ts
29346
29662
  import { existsSync as existsSync45, readFileSync as readFileSync46 } from "fs";
29347
- import { join as join51 } from "path";
29663
+ import { join as join52 } from "path";
29348
29664
  var cached2 = null;
29349
29665
  var cachedAttempted = false;
29350
29666
  function readBrandConfig() {
@@ -29352,7 +29668,7 @@ function readBrandConfig() {
29352
29668
  cachedAttempted = true;
29353
29669
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
29354
29670
  if (!platformRoot5) return null;
29355
- const brandPath = join51(platformRoot5, "config", "brand.json");
29671
+ const brandPath = join52(platformRoot5, "config", "brand.json");
29356
29672
  if (!existsSync45(brandPath)) return null;
29357
29673
  try {
29358
29674
  cached2 = JSON.parse(readFileSync46(brandPath, "utf-8"));
@@ -30133,12 +30449,12 @@ var calendar_public_default = app76;
30133
30449
  init_dist();
30134
30450
  import { createReadStream as createReadStream3 } from "fs";
30135
30451
  import { stat as stat8, readFile as readFile11, realpath } from "fs/promises";
30136
- import { join as join52, resolve as resolve42, sep as sep11 } from "path";
30452
+ import { join as join53, resolve as resolve42, sep as sep11 } from "path";
30137
30453
  import { Readable as Readable3 } from "stream";
30138
30454
  init_data_path();
30139
30455
  init_attachments();
30140
30456
  var app77 = new Hono();
30141
- var TAG49 = "[portal-fetch]";
30457
+ var TAG51 = "[portal-fetch]";
30142
30458
  async function verifySignature(secret, accountId, relPath, expiresAtMs, signature, nowMs) {
30143
30459
  if (!secret || !signature) return false;
30144
30460
  if (!Number.isFinite(expiresAtMs) || expiresAtMs <= nowMs) return false;
@@ -30193,14 +30509,14 @@ async function readAccountSecret(accountId) {
30193
30509
  try {
30194
30510
  text = await readFile11(path, "utf8");
30195
30511
  } catch {
30196
- console.error(`${TAG49} op=no-secret account="${accountId}" path="${path}"`);
30512
+ console.error(`${TAG51} op=no-secret account="${accountId}" path="${path}"`);
30197
30513
  return "";
30198
30514
  }
30199
30515
  for (const line of text.split("\n")) {
30200
30516
  const m = line.match(/^PORTAL_FETCH_SECRET=(.*)$/);
30201
30517
  if (m) return m[1].trim();
30202
30518
  }
30203
- console.error(`${TAG49} op=no-secret account="${accountId}" reason=key-absent path="${path}"`);
30519
+ console.error(`${TAG51} op=no-secret account="${accountId}" reason=key-absent path="${path}"`);
30204
30520
  return "";
30205
30521
  }
30206
30522
  function isValidAccountId2(value) {
@@ -30208,7 +30524,7 @@ function isValidAccountId2(value) {
30208
30524
  }
30209
30525
  async function readExposeFolders2(accountDir) {
30210
30526
  try {
30211
- const cfg = JSON.parse(await readFile11(join52(accountDir, "data-portal.json"), "utf8"));
30527
+ const cfg = JSON.parse(await readFile11(join53(accountDir, "data-portal.json"), "utf8"));
30212
30528
  return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
30213
30529
  } catch {
30214
30530
  return [];
@@ -30217,7 +30533,7 @@ async function readExposeFolders2(accountDir) {
30217
30533
  async function resolveFetchTarget(accountDir, relPath, ownerId) {
30218
30534
  let schemaText = null;
30219
30535
  try {
30220
- schemaText = await readFile11(join52(accountDir, "SCHEMA.md"), "utf8");
30536
+ schemaText = await readFile11(join53(accountDir, "SCHEMA.md"), "utf8");
30221
30537
  } catch {
30222
30538
  schemaText = null;
30223
30539
  }
@@ -30260,16 +30576,16 @@ async function handle(c, headOnly) {
30260
30576
  const sig = c.req.query("sig") ?? "";
30261
30577
  const owner = c.req.query("owner") ?? "";
30262
30578
  console.log(
30263
- `${TAG49} op=request account=${q(accountId)} path=${q(relPath)} owner=${q(owner)} head=${headOnly}`
30579
+ `${TAG51} op=request account=${q(accountId)} path=${q(relPath)} owner=${q(owner)} head=${headOnly}`
30264
30580
  );
30265
30581
  if (!isValidAccountId2(accountId)) {
30266
- console.error(`${TAG49} op=denied account=${q(accountId)} reason=account-id`);
30582
+ console.error(`${TAG51} op=denied account=${q(accountId)} reason=account-id`);
30267
30583
  return c.json({ ok: false, error: "denied" }, 401);
30268
30584
  }
30269
30585
  const secret = await readAccountSecret(accountId);
30270
30586
  const verified = owner ? await verifyOwnUploadSignature(secret, accountId, owner, relPath, exp, sig, Date.now()) : await verifySignature(secret, accountId, relPath, exp, sig, Date.now());
30271
30587
  if (!verified) {
30272
- console.error(`${TAG49} op=denied account=${q(accountId)} reason=secret`);
30588
+ console.error(`${TAG51} op=denied account=${q(accountId)} reason=secret`);
30273
30589
  return c.json({ ok: false, error: "denied" }, 401);
30274
30590
  }
30275
30591
  const target = await resolveFetchTarget(
@@ -30279,14 +30595,14 @@ async function handle(c, headOnly) {
30279
30595
  );
30280
30596
  if (!target.ok) {
30281
30597
  const op = target.reason === "enoent" ? "miss" : "denied";
30282
- console.error(`${TAG49} op=${op} account=${accountId} reason=${target.reason}`);
30598
+ console.error(`${TAG51} op=${op} account=${accountId} reason=${target.reason}`);
30283
30599
  return c.json({ ok: false, error: "not found" }, 404);
30284
30600
  }
30285
30601
  if (headOnly) {
30286
- console.log(`${TAG49} op=served account=${accountId} bytes=${target.sizeBytes} head=true`);
30602
+ console.log(`${TAG51} op=served account=${accountId} bytes=${target.sizeBytes} head=true`);
30287
30603
  return c.body(null, 200);
30288
30604
  }
30289
- console.log(`${TAG49} op=served account=${accountId} bytes=${target.sizeBytes}`);
30605
+ console.log(`${TAG51} op=served account=${accountId} bytes=${target.sizeBytes}`);
30290
30606
  return new Response(Readable3.toWeb(createReadStream3(target.absolute)), {
30291
30607
  status: 200,
30292
30608
  headers: {
@@ -30309,7 +30625,7 @@ init_remote_auth();
30309
30625
 
30310
30626
  // app/lib/timeentry-census.ts
30311
30627
  init_loop_registry();
30312
- var TAG50 = "[timeentry-census]";
30628
+ var TAG52 = "[timeentry-census]";
30313
30629
  function reconcileTimeEntries(rows, now, horizonMs) {
30314
30630
  const openEntries = rows.openEntries.length;
30315
30631
  let oldestOpenAgeMs = 0;
@@ -30349,12 +30665,12 @@ async function runTimeEntryCensusOnce(session, now, horizonMs) {
30349
30665
  sumAdjustments: toNum(r.get("sumAdjustments"))
30350
30666
  }));
30351
30667
  const finding = reconcileTimeEntries({ openEntries, taskSums }, now, horizonMs);
30352
- const line = `${TAG50} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
30668
+ const line = `${TAG52} openEntries=${finding.openEntries} oldestOpenAgeMin=${finding.oldestOpenAgeMin} maxOpenPerAccount=${finding.maxOpenPerAccount} driftTasks=${finding.driftTasks}`;
30353
30669
  if (finding.alarm) console.error(`${line} alarm=true`);
30354
30670
  else console.log(line);
30355
30671
  return finding;
30356
30672
  } catch (err) {
30357
- console.error(`${TAG50} error="${err instanceof Error ? err.message : String(err)}"`);
30673
+ console.error(`${TAG52} error="${err instanceof Error ? err.message : String(err)}"`);
30358
30674
  return null;
30359
30675
  }
30360
30676
  }
@@ -30368,13 +30684,13 @@ function startTimeEntryCensus(openSession, opts = {}) {
30368
30684
  try {
30369
30685
  session = openSession();
30370
30686
  } catch (err) {
30371
- console.error(`${TAG50} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
30687
+ console.error(`${TAG52} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`);
30372
30688
  return;
30373
30689
  }
30374
30690
  try {
30375
30691
  await runTimeEntryCensusOnce(session, Date.now(), horizonMs);
30376
30692
  } catch (err) {
30377
- console.error(`${TAG50} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
30693
+ console.error(`${TAG52} tick-failed error="${err instanceof Error ? err.message : String(err)}"`);
30378
30694
  } finally {
30379
30695
  try {
30380
30696
  await session.close();
@@ -30396,7 +30712,7 @@ init_neo4j_store();
30396
30712
  // app/lib/ledger-census.ts
30397
30713
  init_loop_registry();
30398
30714
  import { readdirSync as readdirSync29, readFileSync as readFileSync47, statSync as statSync26 } from "fs";
30399
- import { join as join53 } from "path";
30715
+ import { join as join54 } from "path";
30400
30716
 
30401
30717
  // ../lib/ledger-core/dist/reconcile.js
30402
30718
  var LEDGER_INDEX_NAMES = [
@@ -30439,7 +30755,7 @@ function formatCensusLine(f) {
30439
30755
  }
30440
30756
 
30441
30757
  // app/lib/ledger-census.ts
30442
- var TAG51 = "[ledger-census]";
30758
+ var TAG53 = "[ledger-census]";
30443
30759
  var DAY_MS = 864e5;
30444
30760
  function countWriteRejects24h(logDir, now) {
30445
30761
  let entries2;
@@ -30450,7 +30766,7 @@ function countWriteRejects24h(logDir, now) {
30450
30766
  }
30451
30767
  let total = 0;
30452
30768
  for (const name of entries2) {
30453
- const path = join53(logDir, name);
30769
+ const path = join54(logDir, name);
30454
30770
  try {
30455
30771
  if (now - statSync26(path).mtimeMs > DAY_MS) continue;
30456
30772
  for (const line of readFileSync47(path, "utf8").split("\n")) {
@@ -30515,7 +30831,7 @@ async function runLedgerCensusOnce(session, now) {
30515
30831
  else console.log(line);
30516
30832
  return finding;
30517
30833
  } catch (err) {
30518
- console.error(`${TAG51} error="${err instanceof Error ? err.message : String(err)}"`);
30834
+ console.error(`${TAG53} error="${err instanceof Error ? err.message : String(err)}"`);
30519
30835
  return null;
30520
30836
  }
30521
30837
  }
@@ -30528,7 +30844,7 @@ function startLedgerCensus(openSession, opts = {}) {
30528
30844
  session = openSession();
30529
30845
  } catch (err) {
30530
30846
  console.error(
30531
- `${TAG51} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`
30847
+ `${TAG53} open-session-failed error="${err instanceof Error ? err.message : String(err)}"`
30532
30848
  );
30533
30849
  return;
30534
30850
  }
@@ -30536,7 +30852,7 @@ function startLedgerCensus(openSession, opts = {}) {
30536
30852
  await runLedgerCensusOnce(session, Date.now());
30537
30853
  } catch (err) {
30538
30854
  console.error(
30539
- `${TAG51} tick-failed error="${err instanceof Error ? err.message : String(err)}"`
30855
+ `${TAG53} tick-failed error="${err instanceof Error ? err.message : String(err)}"`
30540
30856
  );
30541
30857
  } finally {
30542
30858
  try {
@@ -30559,7 +30875,7 @@ init_neo4j_store();
30559
30875
 
30560
30876
  // app/lib/conversation-audit.ts
30561
30877
  init_neo4j_store();
30562
- var TAG52 = "[conversation-audit]";
30878
+ var TAG54 = "[conversation-audit]";
30563
30879
  async function runConversationAudit() {
30564
30880
  const session = getSession();
30565
30881
  try {
@@ -30596,12 +30912,12 @@ async function runConversationAudit() {
30596
30912
  multiAnchored: Number(multiRec?.get("multiAnchored") ?? 0)
30597
30913
  };
30598
30914
  console.error(
30599
- `${TAG52} channel=whatsapp total=${result.total} senders=${result.senders} multiAnchored=${result.multiAnchored} unreconciled=${result.unreconciled} unpairable=${result.unpairable}`
30915
+ `${TAG54} channel=whatsapp total=${result.total} senders=${result.senders} multiAnchored=${result.multiAnchored} unreconciled=${result.unreconciled} unpairable=${result.unpairable}`
30600
30916
  );
30601
30917
  return result;
30602
30918
  } catch (err) {
30603
30919
  const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
30604
- console.error(`${TAG52} op=failed reason=${reason}`);
30920
+ console.error(`${TAG54} op=failed reason=${reason}`);
30605
30921
  return null;
30606
30922
  } finally {
30607
30923
  await session.close();
@@ -30736,8 +31052,8 @@ init_loop_registry();
30736
31052
  init_data_path();
30737
31053
  var import_dist9 = __toESM(require_dist(), 1);
30738
31054
  import { existsSync as existsSync47, statSync as statSync27, readdirSync as readdirSync30 } from "fs";
30739
- import { join as join54 } from "path";
30740
- var TAG53 = "[shared-census]";
31055
+ import { join as join55 } from "path";
31056
+ var TAG55 = "[shared-census]";
30741
31057
  var WIRED_SURFACES = 3;
30742
31058
  function countFiles(dir) {
30743
31059
  let n = 0;
@@ -30748,7 +31064,7 @@ function countFiles(dir) {
30748
31064
  return 0;
30749
31065
  }
30750
31066
  for (const e of entries2) {
30751
- if (e.isDirectory()) n += countFiles(join54(dir, e.name));
31067
+ if (e.isDirectory()) n += countFiles(join55(dir, e.name));
30752
31068
  else if (e.isFile()) n++;
30753
31069
  }
30754
31070
  return n;
@@ -30765,8 +31081,8 @@ function runSharedFolderCensus(dataRoot = DATA_ROOT) {
30765
31081
  }
30766
31082
  }
30767
31083
  const files = isDir ? countFiles(root) : 0;
30768
- console.error(`${TAG53} op=root exists=${exists} isDir=${isDir} files=${files}`);
30769
- console.error(`${TAG53} op=wiring surfaces=${WIRED_SURFACES}/3`);
31084
+ console.error(`${TAG55} op=root exists=${exists} isDir=${isDir} files=${files}`);
31085
+ console.error(`${TAG55} op=wiring surfaces=${WIRED_SURFACES}/3`);
30770
31086
  return `shared root ${exists ? "present" : "ABSENT"}, ${files} file(s)`;
30771
31087
  }
30772
31088
  function startSharedFolderCensus() {
@@ -30886,7 +31202,7 @@ async function startFileWatcher(opts = {}) {
30886
31202
  init_data_path();
30887
31203
  init_neo4j_store();
30888
31204
  init_account();
30889
- import { mkdir as mkdir4, readdir as readdir6, rename as rename4, rm as rm3 } from "fs/promises";
31205
+ import { mkdir as mkdir5, readdir as readdir6, rename as rename4, rm as rm3 } from "fs/promises";
30890
31206
  import { dirname as dirname17, relative as relative8, resolve as resolve44 } from "path";
30891
31207
  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;
30892
31208
  async function walkFiles(dir) {
@@ -30919,7 +31235,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
30919
31235
  for (const oldAbs of files) {
30920
31236
  const suffix = relative8(srcDir, oldAbs);
30921
31237
  const newAbs = resolve44(destDir, suffix);
30922
- await mkdir4(dirname17(newAbs), { recursive: true });
31238
+ await mkdir5(dirname17(newAbs), { recursive: true });
30923
31239
  await rename4(oldAbs, newAbs);
30924
31240
  moved++;
30925
31241
  const oldRel = relative8(dataRoot, oldAbs);
@@ -31013,9 +31329,9 @@ init_paths();
31013
31329
  init_pin_validator();
31014
31330
  init_account();
31015
31331
  init_neo4j_store();
31016
- import { readdir as readdir7, readFile as readFile12, rename as rename5, writeFile as writeFile4, unlink as unlink4 } from "fs/promises";
31332
+ import { readdir as readdir7, readFile as readFile12, rename as rename5, writeFile as writeFile5, unlink as unlink4 } from "fs/promises";
31017
31333
  import { existsSync as existsSync48 } from "fs";
31018
- import { join as join55 } from "path";
31334
+ import { join as join56 } from "path";
31019
31335
  var ADMIN_ROLE2 = "admin";
31020
31336
  var WEBCHAT_CHANNEL2 = "webchat";
31021
31337
  var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
@@ -31040,7 +31356,7 @@ async function readRaw3(path) {
31040
31356
  async function writeRaw(path, obj) {
31041
31357
  const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
31042
31358
  try {
31043
- await writeFile4(tmp, JSON.stringify(obj, null, 2), "utf8");
31359
+ await writeFile5(tmp, JSON.stringify(obj, null, 2), "utf8");
31044
31360
  await rename5(tmp, path);
31045
31361
  } catch (err) {
31046
31362
  try {
@@ -31060,7 +31376,7 @@ async function collectLiveSidecars(projectsRoot) {
31060
31376
  }
31061
31377
  for (const slug of slugs) {
31062
31378
  if (!slug.isDirectory()) continue;
31063
- const slugDir = join55(projectsRoot, slug.name);
31379
+ const slugDir = join56(projectsRoot, slug.name);
31064
31380
  let entries2;
31065
31381
  try {
31066
31382
  entries2 = await readdir7(slugDir, { withFileTypes: true });
@@ -31069,9 +31385,9 @@ async function collectLiveSidecars(projectsRoot) {
31069
31385
  }
31070
31386
  for (const entry of entries2) {
31071
31387
  if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
31072
- out.push(join55(slugDir, entry.name));
31388
+ out.push(join56(slugDir, entry.name));
31073
31389
  } else if (entry.isDirectory() && entry.name === "subagents") {
31074
- const subDir = join55(slugDir, entry.name);
31390
+ const subDir = join56(slugDir, entry.name);
31075
31391
  let subs;
31076
31392
  try {
31077
31393
  subs = await readdir7(subDir, { withFileTypes: true });
@@ -31079,7 +31395,7 @@ async function collectLiveSidecars(projectsRoot) {
31079
31395
  continue;
31080
31396
  }
31081
31397
  for (const s of subs) {
31082
- if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join55(subDir, s.name));
31398
+ if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join56(subDir, s.name));
31083
31399
  }
31084
31400
  }
31085
31401
  }
@@ -31091,7 +31407,7 @@ function shortId(path) {
31091
31407
  return base.slice(0, 8);
31092
31408
  }
31093
31409
  async function migrateAdminWebchatSidecars(opts = {}) {
31094
- const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join55(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
31410
+ const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join56(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
31095
31411
  const usersFile = opts.usersFile ?? USERS_FILE;
31096
31412
  const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
31097
31413
  const resolveName = opts.resolveName ?? defaultResolveName;
@@ -31167,9 +31483,9 @@ async function migrateAdminWebchatSidecars(opts = {}) {
31167
31483
 
31168
31484
  // app/lib/migrate-sidecar-account-ids.ts
31169
31485
  init_account();
31170
- import { readdir as readdir8, readFile as readFile13, rename as rename6, writeFile as writeFile5, unlink as unlink5 } from "fs/promises";
31486
+ import { readdir as readdir8, readFile as readFile13, rename as rename6, writeFile as writeFile6, unlink as unlink5 } from "fs/promises";
31171
31487
  import { existsSync as existsSync49 } from "fs";
31172
- import { join as join56 } from "path";
31488
+ import { join as join57 } from "path";
31173
31489
  var SESSION_META_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
31174
31490
  function projectSlugForCwd(cwd) {
31175
31491
  return cwd.replace(/\//g, "-");
@@ -31191,7 +31507,7 @@ async function readRaw4(path) {
31191
31507
  async function writeRaw2(path, obj) {
31192
31508
  const tmp = `${path}.tmp.${process.pid}.${Date.now()}`;
31193
31509
  try {
31194
- await writeFile5(tmp, JSON.stringify(obj, null, 2), "utf8");
31510
+ await writeFile6(tmp, JSON.stringify(obj, null, 2), "utf8");
31195
31511
  await rename6(tmp, path);
31196
31512
  } catch (err) {
31197
31513
  try {
@@ -31215,7 +31531,7 @@ async function collectSidecars(projectsRoot) {
31215
31531
  }
31216
31532
  for (const slug of slugs) {
31217
31533
  if (!slug.isDirectory()) continue;
31218
- const slugDir = join56(projectsRoot, slug.name);
31534
+ const slugDir = join57(projectsRoot, slug.name);
31219
31535
  let entries2;
31220
31536
  try {
31221
31537
  entries2 = await readdir8(slugDir, { withFileTypes: true });
@@ -31224,9 +31540,9 @@ async function collectSidecars(projectsRoot) {
31224
31540
  }
31225
31541
  for (const entry of entries2) {
31226
31542
  if (entry.isFile() && SESSION_META_RE2.test(entry.name)) {
31227
- out.push({ path: join56(slugDir, entry.name), slug: slug.name });
31543
+ out.push({ path: join57(slugDir, entry.name), slug: slug.name });
31228
31544
  } else if (entry.isDirectory() && (entry.name === "subagents" || entry.name === "archive")) {
31229
- const subDir = join56(slugDir, entry.name);
31545
+ const subDir = join57(slugDir, entry.name);
31230
31546
  let subs;
31231
31547
  try {
31232
31548
  subs = await readdir8(subDir, { withFileTypes: true });
@@ -31235,7 +31551,7 @@ async function collectSidecars(projectsRoot) {
31235
31551
  }
31236
31552
  for (const s of subs) {
31237
31553
  if (s.isFile() && SESSION_META_RE2.test(s.name)) {
31238
- out.push({ path: join56(subDir, s.name), slug: slug.name });
31554
+ out.push({ path: join57(subDir, s.name), slug: slug.name });
31239
31555
  }
31240
31556
  }
31241
31557
  }
@@ -31244,7 +31560,7 @@ async function collectSidecars(projectsRoot) {
31244
31560
  return out;
31245
31561
  }
31246
31562
  async function migrateSidecarAccountIds(opts = {}) {
31247
- const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join56(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
31563
+ const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join57(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
31248
31564
  const accounts = opts.accounts ?? listValidAccounts();
31249
31565
  const result = {
31250
31566
  scanned: 0,
@@ -31459,15 +31775,15 @@ var InboundHub = class {
31459
31775
 
31460
31776
  // app/lib/whatsapp/inbound/public-inbound-census.ts
31461
31777
  var routed = 0;
31462
- var answered = 0;
31778
+ var answered2 = 0;
31463
31779
  function noteRouted() {
31464
31780
  routed += 1;
31465
31781
  }
31466
- function noteAnswered() {
31467
- answered += 1;
31782
+ function noteAnswered2() {
31783
+ answered2 += 1;
31468
31784
  }
31469
31785
  function readPublicInboundCensus() {
31470
- return { routed, answered, answerGap: Math.max(0, routed - answered) };
31786
+ return { routed, answered: answered2, answerGap: Math.max(0, routed - answered2) };
31471
31787
  }
31472
31788
  function runPublicNotifyReconcile() {
31473
31789
  const c = readPublicInboundCensus();
@@ -32013,7 +32329,7 @@ var WaGateway = class {
32013
32329
  * inbound; it is dropped and counted as expired, not reported as a race. */
32014
32330
  noteReplyDispatch(senderId, atMs) {
32015
32331
  const key2 = normalizeTarget(senderId) ?? senderId;
32016
- if (this.awaitingPublicAnswer.delete(key2)) noteAnswered();
32332
+ if (this.awaitingPublicAnswer.delete(key2)) noteAnswered2();
32017
32333
  const inFlight2 = this.pendingMediaStanza.get(key2);
32018
32334
  if (inFlight2 === void 0) return;
32019
32335
  this.expireStaleStanzas(key2, inFlight2, atMs);
@@ -32770,7 +33086,7 @@ function createWebchatChannelRoutes(deps) {
32770
33086
 
32771
33087
  // app/lib/webchat/gateway/resolve-turn-answer.ts
32772
33088
  import { existsSync as existsSync50, openSync as openSync9, readSync as readSync8, closeSync as closeSync9, readdirSync as readdirSync31 } from "fs";
32773
- import { join as join57 } from "path";
33089
+ import { join as join58 } from "path";
32774
33090
  function resolveTurnAnswer(p) {
32775
33091
  if (!SESSION_ID_RE2.test(p.sessionId)) return "";
32776
33092
  const path = findJsonl(p.projectsRoot, p.sessionId);
@@ -32806,7 +33122,7 @@ function findJsonl(projectsRoot, sessionId) {
32806
33122
  return null;
32807
33123
  }
32808
33124
  for (const slug of slugs) {
32809
- const live = join57(projectsRoot, slug, `${sessionId}.jsonl`);
33125
+ const live = join58(projectsRoot, slug, `${sessionId}.jsonl`);
32810
33126
  if (existsSync50(live)) return live;
32811
33127
  }
32812
33128
  return null;
@@ -33604,14 +33920,14 @@ function makeFileDelivery(opts) {
33604
33920
  }
33605
33921
 
33606
33922
  // app/lib/webchat/file-delivery.ts
33607
- var TAG54 = "[webchat-adaptor]";
33923
+ var TAG56 = "[webchat-adaptor]";
33608
33924
  function platformRoot2() {
33609
33925
  return process.env.MAXY_PLATFORM_ROOT || "";
33610
33926
  }
33611
33927
  function makeWebchatSendFile(entry) {
33612
33928
  return async (filePath) => {
33613
33929
  if (!entry.accountId) {
33614
- console.error(`${TAG54} file-delivery reject reason=no-account sender=${entry.senderId}`);
33930
+ console.error(`${TAG56} file-delivery reject reason=no-account sender=${entry.senderId}`);
33615
33931
  return { ok: false, error: "no-account" };
33616
33932
  }
33617
33933
  const accountDir = resolve45(platformRoot2(), "..", "data/accounts", entry.accountId);
@@ -33619,14 +33935,14 @@ function makeWebchatSendFile(entry) {
33619
33935
  const resolved = realpathSync9(filePath);
33620
33936
  const accountResolved = realpathSync9(accountDir);
33621
33937
  if (!resolved.startsWith(accountResolved + "/")) {
33622
- console.error(`${TAG54} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
33938
+ console.error(`${TAG56} file-delivery reject reason=outside_account_directory sender=${entry.senderId}`);
33623
33939
  return { ok: false, error: "outside-account" };
33624
33940
  }
33625
33941
  return { ok: true };
33626
33942
  } catch (err) {
33627
33943
  const code = err.code;
33628
33944
  console.error(
33629
- `${TAG54} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
33945
+ `${TAG56} file-delivery reject reason=${code === "ENOENT" ? "not-found" : "path-error"} sender=${entry.senderId}`
33630
33946
  );
33631
33947
  return { ok: false, error: code === "ENOENT" ? "not-found" : "path-error" };
33632
33948
  }
@@ -33635,7 +33951,7 @@ function makeWebchatSendFile(entry) {
33635
33951
  function makeWebchatFileDelivery(entry) {
33636
33952
  return makeFileDelivery({
33637
33953
  entry,
33638
- tag: TAG54,
33954
+ tag: TAG56,
33639
33955
  channel: "webchat",
33640
33956
  sendFile: makeWebchatSendFile(entry),
33641
33957
  deferUntilVerdict: true
@@ -33699,7 +34015,7 @@ function buildPublicWebchatSpawnRequest(input) {
33699
34015
  }
33700
34016
 
33701
34017
  // app/lib/whatsapp/inbound/file-delivery-bridge.ts
33702
- var TAG55 = "[whatsapp-adaptor]";
34018
+ var TAG57 = "[whatsapp-adaptor]";
33703
34019
  var SEND_USER_FILE2 = "SendUserFile";
33704
34020
  var WHATSAPP_SEND_DOCUMENT = "whatsapp-send-document";
33705
34021
  function platformRoot3() {
@@ -33717,7 +34033,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
33717
34033
  });
33718
34034
  if (result.ok) return { ok: true };
33719
34035
  console.error(
33720
- `${TAG55} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
34036
+ `${TAG57} file-delivery reject reason=send-failed sender=${entry.senderId} status=${result.status} message=${result.error}`
33721
34037
  );
33722
34038
  return { ok: false, error: result.error };
33723
34039
  };
@@ -33725,7 +34041,7 @@ function makeWhatsAppSendFile(entry, maxyAccountId) {
33725
34041
  function makeWhatsAppFileDelivery(entry, maxyAccountId) {
33726
34042
  const shared = makeFileDelivery({
33727
34043
  entry,
33728
- tag: TAG55,
34044
+ tag: TAG57,
33729
34045
  channel: "whatsapp",
33730
34046
  sendFile: makeWhatsAppSendFile(entry, maxyAccountId)
33731
34047
  });
@@ -33760,7 +34076,7 @@ function makeWhatsAppFileDelivery(entry, maxyAccountId) {
33760
34076
  if (!delivered) {
33761
34077
  const fileField = call.filePath !== void 0 ? ` file=${call.filePath}` : "";
33762
34078
  console.error(
33763
- `${TAG55} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
34079
+ `${TAG57} file-delivery-unreconciled sender=${entry.senderId} sessionId=${sid} tool=${WHATSAPP_SEND_DOCUMENT}${fileField}`
33764
34080
  );
33765
34081
  }
33766
34082
  }
@@ -34065,52 +34381,6 @@ function createTelegramChannelRoutes(deps) {
34065
34381
  init_admin_session_id();
34066
34382
  init_channel_key();
34067
34383
 
34068
- // app/lib/telegram/gateway/telegram-inbound-census.ts
34069
- var ANSWER_THRESHOLD_MS = 3e4;
34070
- var GAP_NAME_LIMIT2 = 10;
34071
- var received = 0;
34072
- var answered2 = 0;
34073
- var outstanding2 = /* @__PURE__ */ new Map();
34074
- function noteReceived(key2, botId, messageId, now) {
34075
- received += 1;
34076
- const list = outstanding2.get(key2);
34077
- if (list) list.push({ messageId, botId, receivedAt: now });
34078
- else outstanding2.set(key2, [{ messageId, botId, receivedAt: now }]);
34079
- }
34080
- function noteAnswered2(key2) {
34081
- const list = outstanding2.get(key2);
34082
- if (!list || list.length === 0) return;
34083
- list.shift();
34084
- if (list.length === 0) outstanding2.delete(key2);
34085
- answered2 += 1;
34086
- }
34087
- function readTelegramInboundCensus(now) {
34088
- const gaps = [];
34089
- for (const [key2, list] of outstanding2) {
34090
- for (const o of list) {
34091
- const ageMs2 = now - o.receivedAt;
34092
- if (ageMs2 > ANSWER_THRESHOLD_MS) gaps.push({ messageId: o.messageId, botId: o.botId, key: key2, ageMs: ageMs2 });
34093
- }
34094
- }
34095
- gaps.sort((a, b) => b.ageMs - a.ageMs);
34096
- return { received, answered: answered2, gaps };
34097
- }
34098
- function buildTelegramNotifyReconcileLines(input) {
34099
- const named = input.gaps.slice(0, GAP_NAME_LIMIT2);
34100
- const lines = [
34101
- `[telegram-native] op=telegram-notify-reconcile received=${input.received} answered=${input.answered} answerGap=${input.gaps.length} named=${named.length}`
34102
- ];
34103
- for (const g of named) {
34104
- lines.push(
34105
- `[telegram-native] op=telegram-answer-gap messageId=${g.messageId} botId=${g.botId} key=${g.key} ageMs=${g.ageMs}`
34106
- );
34107
- }
34108
- return lines;
34109
- }
34110
- function runTelegramNotifyReconcile(now) {
34111
- for (const line of buildTelegramNotifyReconcileLines(readTelegramInboundCensus(now))) console.error(line);
34112
- }
34113
-
34114
34384
  // app/lib/telegram/gateway/telegram-spawn-census.ts
34115
34385
  var byBot = /* @__PURE__ */ new Map();
34116
34386
  function bucket(botId) {
@@ -34282,7 +34552,7 @@ var TelegramGateway = class {
34282
34552
  );
34283
34553
  }
34284
34554
  this.hub.deliver(
34285
- { key: key2, text: input.text, messageId: `tg-${++this.seq}`, source, standingRules, scheduleProvenance: input.scheduleProvenance },
34555
+ { key: key2, text: input.text, media: input.media, messageId: `tg-${++this.seq}`, source, standingRules, scheduleProvenance: input.scheduleProvenance },
34286
34556
  Date.now()
34287
34557
  );
34288
34558
  const resolvedSessionId = this.sessionIdFor(input);
@@ -34326,7 +34596,7 @@ var TelegramGateway = class {
34326
34596
  const reply = this.replies.get(key2);
34327
34597
  if (!reply) throw new Error(`telegram-gateway: no reply route for key ${key2}`);
34328
34598
  await reply(text);
34329
- noteAnswered2(key2);
34599
+ noteAnswered(key2);
34330
34600
  }
34331
34601
  };
34332
34602
 
@@ -34362,7 +34632,7 @@ function buildTelegramSpawnRequest(input) {
34362
34632
  }
34363
34633
 
34364
34634
  // server/telegram-ensure-session.ts
34365
- var TAG56 = "[telegram-inbound]";
34635
+ var TAG58 = "[telegram-inbound]";
34366
34636
  function buildTelegramEnsureSession(deps) {
34367
34637
  return async (input) => {
34368
34638
  const req = buildTelegramSpawnRequest({
@@ -34396,10 +34666,10 @@ function buildTelegramEnsureSession(deps) {
34396
34666
  return;
34397
34667
  }
34398
34668
  console.error(
34399
- `${TAG56} op=telegram-spawn-door botId=${input.botId} role=public door=rc agent=${input.agentSlug}`
34669
+ `${TAG58} op=telegram-spawn-door botId=${input.botId} role=public door=rc agent=${input.agentSlug}`
34400
34670
  );
34401
34671
  console.error(
34402
- `${TAG56} op=spawn botId=${input.botId} sessionId=${result2.sessionId} targetAccountId=${input.accountId} role=public`
34672
+ `${TAG58} op=spawn botId=${input.botId} sessionId=${result2.sessionId} targetAccountId=${input.accountId} role=public`
34403
34673
  );
34404
34674
  noteSpawnOk2(input.botId);
34405
34675
  return;
@@ -34413,7 +34683,7 @@ function buildTelegramEnsureSession(deps) {
34413
34683
  return;
34414
34684
  }
34415
34685
  console.error(
34416
- `${TAG56} op=spawn botId=${input.botId} sessionId=${req.sessionId} targetAccountId=${input.accountId} role=admin`
34686
+ `${TAG58} op=spawn botId=${input.botId} sessionId=${req.sessionId} targetAccountId=${input.accountId} role=admin`
34417
34687
  );
34418
34688
  noteSpawnOk2(input.botId);
34419
34689
  deps.followers.get(req.channelKey)?.abort();
@@ -34439,7 +34709,7 @@ init_attachments();
34439
34709
  import { realpathSync as realpathSync10 } from "fs";
34440
34710
  import { readFile as readFile14, stat as stat10 } from "fs/promises";
34441
34711
  import { resolve as resolve46, basename as basename16 } from "path";
34442
- var TAG57 = "[telegram:outbound]";
34712
+ var TAG59 = "[telegram:outbound]";
34443
34713
  var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
34444
34714
  async function sendTelegramDocument(input) {
34445
34715
  const { botToken, chatId, filePath, caption, maxyAccountId, platformRoot: platformRoot5 } = input;
@@ -34456,10 +34726,10 @@ async function sendTelegramDocument(input) {
34456
34726
  } catch (err) {
34457
34727
  const code = err.code;
34458
34728
  if (code === "ENOENT") {
34459
- console.error(`${TAG57} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
34729
+ console.error(`${TAG59} document ENOENT scope=account-dir accountDir=${accountDir} maxyAccountId=${maxyAccountId}`);
34460
34730
  return { ok: false, status: 500, error: `Account directory not resolvable for ${maxyAccountId}` };
34461
34731
  }
34462
- console.error(`${TAG57} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
34732
+ console.error(`${TAG59} document path error scope=account-dir maxyAccountId=${maxyAccountId}: ${String(err)}`);
34463
34733
  return { ok: false, status: 500, error: String(err) };
34464
34734
  }
34465
34735
  let resolvedPath;
@@ -34468,14 +34738,14 @@ async function sendTelegramDocument(input) {
34468
34738
  } catch (err) {
34469
34739
  const code = err.code;
34470
34740
  if (code === "ENOENT") {
34471
- console.error(`${TAG57} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
34741
+ console.error(`${TAG59} document ENOENT scope=file path=${filePath} maxyAccountId=${maxyAccountId}`);
34472
34742
  return { ok: false, status: 404, error: `File not found: ${filePath}` };
34473
34743
  }
34474
- console.error(`${TAG57} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
34744
+ console.error(`${TAG59} document path error scope=file maxyAccountId=${maxyAccountId}: ${String(err)}`);
34475
34745
  return { ok: false, status: 500, error: String(err) };
34476
34746
  }
34477
34747
  if (!resolvedPath.startsWith(accountResolved + "/")) {
34478
- console.error(`${TAG57} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
34748
+ console.error(`${TAG59} document REJECTED reason=outside_account_directory maxyAccountId=${maxyAccountId}`);
34479
34749
  return { ok: false, status: 403, error: "Access denied: file is outside the account directory" };
34480
34750
  }
34481
34751
  const fileStat = await stat10(resolvedPath);
@@ -34508,24 +34778,24 @@ async function sendTelegramDocument(input) {
34508
34778
  error = e instanceof Error ? e.message : String(e);
34509
34779
  }
34510
34780
  console.error(
34511
- `${TAG57} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok2}` + (messageId !== void 0 ? ` id=${messageId}` : "")
34781
+ `${TAG59} sent document to=${chatId} file=${filename} bytes=${fileStat.size} ok=${ok2}` + (messageId !== void 0 ? ` id=${messageId}` : "")
34512
34782
  );
34513
34783
  return ok2 ? { ok: true, messageId } : { ok: false, status: 500, error };
34514
34784
  }
34515
34785
 
34516
34786
  // app/lib/telegram/outbound/file-delivery.ts
34517
- var TAG58 = "[telegram:outbound]";
34787
+ var TAG60 = "[telegram:outbound]";
34518
34788
  function platformRoot4() {
34519
34789
  return process.env.MAXY_PLATFORM_ROOT || "";
34520
34790
  }
34521
34791
  function makeTelegramSendFile(entry, botToken) {
34522
34792
  return async (filePath, caption) => {
34523
34793
  if (!botToken) {
34524
- console.error(`${TAG58} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
34794
+ console.error(`${TAG60} file-delivery reject reason=no-bot-token sender=${entry.senderId} role=${entry.role}`);
34525
34795
  return { ok: false, error: "no-bot-token" };
34526
34796
  }
34527
34797
  if (entry.replyTarget == null) {
34528
- console.error(`${TAG58} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
34798
+ console.error(`${TAG60} file-delivery reject reason=no-reply-target sender=${entry.senderId} role=${entry.role}`);
34529
34799
  return { ok: false, error: "no-reply-target" };
34530
34800
  }
34531
34801
  const result = await sendTelegramDocument({
@@ -34542,7 +34812,7 @@ function makeTelegramSendFile(entry, botToken) {
34542
34812
  function makeTelegramFileDelivery(entry, botToken) {
34543
34813
  return makeFileDelivery({
34544
34814
  entry,
34545
- tag: TAG58,
34815
+ tag: TAG60,
34546
34816
  channel: "telegram",
34547
34817
  sendFile: makeTelegramSendFile(entry, botToken)
34548
34818
  });
@@ -34631,7 +34901,7 @@ init_webchat();
34631
34901
  // app/lib/channel-pty-bridge/public-session-end-review.ts
34632
34902
  init_src3();
34633
34903
  import { randomUUID as randomUUID14 } from "crypto";
34634
- var TAG59 = "[public-session-review]";
34904
+ var TAG61 = "[public-session-review]";
34635
34905
  var CONSUMED_CAP = 500;
34636
34906
  var consumed = /* @__PURE__ */ new Set();
34637
34907
  function consumeOnce(sessionId) {
@@ -34658,7 +34928,7 @@ async function fetchJsonl(sessionId) {
34658
34928
  return await res.text();
34659
34929
  } catch (err) {
34660
34930
  console.error(
34661
- `${TAG59} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
34931
+ `${TAG61} jsonl-fetch-failed sessionId=${sessionId} err="${err instanceof Error ? err.message : String(err)}"`
34662
34932
  );
34663
34933
  return null;
34664
34934
  }
@@ -34682,7 +34952,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
34682
34952
  const res = await fetch(url);
34683
34953
  if (!res.ok) {
34684
34954
  console.error(
34685
- `${TAG59} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
34955
+ `${TAG61} prior-writes-fetch-failed sliceToken=${sliceToken.slice(0, 8)} status=${res.status}`
34686
34956
  );
34687
34957
  return [];
34688
34958
  }
@@ -34690,7 +34960,7 @@ async function fetchPriorWrites(sliceToken, accountId) {
34690
34960
  return Array.isArray(body.writes) ? body.writes : [];
34691
34961
  } catch (err) {
34692
34962
  console.error(
34693
- `${TAG59} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
34963
+ `${TAG61} prior-writes-fetch-threw sliceToken=${sliceToken.slice(0, 8)} err="${err instanceof Error ? err.message : String(err)}"`
34694
34964
  );
34695
34965
  return [];
34696
34966
  }
@@ -34719,7 +34989,7 @@ function composeInitialMessage(input) {
34719
34989
  }
34720
34990
  async function dispatchReviewer(input, initialMessage) {
34721
34991
  const sessionId = randomUUID14();
34722
- console.log(`${TAG59} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
34992
+ console.log(`${TAG61} route target=rc-spawn sessionId=${sessionId.slice(0, 8)} sourceSession=${input.sessionId.slice(0, 8)}`);
34723
34993
  const spawned = await managerRcSpawn({
34724
34994
  sessionId,
34725
34995
  initialMessage,
@@ -34743,21 +35013,21 @@ async function firePublicSessionEndReview(input) {
34743
35013
  const dispatchedAt = Date.now();
34744
35014
  if (consumed.has(input.sessionId)) {
34745
35015
  console.log(
34746
- `${TAG59} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
35016
+ `${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
34747
35017
  );
34748
35018
  return;
34749
35019
  }
34750
35020
  const jsonl = await fetchJsonl(input.sessionId);
34751
35021
  if (!jsonl) {
34752
35022
  console.log(
34753
- `${TAG59} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
35023
+ `${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-jsonl-missing`
34754
35024
  );
34755
35025
  return;
34756
35026
  }
34757
35027
  const operatorTurns = countOperatorTurns(jsonl);
34758
35028
  if (operatorTurns === 0) {
34759
35029
  console.log(
34760
- `${TAG59} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
35030
+ `${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-no-turns`
34761
35031
  );
34762
35032
  return;
34763
35033
  }
@@ -34771,19 +35041,19 @@ async function firePublicSessionEndReview(input) {
34771
35041
  });
34772
35042
  if (!consumeOnce(input.sessionId)) {
34773
35043
  console.log(
34774
- `${TAG59} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
35044
+ `${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-already-reviewed`
34775
35045
  );
34776
35046
  return;
34777
35047
  }
34778
35048
  const dispatched = await dispatchReviewer(input, initialMessage);
34779
35049
  if (!dispatched.ok) {
34780
35050
  console.error(
34781
- `${TAG59} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
35051
+ `${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=skipped-spawn-failed reason=${dispatched.reason}`
34782
35052
  );
34783
35053
  return;
34784
35054
  }
34785
35055
  console.log(
34786
- `${TAG59} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
35056
+ `${TAG61} dispatchFor=${input.dispatchFor} sessionId=${input.sessionId} sliceToken=${sliceShort} personId=${personField} result=dispatched managerSessionId=${dispatched.managerSessionId} operatorTurns=${operatorTurns} priorWrites=${priorWrites.length} ms=${Date.now() - dispatchedAt}`
34787
35057
  );
34788
35058
  }
34789
35059
 
@@ -34935,7 +35205,7 @@ init_account();
34935
35205
 
34936
35206
  // server/telegram-audit.ts
34937
35207
  import { statSync as statSync28 } from "fs";
34938
- import { join as join58 } from "path";
35208
+ import { join as join59 } from "path";
34939
35209
  init_channel_key();
34940
35210
  init_sidebar_sessions();
34941
35211
  function buildTelegramAuditLines(input) {
@@ -35001,7 +35271,7 @@ function countTelegramSessionsForAccount(accountId) {
35001
35271
  function* walkTelegramSidecars() {
35002
35272
  const cfg = claudeConfigDir();
35003
35273
  if (!cfg) return;
35004
- const projectsRoot = join58(cfg, "projects");
35274
+ const projectsRoot = join59(cfg, "projects");
35005
35275
  for (const { path } of enumerateSessionSidecars(projectsRoot)) {
35006
35276
  const meta = readSidecarMeta(path);
35007
35277
  if (meta.channel !== "telegram" || !meta.accountId) continue;
@@ -35028,11 +35298,11 @@ function* walkTelegramSidecars() {
35028
35298
 
35029
35299
  // server/telegram-migrate.ts
35030
35300
  import { readFileSync as readFileSync48, writeFileSync as writeFileSync19, existsSync as existsSync51, renameSync as renameSync11, mkdirSync as mkdirSync11 } from "fs";
35031
- import { dirname as dirname18, join as join59 } from "path";
35301
+ import { dirname as dirname18, join as join60 } from "path";
35032
35302
  function migrateTelegramTwoSlot(input) {
35033
35303
  const out = [];
35034
35304
  for (const account of input.accounts) {
35035
- const configPath3 = join59(account.accountDir, "account.json");
35305
+ const configPath3 = join60(account.accountDir, "account.json");
35036
35306
  let config;
35037
35307
  try {
35038
35308
  config = JSON.parse(readFileSync48(configPath3, "utf-8"));
@@ -35429,7 +35699,7 @@ function clientFrom(c) {
35429
35699
  }
35430
35700
  installMediaDownloadGuard();
35431
35701
  var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT || "";
35432
- var BRAND_JSON_PATH = PLATFORM_ROOT6 ? join60(PLATFORM_ROOT6, "config", "brand.json") : "";
35702
+ var BRAND_JSON_PATH = PLATFORM_ROOT6 ? join61(PLATFORM_ROOT6, "config", "brand.json") : "";
35433
35703
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
35434
35704
  if (BRAND_JSON_PATH && !existsSync54(BRAND_JSON_PATH)) {
35435
35705
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
@@ -35468,7 +35738,7 @@ var brandLoginOpts = {
35468
35738
  appleTouchIconPath: brandAppIcon512Path,
35469
35739
  themeColor: BRAND.defaultColors?.primary
35470
35740
  };
35471
- var ALIAS_DOMAINS_PATH = join60(homedir5(), BRAND.configDir, "alias-domains.json");
35741
+ var ALIAS_DOMAINS_PATH = join61(homedir5(), BRAND.configDir, "alias-domains.json");
35472
35742
  function loadAliasDomains() {
35473
35743
  try {
35474
35744
  if (!existsSync54(ALIAS_DOMAINS_PATH)) return null;
@@ -35573,7 +35843,7 @@ var waGateway = new WaGateway({
35573
35843
  deps: adminFanDeps("whatsapp", accountId)
35574
35844
  }),
35575
35845
  gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
35576
- serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve49(process.env.MAXY_PLATFORM_ROOT ?? join60(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
35846
+ serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve49(process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
35577
35847
  // Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
35578
35848
  // path-validation scope) is the sender's effective SESSION account, resolved
35579
35849
  // once at the inbound gate and threaded here via the gateway's per-sender doc
@@ -35588,7 +35858,7 @@ var waGateway = new WaGateway({
35588
35858
  caption,
35589
35859
  accountId,
35590
35860
  maxyAccountId,
35591
- platformRoot: resolve49(process.env.MAXY_PLATFORM_ROOT ?? join60(__dirname, ".."))
35861
+ platformRoot: resolve49(process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, ".."))
35592
35862
  });
35593
35863
  return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
35594
35864
  },
@@ -35755,7 +36025,7 @@ function runDuplicateSenderAudit() {
35755
36025
  try {
35756
36026
  const configDir = process.env.CLAUDE_CONFIG_DIR;
35757
36027
  if (!configDir) return;
35758
- const projectsRoot = join60(configDir, "projects");
36028
+ const projectsRoot = join61(configDir, "projects");
35759
36029
  const records2 = [];
35760
36030
  for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
35761
36031
  if (isSubagent || archived) continue;
@@ -35807,7 +36077,7 @@ var webchatGateway = new WebchatGateway({
35807
36077
  // rather than hanging the POST.
35808
36078
  publicProjectsRoot: () => {
35809
36079
  const cfg = claudeConfigDir();
35810
- return cfg ? join60(cfg, "projects") : "";
36080
+ return cfg ? join61(cfg, "projects") : "";
35811
36081
  },
35812
36082
  gatewayUrl: webchatGatewayUrl(),
35813
36083
  serverPath: webchatServerPath(),
@@ -36481,7 +36751,7 @@ var SW_SOURCE = (() => {
36481
36751
  function readInstalledVersion() {
36482
36752
  try {
36483
36753
  if (!PLATFORM_ROOT6) return "unknown";
36484
- const versionFile = join60(PLATFORM_ROOT6, "config", `.${BRAND.hostname}-version`);
36754
+ const versionFile = join61(PLATFORM_ROOT6, "config", `.${BRAND.hostname}-version`);
36485
36755
  if (!existsSync54(versionFile)) return "unknown";
36486
36756
  const content = readFileSync51(versionFile, "utf-8").trim();
36487
36757
  return content || "unknown";
@@ -36511,12 +36781,12 @@ ${clientErrorReporterScript}
36511
36781
  return html;
36512
36782
  }
36513
36783
  function loadBrandingCache(agentSlug) {
36514
- const configDir = join60(homedir5(), BRAND.configDir);
36784
+ const configDir = join61(homedir5(), BRAND.configDir);
36515
36785
  try {
36516
36786
  const verdict = resolvePublicAddressFromDisk(agentSlug);
36517
36787
  const accountId = verdict.kind === "served" ? verdict.owner.accountId : getDefaultAccountId();
36518
36788
  if (!accountId) return null;
36519
- const cachePath = join60(configDir, "branding-cache", accountId, `${agentSlug}.json`);
36789
+ const cachePath = join61(configDir, "branding-cache", accountId, `${agentSlug}.json`);
36520
36790
  if (!existsSync54(cachePath)) return null;
36521
36791
  return JSON.parse(readFileSync51(cachePath, "utf-8"));
36522
36792
  } catch {
@@ -36766,7 +37036,7 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
36766
37036
  var httpServer = serve({ fetch: app78.fetch, port, hostname });
36767
37037
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
36768
37038
  {
36769
- const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join60(__dirname, "..");
37039
+ const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
36770
37040
  const reconcileScript = resolve49(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
36771
37041
  const runReconcile = (ctx) => {
36772
37042
  if (!existsSync54(reconcileScript)) return;
@@ -36789,7 +37059,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
36789
37059
  detached: true,
36790
37060
  run: runReconcile
36791
37061
  });
36792
- const reconcileStatePath = join60(MAXY_DIR, "booking-reconcile-state.json");
37062
+ const reconcileStatePath = join61(MAXY_DIR, "booking-reconcile-state.json");
36793
37063
  registerLoop({
36794
37064
  name: "calendar-reconcile-liveness",
36795
37065
  intervalMs: 6e5,
@@ -36807,7 +37077,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
36807
37077
  }
36808
37078
  {
36809
37079
  const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
36810
- const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join60(__dirname, "..");
37080
+ const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
36811
37081
  const dreamSweepScript = resolve49(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
36812
37082
  registerLoop({
36813
37083
  name: "dream-cycle-sweep",
@@ -36831,7 +37101,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
36831
37101
  });
36832
37102
  }
36833
37103
  {
36834
- const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join60(__dirname, "..");
37104
+ const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
36835
37105
  const outlookScript = resolve49(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
36836
37106
  const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
36837
37107
  const runOutlookComplete = (ctx) => {
@@ -36857,7 +37127,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
36857
37127
  });
36858
37128
  }
36859
37129
  {
36860
- const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join60(__dirname, "..");
37130
+ const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
36861
37131
  const strandedAccountsDir = resolve49(auditRoot, "..", "data/accounts");
36862
37132
  const STRANDED_AUDIT_INTERVAL_MS = 3e5;
36863
37133
  const STRANDED_AGE_MS = 16 * 6e4;
@@ -36887,7 +37157,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
36887
37157
  });
36888
37158
  }
36889
37159
  {
36890
- const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join60(__dirname, "..");
37160
+ const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
36891
37161
  const googleAccountsDir = resolve49(googleRoot, "..", "data/accounts");
36892
37162
  const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
36893
37163
  const runGooglePendingAuditSafe = () => {
@@ -36931,7 +37201,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
36931
37201
  });
36932
37202
  }
36933
37203
  {
36934
- const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join60(__dirname, "..");
37204
+ const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
36935
37205
  const STORAGE_AUDIT_INTERVAL_MS = 3e5;
36936
37206
  const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
36937
37207
  console.error(`[storage-audit] error="${err.message}"`);
@@ -37133,7 +37403,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
37133
37403
  });
37134
37404
  }
37135
37405
  {
37136
- const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join60(__dirname, "..");
37406
+ const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
37137
37407
  const publishScript = resolve49(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
37138
37408
  const PUBLISH_INTERVAL_MS = 3e5;
37139
37409
  const bookingAccounts = () => {
@@ -37210,7 +37480,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
37210
37480
  startTimeEntryCensus(() => getSession());
37211
37481
  startLedgerCensus(() => getSession());
37212
37482
  {
37213
- const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join60(__dirname, "..");
37483
+ const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..");
37214
37484
  const auditScript = resolve49(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
37215
37485
  const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
37216
37486
  const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
@@ -37422,8 +37692,8 @@ var runIngestAuditTick = () => {
37422
37692
  },
37423
37693
  agentExists: (accountId, slug) => {
37424
37694
  if (!house) return false;
37425
- const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir : join60(ACCOUNTS_DIR, accountId);
37426
- return existsSync54(join60(dir, "agents", slug, "config.json"));
37695
+ const dir = isHouseAccountKey(house.accountId, accountId) ? house.accountDir : join61(ACCOUNTS_DIR, accountId);
37696
+ return existsSync54(join61(dir, "agents", slug, "config.json"));
37427
37697
  }
37428
37698
  });
37429
37699
  } catch (err) {
@@ -37471,7 +37741,7 @@ registerLoop({
37471
37741
  runPublicAddressCollisionAudit({
37472
37742
  houseAccountId: () => resolveAccount()?.accountId ?? null,
37473
37743
  activeSlugs: () => listValidAccounts().map((a) => {
37474
- const agentsRoot = join60(a.accountDir, "agents");
37744
+ const agentsRoot = join61(a.accountDir, "agents");
37475
37745
  if (!existsSync54(agentsRoot)) return { accountId: a.accountId, slugs: [] };
37476
37746
  const slugs = readdirSync32(agentsRoot, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).filter((slug) => isActiveAgentSlug(a.accountDir, slug));
37477
37747
  return { accountId: a.accountId, slugs };
@@ -37655,7 +37925,7 @@ if (bootAccountConfig?.whatsapp) {
37655
37925
  }
37656
37926
  init({
37657
37927
  configDir: configDirForWhatsApp,
37658
- platformRoot: resolve49(process.env.MAXY_PLATFORM_ROOT ?? join60(__dirname, "..")),
37928
+ platformRoot: resolve49(process.env.MAXY_PLATFORM_ROOT ?? join61(__dirname, "..")),
37659
37929
  accountConfig: bootAccountConfig,
37660
37930
  // Task 2074 — enrich with the sub-account name and fan out to every open
37661
37931
  // admin SSE stream. Fire-and-forget: the manager's persist path must not