@rubytech/create-maxy-code 0.1.39 → 0.1.41

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 (132) hide show
  1. package/dist/index.js +35 -101
  2. package/dist/uninstall.js +11 -102
  3. package/package.json +1 -1
  4. package/payload/platform/lib/mcp-stderr-tee/package.json +7 -0
  5. package/payload/platform/plugins/admin/hooks/turn-completed-graph-write.sh +142 -52
  6. package/payload/platform/plugins/docs/references/deployment.md +7 -3
  7. package/payload/platform/plugins/docs/references/platform.md +18 -4
  8. package/payload/platform/plugins/docs/references/plugins-guide.md +2 -0
  9. package/payload/platform/services/claude-session-manager/dist/config.d.ts +17 -0
  10. package/payload/platform/services/claude-session-manager/dist/config.d.ts.map +1 -1
  11. package/payload/platform/services/claude-session-manager/dist/config.js +37 -1
  12. package/payload/platform/services/claude-session-manager/dist/config.js.map +1 -1
  13. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts +54 -0
  14. package/payload/platform/services/claude-session-manager/dist/fs-watcher.d.ts.map +1 -0
  15. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js +516 -0
  16. package/payload/platform/services/claude-session-manager/dist/fs-watcher.js.map +1 -0
  17. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.d.ts +7 -0
  18. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.d.ts.map +1 -0
  19. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.js +90 -0
  20. package/payload/platform/services/claude-session-manager/dist/hooks-discovery.js.map +1 -0
  21. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts +3 -1
  22. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  23. package/payload/platform/services/claude-session-manager/dist/http-server.js +426 -204
  24. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  25. package/payload/platform/services/claude-session-manager/dist/index.js +60 -13
  26. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  27. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts +2 -0
  28. package/payload/platform/services/claude-session-manager/dist/jsonl-path.d.ts.map +1 -1
  29. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js +11 -6
  30. package/payload/platform/services/claude-session-manager/dist/jsonl-path.js.map +1 -1
  31. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +40 -45
  32. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  33. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +146 -162
  34. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  35. package/payload/platform/services/claude-session-manager/dist/reaper.d.ts +24 -0
  36. package/payload/platform/services/claude-session-manager/dist/reaper.d.ts.map +1 -0
  37. package/payload/platform/services/claude-session-manager/dist/reaper.js +114 -0
  38. package/payload/platform/services/claude-session-manager/dist/reaper.js.map +1 -0
  39. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts +16 -41
  40. package/payload/platform/services/claude-session-manager/dist/session-store.d.ts.map +1 -1
  41. package/payload/platform/services/claude-session-manager/dist/session-store.js +29 -68
  42. package/payload/platform/services/claude-session-manager/dist/session-store.js.map +1 -1
  43. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts +54 -0
  44. package/payload/platform/services/claude-session-manager/dist/system-prompt.d.ts.map +1 -1
  45. package/payload/platform/services/claude-session-manager/dist/system-prompt.js +111 -0
  46. package/payload/platform/services/claude-session-manager/dist/system-prompt.js.map +1 -1
  47. package/payload/platform/templates/agents/admin/IDENTITY.md +4 -2
  48. package/payload/platform/templates/agents/admin/SOUL.md +8 -14
  49. package/payload/premium-plugins/real-agent/lib/mcp-stderr-tee/dist/index.d.ts +51 -0
  50. package/payload/premium-plugins/real-agent/lib/mcp-stderr-tee/dist/index.d.ts.map +1 -0
  51. package/payload/premium-plugins/real-agent/lib/mcp-stderr-tee/dist/index.js +196 -0
  52. package/payload/premium-plugins/real-agent/lib/mcp-stderr-tee/dist/index.js.map +1 -0
  53. package/payload/premium-plugins/real-agent/lib/mcp-stderr-tee/package.json +7 -0
  54. package/payload/server/{chunk-NNHHGQJL.js → chunk-4P2MPERV.js} +6 -163
  55. package/payload/server/{chunk-3G6JMV7N.js → chunk-MEGIQYUD.js} +1 -1
  56. package/payload/server/{chunk-QC5LHYPH.js → chunk-XJVJ2B2Q.js} +1 -1
  57. package/payload/server/{cloudflare-task-tracker-NEB3X6O2.js → cloudflare-task-tracker-R6MMORFU.js} +2 -2
  58. package/payload/server/maxy-edge.js +2 -2
  59. package/payload/server/public/assets/{Checkbox-CmCjmfJy.js → Checkbox-blxv2XPY.js} +1 -1
  60. package/payload/server/public/assets/{admin-CtodW6As.js → admin-C3EvHpLN.js} +1 -1
  61. package/payload/server/public/assets/{architectureDiagram-Q4EWVU46-CfOjbx0H.js → architectureDiagram-Q4EWVU46-bETsVzGS.js} +1 -1
  62. package/payload/server/public/assets/{blockDiagram-DXYQGD6D-D0kA2C9i.js → blockDiagram-DXYQGD6D-5y0GBnfQ.js} +1 -1
  63. package/payload/server/public/assets/{brand-6hKfBgOI.css → brand-DQlLKLDH.css} +1 -1
  64. package/payload/server/public/assets/{c4Diagram-AHTNJAMY-CDgXiXgj.js → c4Diagram-AHTNJAMY-C1znpVGu.js} +1 -1
  65. package/payload/server/public/assets/channel-BWqTaXzb.js +1 -0
  66. package/payload/server/public/assets/{chunk-336JU56O-BfBTcT5X.js → chunk-336JU56O-DlCVUGzQ.js} +2 -2
  67. package/payload/server/public/assets/{chunk-426QAEUC-BdSSZ1Kw.js → chunk-426QAEUC-bGYkmA4z.js} +1 -1
  68. package/payload/server/public/assets/{chunk-4TB4RGXK-UvE1im9g.js → chunk-4TB4RGXK-6Sb0Undm.js} +1 -1
  69. package/payload/server/public/assets/{chunk-5FUZZQ4R-Dx4DslXz.js → chunk-5FUZZQ4R-CAT_Pq2T.js} +1 -1
  70. package/payload/server/public/assets/{chunk-5PVQY5BW-CNHawhLJ.js → chunk-5PVQY5BW-j231ESse.js} +1 -1
  71. package/payload/server/public/assets/{chunk-EDXVE4YY-Rmjv-1et.js → chunk-EDXVE4YY-BAlS4QL7.js} +1 -1
  72. package/payload/server/public/assets/{chunk-ENJZ2VHE-CL-LeH3r.js → chunk-ENJZ2VHE-D3Ku_BMP.js} +1 -1
  73. package/payload/server/public/assets/{chunk-ICPOFSXX-B2MFOJDt.js → chunk-ICPOFSXX-AR86A5WB.js} +1 -1
  74. package/payload/server/public/assets/{chunk-OYMX7WX6-BxcIcCt5.js → chunk-OYMX7WX6-DxGhapkW.js} +1 -1
  75. package/payload/server/public/assets/{chunk-U2HBQHQK-COzwOBrY.js → chunk-U2HBQHQK-DAlqsDo_.js} +1 -1
  76. package/payload/server/public/assets/{chunk-X2U36JSP-B0rjT5hL.js → chunk-X2U36JSP-lZdkkdyB.js} +1 -1
  77. package/payload/server/public/assets/{chunk-YZCP3GAM-pwrIw0XH.js → chunk-YZCP3GAM-CCjtXOFD.js} +1 -1
  78. package/payload/server/public/assets/{chunk-ZZ45TVLE-BXpeAm0k.js → chunk-ZZ45TVLE-ComtdKny.js} +1 -1
  79. package/payload/server/public/assets/classDiagram-6PBFFD2Q-B9hC6fOR.js +1 -0
  80. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-afl_ydIG.js +1 -0
  81. package/payload/server/public/assets/clone-Lj83OaZ3.js +1 -0
  82. package/payload/server/public/assets/{dagre-DjOJn05k.js → dagre-DX8QJeVt.js} +1 -1
  83. package/payload/server/public/assets/{dagre-KV5264BT-PczvQiEh.js → dagre-KV5264BT-BcRbiZ1q.js} +1 -1
  84. package/payload/server/public/assets/data-CS_R5VWQ.js +1 -0
  85. package/payload/server/public/assets/{device-url-actions-C55ZS_Zg.js → device-url-actions-Cag9IJ7n.js} +1 -1
  86. package/payload/server/public/assets/{diagram-5BDNPKRD-D477xo5F.js → diagram-5BDNPKRD-Bw47VwHO.js} +1 -1
  87. package/payload/server/public/assets/{diagram-G4DWMVQ6-C-HAtbtT.js → diagram-G4DWMVQ6-B-aVfhiD.js} +1 -1
  88. package/payload/server/public/assets/{diagram-MMDJMWI5-B9wus4H0.js → diagram-MMDJMWI5-DERz2dKo.js} +1 -1
  89. package/payload/server/public/assets/{diagram-TYMM5635-UMZLloFr.js → diagram-TYMM5635-B7eEX9Ta.js} +1 -1
  90. package/payload/server/public/assets/{erDiagram-SMLLAGMA-B8E52Mp4.js → erDiagram-SMLLAGMA-G_JJq3zB.js} +1 -1
  91. package/payload/server/public/assets/{flowDiagram-DWJPFMVM-CUel34tq.js → flowDiagram-DWJPFMVM-BeY9QaO0.js} +1 -1
  92. package/payload/server/public/assets/{ganttDiagram-T4ZO3ILL-BfwE-Xav.js → ganttDiagram-T4ZO3ILL-IXviGYnx.js} +1 -1
  93. package/payload/server/public/assets/{gitGraphDiagram-UUTBAWPF-2d6tXRIM.js → gitGraphDiagram-UUTBAWPF-GlY6pZQ1.js} +1 -1
  94. package/payload/server/public/assets/graph-DtGkQBFr.js +1 -0
  95. package/payload/server/public/assets/graph-labels-Dwu1ON5v.js +1 -0
  96. package/payload/server/public/assets/{graphlib-CCo9-wNJ.js → graphlib-BWgAjZSb.js} +1 -1
  97. package/payload/server/public/assets/{infoDiagram-42DDH7IO-DB1SVWL6.js → infoDiagram-42DDH7IO-D4YZM0gD.js} +1 -1
  98. package/payload/server/public/assets/{ishikawaDiagram-UXIWVN3A-CdeMUTYS.js → ishikawaDiagram-UXIWVN3A-fR71GDOp.js} +1 -1
  99. package/payload/server/public/assets/{journeyDiagram-VCZTEJTY-D8x8TUoc.js → journeyDiagram-VCZTEJTY-C1TcY_6m.js} +1 -1
  100. package/payload/server/public/assets/{kanban-definition-6JOO6SKY-Cmkhd1mO.js → kanban-definition-6JOO6SKY-IPZKpnnG.js} +1 -1
  101. package/payload/server/public/assets/{line-CoHkpBv3.js → line-B2JtEL1B.js} +1 -1
  102. package/payload/server/public/assets/{mermaid-parser.core-C7R2PfZC.js → mermaid-parser.core-BKCLXqUh.js} +1 -1
  103. package/payload/server/public/assets/{mermaid.core-lQaq-kll.js → mermaid.core-CmNpCLB-.js} +3 -3
  104. package/payload/server/public/assets/{mindmap-definition-QFDTVHPH-CsPq3pX1.js → mindmap-definition-QFDTVHPH-BS0E2FPD.js} +1 -1
  105. package/payload/server/public/assets/{page-DwEaAdVp.js → page-BdI3GCun.js} +1 -1
  106. package/payload/server/public/assets/{page-CBKzjUHO.js → page-zIjAkU2y.js} +1 -1
  107. package/payload/server/public/assets/{pieDiagram-DEJITSTG-FZH9sTnP.js → pieDiagram-DEJITSTG-J61JDyk8.js} +1 -1
  108. package/payload/server/public/assets/{public-hGLzxhE_.js → public-C5vaQnC_.js} +4 -4
  109. package/payload/server/public/assets/{quadrantDiagram-34T5L4WZ-9poxfoqh.js → quadrantDiagram-34T5L4WZ-CLI03OtR.js} +1 -1
  110. package/payload/server/public/assets/{requirementDiagram-MS252O5E-Ce7iOdT_.js → requirementDiagram-MS252O5E-C8MCt5NO.js} +1 -1
  111. package/payload/server/public/assets/{sankeyDiagram-XADWPNL6-DINuXatI.js → sankeyDiagram-XADWPNL6-DQuugruj.js} +1 -1
  112. package/payload/server/public/assets/{sequenceDiagram-FGHM5R23-CSMec3EK.js → sequenceDiagram-FGHM5R23-CoYitwhO.js} +1 -1
  113. package/payload/server/public/assets/{stateDiagram-FHFEXIEX-15DKzypj.js → stateDiagram-FHFEXIEX-G68cHHoI.js} +1 -1
  114. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-Dtgpgr_D.js +1 -0
  115. package/payload/server/public/assets/{timeline-definition-GMOUNBTQ-BxIRc9Pu.js → timeline-definition-GMOUNBTQ-CelLeJVS.js} +1 -1
  116. package/payload/server/public/assets/{vennDiagram-DHZGUBPP-DdgRyU55.js → vennDiagram-DHZGUBPP-BVgFPkJq.js} +1 -1
  117. package/payload/server/public/assets/{wardleyDiagram-NUSXRM2D-CKvhU1Uj.js → wardleyDiagram-NUSXRM2D-CzD_8hl2.js} +1 -1
  118. package/payload/server/public/assets/{xychartDiagram-5P7HB3ND-d0V1V4PD.js → xychartDiagram-5P7HB3ND-BuTxWdX5.js} +1 -1
  119. package/payload/server/public/data.html +5 -5
  120. package/payload/server/public/graph.html +6 -6
  121. package/payload/server/public/index.html +8 -8
  122. package/payload/server/public/public.html +5 -5
  123. package/payload/server/server.js +1058 -846
  124. package/payload/server/public/assets/channel-DA7MGMzQ.js +0 -1
  125. package/payload/server/public/assets/classDiagram-6PBFFD2Q-DqfmcWSr.js +0 -1
  126. package/payload/server/public/assets/classDiagram-v2-HSJHXN6E-BVOMSbZ_.js +0 -1
  127. package/payload/server/public/assets/clone-Byp7hagU.js +0 -1
  128. package/payload/server/public/assets/data-A7azIkZU.js +0 -1
  129. package/payload/server/public/assets/graph-Dx83EhtP.js +0 -1
  130. package/payload/server/public/assets/graph-labels-Bg2Bzelb.js +0 -1
  131. package/payload/server/public/assets/stateDiagram-v2-QKLJ7IA2-AcaK_QfD.js +0 -1
  132. /package/payload/server/public/assets/{brand-DXOx08r0.js → brand-D6mXeyxV.js} +0 -0
@@ -60,7 +60,7 @@ import {
60
60
  vncLog,
61
61
  waitForExit,
62
62
  walkPremiumBundles
63
- } from "./chunk-3G6JMV7N.js";
63
+ } from "./chunk-MEGIQYUD.js";
64
64
  import {
65
65
  CLOUDFLARE_TASK_DIAGNOSTICS,
66
66
  appendCloudflareSteps,
@@ -69,7 +69,7 @@ import {
69
69
  openCloudflareTask,
70
70
  readTunnelState,
71
71
  resolveUnitGoneVerdict
72
- } from "./chunk-QC5LHYPH.js";
72
+ } from "./chunk-XJVJ2B2Q.js";
73
73
  import {
74
74
  GREETING_DIRECTIVE,
75
75
  HAIKU_MODEL,
@@ -93,7 +93,7 @@ import {
93
93
  verifyAndGetConversationUpdatedAt,
94
94
  verifyConversationOwnership,
95
95
  writeAdminUserAndPerson
96
- } from "./chunk-NNHHGQJL.js";
96
+ } from "./chunk-4P2MPERV.js";
97
97
  import {
98
98
  __commonJS,
99
99
  __toESM
@@ -596,14 +596,14 @@ var serveStatic = (options = { root: "" }) => {
596
596
 
597
597
  // server/index.ts
598
598
  import { readFileSync as readFileSync20, existsSync as existsSync22, watchFile } from "fs";
599
- import { resolve as resolve23, join as join12, basename as basename5 } from "path";
599
+ import { resolve as resolve23, join as join13, basename as basename5 } from "path";
600
600
  import { homedir as homedir4 } from "os";
601
601
 
602
602
  // app/lib/agent-slug-pattern.ts
603
603
  var AGENT_SLUG_PATTERN = /^\/([a-z][a-z0-9-]{2,49})$/;
604
604
 
605
605
  // server/routes/health.ts
606
- import { existsSync as existsSync3, readFileSync as readFileSync5 } from "fs";
606
+ import { existsSync as existsSync2, readFileSync as readFileSync4 } from "fs";
607
607
  import { createConnection as createConnection2 } from "net";
608
608
 
609
609
  // app/lib/claude-auth.ts
@@ -863,617 +863,254 @@ var WhatsAppConfigSchema = z.object({
863
863
  });
864
864
  });
865
865
 
