@rubytech/create-maxy-code 0.1.378 → 0.1.382

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 (52) hide show
  1. package/dist/__tests__/plugin-install.test.js +18 -1
  2. package/dist/index.js +22 -8
  3. package/dist/lib/plugin-install.js +22 -0
  4. package/package.json +1 -1
  5. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +11 -3
  6. package/payload/platform/plugins/docs/references/admin-ui.md +4 -2
  7. package/payload/platform/plugins/docs/references/internals.md +4 -0
  8. package/payload/platform/plugins/docs/references/plugins-guide.md +2 -0
  9. package/payload/platform/plugins/whatsapp/references/channels-whatsapp.md +13 -0
  10. package/payload/platform/services/claude-session-manager/dist/index.js +32 -0
  11. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  12. package/payload/platform/services/claude-session-manager/dist/skill-registration-drift.d.ts +51 -0
  13. package/payload/platform/services/claude-session-manager/dist/skill-registration-drift.d.ts.map +1 -0
  14. package/payload/platform/services/claude-session-manager/dist/skill-registration-drift.js +163 -0
  15. package/payload/platform/services/claude-session-manager/dist/skill-registration-drift.js.map +1 -0
  16. package/payload/server/{chunk-AQO6KLIH.js → chunk-ZYS5V5QG.js} +0 -21
  17. package/payload/server/maxy-edge.js +1 -1
  18. package/payload/server/public/assets/{AdminLoginScreens-B9u1V35g.js → AdminLoginScreens-C_Qn0UPy.js} +1 -1
  19. package/payload/server/public/assets/AdminShell-iHdYhspw.js +1 -0
  20. package/payload/server/public/assets/{Checkbox-B2g2SCpw.js → Checkbox-B76SHnPC.js} +1 -1
  21. package/payload/server/public/assets/admin-RTEhnrPk.js +1 -0
  22. package/payload/server/public/assets/{browser-B8omhYsK.js → browser-Chmp3Xfv.js} +1 -1
  23. package/payload/server/public/assets/calendar-CjE7hiqV.js +1 -0
  24. package/payload/server/public/assets/chat-DiKmCMO1.js +1 -0
  25. package/payload/server/public/assets/data-5PpEsUR3.js +1 -0
  26. package/payload/server/public/assets/{graph-DJOKFr_s.js → graph-DEHmvpNl.js} +3 -3
  27. package/payload/server/public/assets/{graph-labels-DFdBydWC.js → graph-labels-CYAjU3rz.js} +1 -1
  28. package/payload/server/public/assets/operator-BDTnuQhB.js +1 -0
  29. package/payload/server/public/assets/page-D8FFXoI9.js +1 -0
  30. package/payload/server/public/assets/page-HeiBebPq.js +32 -0
  31. package/payload/server/public/assets/{public-CGl0i1f-.js → public-BIOxrxZK.js} +1 -1
  32. package/payload/server/public/assets/{rotate-ccw-Cg_V4XIU.js → rotate-ccw-K1xZvf3B.js} +1 -1
  33. package/payload/server/public/assets/{useSubAccountSwitcher-Ca1GJeBC.css → useSubAccountSwitcher-B44qYovc.css} +1 -1
  34. package/payload/server/public/assets/useSubAccountSwitcher-DPEkYkYd.js +9 -0
  35. package/payload/server/public/browser.html +4 -4
  36. package/payload/server/public/calendar.html +4 -4
  37. package/payload/server/public/chat.html +6 -6
  38. package/payload/server/public/data.html +5 -5
  39. package/payload/server/public/graph.html +7 -7
  40. package/payload/server/public/index.html +8 -8
  41. package/payload/server/public/operator.html +8 -8
  42. package/payload/server/public/public.html +6 -6
  43. package/payload/server/server.js +387 -122
  44. package/payload/server/public/assets/AdminShell-C2UXTLSB.js +0 -1
  45. package/payload/server/public/assets/admin-CRBQgWsm.js +0 -1
  46. package/payload/server/public/assets/calendar-Blb-5arm.js +0 -1
  47. package/payload/server/public/assets/chat--1ajLxwi.js +0 -1
  48. package/payload/server/public/assets/data-BYUmu98z.js +0 -1
  49. package/payload/server/public/assets/operator-DUVqlubZ.js +0 -1
  50. package/payload/server/public/assets/page-BMeSKYGZ.js +0 -32
  51. package/payload/server/public/assets/page-DBkTNfei.js +0 -1
  52. package/payload/server/public/assets/useSubAccountSwitcher-DAgBUed_.js +0 -9
@@ -72,7 +72,6 @@ import {
72
72
  loadAdminUserName,
73
73
  loadPersonNameByElementId,
74
74
  loadUserProfile,
75
- loadWhatsappSenderName,
76
75
  migrateLegacyRemotePassword,
77
76
  persistMessage,
78
77
  projectAgent,
@@ -110,7 +109,7 @@ import {
110
109
  vncLog,
111
110
  walkPremiumBundles,
112
111
  writeAdminUserAndPerson
113
- } from "./chunk-AQO6KLIH.js";
112
+ } from "./chunk-ZYS5V5QG.js";
114
113
  import {
115
114
  __commonJS,
116
115
  __toESM
@@ -1869,6 +1868,32 @@ function readSelfId(authDir) {
1869
1868
  return { e164: null, jid: null, lid: null };
1870
1869
  }
1871
1870
  }
1871
+ function credsCensus(authDir) {
1872
+ const raw = readCredsJsonRaw(resolveCredsPath(authDir));
1873
+ if (!raw) return { credsPresent: false, registered: false, hasAccountSignature: false, e164: null };
1874
+ try {
1875
+ const parsed = JSON.parse(raw);
1876
+ const registered = parsed?.registered === true;
1877
+ const hasAccountSignature = parsed?.account != null;
1878
+ let e164 = null;
1879
+ const jid = parsed?.me?.id;
1880
+ if (jid) {
1881
+ const match = jid.match(/^(\d+)(?::\d+)?@s\.whatsapp\.net$/i);
1882
+ if (match) e164 = match[1];
1883
+ }
1884
+ return { credsPresent: true, registered, hasAccountSignature, e164 };
1885
+ } catch {
1886
+ return { credsPresent: true, registered: false, hasAccountSignature: false, e164: null };
1887
+ }
1888
+ }
1889
+ function getAuthAgeMs(authDir) {
1890
+ try {
1891
+ const stats = fsSync.statSync(resolveCredsPath(authDir));
1892
+ return Date.now() - stats.mtimeMs;
1893
+ } catch {
1894
+ return null;
1895
+ }
1896
+ }
1872
1897
  async function clearAuth(authDir) {
1873
1898
  try {
1874
1899
  await fs.access(authDir);
@@ -1880,6 +1905,17 @@ async function clearAuth(authDir) {
1880
1905
  console.error(`${TAG} cleared credentials at ${authDir}`);
1881
1906
  return true;
1882
1907
  }
1908
+ function discardAuthDirSync(authDir) {
1909
+ try {
1910
+ if (!fsSync.existsSync(authDir)) return false;
1911
+ fsSync.rmSync(authDir, { recursive: true, force: true });
1912
+ console.error(`${TAG} discarded credential dir ${authDir}`);
1913
+ return true;
1914
+ } catch (err) {
1915
+ console.warn(`${TAG} discardAuthDirSync failed authDir=${authDir}: ${String(err)}`);
1916
+ return false;
1917
+ }
1918
+ }
1883
1919
  function listCredentialAccountIds(configDir2) {
1884
1920
  const credsRoot = path.join(os.homedir(), configDir2, "credentials", "whatsapp");
1885
1921
  try {
@@ -2027,13 +2063,22 @@ function enqueueSaveCreds(authDir, saveCreds) {
2027
2063
  });
2028
2064
  }
2029
2065
  async function createWaSocket(opts) {
2030
- const { authDir, onQr, onConnectionUpdate, silent } = opts;
2066
+ const { authDir, onQr, onConnectionUpdate, silent, correlationId, account, getCodeIssuedTs } = opts;
2067
+ const cid = correlationId ?? "none";
2068
+ const acct = account ?? "unknown";
2031
2069
  await fs2.mkdir(authDir, { recursive: true });
2032
2070
  maybeRestoreCredsFromBackup(authDir);
2033
2071
  const { state, saveCreds } = await useMultiFileAuthState(authDir);
2034
2072
  const { version } = await fetchLatestBaileysVersion();
2073
+ if (!silent) {
2074
+ const preCensus = credsCensus(authDir);
2075
+ console.error(
2076
+ `${TAG2} op=creds-pre cid=${cid} account=${acct} credsPresent=${preCensus.credsPresent} registered=${preCensus.registered} hasAccount=${preCensus.hasAccountSignature}`
2077
+ );
2078
+ }
2079
+ const openTs = Date.now();
2035
2080
  console.error(
2036
- `${TAG2} creating socket authDir=${authDir} baileysVersion=${baileysPkgVersion} waProtocolVersion=${version.join(".")}`
2081
+ `${TAG2} op=socket-open cid=${cid} account=${acct} baileysVersion=${baileysPkgVersion} waProtocolVersion=${version.join(".")} openTs=${openTs}`
2037
2082
  );
2038
2083
  const baileysLogger = createBaileysLogger();
2039
2084
  const sock = makeWASocket({
@@ -2054,6 +2099,9 @@ async function createWaSocket(opts) {
2054
2099
  enqueueSaveCreds(authDir, saveCreds);
2055
2100
  });
2056
2101
  let qrSequence = 0;
2102
+ let everOpen = false;
2103
+ let lastQrTs = 0;
2104
+ let pairSuccessLogged = false;
2057
2105
  sock.ev.on("connection.update", (update) => {
2058
2106
  try {
2059
2107
  const parts = [];
@@ -2069,17 +2117,40 @@ async function createWaSocket(opts) {
2069
2117
  if (!silent && parts.length > 0) {
2070
2118
  console.error(`${TAG2} connection.update ${parts.join(" ")}`);
2071
2119
  }
2120
+ if (update.qr && !silent) {
2121
+ const now = Date.now();
2122
+ const sinceLastRefMs = lastQrTs ? now - lastQrTs : null;
2123
+ lastQrTs = now;
2124
+ console.error(
2125
+ `${TAG2} op=qr cid=${cid} qr=#${qrSequence} sinceOpenMs=${now - openTs} sinceLastRefMs=${sinceLastRefMs ?? "n/a"}`
2126
+ );
2127
+ }
2128
+ if (update.isNewLogin === true && !pairSuccessLogged && !silent) {
2129
+ pairSuccessLogged = true;
2130
+ const codeIssuedTs = getCodeIssuedTs?.();
2131
+ const sinceCodeIssuedMs = codeIssuedTs ? Date.now() - codeIssuedTs : null;
2132
+ const afterCensus = credsCensus(authDir);
2133
+ console.error(
2134
+ `${TAG2} op=pair-success cid=${cid} account=${acct} sinceCodeIssuedMs=${sinceCodeIssuedMs ?? "n/a"} hasAccountAfter=${afterCensus.hasAccountSignature}`
2135
+ );
2136
+ }
2072
2137
  if (update.qr && onQr) {
2073
2138
  onQr(update.qr);
2074
2139
  }
2075
2140
  if (update.connection === "close") {
2076
2141
  const status = getStatusCode(update.lastDisconnect?.error);
2142
+ if (!silent) {
2143
+ console.error(
2144
+ `${TAG2} op=close cid=${cid} account=${acct} status=${status ?? "unknown"} reason="${formatError(update.lastDisconnect?.error)}" socketLifeMs=${Date.now() - openTs} kind=${closeKind(status, everOpen)}`
2145
+ );
2146
+ }
2077
2147
  if (status === DisconnectReason.loggedOut && !silent) {
2078
2148
  console.error(`${TAG2} session logged out (401) \u2014 re-link required`);
2079
2149
  }
2080
2150
  }
2081
- if (update.connection === "open" && !silent) {
2082
- console.error(`${TAG2} connected`);
2151
+ if (update.connection === "open") {
2152
+ everOpen = true;
2153
+ if (!silent) console.error(`${TAG2} connected`);
2083
2154
  }
2084
2155
  onConnectionUpdate?.(update);
2085
2156
  } catch (err) {
@@ -2143,6 +2214,12 @@ function extractBoomDetails(err) {
2143
2214
  if (!statusCode && !error && !message) return null;
2144
2215
  return { statusCode, error, message };
2145
2216
  }
2217
+ function closeKind(status, everOpen) {
2218
+ if (status === DisconnectReason.restartRequired) return "restart-required-515";
2219
+ if (status === DisconnectReason.loggedOut) return "logged-out-401";
2220
+ if (status === 408) return everOpen ? "conn-lost-408" : "qr-refs-ended-408";
2221
+ return "other";
2222
+ }
2146
2223
 
2147
2224
  // app/lib/whatsapp/reconnect.ts
2148
2225
  import { DisconnectReason as DisconnectReason2 } from "@whiskeysockets/baileys";
@@ -3096,12 +3173,15 @@ async function sendMediaMessage(sock, to, media, opts) {
3096
3173
  }
3097
3174
 
3098
3175
  // app/lib/whatsapp/message-store.ts
3099
- import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync4, appendFileSync, readdirSync } from "fs";
3176
+ import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync4, appendFileSync, readdirSync, statSync as statSync2 } from "fs";
3100
3177
  import { dirname, join as join3 } from "path";
3101
3178
  var STORE_ROOT = () => join3(process.env.MAXY_DIR_OVERRIDE ?? MAXY_DIR, "data", "whatsapp-messages");
3102
3179
  function conversationFile(platformAccountId, remoteJid) {
3103
3180
  return join3(STORE_ROOT(), platformAccountId, `${remoteJid}.jsonl`);
3104
3181
  }
3182
+ function conversationFilePath(platformAccountId, remoteJid) {
3183
+ return conversationFile(platformAccountId, remoteJid);
3184
+ }
3105
3185
  function parseLines(raw) {
3106
3186
  const out = [];
3107
3187
  for (const line of raw.split("\n")) {
@@ -3114,6 +3194,7 @@ function parseLines(raw) {
3114
3194
  }
3115
3195
  return out;
3116
3196
  }
3197
+ var byDateSentAsc = (a, b) => a.dateSent.localeCompare(b.dateSent);
3117
3198
  function appendMessage(platformAccountId, record) {
3118
3199
  const file = conversationFile(platformAccountId, record.remoteJid);
3119
3200
  try {
@@ -3148,13 +3229,79 @@ function readConversation(platformAccountId, remoteJid) {
3148
3229
  const file = conversationFile(platformAccountId, remoteJid);
3149
3230
  try {
3150
3231
  if (!existsSync3(file)) return [];
3151
- return parseLines(readFileSync4(file, "utf8")).sort((a, b) => a.dateSent.localeCompare(b.dateSent));
3232
+ return parseLines(readFileSync4(file, "utf8")).sort(byDateSentAsc);
3152
3233
  } catch (err) {
3153
3234
  const reason = err instanceof Error ? err.message : String(err);
3154
3235
  console.error(`[whatsapp-message-store] FAIL op=read reason=${reason.slice(0, 100)} remoteJid=${remoteJid}`);
3155
3236
  return [];
3156
3237
  }
3157
3238
  }
3239
+ var summaryCache = /* @__PURE__ */ new Map();
3240
+ function summariseRecords(records) {
3241
+ if (records.length === 0) return null;
3242
+ const sorted = records.slice().sort(byDateSentAsc);
3243
+ return {
3244
+ first: sorted[0],
3245
+ last: sorted[sorted.length - 1],
3246
+ firstNamedSender: sorted.find((r) => r.senderName)?.senderName ?? null
3247
+ };
3248
+ }
3249
+ function readConversationSummaries(platformAccountId) {
3250
+ const dir = join3(STORE_ROOT(), platformAccountId);
3251
+ const out = /* @__PURE__ */ new Map();
3252
+ const seen = /* @__PURE__ */ new Set();
3253
+ let fullReads = 0;
3254
+ let cacheHits = 0;
3255
+ let bytesRead = 0;
3256
+ try {
3257
+ if (!existsSync3(dir)) return out;
3258
+ for (const entry of readdirSync(dir)) {
3259
+ if (!entry.endsWith(".jsonl")) continue;
3260
+ const remoteJid = entry.slice(0, -".jsonl".length);
3261
+ const file = join3(dir, entry);
3262
+ seen.add(file);
3263
+ let size;
3264
+ let mtimeMs;
3265
+ try {
3266
+ const st = statSync2(file);
3267
+ size = st.size;
3268
+ mtimeMs = st.mtimeMs;
3269
+ } catch {
3270
+ continue;
3271
+ }
3272
+ const cached2 = summaryCache.get(file);
3273
+ if (cached2 && cached2.size === size && cached2.mtimeMs === mtimeMs) {
3274
+ cacheHits++;
3275
+ out.set(remoteJid, cached2.summary);
3276
+ continue;
3277
+ }
3278
+ let summary;
3279
+ try {
3280
+ const raw = readFileSync4(file, "utf8");
3281
+ bytesRead += Buffer.byteLength(raw);
3282
+ fullReads++;
3283
+ summary = summariseRecords(parseLines(raw));
3284
+ } catch (err) {
3285
+ const reason = err instanceof Error ? err.message : String(err);
3286
+ console.error(`[whatsapp-message-store] FAIL op=summarise reason=${reason.slice(0, 100)} remoteJid=${remoteJid}`);
3287
+ continue;
3288
+ }
3289
+ if (!summary) continue;
3290
+ summaryCache.set(file, { size, mtimeMs, summary });
3291
+ out.set(remoteJid, summary);
3292
+ }
3293
+ for (const key of summaryCache.keys()) {
3294
+ if (dirname(key) === dir && !seen.has(key)) summaryCache.delete(key);
3295
+ }
3296
+ } catch (err) {
3297
+ const reason = err instanceof Error ? err.message : String(err);
3298
+ console.error(`[whatsapp-message-store] FAIL op=summaries reason=${reason.slice(0, 100)} platformAccountId=${platformAccountId}`);
3299
+ }
3300
+ console.log(
3301
+ `[whatsapp-message-store] op=summaries accountId=${platformAccountId} conversations=${out.size} fullReads=${fullReads} cacheHits=${cacheHits} bytesRead=${bytesRead}`
3302
+ );
3303
+ return out;
3304
+ }
3158
3305
  function readAllConversations(platformAccountId) {
3159
3306
  const dir = join3(STORE_ROOT(), platformAccountId);
3160
3307
  const out = /* @__PURE__ */ new Map();
@@ -6055,6 +6202,13 @@ async function runPostPairing(login) {
6055
6202
  }
6056
6203
  async function loginConnectionLoop(accountId, login) {
6057
6204
  let attempt = 0;
6205
+ const cidShort = login.id.slice(0, 8);
6206
+ const logTerminal = (outcome, errMsg) => {
6207
+ const fc = credsCensus(login.authDir);
6208
+ console.error(
6209
+ `${TAG17} op=terminal cid=${cidShort} outcome=${outcome} credsFinal={registered=${fc.registered},account=${fc.hasAccountSignature},me=${fc.e164 ?? "null"}}` + (errMsg ? ` error="${errMsg}"` : "")
6210
+ );
6211
+ };
6058
6212
  while (true) {
6059
6213
  try {
6060
6214
  await waitForConnection(login.sock);
@@ -6063,6 +6217,7 @@ async function loginConnectionLoop(accountId, login) {
6063
6217
  await runPostPairing(current);
6064
6218
  current.connected = true;
6065
6219
  console.error(`${TAG17} loginConnectionLoop: connected account=${accountId} attempt=${attempt} configPersisted=${current.configPersisted}`);
6220
+ logTerminal("connected");
6066
6221
  }
6067
6222
  return;
6068
6223
  } catch (err) {
@@ -6079,6 +6234,7 @@ async function loginConnectionLoop(accountId, login) {
6079
6234
  current.error = formatError(err);
6080
6235
  }
6081
6236
  current.errorStatus = getStatusCode(err);
6237
+ logTerminal("error", current.error);
6082
6238
  return;
6083
6239
  }
6084
6240
  attempt++;
@@ -6090,14 +6246,19 @@ async function loginConnectionLoop(accountId, login) {
6090
6246
  await new Promise((r) => setTimeout(r, delay));
6091
6247
  const afterDelay = activeLogins.get(accountId);
6092
6248
  if (afterDelay?.id !== login.id) return;
6249
+ const rc = credsCensus(login.authDir);
6250
+ console.error(
6251
+ `${TAG17} op=reconnect cid=${cidShort} attempt=${attempt}/${LOGIN_MAX_RECONNECTS} withRegistered=${rc.registered} withAccount=${rc.hasAccountSignature}`
6252
+ );
6093
6253
  try {
6094
- const newSock = await createWaSocket({ authDir: login.authDir });
6254
+ const newSock = await createWaSocket({ authDir: login.authDir, correlationId: cidShort, account: accountId });
6095
6255
  current.sock = newSock;
6096
6256
  } catch (sockErr) {
6097
6257
  console.error(
6098
6258
  `${TAG17} reconnect socket creation failed (attempt ${attempt}/${LOGIN_MAX_RECONNECTS}): ${String(sockErr)}`
6099
6259
  );
6100
6260
  current.error = `Reconnection failed: ${String(sockErr)}`;
6261
+ logTerminal("error", current.error);
6101
6262
  return;
6102
6263
  }
6103
6264
  }
@@ -6105,11 +6266,13 @@ async function loginConnectionLoop(accountId, login) {
6105
6266
  }
6106
6267
  async function startLogin(opts) {
6107
6268
  const { accountId, authDir, phone, accountDir = null, force, timeoutMs = 3e4 } = opts;
6269
+ const loginId = randomUUID6();
6270
+ const cid = loginId.slice(0, 8);
6108
6271
  const existing0 = activeLogins.get(accountId);
6109
6272
  const hasAuth = await authExists(authDir);
6110
6273
  const selfId = readSelfId(authDir);
6111
6274
  console.error(
6112
- `${TAG17} startLogin account=${accountId} force=${!!force} hasAuth=${hasAuth}` + (existing0 ? ` activeLogin={id=${existing0.id.slice(0, 8)},age=${Math.round((Date.now() - existing0.startedAt) / 1e3)}s,hasCode=${!!existing0.pairingCode}}` : " activeLogin=none")
6275
+ `${TAG17} op=start cid=${cid} account=${accountId} force=${!!force} hasAuth=${hasAuth}` + (existing0 ? ` activeLogin={id=${existing0.id.slice(0, 8)},age=${Math.round((Date.now() - existing0.startedAt) / 1e3)}s,hasCode=${!!existing0.pairingCode}}` : " activeLogin=none")
6113
6276
  );
6114
6277
  if (hasAuth && !force) {
6115
6278
  const who = selfId.e164 ?? selfId.jid ?? "unknown";
@@ -6148,21 +6311,32 @@ async function startLogin(opts) {
6148
6311
  );
6149
6312
  let requested = false;
6150
6313
  let sock;
6314
+ let socketOpenTs = 0;
6315
+ let codeIssuedTs;
6151
6316
  try {
6152
6317
  sock = await createWaSocket({
6153
6318
  authDir,
6319
+ correlationId: cid,
6320
+ account: accountId,
6321
+ getCodeIssuedTs: () => codeIssuedTs,
6154
6322
  // The first QR event means the noise handshake is complete and the
6155
6323
  // socket can send the pairing IQ — the safe moment to request the code.
6156
6324
  // We never render the QR; it is only a readiness signal.
6157
6325
  onQr: () => {
6158
6326
  if (requested) return;
6159
6327
  requested = true;
6328
+ console.error(
6329
+ `${TAG17} op=pairing-request cid=${cid} account=${accountId} qrRef=#1 sinceOpenMs=${socketOpenTs ? Date.now() - socketOpenTs : 0}`
6330
+ );
6160
6331
  void sock.requestPairingCode(digits).then((code) => {
6161
6332
  clearTimeout(codeTimer);
6333
+ codeIssuedTs = Date.now();
6162
6334
  const current = activeLogins.get(accountId);
6163
6335
  if (current?.id !== login.id) return;
6164
6336
  if (!current.pairingCode) current.pairingCode = code;
6165
- console.error(`${TAG17} pairing-code-issued account=${accountId} phone=${maskPhone(digits)} codeLen=${code.length}`);
6337
+ console.error(
6338
+ `${TAG17} op=code-issued cid=${cid} account=${accountId} phone=${maskPhone(digits)} codeLen=${code.length} sinceOpenMs=${socketOpenTs ? codeIssuedTs - socketOpenTs : 0}`
6339
+ );
6166
6340
  resolveCode?.(code);
6167
6341
  }).catch((err) => {
6168
6342
  clearTimeout(codeTimer);
@@ -6170,6 +6344,7 @@ async function startLogin(opts) {
6170
6344
  });
6171
6345
  }
6172
6346
  });
6347
+ socketOpenTs = Date.now();
6173
6348
  } catch (err) {
6174
6349
  clearTimeout(codeTimer);
6175
6350
  resetActiveLogin(accountId);
@@ -6179,7 +6354,7 @@ async function startLogin(opts) {
6179
6354
  accountId,
6180
6355
  authDir,
6181
6356
  accountDir,
6182
- id: randomUUID6(),
6357
+ id: loginId,
6183
6358
  sock,
6184
6359
  startedAt: Date.now(),
6185
6360
  phone: digits,
@@ -6260,6 +6435,13 @@ async function waitForLogin(opts) {
6260
6435
  console.error(`${TAG17} waitForLogin poll timeout account=${accountId} elapsed=${elapsed}s \u2014 login kept alive (pairing code still valid)`);
6261
6436
  return { connected: false, message: "Still waiting for you to enter the pairing code. The code is still valid \u2014 ask me to keep waiting, or request a new code.", configPersisted: false };
6262
6437
  }
6438
+ function listActiveLoginAccountIds() {
6439
+ const ids = [];
6440
+ for (const [accountId, login] of activeLogins) {
6441
+ if (isLoginFresh(login)) ids.push(accountId);
6442
+ }
6443
+ return ids;
6444
+ }
6263
6445
 
6264
6446
  // app/lib/whatsapp/outbound/send-document.ts
6265
6447
  import { realpathSync as realpathSync3 } from "fs";
@@ -6456,6 +6638,7 @@ function serializeWhatsAppSchema() {
6456
6638
  import { readdirSync as readdirSync3 } from "fs";
6457
6639
  import { join as join9 } from "path";
6458
6640
  var TAG19 = "[whatsapp:reconcile]";
6641
+ var HALF_REGISTERED_MIN_AGE_MS = 5 * 6e4;
6459
6642
  function listCredsAccountIds(credsRoot) {
6460
6643
  try {
6461
6644
  return readdirSync3(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(join9(credsRoot, e.name))).map((e) => e.name);
@@ -6469,11 +6652,29 @@ function isAccountConfigured(accountDir, accountId) {
6469
6652
  return !!accounts && Object.prototype.hasOwnProperty.call(accounts, accountId);
6470
6653
  }
6471
6654
  function reconcileCredsOnDisk(opts) {
6472
- const { credsRoot, accountDir, liveAccountIds } = opts;
6655
+ const { credsRoot, accountDir, liveAccountIds, activeLoginAccountIds } = opts;
6473
6656
  const entries = [];
6474
6657
  for (const accountId of listCredsAccountIds(credsRoot)) {
6475
6658
  if (liveAccountIds.has(accountId)) continue;
6476
6659
  const authDir = join9(credsRoot, accountId);
6660
+ const census = credsCensus(authDir);
6661
+ if (census.registered && !census.hasAccountSignature) {
6662
+ const inFlight = activeLoginAccountIds.has(accountId);
6663
+ const ageMs = getAuthAgeMs(authDir);
6664
+ const abandoned = !inFlight && ageMs !== null && ageMs >= HALF_REGISTERED_MIN_AGE_MS;
6665
+ if (!abandoned) {
6666
+ console.error(`${TAG19} op=half-registered account=${accountId} registered=true hasAccount=false inFlight=${inFlight} ageMs=${ageMs ?? "null"}`);
6667
+ entries.push({ accountId, connected: false, linkedUnconfigured: true });
6668
+ continue;
6669
+ }
6670
+ console.error(`${TAG19} op=discard-half-registered account=${accountId} registered=true hasAccount=false ageMs=${ageMs}`);
6671
+ const removed = discardAuthDirSync(authDir);
6672
+ if (!removed) {
6673
+ console.error(`${TAG19} op=discard-half-registered-failed account=${accountId} \u2014 residue persists`);
6674
+ entries.push({ accountId, connected: false, linkedUnconfigured: true });
6675
+ }
6676
+ continue;
6677
+ }
6477
6678
  const selfPhone = readSelfId(authDir).e164 ?? void 0;
6478
6679
  const configured = accountDir ? isAccountConfigured(accountDir, accountId) : false;
6479
6680
  console.error(
@@ -6500,9 +6701,10 @@ app2.get("/status", (c) => {
6500
6701
  try {
6501
6702
  const live = getStatus();
6502
6703
  const liveIds = new Set(live.map((a) => a.accountId));
6704
+ const activeLoginIds = new Set(listActiveLoginAccountIds());
6503
6705
  const credsRoot = join10(MAXY_DIR, "credentials", "whatsapp");
6504
6706
  const accountDir = resolveAccount()?.accountDir ?? null;
6505
- const reconciled = reconcileCredsOnDisk({ credsRoot, accountDir, liveAccountIds: liveIds });
6707
+ const reconciled = reconcileCredsOnDisk({ credsRoot, accountDir, liveAccountIds: liveIds, activeLoginAccountIds: activeLoginIds });
6506
6708
  const accounts = [...live, ...reconciled];
6507
6709
  const summary = accounts.map((a) => `${a.accountId}:${a.connected ? "up" : a.linkedUnconfigured ? "linked-unconfigured" : "down"}`).join(", ");
6508
6710
  console.error(`${TAG20} status accounts=${accounts.length} [${summary}]`);
@@ -6922,11 +7124,11 @@ app2.get("/group-info", async (c) => {
6922
7124
  var whatsapp_default = app2;
6923
7125
 
6924
7126
  // server/routes/whatsapp-reader.ts
6925
- import { readFileSync as readFileSync15, watch, statSync as statSync4, openSync, readSync, closeSync, existsSync as existsSync8, readdirSync as readdirSync8, realpathSync as realpathSync4 } from "fs";
7127
+ import { readFileSync as readFileSync15, watch, statSync as statSync5, openSync, readSync, closeSync, existsSync as existsSync8, readdirSync as readdirSync8, realpathSync as realpathSync4 } from "fs";
6926
7128
  import { basename as basename4, dirname as dirname3, isAbsolute, join as join14, relative as relative2, resolve as resolve12, sep as sep3 } from "path";
6927
7129
 
6928
7130
  // server/routes/admin/sidebar-sessions.ts
6929
- import { readdirSync as readdirSync5, readFileSync as readFileSync12, statSync as statSync2 } from "fs";
7131
+ import { readdirSync as readdirSync5, readFileSync as readFileSync12, statSync as statSync3 } from "fs";
6930
7132
  import { basename as basename3, dirname as dirname2, join as join11, resolve as resolve11 } from "path";
6931
7133
 
6932
7134
  // app/lib/whatsapp-reader/select-sessions.ts
@@ -6947,9 +7149,36 @@ function selectReaderChannelSessions(rows) {
6947
7149
  lastMessageAt: r.lastMessageAt,
6948
7150
  modelGated: r.modelGated,
6949
7151
  model: r.model,
6950
- rowType: "session"
7152
+ source: "session"
6951
7153
  }));
6952
7154
  }
7155
+ function buildStoreConversationRows(accountId, summaries) {
7156
+ const rows = [];
7157
+ for (const [remoteJid, { first, last, firstNamedSender }] of summaries) {
7158
+ const scope = last.scope;
7159
+ const isGroup = remoteJid.endsWith("@g.us");
7160
+ const senderTelephone = isGroup ? null : first.senderTelephone;
7161
+ rows.push({
7162
+ sessionId: "",
7163
+ projectDir: "",
7164
+ title: remoteJid,
7165
+ senderId: senderTelephone,
7166
+ startedAt: first.dateSent,
7167
+ channel: "whatsapp",
7168
+ role: scope === "admin" ? "admin" : "public",
7169
+ operatorName: null,
7170
+ whatsappName: firstNamedSender,
7171
+ lastMessageAt: last.dateSent,
7172
+ modelGated: false,
7173
+ model: null,
7174
+ source: "store",
7175
+ accountId,
7176
+ remoteJid,
7177
+ scope
7178
+ });
7179
+ }
7180
+ return rows.sort((a, b) => (b.lastMessageAt ?? "").localeCompare(a.lastMessageAt ?? ""));
7181
+ }
6953
7182
 
6954
7183
  // server/routes/admin/sidebar-sessions.ts
6955
7184
  var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
@@ -7189,26 +7418,10 @@ app3.get("/", requireAdminSession, async (c) => {
7189
7418
  const scopeAccountId = getAccountIdForSession(cacheKey) ?? null;
7190
7419
  const validAccounts = listValidAccounts();
7191
7420
  const multiAccount = validAccounts.length > 1;
7192
- const accounts = [];
7193
- for (const a of validAccounts) {
7194
- let businessName = null;
7195
- try {
7196
- const branding = await fetchBranding(a.accountId);
7197
- businessName = branding?.name || null;
7198
- } catch {
7199
- }
7200
- accounts.push({
7201
- accountId: a.accountId,
7202
- role: a.config.role ?? "",
7203
- businessName,
7204
- isHouse: a.config.role === "house"
7205
- });
7206
- }
7207
- console.log(`[admin-sessions-list] accounts=${accounts.length}`);
7208
7421
  const configDir2 = claudeConfigDir();
7209
7422
  if (!configDir2) {
7210
7423
  console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
7211
- return c.json({ sessions: [], accountId: scopeAccountId, accounts });
7424
+ return c.json({ sessions: [], accountId: scopeAccountId });
7212
7425
  }
7213
7426
  const projectsRoot = join11(configDir2, "projects");
7214
7427
  const jsonls = enumerateJsonls(projectsRoot);
@@ -7239,7 +7452,7 @@ app3.get("/", requireAdminSession, async (c) => {
7239
7452
  let mtimeMs;
7240
7453
  try {
7241
7454
  body = readFileSync12(path2, "utf8");
7242
- mtimeMs = statSync2(path2).mtimeMs;
7455
+ mtimeMs = statSync3(path2).mtimeMs;
7243
7456
  } catch {
7244
7457
  continue;
7245
7458
  }
@@ -7317,13 +7530,13 @@ app3.get("/", requireAdminSession, async (c) => {
7317
7530
  if (multiAccount) {
7318
7531
  console.log(`[admin-sessions-list] untagged-accountId-rows=${untaggedCount}`);
7319
7532
  }
7320
- return c.json({ sessions: rows, accountId: scopeAccountId, accounts });
7533
+ return c.json({ sessions: rows, accountId: scopeAccountId });
7321
7534
  });
7322
7535
  var sidebar_sessions_default = app3;
7323
7536
 
7324
7537
  // app/lib/admin-identity/pin-validator.ts
7325
7538
  import { createHash } from "crypto";
7326
- import { existsSync as existsSync7, readFileSync as readFileSync13, readdirSync as readdirSync6, statSync as statSync3 } from "fs";
7539
+ import { existsSync as existsSync7, readFileSync as readFileSync13, readdirSync as readdirSync6, statSync as statSync4 } from "fs";
7327
7540
  import { join as join12 } from "path";
7328
7541
  function hashPin(pin) {
7329
7542
  return createHash("sha256").update(pin).digest("hex");
@@ -7744,7 +7957,7 @@ app4.get("/conversations", requireAdminSession, async (c) => {
7744
7957
  model: lastAssistantModel(body)
7745
7958
  });
7746
7959
  }
7747
- const selected = selectReaderChannelSessions(rows);
7960
+ const sessionRows = selectReaderChannelSessions(rows).filter((r) => r.channel !== "whatsapp");
7748
7961
  const account = resolveAccount();
7749
7962
  let users = [];
7750
7963
  if (account) {
@@ -7757,13 +7970,11 @@ app4.get("/conversations", requireAdminSession, async (c) => {
7757
7970
  }
7758
7971
  const admins = account?.config.admins ?? [];
7759
7972
  const nameBySender = /* @__PURE__ */ new Map();
7760
- const whatsappNameBySender = /* @__PURE__ */ new Map();
7761
- const distinct = [...new Set(selected.map((r) => r.senderId).filter((s) => !!s))];
7973
+ const distinct = [...new Set(sessionRows.map((r) => r.senderId).filter((s) => !!s))];
7762
7974
  await Promise.all(
7763
7975
  distinct.map(async (senderId) => {
7764
7976
  if (!account) {
7765
7977
  nameBySender.set(senderId, null);
7766
- whatsappNameBySender.set(senderId, null);
7767
7978
  return;
7768
7979
  }
7769
7980
  const idRes = classifyAdminUserId(users, admins, senderId);
@@ -7771,60 +7982,22 @@ app4.get("/conversations", requireAdminSession, async (c) => {
7771
7982
  const { name, reason } = resolveOperatorDisplay(idRes, nameRes);
7772
7983
  if (reason) console.error(`[wa-reader] op=operator-unresolved senderId=${senderId} reason=${reason}`);
7773
7984
  nameBySender.set(senderId, name);
7774
- if (!name) {
7775
- const waName = await loadWhatsappSenderName(account.accountId, senderId);
7776
- if (waName) console.error(`[wa-reader] op=operator-name-fallback senderId=${senderId} source=whatsapp-pushname`);
7777
- whatsappNameBySender.set(senderId, waName);
7778
- } else {
7779
- whatsappNameBySender.set(senderId, null);
7780
- }
7781
7985
  })
7782
7986
  );
7783
- const conversations = selected.map((r) => ({
7987
+ const sessionConversations = sessionRows.map((r) => ({
7784
7988
  ...r,
7785
- operatorName: r.senderId ? nameBySender.get(r.senderId) ?? null : null,
7786
- whatsappName: r.senderId ? whatsappNameBySender.get(r.senderId) ?? null : null,
7787
- rowType: "session"
7989
+ operatorName: r.senderId ? nameBySender.get(r.senderId) ?? null : null
7788
7990
  }));
7789
- const includePersistedOnly = c.req.query("includePersistedOnly") === "1";
7790
- let persistedOnlyRows = [];
7791
- if (includePersistedOnly && account) {
7792
- const allConvos = readAllConversations(account.accountId);
7793
- const coveredSenderIds = new Set(
7794
- conversations.filter((cv) => cv.role === "public" && cv.channel === "whatsapp" && cv.senderId).map((cv) => cv.senderId)
7795
- );
7796
- for (const [remoteJid, messages] of allConvos) {
7797
- if (messages.length === 0) continue;
7798
- const isGroup = remoteJid.endsWith("@g.us");
7799
- const senderTelephone = isGroup ? null : messages[0].senderTelephone;
7800
- if (!isGroup && senderTelephone && coveredSenderIds.has(senderTelephone)) continue;
7801
- const last = messages[messages.length - 1];
7802
- const resolvedName = isGroup ? null : messages.find((m) => m.senderName)?.senderName ?? null;
7803
- persistedOnlyRows.push({
7804
- sessionId: `persisted:${account.accountId}:${remoteJid}`,
7805
- projectDir: "",
7806
- title: remoteJid,
7807
- senderId: senderTelephone,
7808
- startedAt: messages[0].dateSent,
7809
- channel: "whatsapp",
7810
- role: "public",
7811
- operatorName: null,
7812
- whatsappName: resolvedName,
7813
- lastMessageAt: last.dateSent,
7814
- modelGated: false,
7815
- model: null,
7816
- rowType: "persisted-only",
7817
- accountId: account.accountId,
7818
- remoteJid
7819
- });
7820
- }
7821
- }
7822
- const allRows = [...conversations, ...persistedOnlyRows];
7823
- console.log(`[wa-reader] op=full-list accountId=${account?.accountId ?? "null"} sessionRows=${conversations.length} persistedOnlyRows=${persistedOnlyRows.length}`);
7824
- return c.json({ conversations: allRows });
7991
+ const storeRows = account ? buildStoreConversationRows(account.accountId, readConversationSummaries(account.accountId)) : [];
7992
+ const adminScope = storeRows.filter((r) => r.scope === "admin").length;
7993
+ const publicScope = storeRows.length - adminScope;
7994
+ console.log(
7995
+ `[wa-reader] op=list accountId=${account?.accountId ?? "null"} conversations=${storeRows.length} adminScope=${adminScope} publicScope=${publicScope}`
7996
+ );
7997
+ return c.json({ conversations: [...sessionConversations, ...storeRows] });
7825
7998
  });
7826
7999
  function readFrom(path2, from) {
7827
- const end = statSync4(path2).size;
8000
+ const end = statSync5(path2).size;
7828
8001
  if (end <= from) return { buf: Buffer.alloc(0), end: from };
7829
8002
  const fd = openSync(path2, "r");
7830
8003
  try {
@@ -7941,7 +8114,7 @@ function runActivityTick(c) {
7941
8114
  let size = 0;
7942
8115
  let mtimeMs = 0;
7943
8116
  try {
7944
- const st = statSync4(join14(c.subagentsDir, name));
8117
+ const st = statSync5(join14(c.subagentsDir, name));
7945
8118
  size = st.size;
7946
8119
  mtimeMs = st.mtimeMs;
7947
8120
  } catch {
@@ -8007,7 +8180,7 @@ data: ${JSON.stringify(turn)}
8007
8180
  start(controller) {
8008
8181
  const fileEnd0 = (() => {
8009
8182
  try {
8010
- return statSync4(jsonlPath).size;
8183
+ return statSync5(jsonlPath).size;
8011
8184
  } catch {
8012
8185
  return 0;
8013
8186
  }
@@ -8136,7 +8309,7 @@ app4.get("/directives", requireAdminSession, (c) => {
8136
8309
  const pid = Number(pidPart);
8137
8310
  let len = 0;
8138
8311
  try {
8139
- len = statSync4(join14(dir, name)).size;
8312
+ len = statSync5(join14(dir, name)).size;
8140
8313
  } catch {
8141
8314
  }
8142
8315
  return { name, secs, pid, ts: Number.isFinite(secs) ? new Date(secs * 1e3).toISOString() : null, len };
@@ -8161,7 +8334,7 @@ app4.get("/directive", requireAdminSession, (c) => {
8161
8334
  }
8162
8335
  return c.text(body);
8163
8336
  });
8164
- app4.get("/persisted-messages", requireAdminSession, async (c) => {
8337
+ app4.get("/store-stream", requireAdminSession, (c) => {
8165
8338
  const accountIdRaw = c.req.query("accountId");
8166
8339
  const remoteJid = c.req.query("remoteJid");
8167
8340
  if (!accountIdRaw || !remoteJid) {
@@ -8176,21 +8349,113 @@ app4.get("/persisted-messages", requireAdminSession, async (c) => {
8176
8349
  if (!isUserJid(remoteJid) && !isGroupJid(remoteJid)) {
8177
8350
  return c.json({ error: "invalid remoteJid" }, 400);
8178
8351
  }
8179
- const messages = readConversation(accountId, remoteJid);
8180
- const turns = messages.map((m) => ({
8352
+ const file = conversationFilePath(accountId, remoteJid);
8353
+ const encoder = new TextEncoder();
8354
+ const connId = `${remoteJid.slice(0, 12)}-${process.hrtime.bigint().toString(36).slice(-6)}`;
8355
+ const startedAt = Date.now();
8356
+ const lastEventId = c.req.header("Last-Event-ID");
8357
+ const toTurn = (r) => ({
8181
8358
  kind: "whatsapp-persisted",
8182
- text: m.body,
8183
- ts: m.dateSent,
8184
- fromMe: m.fromMe,
8185
- senderName: m.senderName
8186
- }));
8187
- console.log(`[wa-reader] op=persisted-messages accountId=${accountId} remoteJid=${remoteJid} count=${turns.length}`);
8188
- return c.json({ turns });
8359
+ text: r.body,
8360
+ ts: r.dateSent,
8361
+ fromMe: r.fromMe,
8362
+ senderName: r.senderName
8363
+ });
8364
+ const readable = new ReadableStream({
8365
+ start(controller) {
8366
+ const send = (turn, id) => {
8367
+ try {
8368
+ controller.enqueue(encoder.encode(`id: ${id}
8369
+ data: ${JSON.stringify(turn)}
8370
+
8371
+ `));
8372
+ } catch {
8373
+ }
8374
+ };
8375
+ const fileEnd0 = (() => {
8376
+ try {
8377
+ return statSync5(file).size;
8378
+ } catch {
8379
+ return 0;
8380
+ }
8381
+ })();
8382
+ let offset = resumeOffset(lastEventId, fileEnd0);
8383
+ if (offset === 0) {
8384
+ const records = [];
8385
+ try {
8386
+ const { buf, end } = readFrom(file, 0);
8387
+ offset = end;
8388
+ for (const line of buf.toString("utf8").split("\n")) {
8389
+ if (!line.trim()) continue;
8390
+ try {
8391
+ records.push(JSON.parse(line));
8392
+ } catch {
8393
+ }
8394
+ }
8395
+ } catch {
8396
+ offset = fileEnd0;
8397
+ }
8398
+ records.sort((a, b) => a.dateSent.localeCompare(b.dateSent));
8399
+ const scope = records.length ? records[records.length - 1].scope : "none";
8400
+ for (const m of records) send(toTurn(m), offset);
8401
+ console.log(
8402
+ `[wa-reader] op=open remoteJid=${remoteJid} scope=${scope} messages=${records.length} source=store`
8403
+ );
8404
+ }
8405
+ const drain = () => {
8406
+ try {
8407
+ const { buf, end } = readFrom(file, offset);
8408
+ if (end <= offset) return;
8409
+ const { lines, nextOffset } = splitNewLines(buf, offset);
8410
+ offset = nextOffset;
8411
+ let n = 0;
8412
+ for (const line of lines) {
8413
+ if (!line.trim()) continue;
8414
+ let rec;
8415
+ try {
8416
+ rec = JSON.parse(line);
8417
+ } catch {
8418
+ continue;
8419
+ }
8420
+ send(toTurn(rec), offset);
8421
+ n++;
8422
+ }
8423
+ if (n > 0) console.log(`[wa-reader] op=store-drain conn=${connId} turns=${n}`);
8424
+ } catch {
8425
+ }
8426
+ };
8427
+ let watcher = null;
8428
+ try {
8429
+ watcher = watch(file, drain);
8430
+ } catch {
8431
+ }
8432
+ const poll = setInterval(drain, 1e3);
8433
+ const heartbeat = setInterval(() => {
8434
+ try {
8435
+ controller.enqueue(encoder.encode(": ping\n\n"));
8436
+ } catch {
8437
+ }
8438
+ }, 2e4);
8439
+ c.req.raw.signal.addEventListener("abort", () => {
8440
+ watcher?.close();
8441
+ clearInterval(poll);
8442
+ clearInterval(heartbeat);
8443
+ console.log(`[wa-reader] op=store-close conn=${connId} ranMs=${Date.now() - startedAt}`);
8444
+ try {
8445
+ controller.close();
8446
+ } catch {
8447
+ }
8448
+ });
8449
+ }
8450
+ });
8451
+ return new Response(readable, {
8452
+ headers: { "Content-Type": "text/event-stream", "Cache-Control": "no-cache", Connection: "keep-alive" }
8453
+ });
8189
8454
  });
8190
8455
  var whatsapp_reader_default = app4;
8191
8456
 
8192
8457
  // server/routes/public-reader.ts
8193
- import { statSync as statSync5, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2, readFileSync as readFileSync16, readdirSync as readdirSync9 } from "fs";
8458
+ import { statSync as statSync6, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch2, readFileSync as readFileSync16, readdirSync as readdirSync9 } from "fs";
8194
8459
  import { basename as basename5, dirname as dirname4, join as join15, resolve as resolve13, sep as sep4 } from "path";
8195
8460
 
8196
8461
  // app/lib/whatsapp-reader/delivered-kinds.ts
@@ -8324,7 +8589,7 @@ function enrichPublicAttachments(turns, sessionAttachments, cursor) {
8324
8589
  }
8325
8590
  }
8326
8591
  function readFrom2(path2, from) {
8327
- const end = statSync5(path2).size;
8592
+ const end = statSync6(path2).size;
8328
8593
  if (end <= from) return { buf: Buffer.alloc(0), end: from };
8329
8594
  const fd = openSync2(path2, "r");
8330
8595
  try {
@@ -8487,7 +8752,7 @@ var public_reader_default = app5;
8487
8752
  // server/routes/webchat.ts
8488
8753
  import { basename as basename6, dirname as dirname5 } from "path";
8489
8754
  import { join as join18 } from "path";
8490
- import { existsSync as existsSync10, readdirSync as readdirSync11, readFileSync as readFileSync19, renameSync as renameSync3, statSync as statSync6, writeFileSync as writeFileSync7 } from "fs";
8755
+ import { existsSync as existsSync10, readdirSync as readdirSync11, readFileSync as readFileSync19, renameSync as renameSync3, statSync as statSync7, writeFileSync as writeFileSync7 } from "fs";
8491
8756
 
8492
8757
  // server/canonical-webchat-override.ts
8493
8758
  import { readFileSync as readFileSync17, writeFileSync as writeFileSync5, renameSync } from "fs";
@@ -8757,7 +9022,7 @@ function sessionSidecarExists(sessionId) {
8757
9022
  function jsonlSizeBytes(projectDir, sessionId) {
8758
9023
  if (projectDir === null) return null;
8759
9024
  try {
8760
- return statSync6(join18(projectDir, `${sessionId}.jsonl`)).size;
9025
+ return statSync7(join18(projectDir, `${sessionId}.jsonl`)).size;
8761
9026
  } catch {
8762
9027
  return null;
8763
9028
  }
@@ -8901,7 +9166,7 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId, scopeAccoun
8901
9166
  if (multiAccount && meta.accountId !== scopeAccountId) continue;
8902
9167
  let mtimeMs;
8903
9168
  try {
8904
- mtimeMs = statSync6(path2).mtimeMs;
9169
+ mtimeMs = statSync7(path2).mtimeMs;
8905
9170
  } catch {
8906
9171
  continue;
8907
9172
  }
@@ -9733,7 +9998,7 @@ import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeF
9733
9998
  import { createHash as createHash3, randomUUID as randomUUID7 } from "crypto";
9734
9999
 
9735
10000
  // ../lib/admins-write/src/index.ts
9736
- import { existsSync as existsSync14, readFileSync as readFileSync23, writeFileSync as writeFileSync9, renameSync as renameSync5, mkdirSync as mkdirSync5, readdirSync as readdirSync13, statSync as statSync7, appendFileSync as appendFileSync2 } from "fs";
10001
+ import { existsSync as existsSync14, readFileSync as readFileSync23, writeFileSync as writeFileSync9, renameSync as renameSync5, mkdirSync as mkdirSync5, readdirSync as readdirSync13, statSync as statSync8, appendFileSync as appendFileSync2 } from "fs";
9737
10002
  import { dirname as dirname6, join as join22 } from "path";
9738
10003
  function id8(value) {
9739
10004
  return value.slice(0, 8);
@@ -9856,7 +10121,7 @@ function computeAdminStoreDivergence(input) {
9856
10121
  if (entry.startsWith(".")) continue;
9857
10122
  const accountDir = join22(input.accountsDir, entry);
9858
10123
  try {
9859
- if (!statSync7(accountDir).isDirectory()) continue;
10124
+ if (!statSync8(accountDir).isDirectory()) continue;
9860
10125
  } catch {
9861
10126
  continue;
9862
10127
  }
@@ -10256,7 +10521,7 @@ ${body.newPin}
10256
10521
  var onboarding_default = app9;
10257
10522
 
10258
10523
  // server/routes/client-error.ts
10259
- import { appendFileSync as appendFileSync3, existsSync as existsSync16, renameSync as renameSync6, statSync as statSync8 } from "fs";
10524
+ import { appendFileSync as appendFileSync3, existsSync as existsSync16, renameSync as renameSync6, statSync as statSync9 } from "fs";
10260
10525
  import { join as join23 } from "path";
10261
10526
  var CLIENT_ERRORS_LOG = join23(LOG_DIR, "client-errors.log");
10262
10527
  var MAX_LOG_SIZE = 10 * 1024 * 1024;
@@ -10307,7 +10572,7 @@ function stackHead(stack) {
10307
10572
  function rotateIfNeeded() {
10308
10573
  try {
10309
10574
  if (!existsSync16(CLIENT_ERRORS_LOG)) return;
10310
- const stats = statSync8(CLIENT_ERRORS_LOG);
10575
+ const stats = statSync9(CLIENT_ERRORS_LOG);
10311
10576
  if (stats.size < MAX_LOG_SIZE) return;
10312
10577
  renameSync6(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
10313
10578
  } catch (err) {
@@ -10613,7 +10878,7 @@ app12.get("/", requireAdminSession, async (c) => {
10613
10878
  var accounts_default = app12;
10614
10879
 
10615
10880
  // server/routes/admin/logs.ts
10616
- import { existsSync as existsSync18, readdirSync as readdirSync14, readFileSync as readFileSync25, statSync as statSync9 } from "fs";
10881
+ import { existsSync as existsSync18, readdirSync as readdirSync14, readFileSync as readFileSync25, statSync as statSync10 } from "fs";
10617
10882
  import { resolve as resolve16, basename as basename7 } from "path";
10618
10883
 
10619
10884
  // app/lib/logs-read-resolve.ts
@@ -10653,7 +10918,7 @@ app13.get("/", async (c) => {
10653
10918
  searched.push(filePath);
10654
10919
  try {
10655
10920
  const buffer = readFileSync25(filePath);
10656
- const onDiskBytes = statSync9(filePath).size;
10921
+ const onDiskBytes = statSync10(filePath).size;
10657
10922
  const headers = {
10658
10923
  "Content-Type": "text/plain; charset=utf-8",
10659
10924
  "Content-Length": String(buffer.byteLength)
@@ -10718,7 +10983,7 @@ app13.get("/", async (c) => {
10718
10983
  try {
10719
10984
  const filename = basename7(hit.path);
10720
10985
  const buffer = readFileSync25(hit.path);
10721
- const onDiskBytes = statSync9(hit.path).size;
10986
+ const onDiskBytes = statSync10(hit.path).size;
10722
10987
  const headers = {
10723
10988
  "Content-Type": "text/plain; charset=utf-8",
10724
10989
  "Content-Length": String(buffer.byteLength)
@@ -10761,7 +11026,7 @@ app13.get("/", async (c) => {
10761
11026
  console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
10762
11027
  continue;
10763
11028
  }
10764
- files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync9(resolve16(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
11029
+ files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync10(resolve16(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
10765
11030
  seen.add(name);
10766
11031
  try {
10767
11032
  const content = readFileSync25(resolve16(dir, name));
@@ -11646,7 +11911,7 @@ app17.put("/:id/label", requireAdminSession, async (c) => {
11646
11911
  var sessions_default = app17;
11647
11912
 
11648
11913
  // app/lib/claude-agent/spawn-context.ts
11649
- import { existsSync as existsSync22, readFileSync as readFileSync27, readdirSync as readdirSync16, statSync as statSync10 } from "fs";
11914
+ import { existsSync as existsSync22, readFileSync as readFileSync27, readdirSync as readdirSync16, statSync as statSync11 } from "fs";
11650
11915
  import { dirname as dirname7, resolve as resolve19, join as join25 } from "path";
11651
11916
  async function resolveOwnerProfileBlock(accountId, userId) {
11652
11917
  if (!userId) return { ok: false, reason: "missing-user-id" };
@@ -11749,7 +12014,7 @@ function listPluginDirs() {
11749
12014
  for (const name of readdirSync16(platformPlugins)) {
11750
12015
  const dir = join25(platformPlugins, name);
11751
12016
  try {
11752
- if (statSync10(dir).isDirectory()) out.set(name, dir);
12017
+ if (statSync11(dir).isDirectory()) out.set(name, dir);
11753
12018
  } catch {
11754
12019
  }
11755
12020
  }
@@ -11763,7 +12028,7 @@ function listPluginDirs() {
11763
12028
  for (const name of readdirSync16(bundlePlugins)) {
11764
12029
  const dir = join25(bundlePlugins, name);
11765
12030
  try {
11766
- if (statSync10(dir).isDirectory()) out.set(name, dir);
12031
+ if (statSync11(dir).isDirectory()) out.set(name, dir);
11767
12032
  } catch {
11768
12033
  }
11769
12034
  }
@@ -18350,7 +18615,7 @@ app48.route("/request-magic-link", request_magic_link_default);
18350
18615
  var access_default = app48;
18351
18616
 
18352
18617
  // server/routes/sites.ts
18353
- import { existsSync as existsSync28, readFileSync as readFileSync31, realpathSync as realpathSync6, statSync as statSync11 } from "fs";
18618
+ import { existsSync as existsSync28, readFileSync as readFileSync31, realpathSync as realpathSync6, statSync as statSync12 } from "fs";
18354
18619
  import { resolve as resolve26 } from "path";
18355
18620
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
18356
18621
  var MIME = {
@@ -18416,7 +18681,7 @@ app49.get("/:rel{.*}", (c) => {
18416
18681
  }
18417
18682
  let stat8;
18418
18683
  try {
18419
- stat8 = existsSync28(filePath) ? statSync11(filePath) : null;
18684
+ stat8 = existsSync28(filePath) ? statSync12(filePath) : null;
18420
18685
  } catch {
18421
18686
  stat8 = null;
18422
18687
  }
@@ -22112,7 +22377,7 @@ function broadcastAdminShutdown(reason) {
22112
22377
 
22113
22378
  // ../lib/entitlement/src/index.ts
22114
22379
  import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
22115
- import { existsSync as existsSync32, readFileSync as readFileSync34, statSync as statSync12 } from "fs";
22380
+ import { existsSync as existsSync32, readFileSync as readFileSync34, statSync as statSync13 } from "fs";
22116
22381
  import { resolve as resolve32 } from "path";
22117
22382
 
22118
22383
  // ../lib/entitlement/src/canonicalize.ts
@@ -22164,7 +22429,7 @@ function resolveEntitlement(brand, account) {
22164
22429
  if (!existsSync32(entitlementPath)) {
22165
22430
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
22166
22431
  }
22167
- const stat8 = statSync12(entitlementPath);
22432
+ const stat8 = statSync13(entitlementPath);
22168
22433
  const key = memoKey(stat8.mtimeMs, account);
22169
22434
  if (memo && memo.key === key) {
22170
22435
  return memo.result;