866
- // app/lib/whatsapp/config-persist.ts
867
- import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, existsSync as existsSync2 } from "fs";
868
- import { resolve, join as join2 } from "path";
869
- var TAG = "[whatsapp:config]";
870
- function configPath(accountDir) {
871
- return resolve(accountDir, "account.json");
866
+ // app/lib/whatsapp/auth-store.ts
867
+ import fsSync from "fs";
868
+ import fs from "fs/promises";
869
+ import path from "path";
870
+ import os from "os";
871
+ var TAG = "[whatsapp:auth]";
872
+ function resolveAuthDir(configDir2, accountId) {
873
+ return path.join(os.homedir(), configDir2, "credentials", "whatsapp", accountId);
872
874
  }
873
- function readConfig(accountDir) {
874
- const path2 = configPath(accountDir);
875
- if (!existsSync2(path2)) throw new Error(`account.json not found at ${path2}`);
876
- return JSON.parse(readFileSync2(path2, "utf-8"));
875
+ function resolveCredsPath(authDir) {
876
+ return path.join(authDir, "creds.json");
877
877
  }
878
- function writeConfig(accountDir, config) {
879
- const path2 = configPath(accountDir);
880
- writeFileSync2(path2, JSON.stringify(config, null, 2) + "\n", "utf-8");
878
+ function resolveCredsBackupPath(authDir) {
879
+ return path.join(authDir, "creds.json.bak");
881
880
  }
882
- function reloadManagerConfig(accountDir) {
881
+ function hasCredsSync(authDir) {
883
882
  try {
884
- const config = readConfig(accountDir);
885
- reloadConfig(config);
886
- console.error(`${TAG} reloaded manager config`);
887
- } catch (err) {
888
- console.error(`${TAG} manager config reload failed: ${String(err)}`);
883
+ const stats = fsSync.statSync(resolveCredsPath(authDir));
884
+ return stats.isFile() && stats.size > 1;
885
+ } catch {
886
+ return false;
889
887
  }
890
888
  }
891
- var E164_PATTERN = /^\+\d{7,15}$/;
892
- function migrateAdminPhones(wa) {
893
- if (wa.adminPhones !== void 0) return 0;
894
- if (!Array.isArray(wa.allowFrom)) return 0;
895
- const allowFrom = wa.allowFrom;
896
- const phones = [];
897
- const remaining = [];
898
- for (const entry of allowFrom) {
899
- if (E164_PATTERN.test(entry)) {
900
- phones.push(entry);
901
- } else {
902
- remaining.push(entry);
903
- }
889
+ async function authExists(authDir) {
890
+ const credsPath = resolveCredsPath(authDir);
891
+ try {
892
+ await fs.access(authDir);
893
+ } catch {
894
+ return false;
904
895
  }
905
- if (phones.length === 0) return 0;
906
- wa.adminPhones = phones;
907
- wa.allowFrom = remaining;
908
- console.error(`${TAG} migrated ${phones.length} phone(s) from allowFrom to adminPhones`);
909
- return phones.length;
910
- }
911
- function persistAfterPairing(accountDir, accountId, selfPhone) {
912
896
  try {
913
- const config = readConfig(accountDir);
914
- if (!config.whatsapp || typeof config.whatsapp !== "object") {
915
- config.whatsapp = {};
916
- }
917
- const wa = config.whatsapp;
918
- if (!wa.accounts || typeof wa.accounts !== "object") {
919
- wa.accounts = {};
920
- }
921
- const accounts = wa.accounts;
922
- if (!accounts[accountId] || typeof accounts[accountId] !== "object") {
923
- accounts[accountId] = { name: "Main" };
924
- }
925
- if (selfPhone) {
926
- const normalized = selfPhone.startsWith("+") ? selfPhone : `+${selfPhone}`;
927
- if (!Array.isArray(wa.adminPhones)) {
928
- wa.adminPhones = [];
929
- }
930
- const adminPhones = wa.adminPhones;
931
- if (!adminPhones.includes(normalized)) {
932
- adminPhones.push(normalized);
933
- console.error(`${TAG} added selfPhone=${normalized} to adminPhones`);
934
- }
935
- } else {
936
- console.error(`${TAG} skipping adminPhones \u2014 selfPhone is null account=${accountId}`);
937
- }
938
- const parsed = WhatsAppConfigSchema.safeParse(wa);
939
- if (!parsed.success) {
940
- const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
941
- console.error(`${TAG} validation failed after pairing: ${msg}`);
942
- return { ok: false, error: `Validation failed: ${msg}` };
943
- }
944
- config.whatsapp = parsed.data;
945
- writeConfig(accountDir, config);
946
- console.error(`${TAG} persisted after pairing account=${accountId} phone=${selfPhone ?? "null"}`);
947
- reloadManagerConfig(accountDir);
948
- return { ok: true };
897
+ const stats = await fs.stat(credsPath);
898
+ if (!stats.isFile() || stats.size <= 1) return false;
899
+ const raw = await fs.readFile(credsPath, "utf-8");
900
+ JSON.parse(raw);
901
+ return true;
949
902
  } catch (err) {
950
- const msg = err instanceof Error ? err.message : String(err);
951
- console.error(`${TAG} persist failed account=${accountId}: ${msg}`);
952
- return { ok: false, error: msg };
903
+ console.warn(`${TAG} credential validation failed path=${credsPath}: ${String(err)}`);
904
+ return false;
953
905
  }
954
906
  }
955
- function addAdminPhone(accountDir, phone) {
956
- const normalized = phone.trim();
957
- if (!E164_PATTERN.test(normalized)) {
958
- return { ok: false, error: `Invalid phone format "${normalized}". Expected E.164 (e.g. +441234567890).` };
907
+ function readCredsJsonRaw(filePath) {
908
+ try {
909
+ if (!fsSync.existsSync(filePath)) return null;
910
+ const stats = fsSync.statSync(filePath);
911
+ if (!stats.isFile() || stats.size <= 1) return null;
912
+ return fsSync.readFileSync(filePath, "utf-8");
913
+ } catch {
914
+ return null;
959
915
  }
916
+ }
917
+ function maybeRestoreCredsFromBackup(authDir) {
960
918
  try {
961
- const config = readConfig(accountDir);
962
- if (!config.whatsapp || typeof config.whatsapp !== "object") {
963
- config.whatsapp = {};
964
- }
965
- const wa = config.whatsapp;
966
- migrateAdminPhones(wa);
967
- if (!Array.isArray(wa.adminPhones)) {
968
- wa.adminPhones = [];
969
- }
970
- const adminPhones = wa.adminPhones;
971
- if (adminPhones.includes(normalized)) {
972
- return { ok: true, message: `Phone ${normalized} is already in the admin list.` };
973
- }
974
- adminPhones.push(normalized);
975
- const parsed = WhatsAppConfigSchema.safeParse(wa);
976
- if (!parsed.success) {
977
- const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
978
- return { ok: false, error: `Validation failed: ${msg}` };
919
+ const credsPath = resolveCredsPath(authDir);
920
+ const backupPath = resolveCredsBackupPath(authDir);
921
+ const raw = readCredsJsonRaw(credsPath);
922
+ if (raw) {
923
+ JSON.parse(raw);
924
+ return;
979
925
  }
980
- config.whatsapp = parsed.data;
981
- writeConfig(accountDir, config);
982
- console.error(`${TAG} added admin phone=${normalized}`);
983
- reloadManagerConfig(accountDir);
984
- return { ok: true, message: `Added ${normalized} as admin phone. Messages from this number will route to the admin agent.` };
926
+ const backupRaw = readCredsJsonRaw(backupPath);
927
+ if (!backupRaw) return;
928
+ JSON.parse(backupRaw);
929
+ fsSync.copyFileSync(backupPath, credsPath);
930
+ console.error(`${TAG} restored corrupted creds.json from backup in ${authDir}`);
985
931
  } catch (err) {
986
- const msg = err instanceof Error ? err.message : String(err);
987
- console.error(`${TAG} addAdminPhone failed: ${msg}`);
988
- return { ok: false, error: msg };
932
+ console.warn(`${TAG} credential restore failed authDir=${authDir}: ${String(err)}`);
989
933
  }
990
934
  }
991
- function removeAdminPhone(accountDir, phone) {
992
- const normalized = phone.trim();
935
+ function readSelfId(authDir) {
993
936
  try {
994
- const config = readConfig(accountDir);
995
- if (!config.whatsapp || typeof config.whatsapp !== "object") {
996
- return { ok: true, message: `No WhatsApp config exists \u2014 nothing to remove.` };
997
- }
998
- const wa = config.whatsapp;
999
- migrateAdminPhones(wa);
1000
- if (!Array.isArray(wa.adminPhones)) {
1001
- return { ok: true, message: `No admin phones configured \u2014 nothing to remove.` };
1002
- }
1003
- const adminPhones = wa.adminPhones;
1004
- const idx = adminPhones.indexOf(normalized);
1005
- if (idx === -1) {
1006
- return { ok: true, message: `Phone ${normalized} is not in the admin list.` };
937
+ const credsPath = resolveCredsPath(authDir);
938
+ if (!fsSync.existsSync(credsPath)) return { e164: null, jid: null, lid: null };
939
+ const raw = fsSync.readFileSync(credsPath, "utf-8");
940
+ const parsed = JSON.parse(raw);
941
+ const jid = parsed?.me?.id ?? null;
942
+ const lidRaw = parsed?.me?.lid ?? null;
943
+ let e164 = null;
944
+ if (jid) {
945
+ const match = jid.match(/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i);
946
+ if (match) e164 = match[1];
1007
947
  }
1008
- adminPhones.splice(idx, 1);
1009
- const parsed = WhatsAppConfigSchema.safeParse(wa);
1010
- if (!parsed.success) {
1011
- const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
1012
- return { ok: false, error: `Validation failed: ${msg}` };
948
+ let lid = null;
949
+ if (lidRaw) {
950
+ const lidMatch = lidRaw.match(/^(\d+)(?::\d+)?@lid$/i);
951
+ if (lidMatch) lid = `${lidMatch[1]}@lid`;
1013
952
  }
1014
- config.whatsapp = parsed.data;
1015
- writeConfig(accountDir, config);
1016
- console.error(`${TAG} removed admin phone=${normalized}`);
1017
- reloadManagerConfig(accountDir);
1018
- return { ok: true, message: `Removed ${normalized} from admin phones. Messages from this number will now route to the public agent.` };
953
+ return { e164, jid, lid };
1019
954
  } catch (err) {
1020
- const msg = err instanceof Error ? err.message : String(err);
1021
- console.error(`${TAG} removeAdminPhone failed: ${msg}`);
1022
- return { ok: false, error: msg };
955
+ console.warn(`${TAG} readSelfId failed authDir=${authDir}: ${String(err)}`);
956
+ return { e164: null, jid: null, lid: null };
1023
957
  }
1024
958
  }
1025
- function readAdminPhones(accountDir) {
959
+ async function clearAuth(authDir) {
1026
960
  try {
1027
- const config = readConfig(accountDir);
1028
- const wa = config.whatsapp;
1029
- if (!wa) return [];
1030
- const migrated = migrateAdminPhones(wa);
1031
- if (migrated > 0) {
1032
- const parsed = WhatsAppConfigSchema.safeParse(wa);
1033
- if (parsed.success) {
1034
- config.whatsapp = parsed.data;
1035
- writeConfig(accountDir, config);
1036
- reloadManagerConfig(accountDir);
1037
- }
1038
- }
1039
- if (!Array.isArray(wa.adminPhones)) return [];
1040
- return wa.adminPhones.filter((p) => typeof p === "string");
961
+ await fs.access(authDir);
1041
962
  } catch {
1042
- return [];
963
+ console.error(`${TAG} no auth dir found at ${authDir}`);
964
+ return false;
1043
965
  }
966
+ await fs.rm(authDir, { recursive: true, force: true });
967
+ console.error(`${TAG} cleared credentials at ${authDir}`);
968
+ return true;
1044
969
  }
1045
- function setPublicAgent(accountDir, slug) {
1046
- const trimmed = slug.trim();
1047
- if (!trimmed) {
1048
- return { ok: false, error: "Agent slug cannot be empty." };
970
+ function listCredentialAccountIds(configDir2) {
971
+ const credsRoot = path.join(os.homedir(), configDir2, "credentials", "whatsapp");
972
+ try {
973
+ const entries = fsSync.readdirSync(credsRoot, { withFileTypes: true });
974
+ return entries.filter((e) => e.isDirectory() && hasCredsSync(path.join(credsRoot, e.name))).map((e) => e.name);
975
+ } catch {
976
+ return [];
1049
977
  }
1050
- const agentConfigPath = join2(accountDir, "agents", trimmed, "config.json");
1051
- if (!existsSync2(agentConfigPath)) {
1052
- return { ok: false, error: `Agent "${trimmed}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.` };
978
+ }
979
+
980
+ // app/lib/whatsapp/session.ts
981
+ import { randomUUID } from "crypto";
982
+ import fsSync2 from "fs";
983
+ import fs2 from "fs/promises";
984
+ import { inspect } from "util";
985
+ import {
986
+ Browsers,
987
+ DisconnectReason,
988
+ fetchLatestBaileysVersion,
989
+ makeCacheableSignalKeyStore,
990
+ makeWASocket,
991
+ useMultiFileAuthState
992
+ } from "@whiskeysockets/baileys";
993
+ import { createRequire } from "module";
994
+ var TAG2 = "[whatsapp:session]";
995
+ var baileysPkgVersion = (() => {
996
+ try {
997
+ const req = createRequire(import.meta.url);
998
+ return req("@whiskeysockets/baileys/package.json").version ?? "unknown";
999
+ } catch {
1000
+ return "unknown";
1053
1001
  }
1002
+ })();
1003
+ console.error(`${TAG2} baileys package loaded version=${baileysPkgVersion}`);
1004
+ var __BAILEYS_TAG = "[whatsapp:baileys]";
1005
+ var INSPECT_OPTS = {
1006
+ depth: null,
1007
+ breakLength: Infinity,
1008
+ compact: true,
1009
+ maxArrayLength: 100,
1010
+ maxStringLength: 1e4
1011
+ };
1012
+ function serializeArg(arg) {
1013
+ if (typeof arg === "string") return arg;
1054
1014
  try {
1055
- const config = readConfig(accountDir);
1056
- if (!config.whatsapp || typeof config.whatsapp !== "object") {
1057
- config.whatsapp = {};
1058
- }
1059
- const wa = config.whatsapp;
1060
- wa.publicAgent = trimmed;
1061
- const parsed = WhatsAppConfigSchema.safeParse(wa);
1062
- if (!parsed.success) {
1063
- const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
1064
- return { ok: false, error: `Validation failed: ${msg}` };
1065
- }
1066
- config.whatsapp = parsed.data;
1067
- writeConfig(accountDir, config);
1068
- console.error(`${TAG} publicAgent set to ${trimmed}`);
1069
- reloadManagerConfig(accountDir);
1070
- return { ok: true, message: `Public agent set to "${trimmed}". WhatsApp messages from non-admin phones will be handled by this agent.` };
1015
+ return inspect(arg, INSPECT_OPTS);
1071
1016
  } catch (err) {
1072
- const msg = err instanceof Error ? err.message : String(err);
1073
- console.error(`${TAG} setPublicAgent failed: ${msg}`);
1074
- return { ok: false, error: msg };
1017
+ return `[inspect-failed: ${String(err)}]`;
1075
1018
  }
1076
1019
  }
1077
- function resolvePublicAgent(accountDir, opts) {
1078
- try {
1079
- const config = readConfig(accountDir);
1080
- const wa = config.whatsapp;
1081
- if (!wa) return null;
1082
- if (opts.groupJid) {
1083
- const accounts2 = wa.accounts;
1084
- const account2 = accounts2?.[opts.accountId];
1085
- const groups = account2?.groups;
1086
- const group = groups?.[opts.groupJid];
1087
- const groupSlug = group?.publicAgent;
1088
- if (typeof groupSlug === "string" && groupSlug.trim()) {
1089
- return { slug: groupSlug.trim(), source: "group" };
1090
- }
1091
- }
1092
- const accounts = wa.accounts;
1093
- const account = accounts?.[opts.accountId];
1094
- const accountSlug = account?.publicAgent;
1095
- if (typeof accountSlug === "string" && accountSlug.trim()) {
1096
- return { slug: accountSlug.trim(), source: "account" };
1097
- }
1098
- const topSlug = wa.publicAgent;
1099
- if (typeof topSlug === "string" && topSlug.trim()) {
1100
- return { slug: topSlug.trim(), source: "top-level" };
1101
- }
1102
- return null;
1103
- } catch {
1104
- return null;
1105
- }
1106
- }
1107
- function setGroupPublicAgent(accountDir, accountId, groupJid, slug) {
1108
- const trimmedSlug = slug.trim();
1109
- const trimmedGroup = groupJid.trim();
1110
- const trimmedAccount = accountId.trim();
1111
- if (!trimmedSlug) return { ok: false, error: "Agent slug cannot be empty." };
1112
- if (!trimmedGroup) return { ok: false, error: "Group JID cannot be empty." };
1113
- if (!trimmedAccount) return { ok: false, error: "Account ID cannot be empty." };
1114
- const agentConfigPath = join2(accountDir, "agents", trimmedSlug, "config.json");
1115
- if (!existsSync2(agentConfigPath)) {
1116
- return { ok: false, error: `Agent "${trimmedSlug}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.` };
1117
- }
1118
- try {
1119
- const config = readConfig(accountDir);
1120
- if (!config.whatsapp || typeof config.whatsapp !== "object") config.whatsapp = {};
1121
- const wa = config.whatsapp;
1122
- if (!wa.accounts || typeof wa.accounts !== "object") wa.accounts = {};
1123
- const accounts = wa.accounts;
1124
- if (!accounts[trimmedAccount] || typeof accounts[trimmedAccount] !== "object") accounts[trimmedAccount] = {};
1125
- const account = accounts[trimmedAccount];
1126
- if (!account.groups || typeof account.groups !== "object") account.groups = {};
1127
- const groups = account.groups;
1128
- const existing = groups[trimmedGroup] && typeof groups[trimmedGroup] === "object" ? groups[trimmedGroup] : {};
1129
- groups[trimmedGroup] = { ...existing, publicAgent: trimmedSlug };
1130
- const parsed = WhatsAppConfigSchema.safeParse(wa);
1131
- if (!parsed.success) {
1132
- const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
1133
- return { ok: false, error: `Validation failed: ${msg}` };
1134
- }
1135
- config.whatsapp = parsed.data;
1136
- writeConfig(accountDir, config);
1137
- console.error(`${TAG} setGroupPublicAgent account=${trimmedAccount} groupJid=${trimmedGroup} slug=${trimmedSlug}`);
1138
- reloadManagerConfig(accountDir);
1139
- return { ok: true, message: `Per-group public agent set to "${trimmedSlug}" for group ${trimmedGroup}.` };
1140
- } catch (err) {
1141
- const msg = err instanceof Error ? err.message : String(err);
1142
- console.error(`${TAG} setGroupPublicAgent failed: ${msg}`);
1143
- return { ok: false, error: msg };
1144
- }
1145
- }
1146
- function unsetGroupPublicAgent(accountDir, accountId, groupJid) {
1147
- const trimmedGroup = groupJid.trim();
1148
- const trimmedAccount = accountId.trim();
1149
- if (!trimmedGroup) return { ok: false, error: "Group JID cannot be empty." };
1150
- if (!trimmedAccount) return { ok: false, error: "Account ID cannot be empty." };
1151
- try {
1152
- const config = readConfig(accountDir);
1153
- const wa = config.whatsapp ?? {};
1154
- const accounts = wa.accounts;
1155
- const account = accounts?.[trimmedAccount];
1156
- const groups = account?.groups;
1157
- const group = groups?.[trimmedGroup];
1158
- if (!group || typeof group.publicAgent !== "string") {
1159
- return { ok: true, message: `No per-group publicAgent override for group ${trimmedGroup}; nothing to remove.` };
1160
- }
1161
- delete group.publicAgent;
1162
- const parsed = WhatsAppConfigSchema.safeParse(wa);
1163
- if (!parsed.success) {
1164
- const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
1165
- return { ok: false, error: `Validation failed: ${msg}` };
1166
- }
1167
- config.whatsapp = parsed.data;
1168
- writeConfig(accountDir, config);
1169
- console.error(`${TAG} unsetGroupPublicAgent account=${trimmedAccount} groupJid=${trimmedGroup}`);
1170
- reloadManagerConfig(accountDir);
1171
- return { ok: true, message: `Per-group public agent override removed for group ${trimmedGroup}.` };
1172
- } catch (err) {
1173
- const msg = err instanceof Error ? err.message : String(err);
1174
- console.error(`${TAG} unsetGroupPublicAgent failed: ${msg}`);
1175
- return { ok: false, error: msg };
1176
- }
1177
- }
1178
- function updateConfig(accountDir, fields) {
1179
- const fieldNames = Object.keys(fields);
1180
- if (fieldNames.length === 0) {
1181
- return { ok: false, error: "No fields provided to update." };
1182
- }
1183
- try {
1184
- const config = readConfig(accountDir);
1185
- if (!config.whatsapp || typeof config.whatsapp !== "object") {
1186
- config.whatsapp = {};
1187
- }
1188
- const wa = config.whatsapp;
1189
- migrateAdminPhones(wa);
1190
- for (const [key, value] of Object.entries(fields)) {
1191
- wa[key] = value;
1192
- }
1193
- const parsed = WhatsAppConfigSchema.safeParse(wa);
1194
- if (!parsed.success) {
1195
- const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
1196
- console.error(`${TAG} update validation failed: ${msg}`);
1197
- return { ok: false, error: `Validation failed: ${msg}` };
1198
- }
1199
- config.whatsapp = parsed.data;
1200
- writeConfig(accountDir, config);
1201
- console.error(`${TAG} updated fields=[${fieldNames.join(",")}]`);
1202
- reloadManagerConfig(accountDir);
1203
- return { ok: true, message: `Updated WhatsApp config: ${fieldNames.join(", ")}.` };
1204
- } catch (err) {
1205
- const msg = err instanceof Error ? err.message : String(err);
1206
- console.error(`${TAG} updateConfig failed: ${msg}`);
1207
- return { ok: false, error: msg };
1020
+ function bindingsToPrefix(bindings) {
1021
+ const parts = [];
1022
+ for (const [key, value] of Object.entries(bindings)) {
1023
+ const rendered = typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : serializeArg(value);
1024
+ parts.push(`${key}=${rendered}`);
1208
1025
  }
1026
+ return parts.join(" ");
1209
1027
  }
1210
- function getConfig(accountDir) {
1211
- try {
1212
- const config = readConfig(accountDir);
1213
- const wa = config.whatsapp;
1214
- if (!wa) return null;
1215
- const migrated = migrateAdminPhones(wa);
1216
- const parsed = WhatsAppConfigSchema.safeParse(wa);
1217
- if (!parsed.success) return wa;
1218
- if (migrated > 0) {
1219
- config.whatsapp = parsed.data;
1220
- writeConfig(accountDir, config);
1221
- reloadManagerConfig(accountDir);
1028
+ function createBaileysLogger(bindings = {}) {
1029
+ const prefix = Object.keys(bindings).length > 0 ? bindingsToPrefix(bindings) : "";
1030
+ const emit = (level, args) => {
1031
+ const serialized = args.map(serializeArg).join(" ");
1032
+ if (prefix) {
1033
+ console.error(__BAILEYS_TAG, level, prefix, serialized);
1034
+ } else {
1035
+ console.error(__BAILEYS_TAG, level, serialized);
1222
1036
  }
1223
- return parsed.data;
1224
- } catch {
1225
- return null;
1226
- }
1227
- }
1228
-
1229
- // app/lib/whatsapp/auth-store.ts
1230
- import fsSync from "fs";
1231
- import fs from "fs/promises";
1232
- import path from "path";
1233
- import os from "os";
1234
- var TAG2 = "[whatsapp:auth]";
1235
- function resolveAuthDir(configDir2, accountId) {
1236
- return path.join(os.homedir(), configDir2, "credentials", "whatsapp", accountId);
1237
- }
1238
- function resolveCredsPath(authDir) {
1239
- return path.join(authDir, "creds.json");
1240
- }
1241
- function resolveCredsBackupPath(authDir) {
1242
- return path.join(authDir, "creds.json.bak");
1243
- }
1244
- function hasCredsSync(authDir) {
1245
- try {
1246
- const stats = fsSync.statSync(resolveCredsPath(authDir));
1247
- return stats.isFile() && stats.size > 1;
1248
- } catch {
1249
- return false;
1250
- }
1037
+ };
1038
+ return {
1039
+ level: "warn",
1040
+ trace: () => {
1041
+ },
1042
+ debug: () => {
1043
+ },
1044
+ info: () => {
1045
+ },
1046
+ warn: (...args) => emit("WARN", args),
1047
+ error: (...args) => emit("ERROR", args),
1048
+ fatal: (...args) => emit("FATAL", args),
1049
+ child: (childBindings) => createBaileysLogger({ ...bindings, ...childBindings ?? {} })
1050
+ };
1251
1051
  }
1252
- async function authExists(authDir) {
1253
- const credsPath = resolveCredsPath(authDir);
1254
- try {
1255
- await fs.access(authDir);
1256
- } catch {
1257
- return false;
1258
- }
1259
- try {
1260
- const stats = await fs.stat(credsPath);
1261
- if (!stats.isFile() || stats.size <= 1) return false;
1262
- const raw = await fs.readFile(credsPath, "utf-8");
1263
- JSON.parse(raw);
1264
- return true;
1265
- } catch (err) {
1266
- console.warn(`${TAG2} credential validation failed path=${credsPath}: ${String(err)}`);
1267
- return false;
1052
+ var credsSaveQueue = Promise.resolve();
1053
+ async function drainCredsSaveQueue(timeoutMs = 5e3) {
1054
+ console.error(`${TAG2} draining credential save queue\u2026`);
1055
+ const timer2 = new Promise(
1056
+ (resolve24) => setTimeout(() => resolve24("timeout"), timeoutMs)
1057
+ );
1058
+ const result = await Promise.race([
1059
+ credsSaveQueue.then(() => "drained"),
1060
+ timer2
1061
+ ]);
1062
+ if (result === "timeout") {
1063
+ console.error(`${TAG2} credential save queue drain timed out after ${timeoutMs}ms`);
1064
+ } else {
1065
+ console.error(`${TAG2} credential save queue drained`);
1268
1066
  }
1269
1067
  }
1270
- function readCredsJsonRaw(filePath) {
1068
+ function readCredsJsonRaw2(filePath) {
1271
1069
  try {
1272
- if (!fsSync.existsSync(filePath)) return null;
1273
- const stats = fsSync.statSync(filePath);
1070
+ if (!fsSync2.existsSync(filePath)) return null;
1071
+ const stats = fsSync2.statSync(filePath);
1274
1072
  if (!stats.isFile() || stats.size <= 1) return null;
1275
- return fsSync.readFileSync(filePath, "utf-8");
1073
+ return fsSync2.readFileSync(filePath, "utf-8");
1276
1074
  } catch {
1277
1075
  return null;
1278
1076
  }
1279
1077
  }
1280
- function maybeRestoreCredsFromBackup(authDir) {
1078
+ async function safeSaveCreds(authDir, saveCreds) {
1281
1079
  try {
1282
1080
  const credsPath = resolveCredsPath(authDir);
1283
1081
  const backupPath = resolveCredsBackupPath(authDir);
1284
- const raw = readCredsJsonRaw(credsPath);
1082
+ const raw = readCredsJsonRaw2(credsPath);
1285
1083
  if (raw) {
1286
- JSON.parse(raw);
1287
- return;
1084
+ try {
1085
+ JSON.parse(raw);
1086
+ fsSync2.copyFileSync(credsPath, backupPath);
1087
+ } catch (err) {
1088
+ console.warn(`${TAG2} backup pre-copy failed (parse or write) authDir=${authDir}: ${String(err)}`);
1089
+ }
1288
1090
  }
1289
- const backupRaw = readCredsJsonRaw(backupPath);
1290
- if (!backupRaw) return;
1291
- JSON.parse(backupRaw);
1292
- fsSync.copyFileSync(backupPath, credsPath);
1293
- console.error(`${TAG2} restored corrupted creds.json from backup in ${authDir}`);
1294
1091
  } catch (err) {
1295
- console.warn(`${TAG2} credential restore failed authDir=${authDir}: ${String(err)}`);
1092
+ console.warn(`${TAG2} backup preparation failed authDir=${authDir}: ${String(err)}`);
1296
1093
  }
1297
- }
1298
- function readSelfId(authDir) {
1299
1094
  try {
1095
+ await Promise.resolve(saveCreds());
1300
1096
  const credsPath = resolveCredsPath(authDir);
1301
- if (!fsSync.existsSync(credsPath)) return { e164: null, jid: null, lid: null };
1302
- const raw = fsSync.readFileSync(credsPath, "utf-8");
1303
- const parsed = JSON.parse(raw);
1304
- const jid = parsed?.me?.id ?? null;
1305
- const lidRaw = parsed?.me?.lid ?? null;
1306
- let e164 = null;
1307
- if (jid) {
1308
- const match = jid.match(/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i);
1309
- if (match) e164 = match[1];
1310
- }
1311
- let lid = null;
1312
- if (lidRaw) {
1313
- const lidMatch = lidRaw.match(/^(\d+)(?::\d+)?@lid$/i);
1314
- if (lidMatch) lid = `${lidMatch[1]}@lid`;
1097
+ try {
1098
+ const stats = await fs2.stat(credsPath);
1099
+ if (stats.size <= 1) {
1100
+ console.error(`${TAG2} WARNING: creds file empty/truncated after save path=${credsPath} size=${stats.size}`);
1101
+ } else {
1102
+ console.error(`${TAG2} creds saved and verified path=${credsPath} size=${stats.size}`);
1103
+ }
1104
+ } catch (statErr) {
1105
+ console.error(`${TAG2} creds NOT found on disk after save path=${credsPath}: ${String(statErr)}`);
1315
1106
  }
1316
- return { e164, jid, lid };
1317
1107
  } catch (err) {
1318
- console.warn(`${TAG2} readSelfId failed authDir=${authDir}: ${String(err)}`);
1319
- return { e164: null, jid: null, lid: null };
1320
- }
1321
- }
1322
- async function clearAuth(authDir) {
1323
- try {
1324
- await fs.access(authDir);
1325
- } catch {
1326
- console.error(`${TAG2} no auth dir found at ${authDir}`);
1327
- return false;
1328
- }
1329
- await fs.rm(authDir, { recursive: true, force: true });
1330
- console.error(`${TAG2} cleared credentials at ${authDir}`);
1331
- return true;
1332
- }
1333
- function listCredentialAccountIds(configDir2) {
1334
- const credsRoot = path.join(os.homedir(), configDir2, "credentials", "whatsapp");
1335
- try {
1336
- const entries = fsSync.readdirSync(credsRoot, { withFileTypes: true });
1337
- return entries.filter((e) => e.isDirectory() && hasCredsSync(path.join(credsRoot, e.name))).map((e) => e.name);
1338
- } catch {
1339
- return [];
1340
- }
1341
- }
1342
-
1343
- // app/lib/whatsapp/session.ts
1344
- import { randomUUID } from "crypto";
1345
- import fsSync2 from "fs";
1346
- import fs2 from "fs/promises";
1347
- import { inspect } from "util";
1348
- import {
1349
- Browsers,
1350
- DisconnectReason,
1351
- fetchLatestBaileysVersion,
1352
- makeCacheableSignalKeyStore,
1353
- makeWASocket,
1354
- useMultiFileAuthState
1355
- } from "@whiskeysockets/baileys";
1356
- import { createRequire } from "module";
1357
- var TAG3 = "[whatsapp:session]";
1358
- var baileysPkgVersion = (() => {
1359
- try {
1360
- const req = createRequire(import.meta.url);
1361
- return req("@whiskeysockets/baileys/package.json").version ?? "unknown";
1362
- } catch {
1363
- return "unknown";
1364
- }
1365
- })();
1366
- console.error(`${TAG3} baileys package loaded version=${baileysPkgVersion}`);
1367
- var __BAILEYS_TAG = "[whatsapp:baileys]";
1368
- var INSPECT_OPTS = {
1369
- depth: null,
1370
- breakLength: Infinity,
1371
- compact: true,
1372
- maxArrayLength: 100,
1373
- maxStringLength: 1e4
1374
- };
1375
- function serializeArg(arg) {
1376
- if (typeof arg === "string") return arg;
1377
- try {
1378
- return inspect(arg, INSPECT_OPTS);
1379
- } catch (err) {
1380
- return `[inspect-failed: ${String(err)}]`;
1381
- }
1382
- }
1383
- function bindingsToPrefix(bindings) {
1384
- const parts = [];
1385
- for (const [key, value] of Object.entries(bindings)) {
1386
- const rendered = typeof value === "string" || typeof value === "number" || typeof value === "boolean" ? String(value) : serializeArg(value);
1387
- parts.push(`${key}=${rendered}`);
1388
- }
1389
- return parts.join(" ");
1390
- }
1391
- function createBaileysLogger(bindings = {}) {
1392
- const prefix = Object.keys(bindings).length > 0 ? bindingsToPrefix(bindings) : "";
1393
- const emit = (level, args) => {
1394
- const serialized = args.map(serializeArg).join(" ");
1395
- if (prefix) {
1396
- console.error(__BAILEYS_TAG, level, prefix, serialized);
1397
- } else {
1398
- console.error(__BAILEYS_TAG, level, serialized);
1399
- }
1400
- };
1401
- return {
1402
- level: "warn",
1403
- trace: () => {
1404
- },
1405
- debug: () => {
1406
- },
1407
- info: () => {
1408
- },
1409
- warn: (...args) => emit("WARN", args),
1410
- error: (...args) => emit("ERROR", args),
1411
- fatal: (...args) => emit("FATAL", args),
1412
- child: (childBindings) => createBaileysLogger({ ...bindings, ...childBindings ?? {} })
1413
- };
1414
- }
1415
- var credsSaveQueue = Promise.resolve();
1416
- async function drainCredsSaveQueue(timeoutMs = 5e3) {
1417
- console.error(`${TAG3} draining credential save queue\u2026`);
1418
- const timer2 = new Promise(
1419
- (resolve24) => setTimeout(() => resolve24("timeout"), timeoutMs)
1420
- );
1421
- const result = await Promise.race([
1422
- credsSaveQueue.then(() => "drained"),
1423
- timer2
1424
- ]);
1425
- if (result === "timeout") {
1426
- console.error(`${TAG3} credential save queue drain timed out after ${timeoutMs}ms`);
1427
- } else {
1428
- console.error(`${TAG3} credential save queue drained`);
1429
- }
1430
- }
1431
- function readCredsJsonRaw2(filePath) {
1432
- try {
1433
- if (!fsSync2.existsSync(filePath)) return null;
1434
- const stats = fsSync2.statSync(filePath);
1435
- if (!stats.isFile() || stats.size <= 1) return null;
1436
- return fsSync2.readFileSync(filePath, "utf-8");
1437
- } catch {
1438
- return null;
1439
- }
1440
- }
1441
- async function safeSaveCreds(authDir, saveCreds) {
1442
- try {
1443
- const credsPath = resolveCredsPath(authDir);
1444
- const backupPath = resolveCredsBackupPath(authDir);
1445
- const raw = readCredsJsonRaw2(credsPath);
1446
- if (raw) {
1447
- try {
1448
- JSON.parse(raw);
1449
- fsSync2.copyFileSync(credsPath, backupPath);
1450
- } catch (err) {
1451
- console.warn(`${TAG3} backup pre-copy failed (parse or write) authDir=${authDir}: ${String(err)}`);
1452
- }
1453
- }
1454
- } catch (err) {
1455
- console.warn(`${TAG3} backup preparation failed authDir=${authDir}: ${String(err)}`);
1456
- }
1457
- try {
1458
- await Promise.resolve(saveCreds());
1459
- const credsPath = resolveCredsPath(authDir);
1460
- try {
1461
- const stats = await fs2.stat(credsPath);
1462
- if (stats.size <= 1) {
1463
- console.error(`${TAG3} WARNING: creds file empty/truncated after save path=${credsPath} size=${stats.size}`);
1464
- } else {
1465
- console.error(`${TAG3} creds saved and verified path=${credsPath} size=${stats.size}`);
1466
- }
1467
- } catch (statErr) {
1468
- console.error(`${TAG3} creds NOT found on disk after save path=${credsPath}: ${String(statErr)}`);
1469
- }
1470
- } catch (err) {
1471
- console.error(`${TAG3} failed saving creds to ${authDir}: ${String(err)}`);
1108
+ console.error(`${TAG2} failed saving creds to ${authDir}: ${String(err)}`);
1472
1109
  }
1473
1110
  }
1474
1111
  function enqueueSaveCreds(authDir, saveCreds) {
1475
1112
  credsSaveQueue = credsSaveQueue.then(() => safeSaveCreds(authDir, saveCreds)).catch((err) => {
1476
- console.error(`${TAG3} creds save queue error: ${String(err)}`);
1113
+ console.error(`${TAG2} creds save queue error: ${String(err)}`);
1477
1114
  });
1478
1115
  }
1479
1116
  async function createWaSocket(opts) {
@@ -1483,7 +1120,7 @@ async function createWaSocket(opts) {
1483
1120
  const { state, saveCreds } = await useMultiFileAuthState(authDir);
1484
1121
  const { version } = await fetchLatestBaileysVersion();
1485
1122
  console.error(
1486
- `${TAG3} creating socket authDir=${authDir} baileysVersion=${baileysPkgVersion} waProtocolVersion=${version.join(".")}`
1123
+ `${TAG2} creating socket authDir=${authDir} baileysVersion=${baileysPkgVersion} waProtocolVersion=${version.join(".")}`
1487
1124
  );
1488
1125
  const baileysLogger = createBaileysLogger();
1489
1126
  const sock = makeWASocket({
@@ -1500,7 +1137,7 @@ async function createWaSocket(opts) {
1500
1137
  fireInitQueries: false
1501
1138
  });
1502
1139
  sock.ev.on("creds.update", () => {
1503
- console.error(`${TAG3} creds.update received \u2014 saving to ${authDir}`);
1140
+ console.error(`${TAG2} creds.update received \u2014 saving to ${authDir}`);
1504
1141
  enqueueSaveCreds(authDir, saveCreds);
1505
1142
  });
1506
1143
  let qrSequence = 0;
@@ -1517,7 +1154,7 @@ async function createWaSocket(opts) {
1517
1154
  parts.push(`disconnectReason=${formatError(update.lastDisconnect.error)}`);
1518
1155
  }
1519
1156
  if (!silent && parts.length > 0) {
1520
- console.error(`${TAG3} connection.update ${parts.join(" ")}`);
1157
+ console.error(`${TAG2} connection.update ${parts.join(" ")}`);
1521
1158
  }
1522
1159
  if (update.qr && onQr) {
1523
1160
  onQr(update.qr);
@@ -1525,20 +1162,20 @@ async function createWaSocket(opts) {
1525
1162
  if (update.connection === "close") {
1526
1163
  const status = getStatusCode(update.lastDisconnect?.error);
1527
1164
  if (status === DisconnectReason.loggedOut && !silent) {
1528
- console.error(`${TAG3} session logged out (401) \u2014 re-link required`);
1165
+ console.error(`${TAG2} session logged out (401) \u2014 re-link required`);
1529
1166
  }
1530
1167
  }
1531
1168
  if (update.connection === "open" && !silent) {
1532
- console.error(`${TAG3} connected`);
1169
+ console.error(`${TAG2} connected`);
1533
1170
  }
1534
1171
  onConnectionUpdate?.(update);
1535
1172
  } catch (err) {
1536
- console.error(`${TAG3} connection.update handler error: ${String(err)}`);
1173
+ console.error(`${TAG2} connection.update handler error: ${String(err)}`);
1537
1174
  }
1538
1175
  });
1539
1176
  if (sock.ws && typeof sock.ws.on === "function") {
1540
1177
  sock.ws.on("error", (err) => {
1541
- console.error(`${TAG3} WebSocket error: ${String(err)}`);
1178
+ console.error(`${TAG2} WebSocket error: ${String(err)}`);
1542
1179
  });
1543
1180
  }
1544
1181
  return sock;
@@ -1644,7 +1281,7 @@ function computeBackoff(attempt, config = {}) {
1644
1281
 
1645
1282
  // app/lib/whatsapp/init-queries.ts
1646
1283
  import { inspect as inspect2 } from "util";
1647
- var TAG4 = "[whatsapp:init]";
1284
+ var TAG3 = "[whatsapp:init]";
1648
1285
  var DEFAULT_QUERY_TIMEOUT_MS = 15e3;
1649
1286
  var INSPECT_OPTS2 = {
1650
1287
  depth: null,
@@ -1689,20 +1326,20 @@ async function runInitQueries(sock, ctx) {
1689
1326
  elapsedMs: 0
1690
1327
  };
1691
1328
  console.error(
1692
- `${TAG4} runInitQueries start account=${ctx.accountId} attempt=${ctx.attempt} selfPhone=${ctx.selfPhone ?? "unknown"} authDir=${ctx.authDir} queryTimeoutMs=${queryTimeoutMs}`
1329
+ `${TAG3} runInitQueries start account=${ctx.accountId} attempt=${ctx.attempt} selfPhone=${ctx.selfPhone ?? "unknown"} authDir=${ctx.authDir} queryTimeoutMs=${queryTimeoutMs}`
1693
1330
  );
1694
1331
  console.error(
1695
- `${TAG4} fetchProps SKIPPED account=${ctx.accountId} reason=no-platform-consumer`
1332
+ `${TAG3} fetchProps SKIPPED account=${ctx.accountId} reason=no-platform-consumer`
1696
1333
  );
1697
1334
  if (ctx.signal?.aborted) {
1698
1335
  result.aborted = true;
1699
1336
  result.elapsedMs = Date.now() - startedAt;
1700
1337
  console.error(
1701
- `${TAG4} runInitQueries aborted before start account=${ctx.accountId}`
1338
+ `${TAG3} runInitQueries aborted before start account=${ctx.accountId}`
1702
1339
  );
1703
1340
  return result;
1704
1341
  }
1705
- console.error(`${TAG4} fetchBlocklist start account=${ctx.accountId}`);
1342
+ console.error(`${TAG3} fetchBlocklist start account=${ctx.accountId}`);
1706
1343
  try {
1707
1344
  const blocklist = await withTimeout(
1708
1345
  "fetchBlocklist",
@@ -1712,24 +1349,24 @@ async function runInitQueries(sock, ctx) {
1712
1349
  const count = Array.isArray(blocklist) ? blocklist.length : 0;
1713
1350
  result.blocklistOk = true;
1714
1351
  console.error(
1715
- `${TAG4} fetchBlocklist ok account=${ctx.accountId} count=${count}`
1352
+ `${TAG3} fetchBlocklist ok account=${ctx.accountId} count=${count}`
1716
1353
  );
1717
1354
  } catch (err) {
1718
1355
  const formatted = formatErr(err);
1719
1356
  result.errors.blocklist = formatted;
1720
1357
  console.error(
1721
- `${TAG4} fetchBlocklist FAILED account=${ctx.accountId}: ${formatted}`
1358
+ `${TAG3} fetchBlocklist FAILED account=${ctx.accountId}: ${formatted}`
1722
1359
  );
1723
1360
  }
1724
1361
  if (ctx.signal?.aborted) {
1725
1362
  result.aborted = true;
1726
1363
  result.elapsedMs = Date.now() - startedAt;
1727
1364
  console.error(
1728
- `${TAG4} runInitQueries aborted mid-sequence account=${ctx.accountId} after=fetchBlocklist`
1365
+ `${TAG3} runInitQueries aborted mid-sequence account=${ctx.accountId} after=fetchBlocklist`
1729
1366
  );
1730
1367
  return result;
1731
1368
  }
1732
- console.error(`${TAG4} fetchPrivacySettings start account=${ctx.accountId}`);
1369
+ console.error(`${TAG3} fetchPrivacySettings start account=${ctx.accountId}`);
1733
1370
  try {
1734
1371
  const settings = await withTimeout(
1735
1372
  "fetchPrivacySettings",
@@ -1739,18 +1376,18 @@ async function runInitQueries(sock, ctx) {
1739
1376
  );
1740
1377
  result.privacySettingsOk = true;
1741
1378
  console.error(
1742
- `${TAG4} fetchPrivacySettings ok account=${ctx.accountId} keys=${settings ? Object.keys(settings).join(",") : ""}`
1379
+ `${TAG3} fetchPrivacySettings ok account=${ctx.accountId} keys=${settings ? Object.keys(settings).join(",") : ""}`
1743
1380
  );
1744
1381
  } catch (err) {
1745
1382
  const formatted = formatErr(err);
1746
1383
  result.errors.privacySettings = formatted;
1747
1384
  console.error(
1748
- `${TAG4} fetchPrivacySettings FAILED account=${ctx.accountId}: ${formatted}`
1385
+ `${TAG3} fetchPrivacySettings FAILED account=${ctx.accountId}: ${formatted}`
1749
1386
  );
1750
1387
  }
1751
1388
  result.elapsedMs = Date.now() - startedAt;
1752
1389
  console.error(
1753
- `${TAG4} runInitQueries done account=${ctx.accountId} blocklistOk=${result.blocklistOk} privacySettingsOk=${result.privacySettingsOk} elapsedMs=${result.elapsedMs}`
1390
+ `${TAG3} runInitQueries done account=${ctx.accountId} blocklistOk=${result.blocklistOk} privacySettingsOk=${result.privacySettingsOk} elapsedMs=${result.elapsedMs}`
1754
1391
  );
1755
1392
  return result;
1756
1393
  }
@@ -2054,7 +1691,7 @@ function isDuplicateInbound(key) {
2054
1691
  }
2055
1692
 
2056
1693
  // app/lib/whatsapp/activity.ts
2057
- var TAG5 = "[whatsapp:activity]";
1694
+ var TAG4 = "[whatsapp:activity]";
2058
1695
  var RECENT_EVENTS_MAX = 200;
2059
1696
  var counters = /* @__PURE__ */ new Map();
2060
1697
  var recentEvents = [];
@@ -2082,10 +1719,10 @@ function recordActivity(event) {
2082
1719
  recentEvents.splice(0, recentEvents.length - RECENT_EVENTS_MAX);
2083
1720
  }
2084
1721
  console.error(
2085
- `${TAG5} channel-activity: direction=${direction} account=${accountId} jid=${jid}` + (messageType ? ` type=${messageType}` : "")
1722
+ `${TAG4} channel-activity: direction=${direction} account=${accountId} jid=${jid}` + (messageType ? ` type=${messageType}` : "")
2086
1723
  );
2087
1724
  } catch (err) {
2088
- console.error(`${TAG5} recording failed: ${String(err)}`);
1725
+ console.error(`${TAG4} recording failed: ${String(err)}`);
2089
1726
  }
2090
1727
  }
2091
1728
  function getChannelActivity(accountId) {
@@ -2106,7 +1743,7 @@ function getChannelActivity(accountId) {
2106
1743
  }
2107
1744
 
2108
1745
  // app/lib/whatsapp/outbound/send.ts
2109
- var TAG6 = "[whatsapp:outbound]";
1746
+ var TAG5 = "[whatsapp:outbound]";
2110
1747
  async function sendTextMessage(sock, to, text, opts) {
2111
1748
  try {
2112
1749
  const jid = to.includes("@") ? to : toWhatsappJid(to);
@@ -2118,14 +1755,14 @@ async function sendTextMessage(sock, to, text, opts) {
2118
1755
  const messageId = result?.key?.id;
2119
1756
  if (messageId) {
2120
1757
  trackAgentSentMessage(messageId);
2121
- console.error(`${TAG6} sent text to=${jid} id=${messageId}`);
1758
+ console.error(`${TAG5} sent text to=${jid} id=${messageId}`);
2122
1759
  }
2123
1760
  if (opts?.accountId) {
2124
1761
  recordActivity({ accountId: opts.accountId, direction: "outbound", jid, messageType: "text" });
2125
1762
  }
2126
1763
  return { success: true, messageId: messageId ?? void 0 };
2127
1764
  } catch (err) {
2128
- console.error(`${TAG6} send failed to=${to}: ${String(err)}`);
1765
+ console.error(`${TAG5} send failed to=${to}: ${String(err)}`);
2129
1766
  return { success: false, error: String(err) };
2130
1767
  }
2131
1768
  }
@@ -2180,20 +1817,20 @@ async function sendMediaMessage(sock, to, media, opts) {
2180
1817
  const messageId = result?.key?.id;
2181
1818
  if (messageId) {
2182
1819
  trackAgentSentMessage(messageId);
2183
- console.error(`${TAG6} sent ${media.type} to=${jid} id=${messageId}`);
1820
+ console.error(`${TAG5} sent ${media.type} to=${jid} id=${messageId}`);
2184
1821
  }
2185
1822
  if (opts?.accountId) {
2186
1823
  recordActivity({ accountId: opts.accountId, direction: "outbound", jid, messageType: media.type });
2187
1824
  }
2188
1825
  return { success: true, messageId: messageId ?? void 0 };
2189
1826
  } catch (err) {
2190
- console.error(`${TAG6} send media failed to=${to}: ${String(err)}`);
1827
+ console.error(`${TAG5} send media failed to=${to}: ${String(err)}`);
2191
1828
  return { success: false, error: String(err) };
2192
1829
  }
2193
1830
  }
2194
1831
 
2195
1832
  // app/lib/whatsapp/persist-message.ts
2196
- var TAG7 = "[whatsapp-persist]";
1833
+ var TAG6 = "[whatsapp-persist]";
2197
1834
  var sessionWriteLocks = /* @__PURE__ */ new Map();
2198
1835
  async function persistWhatsAppMessage(input) {
2199
1836
  if (!input.body || !input.msgKeyId) return null;
@@ -2298,7 +1935,7 @@ async function persistWhatsAppMessage(input) {
2298
1935
  const result = await session.run(cypher, params);
2299
1936
  const ms = Date.now() - t0;
2300
1937
  if (result.records.length === 0) {
2301
- console.error(`${TAG7} skip reason=conversation-not-found accountId=${input.platformAccountId} cacheKey=${input.cacheKey} messageId=${messageId}`);
1938
+ console.error(`${TAG6} skip reason=conversation-not-found accountId=${input.platformAccountId} cacheKey=${input.cacheKey} messageId=${messageId}`);
2302
1939
  return null;
2303
1940
  }
2304
1941
  const rec = result.records[0];
@@ -2307,26 +1944,26 @@ async function persistWhatsAppMessage(input) {
2307
1944
  const senderElementId = rec.get("senderElementId");
2308
1945
  const senderReused = rec.get("senderReused") === true;
2309
1946
  if (existed) {
2310
- console.error(`${TAG7} noop reason=existing-message messageId=${messageId}`);
1947
+ console.error(`${TAG6} noop reason=existing-message messageId=${messageId}`);
2311
1948
  return { messageId, created: false, senderElementId };
2312
1949
  }
2313
1950
  console.error(
2314
- `${TAG7} sender-resolved telephone=${senderTelephone} nodeKind=Person elementId=${senderElementId} reused=${senderReused}`
1951
+ `${TAG6} sender-resolved telephone=${senderTelephone} nodeKind=Person elementId=${senderElementId} reused=${senderReused}`
2315
1952
  );
2316
1953
  if (prevMessageId) {
2317
- console.error(`${TAG7} next-merge prior=${prevMessageId} next=${messageId}`);
1954
+ console.error(`${TAG6} next-merge prior=${prevMessageId} next=${messageId}`);
2318
1955
  } else {
2319
- console.error(`${TAG7} next-skip reason=no-prior msgId=${messageId}`);
1956
+ console.error(`${TAG6} next-skip reason=no-prior msgId=${messageId}`);
2320
1957
  }
2321
1958
  console.error(
2322
- `${TAG7} write messageId=${messageId} accountId=${input.platformAccountId} cacheKey=${input.cacheKey} fromMe=${input.fromMe} dateSent=${dateSentIso} bodyBytes=${Buffer.byteLength(input.body, "utf8")} ms=${ms}`
1959
+ `${TAG6} write messageId=${messageId} accountId=${input.platformAccountId} cacheKey=${input.cacheKey} fromMe=${input.fromMe} dateSent=${dateSentIso} bodyBytes=${Buffer.byteLength(input.body, "utf8")} ms=${ms}`
2323
1960
  );
2324
1961
  return { messageId, created: true, senderElementId };
2325
1962
  } catch (err) {
2326
1963
  const ms = Date.now() - t0;
2327
1964
  const reason = sanitizeReason(err);
2328
1965
  console.error(
2329
- `${TAG7} FAIL accountId=${input.platformAccountId} waname=${input.accountId} remoteJid=${input.remoteJid} msgKey=${input.msgKeyId} reason=${reason} ms=${ms}`
1966
+ `${TAG6} FAIL accountId=${input.platformAccountId} waname=${input.accountId} remoteJid=${input.remoteJid} msgKey=${input.msgKeyId} reason=${reason} ms=${ms}`
2330
1967
  );
2331
1968
  return null;
2332
1969
  } finally {
@@ -2359,7 +1996,7 @@ function sanitizeReason(err) {
2359
1996
  }
2360
1997
 
2361
1998
  // app/lib/whatsapp/ensure-conversation.ts
2362
- var TAG8 = "[whatsapp-persist]";
1999
+ var TAG7 = "[whatsapp-persist]";
2363
2000
  async function ensureWhatsAppConversation(input) {
2364
2001
  const t0 = Date.now();
2365
2002
  try {
@@ -2371,27 +2008,27 @@ async function ensureWhatsAppConversation(input) {
2371
2008
  const ms = Date.now() - t0;
2372
2009
  if (!result.conversationId) {
2373
2010
  console.error(
2374
- `${TAG8} conversation-merged FAIL cacheKey=${input.cacheKey} reason=null-conversationId ms=${ms}`
2011
+ `${TAG7} conversation-merged FAIL cacheKey=${input.cacheKey} reason=null-conversationId ms=${ms}`
2375
2012
  );
2376
2013
  return null;
2377
2014
  }
2378
2015
  console.error(
2379
- `${TAG8} conversation-merged cacheKey=${input.cacheKey} agentType=${input.agentType} channel=whatsapp created=${result.created} ms=${ms}`
2016
+ `${TAG7} conversation-merged cacheKey=${input.cacheKey} agentType=${input.agentType} channel=whatsapp created=${result.created} ms=${ms}`
2380
2017
  );
2381
2018
  return { conversationId: result.conversationId, created: result.created };
2382
2019
  } catch (err) {
2383
2020
  const ms = Date.now() - t0;
2384
2021
  const reason = err instanceof Error ? `${err.name}:${err.message.slice(0, 200)}` : String(err).slice(0, 200);
2385
2022
  console.error(
2386
- `${TAG8} conversation-merged FAIL cacheKey=${input.cacheKey} reason=${reason} ms=${ms}`
2023
+ `${TAG7} conversation-merged FAIL cacheKey=${input.cacheKey} reason=${reason} ms=${ms}`
2387
2024
  );
2388
2025
  return null;
2389
2026
  }
2390
2027
  }
2391
2028
 
2392
2029
  // ../lib/account-enumeration/src/index.ts
2393
- import { readdirSync, readFileSync as readFileSync3 } from "fs";
2394
- import { resolve as resolve2 } from "path";
2030
+ import { readdirSync, readFileSync as readFileSync2 } from "fs";
2031
+ import { resolve } from "path";
2395
2032
  var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2396
2033
  var cache = /* @__PURE__ */ new Map();
2397
2034
  function enumerateValidAccountIds(accountsDir) {
@@ -2410,9 +2047,9 @@ function enumerateValidAccountIds(accountsDir) {
2410
2047
  const valid = [];
2411
2048
  for (const name of names) {
2412
2049
  if (!UUID_RE.test(name)) continue;
2413
- const configPath2 = resolve2(accountsDir, name, "account.json");
2050
+ const configPath2 = resolve(accountsDir, name, "account.json");
2414
2051
  try {
2415
- JSON.parse(readFileSync3(configPath2, "utf-8"));
2052
+ JSON.parse(readFileSync2(configPath2, "utf-8"));
2416
2053
  valid.push(name);
2417
2054
  } catch (err) {
2418
2055
  const code = err.code;
@@ -2429,7 +2066,7 @@ function getAccountsDirFromEnv() {
2429
2066
  "[graph-write] MAXY_PLATFORM_ROOT not set \u2014 cannot enforce accountId gate. Set MAXY_PLATFORM_ROOT in the spawning process or pass `accountsDir` explicitly."
2430
2067
  );
2431
2068
  }
2432
- return resolve2(root, "..", "data/accounts");
2069
+ return resolve(root, "..", "data/accounts");
2433
2070
  }
2434
2071
  function validateAccountIdEnv(envValue, diskIds) {
2435
2072
  if (!envValue) {
@@ -2468,13 +2105,13 @@ function resolvePlatformAccountId(accountsDir = ACCOUNTS_DIR) {
2468
2105
  // app/lib/whatsapp/inbound/media.ts
2469
2106
  import { randomUUID as randomUUID2 } from "crypto";
2470
2107
  import { writeFile, mkdir } from "fs/promises";
2471
- import { join as join3 } from "path";
2108
+ import { join as join2 } from "path";
2472
2109
  import {
2473
2110
  downloadMediaMessage,
2474
2111
  downloadContentFromMessage,
2475
2112
  normalizeMessageContent as normalizeMessageContent2
2476
2113
  } from "@whiskeysockets/baileys";
2477
- var TAG9 = "[whatsapp:media]";
2114
+ var TAG8 = "[whatsapp:media]";
2478
2115
  var MEDIA_DIR = "/tmp/maxy-media";
2479
2116
  function mimeToExt(mimetype) {
2480
2117
  const map = {
@@ -2530,47 +2167,47 @@ async function downloadInboundMedia(msg, sock, opts) {
2530
2167
  }
2531
2168
  );
2532
2169
  if (!buffer || buffer.length === 0) {
2533
- console.error(`${TAG9} primary download returned empty, trying direct fallback`);
2170
+ console.error(`${TAG8} primary download returned empty, trying direct fallback`);
2534
2171
  const downloadable = getDownloadableContent(content);
2535
2172
  if (downloadable) {
2536
2173
  try {
2537
2174
  const stream = await downloadContentFromMessage(downloadable.downloadable, downloadable.mediaType);
2538
2175
  buffer = await streamToBuffer(stream);
2539
2176
  } catch (fallbackErr) {
2540
- console.error(`${TAG9} direct download fallback failed: ${String(fallbackErr)}`);
2177
+ console.error(`${TAG8} direct download fallback failed: ${String(fallbackErr)}`);
2541
2178
  }
2542
2179
  }
2543
2180
  }
2544
2181
  if (!buffer || buffer.length === 0) {
2545
- console.error(`${TAG9} download failed: empty buffer for ${mimetype ?? "unknown"}`);
2182
+ console.error(`${TAG8} download failed: empty buffer for ${mimetype ?? "unknown"}`);
2546
2183
  return void 0;
2547
2184
  }
2548
2185
  if (buffer.length > maxBytes) {
2549
2186
  const sizeMB = (buffer.length / (1024 * 1024)).toFixed(1);
2550
2187
  const limitMB = (maxBytes / (1024 * 1024)).toFixed(0);
2551
- console.error(`${TAG9} media too large type=${mimetype ?? "unknown"} size=${sizeMB}MB limit=${limitMB}MB`);
2188
+ console.error(`${TAG8} media too large type=${mimetype ?? "unknown"} size=${sizeMB}MB limit=${limitMB}MB`);
2552
2189
  return void 0;
2553
2190
  }
2554
2191
  await mkdir(MEDIA_DIR, { recursive: true });
2555
2192
  const ext = mimeToExt(mimetype ?? "application/octet-stream");
2556
2193
  const filename = `${randomUUID2()}.${ext}`;
2557
- const filePath = join3(MEDIA_DIR, filename);
2194
+ const filePath = join2(MEDIA_DIR, filename);
2558
2195
  await writeFile(filePath, buffer);
2559
2196
  const sizeKB = (buffer.length / 1024).toFixed(0);
2560
- console.error(`${TAG9} media downloaded type=${mimetype ?? "unknown"} size=${sizeKB}KB path=${filePath}`);
2197
+ console.error(`${TAG8} media downloaded type=${mimetype ?? "unknown"} size=${sizeKB}KB path=${filePath}`);
2561
2198
  return {
2562
2199
  path: filePath,
2563
2200
  mimetype: mimetype ?? "application/octet-stream",
2564
2201
  size: buffer.length
2565
2202
  };
2566
2203
  } catch (err) {
2567
- console.error(`${TAG9} media download failed type=${mimetype ?? "unknown"} error=${String(err)}`);
2204
+ console.error(`${TAG8} media download failed type=${mimetype ?? "unknown"} error=${String(err)}`);
2568
2205
  return void 0;
2569
2206
  }
2570
2207
  }
2571
2208
 
2572
2209
  // app/lib/whatsapp/inbound/debounce.ts
2573
- var TAG10 = "[whatsapp:debounce]";
2210
+ var TAG9 = "[whatsapp:debounce]";
2574
2211
  var STT_TAG = "[whatsapp:stt-await]";
2575
2212
  function createInboundDebouncer(opts) {
2576
2213
  const { debounceMs, buildKey, onFlush, onError } = opts;
@@ -2601,7 +2238,7 @@ function createInboundDebouncer(opts) {
2601
2238
  pending.delete(key);
2602
2239
  const batchSize = batch.entries.length;
2603
2240
  try {
2604
- console.error(`${TAG10} debounce flush key=${key} batchSize=${batchSize}`);
2241
+ console.error(`${TAG9} debounce flush key=${key} batchSize=${batchSize}`);
2605
2242
  const result = onFlush(batch.entries);
2606
2243
  if (result && typeof result.catch === "function") {
2607
2244
  result.catch(onError);
@@ -2673,7 +2310,7 @@ function createInboundDebouncer(opts) {
2673
2310
  }
2674
2311
 
2675
2312
  // app/lib/whatsapp/opening-hours.ts
2676
- var TAG11 = "[whatsapp:hours]";
2313
+ var TAG10 = "[whatsapp:hours]";
2677
2314
  async function isBusinessOpen(accountId) {
2678
2315
  try {
2679
2316
  const timezone = await resolveTimezone(accountId);
@@ -2691,7 +2328,7 @@ async function isBusinessOpen(accountId) {
2691
2328
  { accountId, dayOfWeek, previousDayOfWeek }
2692
2329
  );
2693
2330
  if (result.records.length === 0) {
2694
- console.error(`${TAG11} [${accountId}] business hours check: no opening hours configured, treating as open`);
2331
+ console.error(`${TAG10} [${accountId}] business hours check: no opening hours configured, treating as open`);
2695
2332
  return { open: true, reason: "no opening hours configured" };
2696
2333
  }
2697
2334
  const specs = result.records.filter((r) => r.get("opens") != null && r.get("closes") != null).map((r) => ({
@@ -2700,7 +2337,7 @@ async function isBusinessOpen(accountId) {
2700
2337
  closes: String(r.get("closes")).trim()
2701
2338
  }));
2702
2339
  if (specs.length === 0) {
2703
- console.error(`${TAG11} [${accountId}] business hours check: no opening hours configured, treating as open`);
2340
+ console.error(`${TAG10} [${accountId}] business hours check: no opening hours configured, treating as open`);
2704
2341
  return { open: true, reason: "no opening hours configured" };
2705
2342
  }
2706
2343
  for (const spec of specs) {
@@ -2710,7 +2347,7 @@ async function isBusinessOpen(accountId) {
2710
2347
  if (spec.opens > spec.closes && currentTime < spec.closes) {
2711
2348
  const hoursStr = `${spec.opens}-${spec.closes} (${spec.day})`;
2712
2349
  console.error(
2713
- `${TAG11} [${accountId}] business hours check: open (day=${dayOfWeek}, time=${currentTime}, hours=${hoursStr})`
2350
+ `${TAG10} [${accountId}] business hours check: open (day=${dayOfWeek}, time=${currentTime}, hours=${hoursStr})`
2714
2351
  );
2715
2352
  return {
2716
2353
  open: true,
@@ -2723,7 +2360,7 @@ async function isBusinessOpen(accountId) {
2723
2360
  } else if (isTimeInRange(currentTime, spec.opens, spec.closes)) {
2724
2361
  const hoursStr = `${spec.opens}-${spec.closes}`;
2725
2362
  console.error(
2726
- `${TAG11} [${accountId}] business hours check: open (day=${dayOfWeek}, time=${currentTime}, hours=${hoursStr})`
2363
+ `${TAG10} [${accountId}] business hours check: open (day=${dayOfWeek}, time=${currentTime}, hours=${hoursStr})`
2727
2364
  );
2728
2365
  return {
2729
2366
  open: true,
@@ -2737,7 +2374,7 @@ async function isBusinessOpen(accountId) {
2737
2374
  const todaySpecs = specs.filter((s) => s.day === dayOfWeek);
2738
2375
  const allHours = todaySpecs.map((s) => `${s.opens}-${s.closes}`).join(", ") || "none today";
2739
2376
  console.error(
2740
- `${TAG11} [${accountId}] business hours check: closed (day=${dayOfWeek}, time=${currentTime}, hours=${allHours})`
2377
+ `${TAG10} [${accountId}] business hours check: closed (day=${dayOfWeek}, time=${currentTime}, hours=${allHours})`
2741
2378
  );
2742
2379
  return {
2743
2380
  open: false,
@@ -2751,7 +2388,7 @@ async function isBusinessOpen(accountId) {
2751
2388
  }
2752
2389
  } catch (err) {
2753
2390
  console.error(
2754
- `${TAG11} [${accountId}] business hours check failed, treating as open: ${err instanceof Error ? err.message : String(err)}`
2391
+ `${TAG10} [${accountId}] business hours check failed, treating as open: ${err instanceof Error ? err.message : String(err)}`
2755
2392
  );
2756
2393
  return { open: true, reason: "hours check failed (treating as open)" };
2757
2394
  }
@@ -2797,7 +2434,7 @@ import { execFile } from "child_process";
2797
2434
  import { unlink, stat } from "fs/promises";
2798
2435
  import { promisify } from "util";
2799
2436
  var execFileAsync = promisify(execFile);
2800
- var TAG12 = "[stt]";
2437
+ var TAG11 = "[stt]";
2801
2438
  var WHISPER_BINARY = process.env.WHISPER_BINARY ?? "/opt/whisper.cpp/build/bin/whisper-cli";
2802
2439
  var WHISPER_MODEL = process.env.WHISPER_MODEL ?? "/opt/whisper.cpp/models/ggml-base.bin";
2803
2440
  var WHISPER_TIMEOUT_MS = 20 * 60 * 1e3;
@@ -2808,11 +2445,11 @@ async function transcribe(audioPath, mimetype) {
2808
2445
  const s = await stat(audioPath);
2809
2446
  audioBytes = s.size;
2810
2447
  } catch {
2811
- console.error(`${TAG12} failed: file not readable path=${audioPath}`);
2448
+ console.error(`${TAG11} failed: file not readable path=${audioPath}`);
2812
2449
  return void 0;
2813
2450
  }
2814
2451
  console.error(
2815
- `${TAG12} start provider=whisper-local audio_bytes=${audioBytes} mimetype=${mimetype} path=${audioPath}`
2452
+ `${TAG11} start provider=whisper-local audio_bytes=${audioBytes} mimetype=${mimetype} path=${audioPath}`
2816
2453
  );
2817
2454
  const wavPath = audioPath.replace(/\.[^.]+$/, "") + ".wav";
2818
2455
  try {
@@ -2831,7 +2468,7 @@ async function transcribe(audioPath, mimetype) {
2831
2468
  ], { timeout: 3e4 });
2832
2469
  } catch (err) {
2833
2470
  const reason = err instanceof Error ? err.message : String(err);
2834
- console.error(`${TAG12} failed: ffmpeg conversion error=${reason}`);
2471
+ console.error(`${TAG11} failed: ffmpeg conversion error=${reason}`);
2835
2472
  return void 0;
2836
2473
  }
2837
2474
  try {
@@ -2849,20 +2486,20 @@ async function transcribe(audioPath, mimetype) {
2849
2486
  const text = stdout.trim();
2850
2487
  const durationMs = Date.now() - startMs;
2851
2488
  if (!text) {
2852
- console.error(`${TAG12} failed: whisper returned empty output duration_ms=${durationMs}`);
2489
+ console.error(`${TAG11} failed: whisper returned empty output duration_ms=${durationMs}`);
2853
2490
  return void 0;
2854
2491
  }
2855
2492
  const langMatch = stderr.match(/auto-detected language:\s*(\w+)/);
2856
2493
  const language = langMatch?.[1] ?? "unknown";
2857
2494
  const words = text.split(/\s+/).filter(Boolean).length;
2858
2495
  console.error(
2859
- `${TAG12} done provider=whisper-local duration_ms=${durationMs} words=${words} lang=${language}`
2496
+ `${TAG11} done provider=whisper-local duration_ms=${durationMs} words=${words} lang=${language}`
2860
2497
  );
2861
2498
  return { text, language, durationMs };
2862
2499
  } catch (err) {
2863
2500
  const durationMs = Date.now() - startMs;
2864
2501
  const reason = err instanceof Error ? err.message : String(err);
2865
- console.error(`${TAG12} failed provider=whisper-local duration_ms=${durationMs} error=${reason}`);
2502
+ console.error(`${TAG11} failed provider=whisper-local duration_ms=${durationMs} error=${reason}`);
2866
2503
  return void 0;
2867
2504
  } finally {
2868
2505
  unlink(wavPath).catch(() => {
@@ -2871,7 +2508,7 @@ async function transcribe(audioPath, mimetype) {
2871
2508
  }
2872
2509
 
2873
2510
  // app/lib/whatsapp/manager.ts
2874
- var TAG13 = "[whatsapp:manager]";
2511
+ var TAG12 = "[whatsapp:manager]";
2875
2512
  var MAX_RECONNECT_ATTEMPTS = 10;
2876
2513
  var MESSAGE_STORE_MAX = 500;
2877
2514
  var GROUP_META_TTL = 5 * 60 * 1e3;
@@ -2891,7 +2528,7 @@ function storeMessage(storeKey, entry) {
2891
2528
  if (entries.length > MESSAGE_STORE_MAX) {
2892
2529
  const trimmed = entries.length - MESSAGE_STORE_MAX;
2893
2530
  entries.splice(0, trimmed);
2894
- console.error(`${TAG13} message store trimmed for ${storeKey}: ${trimmed} oldest messages removed`);
2531
+ console.error(`${TAG12} message store trimmed for ${storeKey}: ${trimmed} oldest messages removed`);
2895
2532
  }
2896
2533
  }
2897
2534
  function deriveCacheKey(input) {
@@ -2910,7 +2547,7 @@ function deriveCacheKey(input) {
2910
2547
  }
2911
2548
  async function init(opts) {
2912
2549
  if (initialized) {
2913
- console.error(`${TAG13} already initialized`);
2550
+ console.error(`${TAG12} already initialized`);
2914
2551
  return;
2915
2552
  }
2916
2553
  configDir = opts.configDir;
@@ -2918,20 +2555,20 @@ async function init(opts) {
2918
2555
  loadConfig(opts.accountConfig);
2919
2556
  const accountIds = listCredentialAccountIds(configDir);
2920
2557
  if (accountIds.length === 0) {
2921
- console.error(`${TAG13} init: no stored WhatsApp credentials found`);
2558
+ console.error(`${TAG12} init: no stored WhatsApp credentials found`);
2922
2559
  initialized = true;
2923
2560
  return;
2924
2561
  }
2925
- console.error(`${TAG13} init: found ${accountIds.length} credentialed account(s): ${accountIds.join(", ")}`);
2562
+ console.error(`${TAG12} init: found ${accountIds.length} credentialed account(s): ${accountIds.join(", ")}`);
2926
2563
  initialized = true;
2927
2564
  for (const accountId of accountIds) {
2928
2565
  const accountCfg = whatsAppConfig.accounts?.[accountId];
2929
2566
  if (accountCfg?.enabled === false) {
2930
- console.error(`${TAG13} skipping disabled account=${accountId}`);
2567
+ console.error(`${TAG12} skipping disabled account=${accountId}`);
2931
2568
  continue;
2932
2569
  }
2933
2570
  startConnection(accountId).catch((err) => {
2934
- console.error(`${TAG13} failed to auto-start account=${accountId}: ${formatError(err)}`);
2571
+ console.error(`${TAG12} failed to auto-start account=${accountId}: ${formatError(err)}`);
2935
2572
  });
2936
2573
  }
2937
2574
  }
@@ -2940,7 +2577,7 @@ async function startConnection(accountId) {
2940
2577
  const authDir = resolveAuthDir(configDir, accountId);
2941
2578
  const hasAuth = await authExists(authDir);
2942
2579
  if (!hasAuth) {
2943
- console.error(`${TAG13} no credentials for account=${accountId}`);
2580
+ console.error(`${TAG12} no credentials for account=${accountId}`);
2944
2581
  return;
2945
2582
  }
2946
2583
  let platformAccountId;
@@ -2991,11 +2628,11 @@ async function stopConnection(accountId) {
2991
2628
  conn.sock.ev.removeAllListeners("creds.update");
2992
2629
  conn.sock.ws?.close?.();
2993
2630
  } catch (err) {
2994
- console.warn(`${TAG13} socket cleanup error during stop account=${accountId}: ${String(err)}`);
2631
+ console.warn(`${TAG12} socket cleanup error during stop account=${accountId}: ${String(err)}`);
2995
2632
  }
2996
2633
  }
2997
2634
  connections.delete(accountId);
2998
- console.error(`${TAG13} stopped account=${accountId}`);
2635
+ console.error(`${TAG12} stopped account=${accountId}`);
2999
2636
  }
3000
2637
  function getStatus() {
3001
2638
  return Array.from(connections.values()).map((conn) => ({
@@ -3057,9 +2694,9 @@ async function registerLoginSocket(accountId, sock, authDir) {
3057
2694
  connections.set(accountId, conn);
3058
2695
  try {
3059
2696
  await sock.sendPresenceUpdate("available");
3060
- console.error(`${TAG13} presence set to available account=${accountId}`);
2697
+ console.error(`${TAG12} presence set to available account=${accountId}`);
3061
2698
  } catch (err) {
3062
- console.error(`${TAG13} presence update failed account=${accountId}: ${String(err)}`);
2699
+ console.error(`${TAG12} presence update failed account=${accountId}: ${String(err)}`);
3063
2700
  }
3064
2701
  await runInitQueries(sock, {
3065
2702
  accountId,
@@ -3071,7 +2708,7 @@ async function registerLoginSocket(accountId, sock, authDir) {
3071
2708
  monitorInbound(conn);
3072
2709
  watchForDisconnect(conn);
3073
2710
  attachSelfIdRefreshOnCredsUpdate(conn);
3074
- console.error(`${TAG13} registered login socket for account=${accountId} phone=${selfId.e164 ?? "unknown"}`);
2711
+ console.error(`${TAG12} registered login socket for account=${accountId} phone=${selfId.e164 ?? "unknown"}`);
3075
2712
  }
3076
2713
  function attachSelfIdRefreshOnCredsUpdate(conn) {
3077
2714
  if (!conn.sock) return;
@@ -3122,24 +2759,23 @@ async function shutdown() {
3122
2759
  const ids = Array.from(connections.keys());
3123
2760
  await Promise.all(ids.map((id) => stopConnection(id)));
3124
2761
  initialized = false;
3125
- console.error(`${TAG13} shutdown complete`);
2762
+ console.error(`${TAG12} shutdown complete`);
3126
2763
  }
3127
2764
  function loadConfig(accountConfig) {
3128
2765
  try {
3129
2766
  const raw = accountConfig?.whatsapp;
3130
2767
  if (raw && typeof raw === "object") {
3131
2768
  const wa = raw;
3132
- migrateAdminPhones(wa);
3133
2769
  const parsed = WhatsAppConfigSchema.safeParse(wa);
3134
2770
  if (parsed.success) {
3135
2771
  whatsAppConfig = parsed.data;
3136
2772
  } else {
3137
- console.error(`${TAG13} config validation failed: ${parsed.error.message}`);
2773
+ console.error(`${TAG12} config validation failed: ${parsed.error.message}`);
3138
2774
  whatsAppConfig = {};
3139
2775
  }
3140
2776
  }
3141
2777
  } catch (err) {
3142
- console.error(`${TAG13} config load error: ${String(err)}`);
2778
+ console.error(`${TAG12} config load error: ${String(err)}`);
3143
2779
  whatsAppConfig = {};
3144
2780
  }
3145
2781
  }
@@ -3150,13 +2786,13 @@ async function connectWithReconnect(conn) {
3150
2786
  let cycleError = null;
3151
2787
  let connectedAt;
3152
2788
  try {
3153
- console.error(`${TAG13} connecting account=${conn.accountId} attempt=${conn.reconnectAttempts}`);
2789
+ console.error(`${TAG12} connecting account=${conn.accountId} attempt=${conn.reconnectAttempts}`);
3154
2790
  const sock = await createWaSocket({
3155
2791
  authDir: conn.authDir,
3156
2792
  silent: true
3157
2793
  });
3158
2794
  conn.sock = sock;
3159
- console.error(`${TAG13} socket created account=${conn.accountId} \u2014 waiting for connection`);
2795
+ console.error(`${TAG12} socket created account=${conn.accountId} \u2014 waiting for connection`);
3160
2796
  await waitForConnection(sock);
3161
2797
  const selfId = readSelfId(conn.authDir);
3162
2798
  connectedAt = Date.now();
@@ -3173,12 +2809,12 @@ async function connectWithReconnect(conn) {
3173
2809
  } else {
3174
2810
  console.error(`[whatsapp:lid] FAIL self-lid-resolution accountId=${conn.accountId} reason=creds-missing-lid`);
3175
2811
  }
3176
- console.error(`${TAG13} connected account=${conn.accountId} phone=${selfId.e164 ?? "unknown"}`);
2812
+ console.error(`${TAG12} connected account=${conn.accountId} phone=${selfId.e164 ?? "unknown"}`);
3177
2813
  try {
3178
2814
  await sock.sendPresenceUpdate("available");
3179
- console.error(`${TAG13} presence set to available account=${conn.accountId}`);
2815
+ console.error(`${TAG12} presence set to available account=${conn.accountId}`);
3180
2816
  } catch (err) {
3181
- console.error(`${TAG13} presence update failed account=${conn.accountId}: ${String(err)}`);
2817
+ console.error(`${TAG12} presence update failed account=${conn.accountId}: ${String(err)}`);
3182
2818
  }
3183
2819
  await runInitQueries(sock, {
3184
2820
  accountId: conn.accountId,
@@ -3206,9 +2842,9 @@ async function connectWithReconnect(conn) {
3206
2842
  }
3207
2843
  const classification = classifyDisconnect(err);
3208
2844
  conn.lastError = classification.message;
3209
- console.error(`${TAG13} disconnect account=${conn.accountId}: ${classification.kind} \u2014 ${classification.message}`);
2845
+ console.error(`${TAG12} disconnect account=${conn.accountId}: ${classification.kind} \u2014 ${classification.message}`);
3210
2846
  if (!classification.shouldRetry) {
3211
- console.error(`${TAG13} terminal disconnect for account=${conn.accountId}, stopping reconnection`);
2847
+ console.error(`${TAG12} terminal disconnect for account=${conn.accountId}, stopping reconnection`);
3212
2848
  return;
3213
2849
  }
3214
2850
  }
@@ -3221,7 +2857,7 @@ async function connectWithReconnect(conn) {
3221
2857
  if (decision.action === "abort") {
3222
2858
  const stuckReason = `GIVING UP account=${conn.accountId} attempts=${decision.finalAttempts}/${maxAttempts} uptimeMsLast=${uptimeMs} stableThresholdMs=${STABLE_UPTIME_MS} lastError=${conn.lastError ?? "(none)"}`;
3223
2859
  console.error(
3224
- `${TAG13} ${stuckReason} \u2014 re-pair via QR or restart required; WhatsApp will not reconnect automatically`
2860
+ `${TAG12} ${stuckReason} \u2014 re-pair via QR or restart required; WhatsApp will not reconnect automatically`
3225
2861
  );
3226
2862
  conn.sessionStuckReason = stuckReason;
3227
2863
  conn.lastError = stuckReason;
@@ -3230,17 +2866,17 @@ async function connectWithReconnect(conn) {
3230
2866
  conn.reconnectAttempts = decision.nextAttempts;
3231
2867
  if (decision.reason === "short-lived") {
3232
2868
  console.error(
3233
- `${TAG13} short-lived session account=${conn.accountId} uptimeMs=${uptimeMs} attempt=${decision.nextAttempts}/${maxAttempts} lastError=${conn.lastError ?? "(clean disconnect)"}`
2869
+ `${TAG12} short-lived session account=${conn.accountId} uptimeMs=${uptimeMs} attempt=${decision.nextAttempts}/${maxAttempts} lastError=${conn.lastError ?? "(clean disconnect)"}`
3234
2870
  );
3235
2871
  } else {
3236
2872
  console.error(
3237
- `${TAG13} session stable account=${conn.accountId} uptimeMs=${uptimeMs} \u2014 reconnect counter reset`
2873
+ `${TAG12} session stable account=${conn.accountId} uptimeMs=${uptimeMs} \u2014 reconnect counter reset`
3238
2874
  );
3239
2875
  }
3240
2876
  if (decision.reason === "short-lived" || cycleError) {
3241
2877
  const delay = computeBackoff(Math.max(1, decision.nextAttempts));
3242
2878
  console.error(
3243
- `${TAG13} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
2879
+ `${TAG12} reconnecting account=${conn.accountId} in ${delay}ms (attempt ${decision.nextAttempts}/${maxAttempts})`
3244
2880
  );
3245
2881
  await new Promise((resolve24) => {
3246
2882
  const timer2 = setTimeout(resolve24, delay);
@@ -3274,11 +2910,11 @@ function watchForDisconnect(conn) {
3274
2910
  conn.sock.ev.on("connection.update", (update) => {
3275
2911
  if (update.connection === "close") {
3276
2912
  if (connections.get(conn.accountId) !== conn) return;
3277
- console.error(`${TAG13} socket disconnected for account=${conn.accountId}`);
2913
+ console.error(`${TAG12} socket disconnected for account=${conn.accountId}`);
3278
2914
  conn.connected = false;
3279
2915
  conn.sock = null;
3280
2916
  connectWithReconnect(conn).catch((err) => {
3281
- console.error(`${TAG13} reconnection failed for account=${conn.accountId}: ${formatError(err)}`);
2917
+ console.error(`${TAG12} reconnection failed for account=${conn.accountId}: ${formatError(err)}`);
3282
2918
  });
3283
2919
  }
3284
2920
  });
@@ -3287,7 +2923,7 @@ async function getGroupMeta(conn, jid) {
3287
2923
  const cached2 = conn.groupMetaCache.get(jid);
3288
2924
  if (cached2 && cached2.expires > Date.now()) return cached2;
3289
2925
  if (!conn.sock) return null;
3290
- console.error(`${TAG13} group metadata cache miss for ${jid}, fetching from Baileys account=${conn.accountId}`);
2926
+ console.error(`${TAG12} group metadata cache miss for ${jid}, fetching from Baileys account=${conn.accountId}`);
3291
2927
  try {
3292
2928
  const meta = await conn.sock.groupMetadata(jid);
3293
2929
  const participants = await Promise.all(
@@ -3302,12 +2938,12 @@ async function getGroupMeta(conn, jid) {
3302
2938
  };
3303
2939
  conn.groupMetaCache.set(jid, entry);
3304
2940
  console.error(
3305
- `${TAG13} group metadata cached for ${jid}: "${meta.subject}", ${participants.length} participants, expires in ${GROUP_META_TTL}ms account=${conn.accountId}`
2941
+ `${TAG12} group metadata cached for ${jid}: "${meta.subject}", ${participants.length} participants, expires in ${GROUP_META_TTL}ms account=${conn.accountId}`
3306
2942
  );
3307
2943
  return entry;
3308
2944
  } catch (err) {
3309
2945
  console.error(
3310
- `${TAG13} group metadata fetch failed for ${jid}: ${err instanceof Error ? err.message : String(err)}, caching empty entry for ${GROUP_META_TTL}ms account=${conn.accountId}`
2946
+ `${TAG12} group metadata fetch failed for ${jid}: ${err instanceof Error ? err.message : String(err)}, caching empty entry for ${GROUP_META_TTL}ms account=${conn.accountId}`
3311
2947
  );
3312
2948
  const emptyEntry = { expires: Date.now() + GROUP_META_TTL };
3313
2949
  conn.groupMetaCache.set(jid, emptyEntry);
@@ -3318,7 +2954,7 @@ function monitorInbound(conn) {
3318
2954
  if (!conn.sock || !onInboundMessage) return;
3319
2955
  const sock = conn.sock;
3320
2956
  const debounceMs = whatsAppConfig.accounts?.[conn.accountId]?.debounceMs ?? whatsAppConfig.debounceMs ?? 0;
3321
- console.error(`${TAG13} monitorInbound started account=${conn.accountId} debounceMs=${debounceMs}`);
2957
+ console.error(`${TAG12} monitorInbound started account=${conn.accountId} debounceMs=${debounceMs}`);
3322
2958
  conn.debouncer = createInboundDebouncer({
3323
2959
  debounceMs,
3324
2960
  buildKey: (payload) => {
@@ -3331,7 +2967,7 @@ function monitorInbound(conn) {
3331
2967
  onInboundMessage(entries[0]);
3332
2968
  return;
3333
2969
  }
3334
- console.error(`${TAG13} debounce: combining ${entries.length} messages account=${conn.accountId} from=${entries[0].senderPhone}`);
2970
+ console.error(`${TAG12} debounce: combining ${entries.length} messages account=${conn.accountId} from=${entries[0].senderPhone}`);
3335
2971
  const last = entries[entries.length - 1];
3336
2972
  const mediaEntry = entries.find((e) => e.mediaPath);
3337
2973
  const combinedText = entries.map((e) => e.text).filter(Boolean).join("\n");
@@ -3344,7 +2980,7 @@ function monitorInbound(conn) {
3344
2980
  });
3345
2981
  },
3346
2982
  onError: (err) => {
3347
- console.error(`${TAG13} debounce flush error account=${conn.accountId}: ${String(err)}`);
2983
+ console.error(`${TAG12} debounce flush error account=${conn.accountId}: ${String(err)}`);
3348
2984
  }
3349
2985
  });
3350
2986
  sock.ev.on("messages.upsert", async (upsert) => {
@@ -3372,7 +3008,7 @@ function monitorInbound(conn) {
3372
3008
  });
3373
3009
  const entries = messageStore.get(storeKey);
3374
3010
  console.error(
3375
- `${TAG13} stored message ${msg.key.id ?? "?"} for ${remoteJid} (type: ${upsert.type}, store size: ${entries?.length ?? 0}/${MESSAGE_STORE_MAX}) account=${conn.accountId}`
3011
+ `${TAG12} stored message ${msg.key.id ?? "?"} for ${remoteJid} (type: ${upsert.type}, store size: ${entries?.length ?? 0}/${MESSAGE_STORE_MAX}) account=${conn.accountId}`
3376
3012
  );
3377
3013
  recordActivity({
3378
3014
  accountId: conn.accountId,
@@ -3436,13 +3072,13 @@ function monitorInbound(conn) {
3436
3072
  );
3437
3073
  }
3438
3074
  console.error(
3439
- `${TAG13} append-type message ${msg.key.id ?? "?"} stored, dispatch skipped account=${conn.accountId}`
3075
+ `${TAG12} append-type message ${msg.key.id ?? "?"} stored, dispatch skipped account=${conn.accountId}`
3440
3076
  );
3441
3077
  continue;
3442
3078
  }
3443
3079
  await handleInboundMessage(conn, msg);
3444
3080
  } catch (err) {
3445
- console.error(`${TAG13} inbound handler error account=${conn.accountId}: ${String(err)}`);
3081
+ console.error(`${TAG12} inbound handler error account=${conn.accountId}: ${String(err)}`);
3446
3082
  }
3447
3083
  }
3448
3084
  });
@@ -3452,31 +3088,31 @@ async function handleInboundMessage(conn, msg) {
3452
3088
  const remoteJid = msg.key.remoteJid;
3453
3089
  if (!remoteJid) return;
3454
3090
  if (remoteJid === "status@broadcast") {
3455
- console.error(`${TAG13} drop: status broadcast account=${conn.accountId}`);
3091
+ console.error(`${TAG12} drop: status broadcast account=${conn.accountId}`);
3456
3092
  return;
3457
3093
  }
3458
3094
  if (!msg.message) {
3459
- console.error(`${TAG13} drop: empty message account=${conn.accountId} from=${remoteJid}`);
3095
+ console.error(`${TAG12} drop: empty message account=${conn.accountId} from=${remoteJid}`);
3460
3096
  return;
3461
3097
  }
3462
3098
  const dedupKey = `${conn.accountId}:${remoteJid}:${msg.key.id}`;
3463
3099
  if (isDuplicateInbound(dedupKey)) {
3464
- console.error(`${TAG13} drop: duplicate account=${conn.accountId} key=${dedupKey}`);
3100
+ console.error(`${TAG12} drop: duplicate account=${conn.accountId} key=${dedupKey}`);
3465
3101
  return;
3466
3102
  }
3467
3103
  if (msg.key.fromMe) {
3468
3104
  if (msg.key.id && isAgentSentMessage(msg.key.id)) {
3469
- console.error(`${TAG13} drop: echo suppression account=${conn.accountId} msgId=${msg.key.id}`);
3105
+ console.error(`${TAG12} drop: echo suppression account=${conn.accountId} msgId=${msg.key.id}`);
3470
3106
  return;
3471
3107
  }
3472
3108
  const extracted2 = extractMessage(msg);
3473
3109
  if (!extracted2.text) {
3474
- console.error(`${TAG13} owner reply skipped \u2014 no text content account=${conn.accountId}`);
3110
+ console.error(`${TAG12} owner reply skipped \u2014 no text content account=${conn.accountId}`);
3475
3111
  return;
3476
3112
  }
3477
3113
  const isGroup2 = isGroupJid(remoteJid);
3478
3114
  const senderPhone2 = conn.selfPhone ?? "owner";
3479
- console.error(`${TAG13} owner reply mirrored to session from=${senderPhone2} account=${conn.accountId}`);
3115
+ console.error(`${TAG12} owner reply mirrored to session from=${senderPhone2} account=${conn.accountId}`);
3480
3116
  const reply2 = async (text) => {
3481
3117
  const currentSock = conn.sock;
3482
3118
  if (!currentSock) throw new Error("WhatsApp disconnected \u2014 cannot reply");
@@ -3504,7 +3140,7 @@ async function handleInboundMessage(conn, msg) {
3504
3140
  }
3505
3141
  const extracted = extractMessage(msg);
3506
3142
  if (!extracted.text && !extracted.mediaType) {
3507
- console.error(`${TAG13} drop: no text or media account=${conn.accountId} from=${remoteJid}`);
3143
+ console.error(`${TAG12} drop: no text or media account=${conn.accountId} from=${remoteJid}`);
3508
3144
  return;
3509
3145
  }
3510
3146
  let mediaResult;
@@ -3514,7 +3150,7 @@ async function handleInboundMessage(conn, msg) {
3514
3150
  maxBytes: maxMb * 1024 * 1024
3515
3151
  });
3516
3152
  if (!mediaResult) {
3517
- console.error(`${TAG13} media download returned undefined account=${conn.accountId} type=${extracted.mediaType} from=${remoteJid}`);
3153
+ console.error(`${TAG12} media download returned undefined account=${conn.accountId} type=${extracted.mediaType} from=${remoteJid}`);
3518
3154
  }
3519
3155
  }
3520
3156
  const isGroup = isGroupJid(remoteJid);
@@ -3567,7 +3203,7 @@ async function handleInboundMessage(conn, msg) {
3567
3203
  });
3568
3204
  }
3569
3205
  console.error(
3570
- `${TAG13} inbound account=${conn.accountId} from=${senderPhone} group=${isGroup} access=${accessResult.allowed ? "allowed" : "blocked"}(${accessResult.reason}) agent=${accessResult.agentType}` + (extracted.mediaType ? ` media=${extracted.mediaType}` : "") + (mediaResult ? ` mediaPath=${mediaResult.path}` : "") + (extracted.quotedMessage ? ` replyTo=${extracted.quotedMessage.id}` : "")
3206
+ `${TAG12} inbound account=${conn.accountId} from=${senderPhone} group=${isGroup} access=${accessResult.allowed ? "allowed" : "blocked"}(${accessResult.reason}) agent=${accessResult.agentType}` + (extracted.mediaType ? ` media=${extracted.mediaType}` : "") + (mediaResult ? ` mediaPath=${mediaResult.path}` : "") + (extracted.quotedMessage ? ` replyTo=${extracted.quotedMessage.id}` : "")
3571
3207
  );
3572
3208
  if (!accessResult.allowed) return;
3573
3209
  let groupSubject;
@@ -3610,15 +3246,15 @@ async function handleInboundMessage(conn, msg) {
3610
3246
  if (accessResult.agentType === "public") {
3611
3247
  const hoursResult = await isBusinessOpen(conn.accountId);
3612
3248
  if (!hoursResult.open) {
3613
- console.error(`${TAG13} [${conn.accountId}] dispatch skipped: business closed`);
3249
+ console.error(`${TAG12} [${conn.accountId}] dispatch skipped: business closed`);
3614
3250
  const afterHoursMessage = whatsAppConfig.accounts?.[conn.accountId]?.afterHoursMessage ?? whatsAppConfig.afterHoursMessage;
3615
3251
  if (afterHoursMessage) {
3616
3252
  try {
3617
3253
  await reply(afterHoursMessage);
3618
- console.error(`${TAG13} [${conn.accountId}] after-hours auto-reply sent to ${remoteJid}`);
3254
+ console.error(`${TAG12} [${conn.accountId}] after-hours auto-reply sent to ${remoteJid}`);
3619
3255
  } catch (err) {
3620
3256
  console.error(
3621
- `${TAG13} [${conn.accountId}] after-hours auto-reply failed: ${err instanceof Error ? err.message : String(err)}`
3257
+ `${TAG12} [${conn.accountId}] after-hours auto-reply failed: ${err instanceof Error ? err.message : String(err)}`
3622
3258
  );
3623
3259
  }
3624
3260
  }
@@ -3635,10 +3271,10 @@ async function handleInboundMessage(conn, msg) {
3635
3271
  // app/lib/vnc.ts
3636
3272
  import { spawnSync, execFileSync } from "child_process";
3637
3273
  import { createConnection } from "net";
3638
- import { mkdirSync, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
3639
- import { resolve as resolve3 } from "path";
3640
- var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve3(process.cwd(), "..");
3641
- var VNC_SCRIPT = resolve3(PLATFORM_ROOT2, "scripts/vnc.sh");
3274
+ import { mkdirSync, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
3275
+ import { resolve as resolve2 } from "path";
3276
+ var PLATFORM_ROOT2 = process.env.MAXY_PLATFORM_ROOT ?? resolve2(process.cwd(), "..");
3277
+ var VNC_SCRIPT = resolve2(PLATFORM_ROOT2, "scripts/vnc.sh");
3642
3278
  var displayMode = process.env.DISPLAY_MODE ?? "virtual";
3643
3279
  if (displayMode === "native") {
3644
3280
  console.log(`[vnc] DISPLAY_MODE=native \u2014 local requests use desktop display, remote requests use VNC`);
@@ -3693,7 +3329,7 @@ function discoverNativeDisplay() {
3693
3329
  const leaderPid = leaderResult.stdout?.trim();
3694
3330
  if (leaderPid) {
3695
3331
  try {
3696
- const environ = readFileSync4(`/proc/${leaderPid}/environ`, "utf8");
3332
+ const environ = readFileSync3(`/proc/${leaderPid}/environ`, "utf8");
3697
3333
  const match = environ.split("\0").find((e) => e.startsWith("WAYLAND_DISPLAY="));
3698
3334
  if (match) waylandDisplay = match.split("=")[1];
3699
3335
  } catch {
@@ -3751,7 +3387,7 @@ function ensureLogDir() {
3751
3387
  mkdirSync(LOG_DIR, { recursive: true });
3752
3388
  }
3753
3389
  function logPath(name) {
3754
- return resolve3(LOG_DIR, `${name}.log`);
3390
+ return resolve2(LOG_DIR, `${name}.log`);
3755
3391
  }
3756
3392
  async function ensureVnc() {
3757
3393
  const up = await waitForPort(RFB_PORT, 1e3);
@@ -3830,8 +3466,8 @@ function killChromium() {
3830
3466
  }
3831
3467
  function writeChromiumWrapper() {
3832
3468
  mkdirSync(BIN_DIR, { recursive: true });
3833
- const wrapperPath = resolve3(BIN_DIR, "chromium");
3834
- writeFileSync3(wrapperPath, `#!/bin/bash
3469
+ const wrapperPath = resolve2(BIN_DIR, "chromium");
3470
+ writeFileSync2(wrapperPath, `#!/bin/bash
3835
3471
  LOG="${LOG_DIR}/chromium.log"
3836
3472
  echo "==== [$(date)] chromium wrapper ====" >> "$LOG"
3837
3473
  echo " DISPLAY=$DISPLAY WAYLAND=$WAYLAND_DISPLAY XDG_SESSION_TYPE=$XDG_SESSION_TYPE" >> "$LOG"
@@ -3952,8 +3588,8 @@ app.get("/", async (c) => {
3952
3588
  const browserTransport = resolveBrowserTransport(c.req.raw, c.env?.incoming?.socket?.remoteAddress);
3953
3589
  let pinConfigured = false;
3954
3590
  try {
3955
- if (existsSync3(USERS_FILE)) {
3956
- const raw = readFileSync5(USERS_FILE, "utf-8").trim();
3591
+ if (existsSync2(USERS_FILE)) {
3592
+ const raw = readFileSync4(USERS_FILE, "utf-8").trim();
3957
3593
  if (raw) {
3958
3594
  const users = JSON.parse(raw);
3959
3595
  pinConfigured = Array.isArray(users) && users.length > 0;
@@ -4010,9 +3646,9 @@ var health_default = app;
4010
3646
  import { randomUUID as randomUUID3 } from "crypto";
4011
3647
  import { mkdir as mkdir2, readFile, stat as stat2, writeFile as writeFile2 } from "fs/promises";
4012
3648
  import { realpathSync } from "fs";
4013
- import { resolve as resolve4, extname, basename } from "path";
4014
- var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve4(process.cwd(), "../platform");
4015
- var ATTACHMENTS_ROOT = resolve4(PLATFORM_ROOT3, "..", "data/uploads");
3649
+ import { resolve as resolve3, extname, basename } from "path";
3650
+ var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve3(process.cwd(), "../platform");
3651
+ var ATTACHMENTS_ROOT = resolve3(PLATFORM_ROOT3, "..", "data/uploads");
4016
3652
  var SUPPORTED_MIME_TYPES = /* @__PURE__ */ new Set([
4017
3653
  "image/jpeg",
4018
3654
  "image/png",
@@ -4039,11 +3675,11 @@ function assertSupportedMime(mimeType) {
4039
3675
  }
4040
3676
  async function writeAttachment(scope, filename, mimeType, sizeBytes, buffer) {
4041
3677
  const attachmentId = randomUUID3();
4042
- const dir = resolve4(ATTACHMENTS_ROOT, scope, attachmentId);
3678
+ const dir = resolve3(ATTACHMENTS_ROOT, scope, attachmentId);
4043
3679
  await mkdir2(dir, { recursive: true });
4044
3680
  const ext = extname(filename) || "";
4045
- const storagePath = resolve4(dir, `${attachmentId}${ext}`);
4046
- const metaPath = resolve4(dir, `${attachmentId}.meta.json`);
3681
+ const storagePath = resolve3(dir, `${attachmentId}${ext}`);
3682
+ const metaPath = resolve3(dir, `${attachmentId}.meta.json`);
4047
3683
  const meta = {
4048
3684
  attachmentId,
4049
3685
  scope,
@@ -4119,11 +3755,11 @@ async function storeComponentArtefact(accountId, attachmentId, mimeType, content
4119
3755
  `Component artefact exceeds the 50 MB limit (${(buffer.byteLength / 1024 / 1024).toFixed(1)} MB).`
4120
3756
  );
4121
3757
  }
4122
- const dir = resolve4(ATTACHMENTS_ROOT, accountId, attachmentId);
3758
+ const dir = resolve3(ATTACHMENTS_ROOT, accountId, attachmentId);
4123
3759
  await mkdir2(dir, { recursive: true });
4124
3760
  const ext = extname(filename) || (mimeType === "text/html" ? ".html" : ".md");
4125
- const storagePath = resolve4(dir, `${attachmentId}${ext}`);
4126
- const metaPath = resolve4(dir, `${attachmentId}.meta.json`);
3761
+ const storagePath = resolve3(dir, `${attachmentId}${ext}`);
3762
+ const metaPath = resolve3(dir, `${attachmentId}.meta.json`);
4127
3763
  const meta = {
4128
3764
  attachmentId,
4129
3765
  scope: accountId,
@@ -4140,8 +3776,8 @@ async function storeComponentArtefact(accountId, attachmentId, mimeType, content
4140
3776
  // app/lib/stt/voice-note.ts
4141
3777
  import { writeFile as writeFile3, mkdtemp, rm } from "fs/promises";
4142
3778
  import { tmpdir } from "os";
4143
- import { join as join4 } from "path";
4144
- var TAG14 = "[voice]";
3779
+ import { join as join3 } from "path";
3780
+ var TAG13 = "[voice]";
4145
3781
  var AUDIO_MIME_TYPES = /* @__PURE__ */ new Set([
4146
3782
  "audio/ogg",
4147
3783
  "audio/opus",
@@ -4179,19 +3815,19 @@ async function transcribeVoiceNote(file, source) {
4179
3815
  const bytes = file.size;
4180
3816
  const mimeType = file.type;
4181
3817
  console.error(
4182
- `${TAG14} recording send source=${source} duration_ms=unknown bytes=${bytes} format=${mimeType}`
3818
+ `${TAG13} recording send source=${source} duration_ms=unknown bytes=${bytes} format=${mimeType}`
4183
3819
  );
4184
3820
  let tempDir;
4185
3821
  let tempPath;
4186
3822
  try {
4187
- tempDir = await mkdtemp(join4(tmpdir(), "voice-"));
3823
+ tempDir = await mkdtemp(join3(tmpdir(), "voice-"));
4188
3824
  const ext = audioExtension(mimeType);
4189
- tempPath = join4(tempDir, `recording${ext}`);
3825
+ tempPath = join3(tempDir, `recording${ext}`);
4190
3826
  const buffer = Buffer.from(await file.arrayBuffer());
4191
3827
  await writeFile3(tempPath, buffer);
4192
3828
  } catch (err) {
4193
3829
  const reason = err instanceof Error ? err.message : String(err);
4194
- console.error(`${TAG14} failed source=${source} error=temp-file-write: ${reason}`);
3830
+ console.error(`${TAG13} failed source=${source} error=temp-file-write: ${reason}`);
4195
3831
  return { ok: false, error: "Could not process voice note" };
4196
3832
  }
4197
3833
  try {
@@ -4199,7 +3835,7 @@ async function transcribeVoiceNote(file, source) {
4199
3835
  if (!sttResult) {
4200
3836
  const elapsed2 = Date.now() - startMs;
4201
3837
  console.error(
4202
- `${TAG14} failed source=${source} error=transcription-failed duration_ms=${elapsed2}`
3838
+ `${TAG13} failed source=${source} error=transcription-failed duration_ms=${elapsed2}`
4203
3839
  );
4204
3840
  return { ok: false, error: "Could not transcribe voice note. Please try again or type your message." };
4205
3841
  }
@@ -4207,7 +3843,7 @@ async function transcribeVoiceNote(file, source) {
4207
3843
  const elapsed = Date.now() - startMs;
4208
3844
  const words = rawText.split(/\s+/).filter(Boolean).length;
4209
3845
  console.error(
4210
- `${TAG14} transcribed source=${source} duration_ms=${elapsed} stt_ms=${sttResult.durationMs} words=${words}`
3846
+ `${TAG13} transcribed source=${source} duration_ms=${elapsed} stt_ms=${sttResult.durationMs} words=${words}`
4211
3847
  );
4212
3848
  return {
4213
3849
  ok: true,
@@ -4217,7 +3853,7 @@ async function transcribeVoiceNote(file, source) {
4217
3853
  const elapsed = Date.now() - startMs;
4218
3854
  const reason = err instanceof Error ? err.message : String(err);
4219
3855
  console.error(
4220
- `${TAG14} failed source=${source} error=${reason} duration_ms=${elapsed}`
3856
+ `${TAG13} failed source=${source} error=${reason} duration_ms=${elapsed}`
4221
3857
  );
4222
3858
  return { ok: false, error: "Voice note transcription failed. Please try again or type your message." };
4223
3859
  } finally {
@@ -4227,10 +3863,10 @@ async function transcribeVoiceNote(file, source) {
4227
3863
  }
4228
3864
 
4229
3865
  // ../lib/oauth-llm/src/index.ts
4230
- import { readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
4231
- import { resolve as resolve5 } from "path";
3866
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
3867
+ import { resolve as resolve4 } from "path";
4232
3868
  import { homedir } from "os";
4233
- var CREDENTIALS_FILE = process.env.CLAUDE_CONFIG_DIR ? resolve5(process.env.CLAUDE_CONFIG_DIR, ".credentials.json") : resolve5(homedir(), ".claude", ".credentials.json");
3869
+ var CREDENTIALS_FILE = process.env.CLAUDE_CONFIG_DIR ? resolve4(process.env.CLAUDE_CONFIG_DIR, ".credentials.json") : resolve4(homedir(), ".claude", ".credentials.json");
4234
3870
  var TOKEN_ENDPOINT2 = "https://platform.claude.com/v1/oauth/token";
4235
3871
  var ANTHROPIC_MESSAGES_ENDPOINT = "https://api.anthropic.com/v1/messages";
4236
3872
  var ANTHROPIC_VERSION = "2023-06-01";
@@ -4249,7 +3885,7 @@ function isInputTooLargeBody(body) {
4249
3885
  function readCredentials2() {
4250
3886
  let raw;
4251
3887
  try {
4252
- raw = readFileSync6(CREDENTIALS_FILE, "utf-8");
3888
+ raw = readFileSync5(CREDENTIALS_FILE, "utf-8");
4253
3889
  } catch {
4254
3890
  return null;
4255
3891
  }
@@ -4278,7 +3914,7 @@ function writeCredentials(tokens) {
4278
3914
  const newExpiresAt = typeof tokens.expiresIn === "number" && tokens.expiresIn > 0 ? Date.now() + tokens.expiresIn * 1e3 : Date.now() + 3600 * 1e3;
4279
3915
  let fileData = {};
4280
3916
  try {
4281
- fileData = JSON.parse(readFileSync6(CREDENTIALS_FILE, "utf-8"));
3917
+ fileData = JSON.parse(readFileSync5(CREDENTIALS_FILE, "utf-8"));
4282
3918
  } catch {
4283
3919
  }
4284
3920
  const existing = fileData.claudeAiOauth;
@@ -4288,7 +3924,7 @@ function writeCredentials(tokens) {
4288
3924
  ...tokens.refreshToken != null ? { refreshToken: tokens.refreshToken } : {},
4289
3925
  expiresAt: newExpiresAt
4290
3926
  };
4291
- writeFileSync4(CREDENTIALS_FILE, JSON.stringify(fileData, null, 2), "utf-8");
3927
+ writeFileSync3(CREDENTIALS_FILE, JSON.stringify(fileData, null, 2), "utf-8");
4292
3928
  return newExpiresAt;
4293
3929
  }
4294
3930
  var refreshLock2 = null;
@@ -4556,7 +4192,7 @@ var VERDICT_DEFINITIONS = {
4556
4192
  };
4557
4193
 
4558
4194
  // app/lib/inbound-gateway.ts
4559
- var TAG15 = "[inbound-gateway]";
4195
+ var TAG14 = "[inbound-gateway]";
4560
4196
  var GATEWAY_TIMEOUT_MS = 1e4;
4561
4197
  var MIN_WORDS_FOR_PROCESSING = 5;
4562
4198
  function defaultResult(rawText, latencyMs) {
@@ -4679,11 +4315,11 @@ async function processInbound(rawText, channel) {
4679
4315
  };
4680
4316
  result.fallthrough = false;
4681
4317
  console.warn(
4682
- `${TAG15} short-message-injection channel=${channel} words=${words.length} latency_ms=${result.latencyMs}`
4318
+ `${TAG14} short-message-injection channel=${channel} words=${words.length} latency_ms=${result.latencyMs}`
4683
4319
  );
4684
4320
  } else {
4685
4321
  console.log(
4686
- `${TAG15} passthrough channel=${channel} reason=short-message words=${words.length} latency_ms=${result.latencyMs}`
4322
+ `${TAG14} passthrough channel=${channel} reason=short-message words=${words.length} latency_ms=${result.latencyMs}`
4687
4323
  );
4688
4324
  }
4689
4325
  return result;
@@ -4700,13 +4336,13 @@ async function processInbound(rawText, channel) {
4700
4336
  const latencyMs = Date.now() - startMs;
4701
4337
  if (llmResult.kind === "fallback") {
4702
4338
  console.warn(
4703
- `${TAG15} fallthrough channel=${channel} reason=${llmResult.cause} detail=${llmResult.reason} latency_ms=${latencyMs}`
4339
+ `${TAG14} fallthrough channel=${channel} reason=${llmResult.cause} detail=${llmResult.reason} latency_ms=${latencyMs}`
4704
4340
  );
4705
4341
  return defaultResult(rawText.trim(), latencyMs);
4706
4342
  }
4707
4343
  if (llmResult.kind !== "ok-tool") {
4708
4344
  console.warn(
4709
- `${TAG15} fallthrough channel=${channel} reason=no-tool-response latency_ms=${latencyMs}`
4345
+ `${TAG14} fallthrough channel=${channel} reason=no-tool-response latency_ms=${latencyMs}`
4710
4346
  );
4711
4347
  return defaultResult(rawText.trim(), latencyMs);
4712
4348
  }
@@ -4716,7 +4352,7 @@ async function processInbound(rawText, channel) {
4716
4352
  const verdict = input.verdict;
4717
4353
  if (!processedText || !verdict || !["clean", "suspicious", "discard"].includes(verdict)) {
4718
4354
  console.warn(
4719
- `${TAG15} fallthrough channel=${channel} reason=mandatory-fields-missing latency_ms=${latencyMs} hasProcessedText=${!!processedText} verdict=${String(verdict)}`
4355
+ `${TAG14} fallthrough channel=${channel} reason=mandatory-fields-missing latency_ms=${latencyMs} hasProcessedText=${!!processedText} verdict=${String(verdict)}`
4720
4356
  );
4721
4357
  return defaultResult(rawText.trim(), latencyMs);
4722
4358
  }
@@ -4744,25 +4380,25 @@ async function processInbound(rawText, channel) {
4744
4380
  fallthrough: false
4745
4381
  };
4746
4382
  console.log(
4747
- `${TAG15} channel=${channel} verdict=${verdict} promptInjection=${promptInjectionRisk} intent=${intent} language=${language} complexity=${complexity} requiresHistory=${requiresHistory} rewrite=${!isAdmin && processedText !== rawText.trim()} searchQuery=${searchQuery ? "yes" : "null"} latency_ms=${latencyMs}`
4383
+ `${TAG14} channel=${channel} verdict=${verdict} promptInjection=${promptInjectionRisk} intent=${intent} language=${language} complexity=${complexity} requiresHistory=${requiresHistory} rewrite=${!isAdmin && processedText !== rawText.trim()} searchQuery=${searchQuery ? "yes" : "null"} latency_ms=${latencyMs}`
4748
4384
  );
4749
4385
  if (verdict !== "clean") {
4750
4386
  console.warn(
4751
- `${TAG15} ${verdict.toUpperCase()} channel=${channel} reason=${reason} promptInjection=${promptInjectionRisk}`
4387
+ `${TAG14} ${verdict.toUpperCase()} channel=${channel} reason=${reason} promptInjection=${promptInjectionRisk}`
4752
4388
  );
4753
4389
  }
4754
4390
  return result;
4755
4391
  } catch (err) {
4756
4392
  const reason = err instanceof Error ? err.message : String(err);
4757
4393
  console.warn(
4758
- `${TAG15} fallthrough channel=${channel} reason=parse-error: ${reason} latency_ms=${latencyMs}`
4394
+ `${TAG14} fallthrough channel=${channel} reason=parse-error: ${reason} latency_ms=${latencyMs}`
4759
4395
  );
4760
4396
  return defaultResult(rawText.trim(), latencyMs);
4761
4397
  }
4762
4398
  }
4763
4399
 
4764
4400
  // app/lib/channel-pty-bridge/bridge.ts
4765
- import { resolve as resolve6 } from "path";
4401
+ import { resolve as resolve5 } from "path";
4766
4402
 
4767
4403
  // app/lib/channel-pty-bridge/manager-client.ts
4768
4404
  function managerBase() {
@@ -4780,7 +4416,9 @@ async function managerSpawn(opts) {
4780
4416
  accountId: opts.accountId,
4781
4417
  attachmentDir: opts.attachmentDir,
4782
4418
  aboutOwner: opts.aboutOwner,
4783
- dormantPlugins: opts.dormantPlugins
4419
+ dormantPlugins: opts.dormantPlugins,
4420
+ activePlugins: opts.activePlugins,
4421
+ specialistDomains: opts.specialistDomains
4784
4422
  })
4785
4423
  }).catch((err) => ({ __throw: err instanceof Error ? err.message : String(err) }));
4786
4424
  if ("__throw" in res) {
@@ -4922,7 +4560,7 @@ async function ensureEntry(input) {
4922
4560
  }
4923
4561
  return existing;
4924
4562
  }
4925
- const attachmentDir = input.role === "public" ? resolve6(ATTACHMENTS_ROOT, "public", input.senderId) : void 0;
4563
+ const attachmentDir = input.role === "public" ? resolve5(ATTACHMENTS_ROOT, "public", input.senderId) : void 0;
4926
4564
  const spawned = await managerSpawn({
4927
4565
  senderId: input.senderId,
4928
4566
  role: input.role,
@@ -5285,14 +4923,14 @@ import { realpathSync as realpathSync2, readdirSync as readdirSync2, readFileSyn
5285
4923
 
5286
4924
  // app/lib/whatsapp/login.ts
5287
4925
  import { randomUUID as randomUUID4 } from "crypto";
5288
- var TAG16 = "[whatsapp:login]";
4926
+ var TAG15 = "[whatsapp:login]";
5289
4927
  var ACTIVE_LOGIN_TTL_MS = 3 * 6e4;
5290
4928
  var activeLogins = /* @__PURE__ */ new Map();
5291
4929
  function closeSocket(sock) {
5292
4930
  try {
5293
4931
  sock.ws?.close?.();
5294
4932
  } catch (err) {
5295
- console.warn(`${TAG16} socket close error during cleanup: ${String(err)}`);
4933
+ console.warn(`${TAG15} socket close error during cleanup: ${String(err)}`);
5296
4934
  }
5297
4935
  }
5298
4936
  function resetActiveLogin(accountId) {
@@ -5315,7 +4953,7 @@ async function loginConnectionLoop(accountId, login) {
5315
4953
  const current = activeLogins.get(accountId);
5316
4954
  if (current?.id === login.id) {
5317
4955
  current.connected = true;
5318
- console.error(`${TAG16} loginConnectionLoop: connected account=${accountId} attempt=${attempt}`);
4956
+ console.error(`${TAG15} loginConnectionLoop: connected account=${accountId} attempt=${attempt}`);
5319
4957
  }
5320
4958
  return;
5321
4959
  } catch (err) {
@@ -5325,7 +4963,7 @@ async function loginConnectionLoop(accountId, login) {
5325
4963
  if (!classification.shouldRetry || attempt >= LOGIN_MAX_RECONNECTS) {
5326
4964
  if (attempt >= LOGIN_MAX_RECONNECTS) {
5327
4965
  console.error(
5328
- `${TAG16} login reconnect attempts exhausted (${attempt}/${LOGIN_MAX_RECONNECTS}) \u2014 surfacing error to agent`
4966
+ `${TAG15} login reconnect attempts exhausted (${attempt}/${LOGIN_MAX_RECONNECTS}) \u2014 surfacing error to agent`
5329
4967
  );
5330
4968
  current.error = `Login failed after ${attempt} reconnect attempts: ${formatError(err)}`;
5331
4969
  } else {
@@ -5337,7 +4975,7 @@ async function loginConnectionLoop(accountId, login) {
5337
4975
  attempt++;
5338
4976
  const delay = LOGIN_RECONNECT_DELAYS[attempt - 1] ?? 8e3;
5339
4977
  console.error(
5340
- `${TAG16} status=${classification.statusCode ?? "unknown"} restart required \u2014 reconnecting with saved creds (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}) delay=${delay}ms`
4978
+ `${TAG15} status=${classification.statusCode ?? "unknown"} restart required \u2014 reconnecting with saved creds (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}) delay=${delay}ms`
5341
4979
  );
5342
4980
  closeSocket(current.sock);
5343
4981
  await new Promise((r) => setTimeout(r, delay));
@@ -5348,7 +4986,7 @@ async function loginConnectionLoop(accountId, login) {
5348
4986
  current.sock = newSock;
5349
4987
  } catch (sockErr) {
5350
4988
  console.error(
5351
- `${TAG16} reconnect socket creation failed (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}): ${String(sockErr)}`
4989
+ `${TAG15} reconnect socket creation failed (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}): ${String(sockErr)}`
5352
4990
  );
5353
4991
  current.error = `Reconnection failed: ${String(sockErr)}`;
5354
4992
  return;
@@ -5362,7 +5000,7 @@ async function startLogin(opts) {
5362
5000
  const hasAuth = await authExists(authDir);
5363
5001
  const selfId = readSelfId(authDir);
5364
5002
  console.error(
5365
- `${TAG16} startLogin account=${accountId} force=${!!force} hasAuth=${hasAuth}` + (existing0 ? ` activeLogin={id=${existing0.id.slice(0, 8)},age=${Math.round((Date.now() - existing0.startedAt) / 1e3)}s,hasQr=${!!existing0.qr}}` : " activeLogin=none")
5003
+ `${TAG15} startLogin account=${accountId} force=${!!force} hasAuth=${hasAuth}` + (existing0 ? ` activeLogin={id=${existing0.id.slice(0, 8)},age=${Math.round((Date.now() - existing0.startedAt) / 1e3)}s,hasQr=${!!existing0.qr}}` : " activeLogin=none")
5366
5004
  );
5367
5005
  if (hasAuth && !force) {
5368
5006
  const who = selfId.e164 ?? selfId.jid ?? "unknown";
@@ -5374,7 +5012,7 @@ async function startLogin(opts) {
5374
5012
  await clearAuth(authDir);
5375
5013
  const existing = activeLogins.get(accountId);
5376
5014
  if (existing && isLoginFresh(existing) && existing.qrDataUrl && !force) {
5377
- console.error(`${TAG16} startLogin account=${accountId} guard: returning existing QR (age=${Math.round((Date.now() - existing.startedAt) / 1e3)}s)`);
5015
+ console.error(`${TAG15} startLogin account=${accountId} guard: returning existing QR (age=${Math.round((Date.now() - existing.startedAt) / 1e3)}s)`);
5378
5016
  return {
5379
5017
  qrDataUrl: existing.qrDataUrl,
5380
5018
  qrRaw: existing.qr,
@@ -5382,7 +5020,7 @@ async function startLogin(opts) {
5382
5020
  };
5383
5021
  }
5384
5022
  if (existing) {
5385
- console.error(`${TAG16} startLogin account=${accountId} ${force ? "force override" : "stale/no-QR"}, resetting active login`);
5023
+ console.error(`${TAG15} startLogin account=${accountId} ${force ? "force override" : "stale/no-QR"}, resetting active login`);
5386
5024
  }
5387
5025
  resetActiveLogin(accountId);
5388
5026
  let resolveQr = null;
@@ -5399,99 +5037,425 @@ async function startLogin(opts) {
5399
5037
  let pendingQr = null;
5400
5038
  let loginQrCount = 0;
5401
5039
  try {
5402
- sock = await createWaSocket({
5403
- authDir,
5404
- onQr: (qr2) => {
5405
- loginQrCount++;
5406
- if (pendingQr) {
5407
- console.error(`${TAG16} QR rotation #${loginQrCount} received for account=${accountId} \u2014 not forwarded (initial QR already captured)`);
5408
- return;
5409
- }
5410
- pendingQr = qr2;
5411
- const current = activeLogins.get(accountId);
5412
- if (current && !current.qr) current.qr = qr2;
5413
- clearTimeout(qrTimer);
5414
- console.error(`${TAG16} QR #${loginQrCount} received for account=${accountId} \u2014 forwarding to caller`);
5415
- resolveQr?.(qr2);
5416
- }
5417
- });
5040
+ sock = await createWaSocket({
5041
+ authDir,
5042
+ onQr: (qr2) => {
5043
+ loginQrCount++;
5044
+ if (pendingQr) {
5045
+ console.error(`${TAG15} QR rotation #${loginQrCount} received for account=${accountId} \u2014 not forwarded (initial QR already captured)`);
5046
+ return;
5047
+ }
5048
+ pendingQr = qr2;
5049
+ const current = activeLogins.get(accountId);
5050
+ if (current && !current.qr) current.qr = qr2;
5051
+ clearTimeout(qrTimer);
5052
+ console.error(`${TAG15} QR #${loginQrCount} received for account=${accountId} \u2014 forwarding to caller`);
5053
+ resolveQr?.(qr2);
5054
+ }
5055
+ });
5056
+ } catch (err) {
5057
+ clearTimeout(qrTimer);
5058
+ resetActiveLogin(accountId);
5059
+ return { message: `Failed to start WhatsApp login: ${String(err)}` };
5060
+ }
5061
+ const login = {
5062
+ accountId,
5063
+ authDir,
5064
+ id: randomUUID4(),
5065
+ sock,
5066
+ startedAt: Date.now(),
5067
+ connected: false
5068
+ };
5069
+ activeLogins.set(accountId, login);
5070
+ if (pendingQr && !login.qr) login.qr = pendingQr;
5071
+ loginConnectionLoop(accountId, login).catch((err) => {
5072
+ console.error(`${TAG15} loginConnectionLoop unexpected error: ${String(err)}`);
5073
+ const current = activeLogins.get(accountId);
5074
+ if (current?.id === login.id) {
5075
+ current.error = `Unexpected login error: ${String(err)}`;
5076
+ }
5077
+ });
5078
+ let qr;
5079
+ try {
5080
+ qr = await qrPromise;
5081
+ } catch (err) {
5082
+ clearTimeout(qrTimer);
5083
+ resetActiveLogin(accountId);
5084
+ return { message: `Failed to get QR: ${String(err)}` };
5085
+ }
5086
+ login.qrDataUrl = `qr:${qr}`;
5087
+ return {
5088
+ qrDataUrl: login.qrDataUrl,
5089
+ qrRaw: qr,
5090
+ message: "Scan this QR in WhatsApp \u2192 Linked Devices."
5091
+ };
5092
+ }
5093
+ async function waitForLogin(opts) {
5094
+ const { accountId, timeoutMs = 6e4 } = opts;
5095
+ const login = activeLogins.get(accountId);
5096
+ console.error(
5097
+ `${TAG15} waitForLogin account=${accountId} timeout=${timeoutMs}ms` + (login ? ` login={id=${login.id.slice(0, 8)},age=${Math.round((Date.now() - login.startedAt) / 1e3)}s,connected=${login.connected},hasQr=${!!login.qr}}` : " login=none")
5098
+ );
5099
+ if (!login) {
5100
+ return { connected: false, message: "No active WhatsApp login in progress." };
5101
+ }
5102
+ if (!isLoginFresh(login)) {
5103
+ resetActiveLogin(accountId);
5104
+ return { connected: false, message: "The login QR expired. Ask me to generate a new one." };
5105
+ }
5106
+ const deadline = Date.now() + timeoutMs;
5107
+ while (Date.now() < deadline) {
5108
+ if (login.connected) {
5109
+ const selfId = readSelfId(login.authDir);
5110
+ console.error(`${TAG15} login complete for account=${accountId} phone=${selfId.e164 ?? "unknown"}`);
5111
+ const sock = login.sock;
5112
+ const authDir = login.authDir;
5113
+ activeLogins.delete(accountId);
5114
+ return {
5115
+ connected: true,
5116
+ message: `WhatsApp connected as ${selfId.e164 ?? selfId.jid ?? "unknown"}.`,
5117
+ selfPhone: selfId.e164 ?? void 0,
5118
+ sock,
5119
+ authDir
5120
+ };
5121
+ }
5122
+ if (login.error) {
5123
+ const msg = login.error;
5124
+ resetActiveLogin(accountId);
5125
+ return { connected: false, message: `WhatsApp login failed: ${msg}` };
5126
+ }
5127
+ await new Promise((r) => setTimeout(r, 1e3));
5128
+ }
5129
+ const elapsed = Math.round((Date.now() - (deadline - timeoutMs)) / 1e3);
5130
+ console.error(`${TAG15} waitForLogin timeout account=${accountId} elapsed=${elapsed}s \u2014 cleaning up active login`);
5131
+ resetActiveLogin(accountId);
5132
+ return { connected: false, message: "Login timed out. Try generating a new QR." };
5133
+ }
5134
+
5135
+ // app/lib/whatsapp/config-persist.ts
5136
+ import { readFileSync as readFileSync6, writeFileSync as writeFileSync4, existsSync as existsSync3 } from "fs";
5137
+ import { resolve as resolve6, join as join4 } from "path";
5138
+ var TAG16 = "[whatsapp:config]";
5139
+ function configPath(accountDir) {
5140
+ return resolve6(accountDir, "account.json");
5141
+ }
5142
+ function readConfig(accountDir) {
5143
+ const path2 = configPath(accountDir);
5144
+ if (!existsSync3(path2)) throw new Error(`account.json not found at ${path2}`);
5145
+ return JSON.parse(readFileSync6(path2, "utf-8"));
5146
+ }
5147
+ function writeConfig(accountDir, config) {
5148
+ const path2 = configPath(accountDir);
5149
+ writeFileSync4(path2, JSON.stringify(config, null, 2) + "\n", "utf-8");
5150
+ }
5151
+ function reloadManagerConfig(accountDir) {
5152
+ try {
5153
+ const config = readConfig(accountDir);
5154
+ reloadConfig(config);
5155
+ console.error(`${TAG16} reloaded manager config`);
5156
+ } catch (err) {
5157
+ console.error(`${TAG16} manager config reload failed: ${String(err)}`);
5158
+ }
5159
+ }
5160
+ var E164_PATTERN = /^\+\d{7,15}$/;
5161
+ function persistAfterPairing(accountDir, accountId, selfPhone) {
5162
+ try {
5163
+ const config = readConfig(accountDir);
5164
+ if (!config.whatsapp || typeof config.whatsapp !== "object") {
5165
+ config.whatsapp = {};
5166
+ }
5167
+ const wa = config.whatsapp;
5168
+ if (!wa.accounts || typeof wa.accounts !== "object") {
5169
+ wa.accounts = {};
5170
+ }
5171
+ const accounts = wa.accounts;
5172
+ if (!accounts[accountId] || typeof accounts[accountId] !== "object") {
5173
+ accounts[accountId] = { name: "Main" };
5174
+ }
5175
+ if (selfPhone) {
5176
+ const normalized = selfPhone.startsWith("+") ? selfPhone : `+${selfPhone}`;
5177
+ if (!Array.isArray(wa.adminPhones)) {
5178
+ wa.adminPhones = [];
5179
+ }
5180
+ const adminPhones = wa.adminPhones;
5181
+ if (!adminPhones.includes(normalized)) {
5182
+ adminPhones.push(normalized);
5183
+ console.error(`${TAG16} added selfPhone=${normalized} to adminPhones`);
5184
+ }
5185
+ } else {
5186
+ console.error(`${TAG16} skipping adminPhones \u2014 selfPhone is null account=${accountId}`);
5187
+ }
5188
+ const parsed = WhatsAppConfigSchema.safeParse(wa);
5189
+ if (!parsed.success) {
5190
+ const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
5191
+ console.error(`${TAG16} validation failed after pairing: ${msg}`);
5192
+ return { ok: false, error: `Validation failed: ${msg}` };
5193
+ }
5194
+ config.whatsapp = parsed.data;
5195
+ writeConfig(accountDir, config);
5196
+ console.error(`${TAG16} persisted after pairing account=${accountId} phone=${selfPhone ?? "null"}`);
5197
+ reloadManagerConfig(accountDir);
5198
+ return { ok: true };
5199
+ } catch (err) {
5200
+ const msg = err instanceof Error ? err.message : String(err);
5201
+ console.error(`${TAG16} persist failed account=${accountId}: ${msg}`);
5202
+ return { ok: false, error: msg };
5203
+ }
5204
+ }
5205
+ function addAdminPhone(accountDir, phone) {
5206
+ const normalized = phone.trim();
5207
+ if (!E164_PATTERN.test(normalized)) {
5208
+ return { ok: false, error: `Invalid phone format "${normalized}". Expected E.164 (e.g. +441234567890).` };
5209
+ }
5210
+ try {
5211
+ const config = readConfig(accountDir);
5212
+ if (!config.whatsapp || typeof config.whatsapp !== "object") {
5213
+ config.whatsapp = {};
5214
+ }
5215
+ const wa = config.whatsapp;
5216
+ if (!Array.isArray(wa.adminPhones)) {
5217
+ wa.adminPhones = [];
5218
+ }
5219
+ const adminPhones = wa.adminPhones;
5220
+ if (adminPhones.includes(normalized)) {
5221
+ return { ok: true, message: `Phone ${normalized} is already in the admin list.` };
5222
+ }
5223
+ adminPhones.push(normalized);
5224
+ const parsed = WhatsAppConfigSchema.safeParse(wa);
5225
+ if (!parsed.success) {
5226
+ const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
5227
+ return { ok: false, error: `Validation failed: ${msg}` };
5228
+ }
5229
+ config.whatsapp = parsed.data;
5230
+ writeConfig(accountDir, config);
5231
+ console.error(`${TAG16} added admin phone=${normalized}`);
5232
+ reloadManagerConfig(accountDir);
5233
+ return { ok: true, message: `Added ${normalized} as admin phone. Messages from this number will route to the admin agent.` };
5234
+ } catch (err) {
5235
+ const msg = err instanceof Error ? err.message : String(err);
5236
+ console.error(`${TAG16} addAdminPhone failed: ${msg}`);
5237
+ return { ok: false, error: msg };
5238
+ }
5239
+ }
5240
+ function removeAdminPhone(accountDir, phone) {
5241
+ const normalized = phone.trim();
5242
+ try {
5243
+ const config = readConfig(accountDir);
5244
+ if (!config.whatsapp || typeof config.whatsapp !== "object") {
5245
+ return { ok: true, message: `No WhatsApp config exists \u2014 nothing to remove.` };
5246
+ }
5247
+ const wa = config.whatsapp;
5248
+ if (!Array.isArray(wa.adminPhones)) {
5249
+ return { ok: true, message: `No admin phones configured \u2014 nothing to remove.` };
5250
+ }
5251
+ const adminPhones = wa.adminPhones;
5252
+ const idx = adminPhones.indexOf(normalized);
5253
+ if (idx === -1) {
5254
+ return { ok: true, message: `Phone ${normalized} is not in the admin list.` };
5255
+ }
5256
+ adminPhones.splice(idx, 1);
5257
+ const parsed = WhatsAppConfigSchema.safeParse(wa);
5258
+ if (!parsed.success) {
5259
+ const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
5260
+ return { ok: false, error: `Validation failed: ${msg}` };
5261
+ }
5262
+ config.whatsapp = parsed.data;
5263
+ writeConfig(accountDir, config);
5264
+ console.error(`${TAG16} removed admin phone=${normalized}`);
5265
+ reloadManagerConfig(accountDir);
5266
+ return { ok: true, message: `Removed ${normalized} from admin phones. Messages from this number will now route to the public agent.` };
5267
+ } catch (err) {
5268
+ const msg = err instanceof Error ? err.message : String(err);
5269
+ console.error(`${TAG16} removeAdminPhone failed: ${msg}`);
5270
+ return { ok: false, error: msg };
5271
+ }
5272
+ }
5273
+ function readAdminPhones(accountDir) {
5274
+ try {
5275
+ const config = readConfig(accountDir);
5276
+ const wa = config.whatsapp;
5277
+ if (!wa) return [];
5278
+ if (!Array.isArray(wa.adminPhones)) return [];
5279
+ return wa.adminPhones.filter((p) => typeof p === "string");
5280
+ } catch {
5281
+ return [];
5282
+ }
5283
+ }
5284
+ function setPublicAgent(accountDir, slug) {
5285
+ const trimmed = slug.trim();
5286
+ if (!trimmed) {
5287
+ return { ok: false, error: "Agent slug cannot be empty." };
5288
+ }
5289
+ const agentConfigPath = join4(accountDir, "agents", trimmed, "config.json");
5290
+ if (!existsSync3(agentConfigPath)) {
5291
+ return { ok: false, error: `Agent "${trimmed}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.` };
5292
+ }
5293
+ try {
5294
+ const config = readConfig(accountDir);
5295
+ if (!config.whatsapp || typeof config.whatsapp !== "object") {
5296
+ config.whatsapp = {};
5297
+ }
5298
+ const wa = config.whatsapp;
5299
+ wa.publicAgent = trimmed;
5300
+ const parsed = WhatsAppConfigSchema.safeParse(wa);
5301
+ if (!parsed.success) {
5302
+ const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
5303
+ return { ok: false, error: `Validation failed: ${msg}` };
5304
+ }
5305
+ config.whatsapp = parsed.data;
5306
+ writeConfig(accountDir, config);
5307
+ console.error(`${TAG16} publicAgent set to ${trimmed}`);
5308
+ reloadManagerConfig(accountDir);
5309
+ return { ok: true, message: `Public agent set to "${trimmed}". WhatsApp messages from non-admin phones will be handled by this agent.` };
5310
+ } catch (err) {
5311
+ const msg = err instanceof Error ? err.message : String(err);
5312
+ console.error(`${TAG16} setPublicAgent failed: ${msg}`);
5313
+ return { ok: false, error: msg };
5314
+ }
5315
+ }
5316
+ function resolvePublicAgent(accountDir, opts) {
5317
+ try {
5318
+ const config = readConfig(accountDir);
5319
+ const wa = config.whatsapp;
5320
+ if (!wa) return null;
5321
+ if (opts.groupJid) {
5322
+ const accounts2 = wa.accounts;
5323
+ const account2 = accounts2?.[opts.accountId];
5324
+ const groups = account2?.groups;
5325
+ const group = groups?.[opts.groupJid];
5326
+ const groupSlug = group?.publicAgent;
5327
+ if (typeof groupSlug === "string" && groupSlug.trim()) {
5328
+ return { slug: groupSlug.trim(), source: "group" };
5329
+ }
5330
+ }
5331
+ const accounts = wa.accounts;
5332
+ const account = accounts?.[opts.accountId];
5333
+ const accountSlug = account?.publicAgent;
5334
+ if (typeof accountSlug === "string" && accountSlug.trim()) {
5335
+ return { slug: accountSlug.trim(), source: "account" };
5336
+ }
5337
+ const topSlug = wa.publicAgent;
5338
+ if (typeof topSlug === "string" && topSlug.trim()) {
5339
+ return { slug: topSlug.trim(), source: "top-level" };
5340
+ }
5341
+ return null;
5342
+ } catch {
5343
+ return null;
5344
+ }
5345
+ }
5346
+ function setGroupPublicAgent(accountDir, accountId, groupJid, slug) {
5347
+ const trimmedSlug = slug.trim();
5348
+ const trimmedGroup = groupJid.trim();
5349
+ const trimmedAccount = accountId.trim();
5350
+ if (!trimmedSlug) return { ok: false, error: "Agent slug cannot be empty." };
5351
+ if (!trimmedGroup) return { ok: false, error: "Group JID cannot be empty." };
5352
+ if (!trimmedAccount) return { ok: false, error: "Account ID cannot be empty." };
5353
+ const agentConfigPath = join4(accountDir, "agents", trimmedSlug, "config.json");
5354
+ if (!existsSync3(agentConfigPath)) {
5355
+ return { ok: false, error: `Agent "${trimmedSlug}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.` };
5356
+ }
5357
+ try {
5358
+ const config = readConfig(accountDir);
5359
+ if (!config.whatsapp || typeof config.whatsapp !== "object") config.whatsapp = {};
5360
+ const wa = config.whatsapp;
5361
+ if (!wa.accounts || typeof wa.accounts !== "object") wa.accounts = {};
5362
+ const accounts = wa.accounts;
5363
+ if (!accounts[trimmedAccount] || typeof accounts[trimmedAccount] !== "object") accounts[trimmedAccount] = {};
5364
+ const account = accounts[trimmedAccount];
5365
+ if (!account.groups || typeof account.groups !== "object") account.groups = {};
5366
+ const groups = account.groups;
5367
+ const existing = groups[trimmedGroup] && typeof groups[trimmedGroup] === "object" ? groups[trimmedGroup] : {};
5368
+ groups[trimmedGroup] = { ...existing, publicAgent: trimmedSlug };
5369
+ const parsed = WhatsAppConfigSchema.safeParse(wa);
5370
+ if (!parsed.success) {
5371
+ const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
5372
+ return { ok: false, error: `Validation failed: ${msg}` };
5373
+ }
5374
+ config.whatsapp = parsed.data;
5375
+ writeConfig(accountDir, config);
5376
+ console.error(`${TAG16} setGroupPublicAgent account=${trimmedAccount} groupJid=${trimmedGroup} slug=${trimmedSlug}`);
5377
+ reloadManagerConfig(accountDir);
5378
+ return { ok: true, message: `Per-group public agent set to "${trimmedSlug}" for group ${trimmedGroup}.` };
5418
5379
  } catch (err) {
5419
- clearTimeout(qrTimer);
5420
- resetActiveLogin(accountId);
5421
- return { message: `Failed to start WhatsApp login: ${String(err)}` };
5380
+ const msg = err instanceof Error ? err.message : String(err);
5381
+ console.error(`${TAG16} setGroupPublicAgent failed: ${msg}`);
5382
+ return { ok: false, error: msg };
5422
5383
  }
5423
- const login = {
5424
- accountId,
5425
- authDir,
5426
- id: randomUUID4(),
5427
- sock,
5428
- startedAt: Date.now(),
5429
- connected: false
5430
- };
5431
- activeLogins.set(accountId, login);
5432
- if (pendingQr && !login.qr) login.qr = pendingQr;
5433
- loginConnectionLoop(accountId, login).catch((err) => {
5434
- console.error(`${TAG16} loginConnectionLoop unexpected error: ${String(err)}`);
5435
- const current = activeLogins.get(accountId);
5436
- if (current?.id === login.id) {
5437
- current.error = `Unexpected login error: ${String(err)}`;
5438
- }
5439
- });
5440
- let qr;
5384
+ }
5385
+ function unsetGroupPublicAgent(accountDir, accountId, groupJid) {
5386
+ const trimmedGroup = groupJid.trim();
5387
+ const trimmedAccount = accountId.trim();
5388
+ if (!trimmedGroup) return { ok: false, error: "Group JID cannot be empty." };
5389
+ if (!trimmedAccount) return { ok: false, error: "Account ID cannot be empty." };
5441
5390
  try {
5442
- qr = await qrPromise;
5391
+ const config = readConfig(accountDir);
5392
+ const wa = config.whatsapp ?? {};
5393
+ const accounts = wa.accounts;
5394
+ const account = accounts?.[trimmedAccount];
5395
+ const groups = account?.groups;
5396
+ const group = groups?.[trimmedGroup];
5397
+ if (!group || typeof group.publicAgent !== "string") {
5398
+ return { ok: true, message: `No per-group publicAgent override for group ${trimmedGroup}; nothing to remove.` };
5399
+ }
5400
+ delete group.publicAgent;
5401
+ const parsed = WhatsAppConfigSchema.safeParse(wa);
5402
+ if (!parsed.success) {
5403
+ const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
5404
+ return { ok: false, error: `Validation failed: ${msg}` };
5405
+ }
5406
+ config.whatsapp = parsed.data;
5407
+ writeConfig(accountDir, config);
5408
+ console.error(`${TAG16} unsetGroupPublicAgent account=${trimmedAccount} groupJid=${trimmedGroup}`);
5409
+ reloadManagerConfig(accountDir);
5410
+ return { ok: true, message: `Per-group public agent override removed for group ${trimmedGroup}.` };
5443
5411
  } catch (err) {
5444
- clearTimeout(qrTimer);
5445
- resetActiveLogin(accountId);
5446
- return { message: `Failed to get QR: ${String(err)}` };
5412
+ const msg = err instanceof Error ? err.message : String(err);
5413
+ console.error(`${TAG16} unsetGroupPublicAgent failed: ${msg}`);
5414
+ return { ok: false, error: msg };
5447
5415
  }
5448
- login.qrDataUrl = `qr:${qr}`;
5449
- return {
5450
- qrDataUrl: login.qrDataUrl,
5451
- qrRaw: qr,
5452
- message: "Scan this QR in WhatsApp \u2192 Linked Devices."
5453
- };
5454
5416
  }
5455
- async function waitForLogin(opts) {
5456
- const { accountId, timeoutMs = 6e4 } = opts;
5457
- const login = activeLogins.get(accountId);
5458
- console.error(
5459
- `${TAG16} waitForLogin account=${accountId} timeout=${timeoutMs}ms` + (login ? ` login={id=${login.id.slice(0, 8)},age=${Math.round((Date.now() - login.startedAt) / 1e3)}s,connected=${login.connected},hasQr=${!!login.qr}}` : " login=none")
5460
- );
5461
- if (!login) {
5462
- return { connected: false, message: "No active WhatsApp login in progress." };
5463
- }
5464
- if (!isLoginFresh(login)) {
5465
- resetActiveLogin(accountId);
5466
- return { connected: false, message: "The login QR expired. Ask me to generate a new one." };
5417
+ function updateConfig(accountDir, fields) {
5418
+ const fieldNames = Object.keys(fields);
5419
+ if (fieldNames.length === 0) {
5420
+ return { ok: false, error: "No fields provided to update." };
5467
5421
  }
5468
- const deadline = Date.now() + timeoutMs;
5469
- while (Date.now() < deadline) {
5470
- if (login.connected) {
5471
- const selfId = readSelfId(login.authDir);
5472
- console.error(`${TAG16} login complete for account=${accountId} phone=${selfId.e164 ?? "unknown"}`);
5473
- const sock = login.sock;
5474
- const authDir = login.authDir;
5475
- activeLogins.delete(accountId);
5476
- return {
5477
- connected: true,
5478
- message: `WhatsApp connected as ${selfId.e164 ?? selfId.jid ?? "unknown"}.`,
5479
- selfPhone: selfId.e164 ?? void 0,
5480
- sock,
5481
- authDir
5482
- };
5422
+ try {
5423
+ const config = readConfig(accountDir);
5424
+ if (!config.whatsapp || typeof config.whatsapp !== "object") {
5425
+ config.whatsapp = {};
5483
5426
  }
5484
- if (login.error) {
5485
- const msg = login.error;
5486
- resetActiveLogin(accountId);
5487
- return { connected: false, message: `WhatsApp login failed: ${msg}` };
5427
+ const wa = config.whatsapp;
5428
+ for (const [key, value] of Object.entries(fields)) {
5429
+ wa[key] = value;
5488
5430
  }
5489
- await new Promise((r) => setTimeout(r, 1e3));
5431
+ const parsed = WhatsAppConfigSchema.safeParse(wa);
5432
+ if (!parsed.success) {
5433
+ const msg = parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ");
5434
+ console.error(`${TAG16} update validation failed: ${msg}`);
5435
+ return { ok: false, error: `Validation failed: ${msg}` };
5436
+ }
5437
+ config.whatsapp = parsed.data;
5438
+ writeConfig(accountDir, config);
5439
+ console.error(`${TAG16} updated fields=[${fieldNames.join(",")}]`);
5440
+ reloadManagerConfig(accountDir);
5441
+ return { ok: true, message: `Updated WhatsApp config: ${fieldNames.join(", ")}.` };
5442
+ } catch (err) {
5443
+ const msg = err instanceof Error ? err.message : String(err);
5444
+ console.error(`${TAG16} updateConfig failed: ${msg}`);
5445
+ return { ok: false, error: msg };
5446
+ }
5447
+ }
5448
+ function getConfig(accountDir) {
5449
+ try {
5450
+ const config = readConfig(accountDir);
5451
+ const wa = config.whatsapp;
5452
+ if (!wa) return null;
5453
+ const parsed = WhatsAppConfigSchema.safeParse(wa);
5454
+ if (!parsed.success) return wa;
5455
+ return parsed.data;
5456
+ } catch {
5457
+ return null;
5490
5458
  }
5491
- const elapsed = Math.round((Date.now() - (deadline - timeoutMs)) / 1e3);
5492
- console.error(`${TAG16} waitForLogin timeout account=${accountId} elapsed=${elapsed}s \u2014 cleaning up active login`);
5493
- resetActiveLogin(accountId);
5494
- return { connected: false, message: "Login timed out. Try generating a new QR." };
5495
5459
  }
5496
5460
 
5497
5461
  // app/lib/whatsapp/validate.ts
@@ -7886,8 +7850,8 @@ app14.put("/:id/label", requireAdminSession, async (c) => {
7886
7850
  var sessions_default = app14;
7887
7851
 
7888
7852
  // app/lib/claude-agent/spawn-context.ts
7889
- import { existsSync as existsSync14, readFileSync as readFileSync13, readdirSync as readdirSync7 } from "fs";
7890
- import { resolve as resolve11 } from "path";
7853
+ import { existsSync as existsSync14, readFileSync as readFileSync13, readdirSync as readdirSync7, statSync as statSync6 } from "fs";
7854
+ import { dirname as dirname2, resolve as resolve11, join as join10 } from "path";
7891
7855
  async function resolveOwnerProfileBlock(accountId, userId) {
7892
7856
  if (!userId) return { ok: false, reason: "missing-user-id" };
7893
7857
  try {
@@ -7913,6 +7877,213 @@ function frontmatterField(manifest, field) {
7913
7877
  }
7914
7878
  return value || null;
7915
7879
  }
7880
+ function extractPluginToolDescriptions(pluginDir) {
7881
+ const out = /* @__PURE__ */ new Map();
7882
+ const candidates = [
7883
+ join10(pluginDir, "mcp/dist/index.js"),
7884
+ join10(pluginDir, "mcp/src/index.ts")
7885
+ ];
7886
+ let raw = null;
7887
+ for (const path2 of candidates) {
7888
+ if (!existsSync14(path2)) continue;
7889
+ try {
7890
+ raw = readFileSync13(path2, "utf-8");
7891
+ break;
7892
+ } catch {
7893
+ }
7894
+ }
7895
+ if (!raw) return out;
7896
+ const re = /(?:server\.tool\(|eagerTool\(\s*server\s*,)\s*"((?:[^"\\]|\\.)*)"\s*,\s*"((?:[^"\\]|\\.)*)"/g;
7897
+ let m;
7898
+ while ((m = re.exec(raw)) !== null) {
7899
+ const name = m[1];
7900
+ const desc = m[2].replace(/\\n/g, " ").replace(/\\"/g, '"').replace(/\\\\/g, "\\").replace(/\s+/g, " ").trim();
7901
+ if (name && desc && !out.has(name)) out.set(name, desc);
7902
+ }
7903
+ return out;
7904
+ }
7905
+ function parseToolNamesFromFrontmatter(fm) {
7906
+ const lines = fm.split(/\r?\n/);
7907
+ let i = 0;
7908
+ while (i < lines.length && !/^tools:\s*$/.test(lines[i])) i++;
7909
+ if (i >= lines.length) return [];
7910
+ i++;
7911
+ const out = [];
7912
+ for (; i < lines.length; i++) {
7913
+ const line = lines[i];
7914
+ if (line.length === 0) continue;
7915
+ if (/^[A-Za-z_]/.test(line)) break;
7916
+ const m = line.match(/^\s+-\s+name:\s*(.+?)\s*$/);
7917
+ if (m) out.push(m[1]);
7918
+ }
7919
+ return out;
7920
+ }
7921
+ function parseSkillPathsFromFrontmatter(fm) {
7922
+ const lines = fm.split(/\r?\n/);
7923
+ let i = 0;
7924
+ while (i < lines.length && !/^skills:\s*$/.test(lines[i])) i++;
7925
+ if (i >= lines.length) return [];
7926
+ i++;
7927
+ const out = [];
7928
+ for (; i < lines.length; i++) {
7929
+ const line = lines[i];
7930
+ if (line.length === 0) continue;
7931
+ if (/^[A-Za-z_]/.test(line)) break;
7932
+ const m = line.match(/^\s+-\s+(.+?)\s*$/);
7933
+ if (m) out.push(m[1]);
7934
+ }
7935
+ return out;
7936
+ }
7937
+ function listPluginDirs() {
7938
+ const out = /* @__PURE__ */ new Map();
7939
+ const platformPlugins = resolve11(PLATFORM_ROOT, "plugins");
7940
+ if (existsSync14(platformPlugins)) {
7941
+ for (const name of readdirSync7(platformPlugins)) {
7942
+ const dir = join10(platformPlugins, name);
7943
+ try {
7944
+ if (statSync6(dir).isDirectory()) out.set(name, dir);
7945
+ } catch {
7946
+ }
7947
+ }
7948
+ }
7949
+ const premiumRoot = resolve11(dirname2(PLATFORM_ROOT), "premium-plugins");
7950
+ if (existsSync14(premiumRoot)) {
7951
+ for (const bundle of readdirSync7(premiumRoot)) {
7952
+ const bundlePlugins = join10(premiumRoot, bundle, "plugins");
7953
+ if (!existsSync14(bundlePlugins)) continue;
7954
+ try {
7955
+ for (const name of readdirSync7(bundlePlugins)) {
7956
+ const dir = join10(bundlePlugins, name);
7957
+ try {
7958
+ if (statSync6(dir).isDirectory()) out.set(name, dir);
7959
+ } catch {
7960
+ }
7961
+ }
7962
+ } catch {
7963
+ }
7964
+ }
7965
+ }
7966
+ return out;
7967
+ }
7968
+ function readEnabledPlugins(accountId) {
7969
+ const accountFile = resolve11(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
7970
+ if (!existsSync14(accountFile)) return /* @__PURE__ */ new Set();
7971
+ try {
7972
+ const parsed = JSON.parse(readFileSync13(accountFile, "utf-8"));
7973
+ return new Set(
7974
+ Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
7975
+ );
7976
+ } catch {
7977
+ return /* @__PURE__ */ new Set();
7978
+ }
7979
+ }
7980
+ function readFrontmatter(path2) {
7981
+ if (!existsSync14(path2)) return null;
7982
+ let raw;
7983
+ try {
7984
+ raw = readFileSync13(path2, "utf-8");
7985
+ } catch {
7986
+ return null;
7987
+ }
7988
+ const m = raw.match(/^---\r?\n([\s\S]*?)\r?\n---/);
7989
+ return m ? m[1] : null;
7990
+ }
7991
+ function computeActivePlugins(accountId) {
7992
+ const enabled = readEnabledPlugins(accountId);
7993
+ if (enabled.size === 0) return [];
7994
+ const pluginDirs = listPluginDirs();
7995
+ const out = [];
7996
+ for (const name of Array.from(enabled).sort()) {
7997
+ const dir = pluginDirs.get(name);
7998
+ if (!dir) continue;
7999
+ const fm = readFrontmatter(join10(dir, "PLUGIN.md"));
8000
+ if (!fm) continue;
8001
+ const description = frontmatterField(`---
8002
+ ${fm}
8003
+ ---`, "description");
8004
+ if (!description) continue;
8005
+ const toolNames = parseToolNamesFromFrontmatter(fm);
8006
+ const descMap = extractPluginToolDescriptions(dir);
8007
+ const tools = toolNames.map((n) => {
8008
+ const d = descMap.get(n);
8009
+ return d ? { name: n, description: d } : { name: n };
8010
+ });
8011
+ const withDesc = tools.filter((t) => t.description).length;
8012
+ console.log(
8013
+ `plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
8014
+ );
8015
+ if (toolNames.length > 0 && descMap.size === 0) {
8016
+ const hasSource = existsSync14(join10(dir, "mcp/dist/index.js")) || existsSync14(join10(dir, "mcp/src/index.ts"));
8017
+ if (hasSource) {
8018
+ console.warn(
8019
+ `[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
8020
+ );
8021
+ }
8022
+ }
8023
+ const skillPaths = parseSkillPathsFromFrontmatter(fm);
8024
+ const skills = [];
8025
+ for (const relPath2 of skillPaths) {
8026
+ const skillPath = join10(dir, relPath2);
8027
+ const skillFm = readFrontmatter(skillPath);
8028
+ if (!skillFm) continue;
8029
+ const skillName = frontmatterField(`---
8030
+ ${skillFm}
8031
+ ---`, "name") ?? relPath2;
8032
+ const skillDesc = frontmatterField(`---
8033
+ ${skillFm}
8034
+ ---`, "description");
8035
+ skills.push(skillDesc ? { name: skillName, description: skillDesc } : { name: skillName });
8036
+ }
8037
+ out.push({ name, description, tools, skills });
8038
+ }
8039
+ return out;
8040
+ }
8041
+ function computeSpecialistDomains(accountId) {
8042
+ const specialistsDir = resolve11(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
8043
+ if (!existsSync14(specialistsDir)) return [];
8044
+ let entries;
8045
+ try {
8046
+ entries = readdirSync7(specialistsDir);
8047
+ } catch {
8048
+ return [];
8049
+ }
8050
+ const pluginDirs = listPluginDirs();
8051
+ const descByPlugin = /* @__PURE__ */ new Map();
8052
+ const resolveDesc = (qualified) => {
8053
+ if (!qualified.startsWith("mcp__")) return void 0;
8054
+ const rest = qualified.slice(5);
8055
+ const sep4 = rest.indexOf("__");
8056
+ if (sep4 < 0) return void 0;
8057
+ const plugin = rest.slice(0, sep4);
8058
+ const tool = rest.slice(sep4 + 2);
8059
+ let map = descByPlugin.get(plugin);
8060
+ if (!map) {
8061
+ const dir = pluginDirs.get(plugin);
8062
+ map = dir ? extractPluginToolDescriptions(dir) : /* @__PURE__ */ new Map();
8063
+ descByPlugin.set(plugin, map);
8064
+ }
8065
+ return map.get(tool);
8066
+ };
8067
+ const out = [];
8068
+ for (const file of entries.sort()) {
8069
+ if (!file.endsWith(".md")) continue;
8070
+ const fm = readFrontmatter(join10(specialistsDir, file));
8071
+ if (!fm) continue;
8072
+ const wrapped = `---
8073
+ ${fm}
8074
+ ---`;
8075
+ const name = frontmatterField(wrapped, "name");
8076
+ const description = frontmatterField(wrapped, "description");
8077
+ if (!name || !description) continue;
8078
+ const toolsRaw = frontmatterField(wrapped, "tools") ?? "";
8079
+ const tools = toolsRaw.split(",").map((t) => t.trim()).filter((t) => t.length > 0).map((t) => {
8080
+ const d = resolveDesc(t);
8081
+ return d ? { name: t, description: d } : { name: t };
8082
+ });
8083
+ out.push({ name, description, tools });
8084
+ }
8085
+ return out;
8086
+ }
7916
8087
  function computeDormantPlugins(accountId) {
7917
8088
  const accountFile = resolve11(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
7918
8089
  if (!existsSync14(accountFile)) return [];
@@ -8007,6 +8178,12 @@ app15.post("/", async (c) => {
8007
8178
  const dormantStart = Date.now();
8008
8179
  const dormantPlugins = computeDormantPlugins(senderId);
8009
8180
  console.log(`${TAG18} dormant-plugins-computed count=${Array.isArray(dormantPlugins) ? dormantPlugins.length : 0} ms=${Date.now() - dormantStart}`);
8181
+ const activeStart = Date.now();
8182
+ const activePlugins = computeActivePlugins(senderId);
8183
+ console.log(`${TAG18} active-plugins-computed count=${activePlugins.length} ms=${Date.now() - activeStart}`);
8184
+ const specStart = Date.now();
8185
+ const specialistDomains = computeSpecialistDomains(senderId);
8186
+ console.log(`${TAG18} specialist-domains-computed count=${specialistDomains.length} ms=${Date.now() - specStart}`);
8010
8187
  const tunnelUrl = resolveTunnelUrl();
8011
8188
  console.log(`${TAG18} tunnel-url-resolved value=${tunnelUrl ?? "null"}`);
8012
8189
  const forwardStart = Date.now();
@@ -8017,6 +8194,8 @@ app15.post("/", async (c) => {
8017
8194
  permissionMode,
8018
8195
  aboutOwner,
8019
8196
  dormantPlugins,
8197
+ activePlugins,
8198
+ specialistDomains,
8020
8199
  tunnelUrl
8021
8200
  });
8022
8201
  console.log(`${TAG18} forward-spawn-start managerBase=${managerBase2()} bytes=${upstreamPayload.length}`);
@@ -8048,6 +8227,24 @@ app15.post("/", async (c) => {
8048
8227
  }
8049
8228
  return new Response(upstream.body, { status: upstream.status, headers: upstream.headers });
8050
8229
  });
8230
+ app15.get("/events", async (c) => {
8231
+ const upstream = await fetch(`${managerBase2()}/events`, {
8232
+ headers: { accept: "text/event-stream" }
8233
+ }).catch((err) => {
8234
+ console.error(`${TAG18} fetch-failed op=events message=${err instanceof Error ? err.message : String(err)}`);
8235
+ return null;
8236
+ });
8237
+ if (!upstream || !upstream.body) return c.json({ error: "manager-unreachable" }, 503);
8238
+ return new Response(upstream.body, {
8239
+ status: upstream.status,
8240
+ headers: {
8241
+ "content-type": "text/event-stream",
8242
+ "cache-control": "no-cache, no-transform",
8243
+ "x-accel-buffering": "no",
8244
+ connection: "keep-alive"
8245
+ }
8246
+ });
8247
+ });
8051
8248
  app15.get("/", async (c) => {
8052
8249
  const cacheKey = c.get("cacheKey") ?? "";
8053
8250
  const senderId = getAccountIdForSession(cacheKey) ?? "";
@@ -8078,6 +8275,8 @@ app15.post("/resume", async (c) => {
8078
8275
  const channel = typeof body.channel === "string" ? body.channel : "browser";
8079
8276
  const aboutOwner = await resolveOwnerProfileBlock(senderId, userId);
8080
8277
  const dormantPlugins = computeDormantPlugins(senderId);
8278
+ const activePlugins = computeActivePlugins(senderId);
8279
+ const specialistDomains = computeSpecialistDomains(senderId);
8081
8280
  const tunnelUrl = resolveTunnelUrl();
8082
8281
  const upstream = await fetch(`${managerBase2()}/resume`, {
8083
8282
  method: "POST",
@@ -8089,6 +8288,8 @@ app15.post("/resume", async (c) => {
8089
8288
  claudeSessionId: body.claudeSessionId,
8090
8289
  aboutOwner,
8091
8290
  dormantPlugins,
8291
+ activePlugins,
8292
+ specialistDomains,
8092
8293
  tunnelUrl
8093
8294
  })
8094
8295
  }).catch((err) => {
@@ -8098,11 +8299,22 @@ app15.post("/resume", async (c) => {
8098
8299
  if (!upstream) return c.json({ error: "manager-unreachable" }, 503);
8099
8300
  return new Response(upstream.body, { status: upstream.status, headers: upstream.headers });
8100
8301
  });
8302
+ app15.post("/:sessionId/stop", async (c) => {
8303
+ const sessionId = c.req.param("sessionId");
8304
+ const upstream = await fetch(
8305
+ `${managerBase2()}/${encodeURIComponent(sessionId)}/stop`,
8306
+ { method: "POST" }
8307
+ ).catch((err) => {
8308
+ console.error(`${TAG18} fetch-failed op=stop message=${err instanceof Error ? err.message : String(err)}`);
8309
+ return null;
8310
+ });
8311
+ if (!upstream) return c.json({ error: "manager-unreachable" }, 503);
8312
+ return new Response(upstream.body, { status: upstream.status, headers: upstream.headers });
8313
+ });
8101
8314
  app15.delete("/:sessionId", async (c) => {
8102
8315
  const sessionId = c.req.param("sessionId");
8103
- const purge = c.req.query("purge") === "1" ? "?purge=1" : "";
8104
8316
  const upstream = await fetch(
8105
- `${managerBase2()}/${encodeURIComponent(sessionId)}${purge}`,
8317
+ `${managerBase2()}/${encodeURIComponent(sessionId)}`,
8106
8318
  { method: "DELETE" }
8107
8319
  ).catch((err) => {
8108
8320
  console.error(`${TAG18} fetch-failed op=delete message=${err instanceof Error ? err.message : String(err)}`);
@@ -8444,7 +8656,7 @@ function isValidDomain(value) {
8444
8656
 
8445
8657
  // app/lib/alias-domains.ts
8446
8658
  import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
8447
- import { dirname as dirname2 } from "path";
8659
+ import { dirname as dirname3 } from "path";
8448
8660
  import { resolve as resolve13 } from "path";
8449
8661
  var ALIAS_DOMAINS_PATH = resolve13(MAXY_DIR, "alias-domains.json");
8450
8662
  function readExisting() {
@@ -8461,14 +8673,14 @@ function addAliasDomain(hostname2) {
8461
8673
  const existing = readExisting();
8462
8674
  if (existing.has(hostname2)) return;
8463
8675
  existing.add(hostname2);
8464
- mkdirSync4(dirname2(ALIAS_DOMAINS_PATH), { recursive: true });
8676
+ mkdirSync4(dirname3(ALIAS_DOMAINS_PATH), { recursive: true });
8465
8677
  writeFileSync8(ALIAS_DOMAINS_PATH, JSON.stringify([...existing], null, 2) + "\n", "utf-8");
8466
8678
  }
8467
8679
 
8468
8680
  // app/lib/script-stream-tailer.ts
8469
8681
  import * as childProcess from "child_process";
8470
- import { appendFileSync as appendFileSync2, createReadStream as createReadStream2, mkdirSync as mkdirSync5, statSync as statSync6 } from "fs";
8471
- import { dirname as dirname3 } from "path";
8682
+ import { appendFileSync as appendFileSync2, createReadStream as createReadStream2, mkdirSync as mkdirSync5, statSync as statSync7 } from "fs";
8683
+ import { dirname as dirname4 } from "path";
8472
8684
  import { StringDecoder } from "string_decoder";
8473
8685
  var SCRIPT_STREAM_RE = /^\[([^\]]+)\] \[script:([a-z][a-z0-9-]*)((?::[a-z0-9:_-]+)?)\] (.*)$/;
8474
8686
  function parseLine(line) {
@@ -8486,7 +8698,7 @@ function startScriptStreamTailer(opts) {
8486
8698
  const { path: path2, onEvent, onError } = opts;
8487
8699
  let offset;
8488
8700
  try {
8489
- offset = statSync6(path2).size;
8701
+ offset = statSync7(path2).size;
8490
8702
  } catch {
8491
8703
  offset = 0;
8492
8704
  }
@@ -8505,7 +8717,7 @@ function startScriptStreamTailer(opts) {
8505
8717
  try {
8506
8718
  let size;
8507
8719
  try {
8508
- size = statSync6(path2).size;
8720
+ size = statSync7(path2).size;
8509
8721
  } catch {
8510
8722
  return;
8511
8723
  }
@@ -8577,7 +8789,7 @@ function writeRouteMilestone(streamLogPath, scope, line) {
8577
8789
  }
8578
8790
  const ts = (/* @__PURE__ */ new Date()).toISOString();
8579
8791
  try {
8580
- mkdirSync5(dirname3(streamLogPath), { recursive: true });
8792
+ mkdirSync5(dirname4(streamLogPath), { recursive: true });
8581
8793
  appendFileSync2(streamLogPath, `[${ts}] [script:${scope}] ${line}
8582
8794
  `);
8583
8795
  } catch (err) {
@@ -9295,7 +9507,7 @@ var cloudflare_default = app20;
9295
9507
  import { createReadStream as createReadStream3 } from "fs";
9296
9508
  import { readdir as readdir2, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
9297
9509
  import { realpathSync as realpathSync4 } from "fs";
9298
- import { basename as basename4, dirname as dirname4, join as join10, resolve as resolve16, sep as sep3 } from "path";
9510
+ import { basename as basename4, dirname as dirname5, join as join11, resolve as resolve16, sep as sep3 } from "path";
9299
9511
  import { Readable as Readable2 } from "stream";
9300
9512
 
9301
9513
  // app/lib/data-path.ts
@@ -9652,7 +9864,7 @@ async function cascadeDeleteDocument(params) {
9652
9864
  var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
9653
9865
  async function readMeta(absDir, baseName) {
9654
9866
  try {
9655
- const raw = await readFile4(join10(absDir, `${baseName}.meta.json`), "utf8");
9867
+ const raw = await readFile4(join11(absDir, `${baseName}.meta.json`), "utf8");
9656
9868
  const parsed = JSON.parse(raw);
9657
9869
  if (typeof parsed?.filename === "string") {
9658
9870
  return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
@@ -9690,7 +9902,7 @@ async function readAccountNames() {
9690
9902
  }
9691
9903
  async function enrich(absolute, entry, accountNames) {
9692
9904
  if (entry.kind === "directory" && UUID_RE4.test(entry.name)) {
9693
- const meta = await readMeta(join10(absolute, entry.name), entry.name);
9905
+ const meta = await readMeta(join11(absolute, entry.name), entry.name);
9694
9906
  if (meta?.filename) {
9695
9907
  entry.displayName = meta.filename;
9696
9908
  entry.mimeType = meta.mimeType;
@@ -9749,7 +9961,7 @@ app21.get("/", requireAdminSession, async (c) => {
9749
9961
  continue;
9750
9962
  }
9751
9963
  try {
9752
- const entryPath = join10(absolute, name);
9964
+ const entryPath = join11(absolute, name);
9753
9965
  const s = await stat4(entryPath);
9754
9966
  entries.push({
9755
9967
  name,
@@ -9922,7 +10134,7 @@ app21.delete("/", requireAdminSession, async (c) => {
9922
10134
  }
9923
10135
  const dot = base.lastIndexOf(".");
9924
10136
  const stem = dot === -1 ? base : base.slice(0, dot);
9925
- const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join10(dirname4(absolute), `${stem}.meta.json`) : null;
10137
+ const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join11(dirname5(absolute), `${stem}.meta.json`) : null;
9926
10138
  await unlink2(absolute);
9927
10139
  if (sidecarPath) {
9928
10140
  try {
@@ -11969,10 +12181,10 @@ var sidebar_artefact_content_default = app31;
11969
12181
 
11970
12182
  // server/routes/admin/health.ts
11971
12183
  import { existsSync as existsSync19, readFileSync as readFileSync17 } from "fs";
11972
- import { resolve as resolve20, join as join11 } from "path";
12184
+ import { resolve as resolve20, join as join12 } from "path";
11973
12185
  var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
11974
12186
  var brandHostname = "maxy";
11975
- var brandJsonPath = join11(PLATFORM_ROOT6, "config", "brand.json");
12187
+ var brandJsonPath = join12(PLATFORM_ROOT6, "config", "brand.json");
11976
12188
  if (existsSync19(brandJsonPath)) {
11977
12189
  try {
11978
12190
  const brand = JSON.parse(readFileSync17(brandJsonPath, "utf-8"));
@@ -12067,7 +12279,7 @@ app33.route("/health-brand", health_default2);
12067
12279
  var admin_default = app33;
12068
12280
 
12069
12281
  // server/routes/sites.ts
12070
- import { existsSync as existsSync20, readFileSync as readFileSync18, realpathSync as realpathSync5, statSync as statSync7 } from "fs";
12282
+ import { existsSync as existsSync20, readFileSync as readFileSync18, realpathSync as realpathSync5, statSync as statSync8 } from "fs";
12071
12283
  import { resolve as resolve21 } from "path";
12072
12284
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
12073
12285
  var MIME = {
@@ -12133,7 +12345,7 @@ app34.get("/:rel{.*}", (c) => {
12133
12345
  }
12134
12346
  let stat7;
12135
12347
  try {
12136
- stat7 = existsSync20(filePath) ? statSync7(filePath) : null;
12348
+ stat7 = existsSync20(filePath) ? statSync8(filePath) : null;
12137
12349
  } catch {
12138
12350
  stat7 = null;
12139
12351
  }
@@ -12317,7 +12529,7 @@ function startReaper2() {
12317
12529
 
12318
12530
  // ../lib/entitlement/src/index.ts
12319
12531
  import { createPublicKey, createHash as createHash3, verify as cryptoVerify } from "crypto";
12320
- import { existsSync as existsSync21, readFileSync as readFileSync19, statSync as statSync8 } from "fs";
12532
+ import { existsSync as existsSync21, readFileSync as readFileSync19, statSync as statSync9 } from "fs";
12321
12533
  import { resolve as resolve22 } from "path";
12322
12534
 
12323
12535
  // ../lib/entitlement/src/canonicalize.ts
@@ -12369,7 +12581,7 @@ function resolveEntitlement(brand, account) {
12369
12581
  if (!existsSync21(entitlementPath)) {
12370
12582
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
12371
12583
  }
12372
- const stat7 = statSync8(entitlementPath);
12584
+ const stat7 = statSync9(entitlementPath);
12373
12585
  const key = memoKey(stat7.mtimeMs, account);
12374
12586
  if (memo && memo.key === key) {
12375
12587
  return memo.result;
@@ -12556,7 +12768,7 @@ function clientFrom(c) {
12556
12768
  );
12557
12769
  }
12558
12770
  var PLATFORM_ROOT7 = process.env.MAXY_PLATFORM_ROOT || "";
12559
- var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join12(PLATFORM_ROOT7, "config", "brand.json") : "";
12771
+ var BRAND_JSON_PATH = PLATFORM_ROOT7 ? join13(PLATFORM_ROOT7, "config", "brand.json") : "";
12560
12772
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", domain: "getmaxy.com" };
12561
12773
  if (BRAND_JSON_PATH && !existsSync22(BRAND_JSON_PATH)) {
12562
12774
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
@@ -12582,7 +12794,7 @@ var brandLoginOpts = {
12582
12794
  bodyFont: BRAND.defaultFonts?.body,
12583
12795
  logoContainsName: !!BRAND.logoContainsName
12584
12796
  };
12585
- var ALIAS_DOMAINS_PATH2 = join12(homedir4(), BRAND.configDir, "alias-domains.json");
12797
+ var ALIAS_DOMAINS_PATH2 = join13(homedir4(), BRAND.configDir, "alias-domains.json");
12586
12798
  function loadAliasDomains() {
12587
12799
  try {
12588
12800
  if (!existsSync22(ALIAS_DOMAINS_PATH2)) return null;
@@ -13028,7 +13240,7 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
13028
13240
  function readInstalledVersion() {
13029
13241
  try {
13030
13242
  if (!PLATFORM_ROOT7) return "unknown";
13031
- const versionFile = join12(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
13243
+ const versionFile = join13(PLATFORM_ROOT7, "config", `.${BRAND.hostname}-version`);
13032
13244
  if (!existsSync22(versionFile)) return "unknown";
13033
13245
  const content = readFileSync20(versionFile, "utf-8").trim();
13034
13246
  return content || "unknown";
@@ -13087,14 +13299,14 @@ ${clientErrorReporterScript}
13087
13299
  }
13088
13300
  var brandedHtmlCache = /* @__PURE__ */ new Map();
13089
13301
  function loadBrandingCache(agentSlug) {
13090
- const configDir2 = join12(homedir4(), BRAND.configDir);
13302
+ const configDir2 = join13(homedir4(), BRAND.configDir);
13091
13303
  try {
13092
- const accountJsonPath = join12(configDir2, "account.json");
13304
+ const accountJsonPath = join13(configDir2, "account.json");
13093
13305
  if (!existsSync22(accountJsonPath)) return null;
13094
13306
  const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
13095
13307
  const accountId = account.accountId;
13096
13308
  if (!accountId) return null;
13097
- const cachePath = join12(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
13309
+ const cachePath = join13(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
13098
13310
  if (!existsSync22(cachePath)) return null;
13099
13311
  return JSON.parse(readFileSync20(cachePath, "utf-8"));
13100
13312
  } catch {
@@ -13103,8 +13315,8 @@ function loadBrandingCache(agentSlug) {
13103
13315
  }
13104
13316
  function resolveDefaultSlug() {
13105
13317
  try {
13106
- const configDir2 = join12(homedir4(), BRAND.configDir);
13107
- const accountJsonPath = join12(configDir2, "account.json");
13318
+ const configDir2 = join13(homedir4(), BRAND.configDir);
13319
+ const accountJsonPath = join13(configDir2, "account.json");
13108
13320
  if (!existsSync22(accountJsonPath)) return null;
13109
13321
  const account = JSON.parse(readFileSync20(accountJsonPath, "utf-8"));
13110
13322
  return account.defaultAgent || null;
@@ -13352,7 +13564,7 @@ reconcileEnabledPlugins(bootAccount?.accountDir, bootAccount?.config);
13352
13564
  (async () => {
13353
13565
  if (!bootAccount) return;
13354
13566
  try {
13355
- const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-NEB3X6O2.js");
13567
+ const { recoverRunningCloudflareTasks } = await import("./cloudflare-task-tracker-R6MMORFU.js");
13356
13568
  const result = await recoverRunningCloudflareTasks(
13357
13569
  bootAccount.accountId,
13358
13570
  configDirForWhatsApp,
@@ -13412,7 +13624,7 @@ if (bootAccountConfig?.whatsapp) {
13412
13624
  }
13413
13625
  init({
13414
13626
  configDir: configDirForWhatsApp,
13415
- platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join12(__dirname, "..")),
13627
+ platformRoot: resolve23(process.env.MAXY_PLATFORM_ROOT ?? join13(__dirname, "..")),
13416
13628
  accountConfig: bootAccountConfig,
13417
13629
  onMessage: async (msg) => {
13418
13630
  if (process.env.WHATSAPP_PTY_BRIDGE_ENABLED === "true" && msg.text && !msg.isOwnerMirror) {