@rubytech/create-sitedesk-code 0.1.511 → 0.1.513

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 (48) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/docs/superpowers/plans/2026-07-27-task-2028-declared-file-write-deny.md +303 -0
  3. package/payload/platform/docs/superpowers/specs/2026-07-27-task-2028-declared-file-write-deny-design.md +126 -0
  4. package/payload/platform/lib/account-schema-regions/dist/index.d.ts +5 -0
  5. package/payload/platform/lib/account-schema-regions/dist/index.d.ts.map +1 -1
  6. package/payload/platform/lib/account-schema-regions/dist/index.js +5 -0
  7. package/payload/platform/lib/account-schema-regions/dist/index.js.map +1 -1
  8. package/payload/platform/lib/account-schema-regions/src/index.ts +5 -0
  9. package/payload/platform/package.json +3 -0
  10. package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard-bash.test.sh +14 -0
  11. package/payload/platform/plugins/admin/hooks/__tests__/fs-schema-guard.test.sh +38 -0
  12. package/payload/platform/plugins/admin/hooks/fs-schema-guard-bash-post.sh +11 -0
  13. package/payload/platform/plugins/admin/hooks/fs-schema-guard.sh +25 -1
  14. package/payload/platform/plugins/admin/skills/deck-pages/SKILL.md +2 -2
  15. package/payload/platform/plugins/admin/skills/skill-builder/SKILL.md +1 -1
  16. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +12 -0
  17. package/payload/platform/plugins/business-assistant/skills/e-sign/SKILL.md +15 -34
  18. package/payload/platform/plugins/business-assistant/skills/e-sign/stamp.mjs +269 -0
  19. package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -1
  20. package/payload/platform/plugins/cloudflare/bin/schema-exposed-dirs.mjs +1 -1
  21. package/payload/platform/plugins/linkedin-import/skills/linkedin-import/references/profile.md +5 -5
  22. package/payload/platform/plugins/memory/skills/conversation-archive-enrich/SKILL.md +2 -2
  23. package/payload/platform/plugins/memory/skills/document-ingest/SKILL.md +1 -1
  24. package/payload/platform/plugins/scheduling/PLUGIN.md +1 -1
  25. package/payload/platform/plugins/x-import/skills/x-import/SKILL.md +1 -1
  26. package/payload/platform/scripts/__tests__/account-schema-owned-dirs.test.sh +26 -0
  27. package/payload/platform/scripts/check-no-esm-require.mjs +6 -0
  28. package/payload/platform/scripts/lib/account-schema-owned-dirs.py +40 -4
  29. package/payload/platform/scripts/logs-read.sh +154 -50
  30. package/payload/platform/scripts/logs-read.test.sh +276 -0
  31. package/payload/platform/scripts/provision-worktree.sh +80 -0
  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 +13 -0
  34. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  35. package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts +7 -3
  36. package/payload/platform/services/claude-session-manager/dist/session-sidecar.d.ts.map +1 -1
  37. package/payload/platform/services/claude-session-manager/dist/session-sidecar.js +17 -11
  38. package/payload/platform/services/claude-session-manager/dist/session-sidecar.js.map +1 -1
  39. package/payload/server/{chunk-2WAXM5N2.js → chunk-S6HYTIU3.js} +2 -3
  40. package/payload/server/maxy-edge.js +7 -3
  41. package/payload/server/public/assets/admin-6QN-k3zQ.js +1 -0
  42. package/payload/server/public/assets/admin-6QN-k3zQ.js.br +0 -0
  43. package/payload/server/public/assets/admin-6QN-k3zQ.js.gz +0 -0
  44. package/payload/server/public/index.html +1 -1
  45. package/payload/server/server.js +860 -384
  46. package/payload/server/public/assets/admin-Do53K90C.js +0 -1
  47. package/payload/server/public/assets/admin-Do53K90C.js.br +0 -0
  48. package/payload/server/public/assets/admin-Do53K90C.js.gz +0 -0
@@ -118,7 +118,7 @@ import {
118
118
  vncLog,
119
119
  walkPremiumBundles,
120
120
  writeAdminUserAndPerson
121
- } from "./chunk-2WAXM5N2.js";
121
+ } from "./chunk-S6HYTIU3.js";
122
122
  import {
123
123
  D1_MAX_SQL_STATEMENT_BYTES,
124
124
  D1_QUERY_MAX_BODY_BYTES,
@@ -1602,10 +1602,10 @@ var require_dist5 = __commonJS({
1602
1602
  });
1603
1603
 
1604
1604
  // server/index.ts
1605
- import { readFileSync as readFileSync48, existsSync as existsSync47, watchFile, readdirSync as readdirSync29, statSync as statSync21 } from "fs";
1605
+ import { readFileSync as readFileSync48, existsSync as existsSync48, watchFile, readdirSync as readdirSync29, statSync as statSync21 } from "fs";
1606
1606
  import { spawn as spawn3 } from "child_process";
1607
1607
  import { createHash as createHash8 } from "crypto";
1608
- import { resolve as resolve45, join as join49, basename as basename14 } from "path";
1608
+ import { resolve as resolve45, join as join51, basename as basename14 } from "path";
1609
1609
  import { homedir as homedir4 } from "os";
1610
1610
 
1611
1611
  // server/lib/route-cache-watchers.ts
@@ -2471,6 +2471,44 @@ var assetsVary = async (c, next) => {
2471
2471
  if (!c.res.headers.has("Vary")) c.res.headers.set("Vary", "Accept-Encoding");
2472
2472
  };
2473
2473
 
2474
+ // server/lib/client-error-reporter.ts
2475
+ var CLIENT_ERROR_SINK_PATH = "/api/_client-error";
2476
+ var clientErrorReporterBody = `(function(){
2477
+ var SINK=${JSON.stringify(CLIENT_ERROR_SINK_PATH)};
2478
+ var send=function(b){
2479
+ try{
2480
+ fetch(SINK,{
2481
+ method:'POST',
2482
+ headers:{'content-type':'application/json'},
2483
+ body:JSON.stringify(Object.assign({url:location.href,ua:navigator.userAgent,version:(window.__MAXY_VERSION__||'unknown')},b)),
2484
+ keepalive:true
2485
+ }).catch(function(){});
2486
+ }catch(e){}
2487
+ };
2488
+ window.addEventListener('error',function(e){
2489
+ var t=e.target;
2490
+ if(t&&t!==window&&t.tagName)send({kind:'subresource',tag:t.tagName,url:t.src||t.href||''});
2491
+ else send({kind:'uncaught',msg:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno,stack:(e.error&&e.error.stack)||''});
2492
+ },true);
2493
+ window.addEventListener('unhandledrejection',function(e){
2494
+ var r=e.reason;
2495
+ send({kind:'unhandled-rejection',msg:String((r&&r.message)||r),stack:(r&&r.stack)||''});
2496
+ });
2497
+ try{
2498
+ new PerformanceObserver(function(list){
2499
+ list.getEntries().forEach(function(entry){
2500
+ var p;
2501
+ try{p=new URL(entry.name,location.href).pathname}catch(_){p=''}
2502
+ if(p===SINK)return;
2503
+ if(entry.responseStatus>=400)send({kind:'subresource',url:entry.name,status:entry.responseStatus});
2504
+ });
2505
+ }).observe({type:'resource',buffered:true});
2506
+ }catch(e){}
2507
+ })();`;
2508
+ var clientErrorReporterScript = `<script>
2509
+ ${clientErrorReporterBody}
2510
+ </script>`;
2511
+
2474
2512
  // app/lib/whatsapp/inbound/media-download-guard.ts
2475
2513
  var TAG2 = "[media-guard]";
2476
2514
  var inFlight2 = 0;
@@ -5067,6 +5105,18 @@ function resolvePlatformAccountId(accountsDir = ACCOUNTS_DIR) {
5067
5105
  return routed ?? houseId;
5068
5106
  }
5069
5107
 
5108
+ // app/lib/whatsapp/account-id-shape.ts
5109
+ var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
5110
+ function isUuidAccountId(id) {
5111
+ return UUID_RE2.test(id);
5112
+ }
5113
+ function warnNonUuidAccount(caller2, accountId) {
5114
+ if (isUuidAccountId(accountId)) return;
5115
+ console.error(
5116
+ `[whatsapp-account-scope] op=non-uuid-account caller=${caller2} accountId=${accountId}`
5117
+ );
5118
+ }
5119
+
5070
5120
  // app/lib/managed-service.ts
5071
5121
  import { join as join7 } from "path";
5072
5122
  import { readFileSync as readFileSync9 } from "fs";
@@ -6183,8 +6233,9 @@ function buildSelfChatDispatch(input) {
6183
6233
  isGroup: false
6184
6234
  }),
6185
6235
  media: [],
6186
- // Self-chat is the owner: the session scopes to the house account (Task 1383).
6187
- effectiveAccountId: input.accountId,
6236
+ // Self-chat is the owner: the session scopes to the house account (Task 1383),
6237
+ // named by its platform UUID (Task 1850).
6238
+ effectiveAccountId: input.platformAccountId,
6188
6239
  // Task 1575 — self-chat is unambiguously the owner, so attribute the spawn
6189
6240
  // to the owner userId even when the owner phone is unbound in users.json.
6190
6241
  ownerSelfPhone: true
@@ -6315,20 +6366,26 @@ function resolveReadStoreKey(accountId) {
6315
6366
  }
6316
6367
  function resolveInboundPersistAccount(args) {
6317
6368
  const result = args.accessResult;
6318
- if (result?.allowed && result.reason === "account-manager" && result.effectiveAccountId) {
6319
- return result.effectiveAccountId;
6320
- }
6321
- return args.connPlatformAccountId;
6369
+ const account = result?.allowed && result.reason === "account-manager" && result.effectiveAccountId ? result.effectiveAccountId : args.connPlatformAccountId;
6370
+ warnNonUuidAccount("inbound-persist", account);
6371
+ return account;
6322
6372
  }
6323
6373
  function resolveConversationPersistAccount(sendAccountId, counterpartyPhone) {
6324
6374
  const conn = findConnectionByKey(Array.from(connections2.values()), sendAccountId);
6325
- if (!conn) return sendAccountId;
6375
+ if (!conn) {
6376
+ warnNonUuidAccount("reply-append-no-connection", sendAccountId);
6377
+ return sendAccountId;
6378
+ }
6326
6379
  const access = checkDmAccess({
6327
6380
  senderPhone: counterpartyPhone,
6328
6381
  selfPhone: conn.selfPhone ?? "",
6329
6382
  config: whatsAppConfig,
6383
+ // The per-number sub-config is keyed by the credential DIRNAME.
6330
6384
  accountConfig: whatsAppConfig.accounts?.[conn.accountId],
6331
- accountId: conn.accountId,
6385
+ // Task 1850 — the account SCOPE is the platform UUID. The gate assigns this
6386
+ // to `effectiveAccountId` for every non-manager admit, and that value reaches
6387
+ // the graph and the spawn; the dirname is a credential path, not an account.
6388
+ accountId: conn.platformAccountId,
6332
6389
  isValidAccount: (id) => isValidAccountId(id)
6333
6390
  });
6334
6391
  return resolveInboundPersistAccount({
@@ -6662,8 +6719,11 @@ function monitorInbound(conn) {
6662
6719
  senderPhone,
6663
6720
  selfPhone: conn.selfPhone ?? "",
6664
6721
  config: whatsAppConfig,
6722
+ // Keyed by the credential DIRNAME — a per-number sub-config.
6665
6723
  accountConfig: whatsAppConfig.accounts?.[conn.accountId],
6666
- accountId: conn.accountId,
6724
+ // Task 1850 — the account SCOPE is the platform UUID, never the
6725
+ // dirname. See resolveConversationPersistAccount.
6726
+ accountId: conn.platformAccountId,
6667
6727
  isValidAccount: (id) => isValidAccountId(id)
6668
6728
  });
6669
6729
  const persistAccountId = resolveInboundPersistAccount({
@@ -6856,6 +6916,7 @@ function monitorInbound(conn) {
6856
6916
  };
6857
6917
  dispatchInboundPayload(conn, buildSelfChatDispatch({
6858
6918
  accountId: conn.accountId,
6919
+ platformAccountId: conn.platformAccountId,
6859
6920
  selfPhone: conn.selfPhone,
6860
6921
  remoteJid,
6861
6922
  text: decision.text,
@@ -7005,7 +7066,7 @@ async function handleInboundMessage(conn, msg) {
7005
7066
  selfPhone,
7006
7067
  config: whatsAppConfig,
7007
7068
  accountConfig: whatsAppConfig.accounts?.[conn.accountId],
7008
- accountId: conn.accountId,
7069
+ accountId: conn.platformAccountId,
7009
7070
  isValidAccount: (id) => isValidAccountId(id),
7010
7071
  resolvePersonByPhone
7011
7072
  });
@@ -8114,6 +8175,11 @@ function createScheduleInjectRoutes(deps) {
8114
8175
  // server/index.ts
8115
8176
  var import_dist9 = __toESM(require_dist(), 1);
8116
8177
 
8178
+ // app/lib/whatsapp/gateway/manages-account.ts
8179
+ function managesAccountFor(effectiveAccountId, connPlatformAccountId) {
8180
+ return effectiveAccountId === connPlatformAccountId ? "none" : effectiveAccountId;
8181
+ }
8182
+
8117
8183
  // app/lib/whatsapp/socket-resolution-error.ts
8118
8184
  function formatPresentKeys(presentKeys) {
8119
8185
  return presentKeys.join(",") || "none";
@@ -11531,13 +11597,13 @@ async function runPortalIndexPush(root) {
11531
11597
  import { existsSync as existsSync12, readdirSync as readdirSync9, statSync as statSync5 } from "fs";
11532
11598
  import { join as join17 } from "path";
11533
11599
  var GOOGLE_PENDING_LIFETIME_SEC = 600;
11534
- var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
11600
+ var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
11535
11601
  function runGooglePendingAudit(accountsDir, nowMs, emit, readMtimeMs = (path3) => statSync5(path3).mtimeMs) {
11536
11602
  let scanned = 0;
11537
11603
  let stranded = 0;
11538
11604
  if (existsSync12(accountsDir)) {
11539
11605
  for (const accountId of readdirSync9(accountsDir)) {
11540
- if (!UUID_RE2.test(accountId)) continue;
11606
+ if (!UUID_RE3.test(accountId)) continue;
11541
11607
  const pendingPath2 = join17(accountsDir, accountId, "secrets", "google", "pending-oauth.enc");
11542
11608
  try {
11543
11609
  if (!existsSync12(pendingPath2)) continue;
@@ -11596,19 +11662,202 @@ function runReconcileLivenessAudit(statePath, nowMs, intervalMs, emit) {
11596
11662
 
11597
11663
  // server/routes/whatsapp-reader.ts
11598
11664
  import { readFileSync as readFileSync21, watch as watch2, statSync as statSync8, openSync, readSync, closeSync, existsSync as existsSync17, readdirSync as readdirSync14, realpathSync as realpathSync6 } from "fs";
11599
- import { basename as basename6, dirname as dirname7, isAbsolute, join as join22, relative as relative3, resolve as resolve17, sep as sep5 } from "path";
11665
+ import { basename as basename6, dirname as dirname7, isAbsolute, join as join23, relative as relative3, resolve as resolve17, sep as sep5 } from "path";
11600
11666
 
11601
11667
  // server/routes/admin/sidebar-sessions.ts
11602
11668
  import { readdirSync as readdirSync12, readFileSync as readFileSync19 } from "fs";
11603
- import { readFile as readFile4, stat as stat5 } from "fs/promises";
11604
- import { dirname as dirname5, join as join20, resolve as resolve15 } from "path";
11669
+ import { open as open2, readFile as readFile5, stat as stat5 } from "fs/promises";
11670
+ import { dirname as dirname5, join as join21, resolve as resolve15 } from "path";
11671
+
11672
+ // server/lib/session-title-cache.ts
11673
+ import { open, readFile as readFile4, rename as rename2, unlink as unlink3, writeFile as writeFile5 } from "fs/promises";
11674
+ import { join as join18 } from "path";
11675
+ var CACHE_FILENAME = "ai-title-cache.json";
11676
+ var tmpSeq = 0;
11677
+ function nextTmpSeq() {
11678
+ tmpSeq = (tmpSeq + 1) % Number.MAX_SAFE_INTEGER;
11679
+ return tmpSeq;
11680
+ }
11681
+ function errCode(err) {
11682
+ const code = err?.code;
11683
+ if (code) return code;
11684
+ return err instanceof Error && err.message ? err.message : String(err);
11685
+ }
11686
+ function titleCachePath(accountDir) {
11687
+ return join18(accountDir, CACHE_FILENAME);
11688
+ }
11689
+ function parseTitleCacheWithDropped(raw) {
11690
+ const out = /* @__PURE__ */ new Map();
11691
+ let dropped = 0;
11692
+ let parsed;
11693
+ try {
11694
+ parsed = JSON.parse(raw);
11695
+ } catch {
11696
+ return { cache: out, dropped, wellFormed: false };
11697
+ }
11698
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
11699
+ return { cache: out, dropped, wellFormed: false };
11700
+ }
11701
+ for (const [sessionId, value] of Object.entries(parsed)) {
11702
+ if (!sessionId) {
11703
+ dropped += 1;
11704
+ continue;
11705
+ }
11706
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
11707
+ dropped += 1;
11708
+ continue;
11709
+ }
11710
+ const v = value;
11711
+ const aiTitle = v.aiTitle === null ? null : typeof v.aiTitle === "string" ? v.aiTitle : void 0;
11712
+ if (aiTitle === void 0) {
11713
+ dropped += 1;
11714
+ continue;
11715
+ }
11716
+ if (typeof v.scannedBytes !== "number" || !Number.isFinite(v.scannedBytes) || v.scannedBytes < 0) {
11717
+ dropped += 1;
11718
+ continue;
11719
+ }
11720
+ out.set(sessionId, { aiTitle, scannedBytes: v.scannedBytes });
11721
+ }
11722
+ return { cache: out, dropped, wellFormed: true };
11723
+ }
11724
+ function parseTitleCache(raw) {
11725
+ return parseTitleCacheWithDropped(raw).cache;
11726
+ }
11727
+ function serializeTitleCache(cache3) {
11728
+ const obj = {};
11729
+ for (const [sessionId, entry] of cache3) obj[sessionId] = entry;
11730
+ return JSON.stringify(obj);
11731
+ }
11732
+ async function loadTitleCacheOutcome(accountDir) {
11733
+ if (!accountDir) return { cache: /* @__PURE__ */ new Map(), state: "no-dir", dropped: 0 };
11734
+ let raw;
11735
+ try {
11736
+ raw = await readFile4(titleCachePath(accountDir), "utf8");
11737
+ } catch (err) {
11738
+ const code = err.code;
11739
+ if (code === "ENOENT") return { cache: /* @__PURE__ */ new Map(), state: "absent", dropped: 0 };
11740
+ console.error(
11741
+ `[session-title-cache] op=load-failed dir=${accountDir} code=${code ?? "unknown"} reason=${err instanceof Error ? err.message : String(err)}`
11742
+ );
11743
+ return { cache: /* @__PURE__ */ new Map(), state: "unreadable", dropped: 0 };
11744
+ }
11745
+ const { cache: cache3, dropped, wellFormed } = parseTitleCacheWithDropped(raw);
11746
+ const corrupt = !wellFormed || cache3.size === 0 && dropped > 0;
11747
+ return { cache: cache3, state: corrupt ? "corrupt" : "loaded", dropped };
11748
+ }
11749
+ async function loadTitleCache(accountDir) {
11750
+ return (await loadTitleCacheOutcome(accountDir)).cache;
11751
+ }
11752
+ async function saveTitleCacheMerged(accountDir, updates, evict) {
11753
+ if (updates.size === 0 && (evict === void 0 || evict.size === 0)) return 0;
11754
+ const path3 = titleCachePath(accountDir);
11755
+ let merged;
11756
+ try {
11757
+ merged = parseTitleCache(await readFile4(path3, "utf8"));
11758
+ } catch (err) {
11759
+ if (err.code !== "ENOENT") throw err;
11760
+ merged = /* @__PURE__ */ new Map();
11761
+ }
11762
+ for (const [sessionId, entry] of updates) merged.set(sessionId, entry);
11763
+ let evicted = 0;
11764
+ if (evict !== void 0) {
11765
+ for (const sessionId of evict) {
11766
+ if (merged.delete(sessionId)) evicted += 1;
11767
+ }
11768
+ }
11769
+ const tmp = `${path3}.tmp.${process.pid}.${Date.now()}.${nextTmpSeq()}`;
11770
+ try {
11771
+ await writeFile5(tmp, serializeTitleCache(merged), "utf8");
11772
+ await rename2(tmp, path3);
11773
+ } catch (err) {
11774
+ try {
11775
+ await unlink3(tmp);
11776
+ } catch (cleanupErr) {
11777
+ const code = cleanupErr.code;
11778
+ if (code !== "ENOENT") {
11779
+ console.error(`[session-title-cache] op=tmp-cleanup-failed path=${tmp} code=${code ?? "unknown"}`);
11780
+ }
11781
+ }
11782
+ throw err;
11783
+ }
11784
+ return evicted;
11785
+ }
11786
+ function lastAiTitleIn(text, initial) {
11787
+ let aiTitle = initial;
11788
+ for (const line of text.split("\n")) {
11789
+ if (!line || line[0] !== "{") continue;
11790
+ let parsed;
11791
+ try {
11792
+ parsed = JSON.parse(line);
11793
+ } catch {
11794
+ continue;
11795
+ }
11796
+ if (!parsed || typeof parsed !== "object") continue;
11797
+ const row = parsed;
11798
+ if (row.type !== "ai-title" || typeof row.aiTitle !== "string") continue;
11799
+ const t = row.aiTitle.trim();
11800
+ if (t) aiTitle = t;
11801
+ }
11802
+ return aiTitle;
11803
+ }
11804
+ function scanAiTitleFromBody(body) {
11805
+ const lastNl = body.lastIndexOf("\n");
11806
+ const complete = lastNl === -1 ? "" : body.slice(0, lastNl + 1);
11807
+ return {
11808
+ aiTitle: lastAiTitleIn(body, null),
11809
+ scannedBytes: Buffer.byteLength(complete, "utf8")
11810
+ };
11811
+ }
11812
+ async function scanAiTitleIncremental(path3, size, prior) {
11813
+ const usable = prior !== void 0 && prior.scannedBytes <= size;
11814
+ const start = usable ? prior.scannedBytes : 0;
11815
+ const carried = usable ? prior.aiTitle : null;
11816
+ if (start >= size) return { entry: { aiTitle: carried, scannedBytes: start }, bytesRead: 0 };
11817
+ const length = size - start;
11818
+ let chunk;
11819
+ let handle2;
11820
+ try {
11821
+ handle2 = await open(path3, "r");
11822
+ } catch (err) {
11823
+ return {
11824
+ entry: { aiTitle: carried, scannedBytes: start },
11825
+ bytesRead: 0,
11826
+ failure: `open ${errCode(err)}`
11827
+ };
11828
+ }
11829
+ try {
11830
+ const buf = Buffer.alloc(length);
11831
+ const { bytesRead } = await handle2.read(buf, 0, length, start);
11832
+ chunk = bytesRead < length ? buf.subarray(0, bytesRead) : buf;
11833
+ } catch (err) {
11834
+ return {
11835
+ entry: { aiTitle: carried, scannedBytes: start },
11836
+ bytesRead: 0,
11837
+ failure: `read ${errCode(err)}`
11838
+ };
11839
+ } finally {
11840
+ await handle2.close().catch(() => {
11841
+ });
11842
+ }
11843
+ const text = chunk.toString("utf8");
11844
+ const lastNl = text.lastIndexOf("\n");
11845
+ const complete = lastNl === -1 ? "" : text.slice(0, lastNl + 1);
11846
+ return {
11847
+ entry: {
11848
+ aiTitle: lastAiTitleIn(text, carried),
11849
+ scannedBytes: start + Buffer.byteLength(complete, "utf8")
11850
+ },
11851
+ bytesRead: chunk.length
11852
+ };
11853
+ }
11605
11854
 
11606
11855
  // ../services/claude-session-manager/src/jsonl-path.ts
11607
11856
  import { existsSync as existsSync14, readdirSync as readdirSync10 } from "fs";
11608
11857
  import { homedir } from "os";
11609
- import { join as join18 } from "path";
11858
+ import { join as join19 } from "path";
11610
11859
  function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
11611
- const projectsRoot = join18(claudeConfigDir2, "projects");
11860
+ const projectsRoot = join19(claudeConfigDir2, "projects");
11612
11861
  if (!existsSync14(projectsRoot)) return null;
11613
11862
  let slugs;
11614
11863
  try {
@@ -11618,9 +11867,9 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
11618
11867
  }
11619
11868
  const basename15 = `${sessionId}.jsonl`;
11620
11869
  for (const slug of slugs) {
11621
- const live = join18(projectsRoot, slug, basename15);
11870
+ const live = join19(projectsRoot, slug, basename15);
11622
11871
  if (existsSync14(live)) return live;
11623
- const archived = join18(projectsRoot, slug, "archive", basename15);
11872
+ const archived = join19(projectsRoot, slug, "archive", basename15);
11624
11873
  if (existsSync14(archived)) return archived;
11625
11874
  }
11626
11875
  return null;
@@ -11629,7 +11878,7 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
11629
11878
  // app/lib/admin-identity/pin-validator.ts
11630
11879
  import { createHash as createHash3 } from "crypto";
11631
11880
  import { existsSync as existsSync15, readFileSync as readFileSync18, readdirSync as readdirSync11, statSync as statSync6 } from "fs";
11632
- import { join as join19 } from "path";
11881
+ import { join as join20 } from "path";
11633
11882
  function hashPin(pin) {
11634
11883
  return createHash3("sha256").update(pin).digest("hex");
11635
11884
  }
@@ -11737,7 +11986,29 @@ function lastAssistantModel(body) {
11737
11986
  }
11738
11987
  return null;
11739
11988
  }
11740
- var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
11989
+ async function lastAssistantModelFromTail(path3, size, maxBytes = 256 * 1024) {
11990
+ if (size <= 0) return { model: null, bytesRead: 0 };
11991
+ const start = Math.max(0, size - maxBytes);
11992
+ const length = size - start;
11993
+ let handle2;
11994
+ try {
11995
+ handle2 = await open2(path3, "r");
11996
+ } catch (err) {
11997
+ return { model: null, bytesRead: 0, failure: `open ${errCode(err)}` };
11998
+ }
11999
+ let chunk;
12000
+ try {
12001
+ const buf = Buffer.alloc(length);
12002
+ const { bytesRead } = await handle2.read(buf, 0, length, start);
12003
+ chunk = bytesRead < length ? buf.subarray(0, bytesRead) : buf;
12004
+ } catch (err) {
12005
+ return { model: null, bytesRead: 0, failure: `read ${errCode(err)}` };
12006
+ } finally {
12007
+ await handle2.close().catch(() => {
12008
+ });
12009
+ }
12010
+ return { model: lastAssistantModel(chunk.toString("utf8")), bytesRead: chunk.length };
12011
+ }
11741
12012
  var ADMIN_ROLE = "admin";
11742
12013
  var WEBCHAT_CHANNEL = "webchat";
11743
12014
  var app4 = new Hono();
@@ -11750,62 +12021,69 @@ function findSessionProjectDir(sessionId) {
11750
12021
  const jsonlPath = findExistingJsonlForSessionId(cfg, sessionId);
11751
12022
  return jsonlPath ? dirname5(jsonlPath) : null;
11752
12023
  }
11753
- function enumerateJsonls(projectsRoot) {
12024
+ function enumerateJsonlsWithSkips(projectsRoot) {
11754
12025
  const out = [];
12026
+ let skipped = 0;
11755
12027
  let slugs;
11756
12028
  try {
11757
12029
  slugs = readdirSync12(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
11758
12030
  } catch (err) {
11759
- if (err.code === "ENOENT") return out;
12031
+ if (err.code === "ENOENT") return { files: out, skipped };
11760
12032
  throw err;
11761
12033
  }
11762
12034
  for (const slug of slugs) {
11763
- const slugDir = join20(projectsRoot, slug);
12035
+ const slugDir = join21(projectsRoot, slug);
11764
12036
  let entries2;
11765
12037
  try {
11766
12038
  entries2 = readdirSync12(slugDir, { withFileTypes: true });
11767
12039
  } catch (err) {
11768
12040
  const code = err.code ?? "unknown";
11769
12041
  console.error(`[admin-sessions-list] slug-skipped slug=${slug} code=${code}`);
12042
+ skipped += 1;
11770
12043
  continue;
11771
12044
  }
11772
12045
  for (const entry of entries2) {
11773
12046
  if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
11774
- out.push({ path: join20(slugDir, entry.name), isSubagent: false, archived: false });
12047
+ out.push({ path: join21(slugDir, entry.name), isSubagent: false, archived: false });
11775
12048
  } else if (entry.isDirectory() && entry.name === "subagents") {
11776
- const subDir = join20(slugDir, entry.name);
12049
+ const subDir = join21(slugDir, entry.name);
11777
12050
  let subEntries;
11778
12051
  try {
11779
12052
  subEntries = readdirSync12(subDir, { withFileTypes: true });
11780
12053
  } catch (err) {
11781
12054
  const code = err.code ?? "unknown";
11782
12055
  console.error(`[admin-sessions-list] subagents-skipped slug=${slug} code=${code}`);
12056
+ skipped += 1;
11783
12057
  continue;
11784
12058
  }
11785
12059
  for (const sub of subEntries) {
11786
12060
  if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
11787
- out.push({ path: join20(subDir, sub.name), isSubagent: true, archived: false });
12061
+ out.push({ path: join21(subDir, sub.name), isSubagent: true, archived: false });
11788
12062
  }
11789
12063
  }
11790
12064
  } else if (entry.isDirectory() && entry.name === "archive") {
11791
- const archiveDir = join20(slugDir, entry.name);
12065
+ const archiveDir = join21(slugDir, entry.name);
11792
12066
  let archiveEntries;
11793
12067
  try {
11794
12068
  archiveEntries = readdirSync12(archiveDir, { withFileTypes: true });
11795
12069
  } catch (err) {
11796
12070
  const code = err.code ?? "unknown";
11797
12071
  console.error(`[admin-sessions-list] archive-skipped slug=${slug} code=${code}`);
12072
+ skipped += 1;
11798
12073
  continue;
11799
12074
  }
11800
12075
  for (const arc of archiveEntries) {
11801
12076
  if (arc.isFile() && SESSION_ID_RE.test(arc.name)) {
11802
- out.push({ path: join20(archiveDir, arc.name), isSubagent: false, archived: true });
12077
+ out.push({ path: join21(archiveDir, arc.name), isSubagent: false, archived: true });
11803
12078
  }
11804
12079
  }
11805
12080
  }
11806
12081
  }
11807
12082
  }
11808
- return out;
12083
+ return { files: out, skipped };
12084
+ }
12085
+ function enumerateJsonls(projectsRoot) {
12086
+ return enumerateJsonlsWithSkips(projectsRoot).files;
11809
12087
  }
11810
12088
  async function fetchLiveSessions() {
11811
12089
  const out = /* @__PURE__ */ new Map();
@@ -11833,7 +12111,7 @@ function loadUserTitles(accountDir) {
11833
12111
  if (!accountDir) return /* @__PURE__ */ new Map();
11834
12112
  let raw;
11835
12113
  try {
11836
- raw = readFileSync19(join20(accountDir, "session-titles.json"), "utf8");
12114
+ raw = readFileSync19(join21(accountDir, "session-titles.json"), "utf8");
11837
12115
  } catch {
11838
12116
  return /* @__PURE__ */ new Map();
11839
12117
  }
@@ -11843,7 +12121,7 @@ async function loadUserTitlesAsync(accountDir) {
11843
12121
  if (!accountDir) return /* @__PURE__ */ new Map();
11844
12122
  let raw;
11845
12123
  try {
11846
- raw = await readFile4(join20(accountDir, "session-titles.json"), "utf8");
12124
+ raw = await readFile5(join21(accountDir, "session-titles.json"), "utf8");
11847
12125
  } catch {
11848
12126
  return /* @__PURE__ */ new Map();
11849
12127
  }
@@ -11884,7 +12162,7 @@ function emptySidecarMeta() {
11884
12162
  async function readSidecarMetaAsync(metaPath) {
11885
12163
  let raw;
11886
12164
  try {
11887
- raw = await readFile4(metaPath, "utf8");
12165
+ raw = await readFile5(metaPath, "utf8");
11888
12166
  } catch {
11889
12167
  return emptySidecarMeta();
11890
12168
  }
@@ -11913,67 +12191,14 @@ function parseSidecarMeta(raw) {
11913
12191
  accountId: typeof r.accountId === "string" ? r.accountId : null
11914
12192
  };
11915
12193
  }
11916
- function startsWithCliMarker(s) {
11917
- for (const p of CLI_MARKER_PREFIXES) if (s.startsWith(p)) return true;
11918
- return false;
11919
- }
11920
12194
  function trimToTitle(raw) {
11921
12195
  return raw.trim().replace(/\s+/g, " ");
11922
12196
  }
11923
- var CHANNEL_WRAPPER = /^<channel\b([^>]*)>\n?([\s\S]*?)\n?<\/channel>$/;
11924
- var SOURCE_ATTR = /\bsource="([^"]+)"/;
11925
- var CHANNEL_SOURCE_MAP = {
11926
- whatsapp: "whatsapp",
11927
- "whatsapp-channel": "whatsapp",
11928
- webchat: "webchat",
11929
- "webchat-channel": "webchat"
11930
- };
11931
- function stripChannelEnvelope(text) {
11932
- const m = text.match(CHANNEL_WRAPPER);
11933
- if (!m) return { inner: text, channel: null };
11934
- let raw = m[1].match(SOURCE_ATTR)?.[1] ?? "";
11935
- let inner = m[2];
11936
- const im = inner.match(CHANNEL_WRAPPER);
11937
- const innerRaw = im?.[1].match(SOURCE_ATTR)?.[1];
11938
- if (im && innerRaw) {
11939
- raw = innerRaw;
11940
- inner = im[2];
11941
- }
11942
- return { inner, channel: CHANNEL_SOURCE_MAP[raw] ?? (raw || null) };
11943
- }
11944
- function resolveTitle(body, sessionId, userTitles) {
12197
+ function resolveTitleFromParts(sessionId, userTitles, aiTitle) {
11945
12198
  const userTitle = userTitles.get(sessionId);
11946
- let aiTitle = null;
11947
- let firstUserMessage = null;
11948
- for (const line of body.split("\n")) {
11949
- if (!line || line[0] !== "{") continue;
11950
- let parsed;
11951
- try {
11952
- parsed = JSON.parse(line);
11953
- } catch {
11954
- continue;
11955
- }
11956
- if (!parsed || typeof parsed !== "object") continue;
11957
- const row = parsed;
11958
- if (row.type === "ai-title" && typeof row.aiTitle === "string") {
11959
- const t = row.aiTitle.trim();
11960
- if (t) aiTitle = t;
11961
- continue;
11962
- }
11963
- if (firstUserMessage === null && row.type === "user" && row.message && row.message.role === "user") {
11964
- const content = row.message.content;
11965
- if (typeof content !== "string") continue;
11966
- const trimmed = content.trim();
11967
- if (!trimmed) continue;
11968
- if (startsWithCliMarker(trimmed)) continue;
11969
- firstUserMessage = trimmed;
11970
- }
11971
- }
11972
- const stripped = firstUserMessage !== null ? stripChannelEnvelope(firstUserMessage) : { inner: null, channel: null };
11973
- const channel = stripped.channel;
11974
- if (userTitle) return { title: trimToTitle(userTitle), source: "user", channel };
11975
- if (aiTitle) return { title: trimToTitle(aiTitle), source: "ai", channel };
11976
- return { title: sessionId.slice(0, 8), source: "prefix", channel };
12199
+ if (userTitle) return { title: trimToTitle(userTitle), source: "user" };
12200
+ if (aiTitle) return { title: trimToTitle(aiTitle), source: "ai" };
12201
+ return { title: sessionId.slice(0, 8), source: "prefix" };
11977
12202
  }
11978
12203
  app4.get("/", requireAdminSession, async (c) => {
11979
12204
  const cacheKey = c.var.cacheKey;
@@ -11998,8 +12223,7 @@ async function computeSessionList(scopeAccountId) {
11998
12223
  console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
11999
12224
  return { sessions: [], accountId: scopeAccountId };
12000
12225
  }
12001
- const projectsRoot = join20(configDir2, "projects");
12002
- const jsonls = enumerateJsonls(projectsRoot);
12226
+ const projectsRoot = join21(configDir2, "projects");
12003
12227
  const liveSessions = await fetchLiveSessions();
12004
12228
  const accountDir = scopeAccountId ? resolve15(ACCOUNTS_DIR, scopeAccountId) : null;
12005
12229
  const userTitles = await loadUserTitlesAsync(accountDir);
@@ -12029,6 +12253,24 @@ async function computeSessionList(scopeAccountId) {
12029
12253
  const adminUserIdBySession = /* @__PURE__ */ new Map();
12030
12254
  const channelSenderBySession = /* @__PURE__ */ new Map();
12031
12255
  const channelMissNoSender = [];
12256
+ const titleCacheDir = account?.accountDir ?? accountDir;
12257
+ const cacheLoad = await loadTitleCacheOutcome(titleCacheDir);
12258
+ const titleCache = cacheLoad.cache;
12259
+ const cacheUpdates = /* @__PURE__ */ new Map();
12260
+ const { files: jsonls, skipped: enumSkipped } = enumerateJsonlsWithSkips(projectsRoot);
12261
+ let enumeratedCount = 0;
12262
+ let scopedCount = 0;
12263
+ let titleCacheHits = 0;
12264
+ let bodyScans = 0;
12265
+ let titleReadFails = 0;
12266
+ let titleBytes = 0;
12267
+ let tailReads = 0;
12268
+ let tailModelMiss = 0;
12269
+ let tailReadFails = 0;
12270
+ let tailBytes = 0;
12271
+ let cacheWriteFails = 0;
12272
+ let evicted = 0;
12273
+ const walkStartedAt = Date.now();
12032
12274
  for (const { path: path3, isSubagent, archived } of jsonls) {
12033
12275
  const lastSlash = path3.lastIndexOf("/");
12034
12276
  const base = path3.slice(lastSlash + 1);
@@ -12039,24 +12281,40 @@ async function computeSessionList(scopeAccountId) {
12039
12281
  continue;
12040
12282
  }
12041
12283
  seenIds.add(sessionId);
12042
- let body;
12284
+ enumeratedCount += 1;
12043
12285
  let mtimeMs;
12286
+ let size;
12044
12287
  try {
12045
- body = await readFile4(path3, "utf8");
12046
- mtimeMs = (await stat5(path3)).mtimeMs;
12288
+ const st = await stat5(path3);
12289
+ mtimeMs = st.mtimeMs;
12290
+ size = st.size;
12047
12291
  } catch {
12048
12292
  continue;
12049
12293
  }
12050
- const live = liveSessions.has(sessionId);
12051
- const pid = live ? liveSessions.get(sessionId) ?? null : null;
12052
- const resolved = resolveTitle(body, sessionId, userTitles);
12053
- titleSourceCounts[resolved.source] += 1;
12054
- const metaPath = join20(projectDir, `${sessionId}.meta.json`);
12294
+ const metaPath = join21(projectDir, `${sessionId}.meta.json`);
12055
12295
  const { bridgeIds, role, channel: sidecarChannel, senderId, personId, adminUserId, accountId: rowAccountId } = await readSidecarMetaAsync(metaPath);
12056
12296
  if (multiAccount) {
12057
12297
  if (rowAccountId === null) untaggedCount += 1;
12058
12298
  if (rowAccountId !== scopeAccountId) continue;
12059
12299
  }
12300
+ scopedCount += 1;
12301
+ const live = liveSessions.has(sessionId);
12302
+ const pid = live ? liveSessions.get(sessionId) ?? null : null;
12303
+ const prior = titleCache.get(sessionId);
12304
+ const scan = await scanAiTitleIncremental(path3, size, prior);
12305
+ if (scan.failure) {
12306
+ titleReadFails += 1;
12307
+ console.error(
12308
+ `[admin-sessions-list] op=title-scan-failed sessionId=${sessionId.slice(0, 8)} reason=${scan.failure}`
12309
+ );
12310
+ } else if (scan.bytesRead > 0) bodyScans += 1;
12311
+ else if (prior !== void 0) titleCacheHits += 1;
12312
+ titleBytes += scan.bytesRead;
12313
+ if (!prior || prior.aiTitle !== scan.entry.aiTitle || prior.scannedBytes !== scan.entry.scannedBytes) {
12314
+ cacheUpdates.set(sessionId, scan.entry);
12315
+ }
12316
+ const resolved = resolveTitleFromParts(sessionId, userTitles, scan.entry.aiTitle);
12317
+ titleSourceCounts[resolved.source] += 1;
12060
12318
  if (isSessionListExcluded(role, sidecarChannel)) {
12061
12319
  excludedPublicWebchatCount += 1;
12062
12320
  continue;
@@ -12065,6 +12323,17 @@ async function computeSessionList(scopeAccountId) {
12065
12323
  if (adminUserId && role === ADMIN_ROLE && sidecarChannel === WEBCHAT_CHANNEL) {
12066
12324
  adminUserIdBySession.set(sessionId, adminUserId);
12067
12325
  }
12326
+ const tail = await lastAssistantModelFromTail(path3, size);
12327
+ if (tail.failure) {
12328
+ tailReadFails += 1;
12329
+ console.error(
12330
+ `[admin-sessions-list] op=tail-read-failed sessionId=${sessionId.slice(0, 8)} reason=${tail.failure}`
12331
+ );
12332
+ } else {
12333
+ if (tail.bytesRead > 0) tailReads += 1;
12334
+ if (tail.model === null) tailModelMiss += 1;
12335
+ }
12336
+ tailBytes += tail.bytesRead;
12068
12337
  rows.push({
12069
12338
  sessionId,
12070
12339
  title: resolved.title,
@@ -12083,7 +12352,7 @@ async function computeSessionList(scopeAccountId) {
12083
12352
  // diverge from the sidecar (e.g. an ai-titled channel row).
12084
12353
  channel: sidecarChannel,
12085
12354
  personName: null,
12086
- model: lastAssistantModel(body),
12355
+ model: tail.model,
12087
12356
  accountId: rowAccountId,
12088
12357
  senderId,
12089
12358
  whatsappName: null
@@ -12163,6 +12432,24 @@ async function computeSessionList(scopeAccountId) {
12163
12432
  console.error(`[admin-sessions-list] op=channel-name-unresolved sessionId=${m.sessionId.slice(0, 8)} channel=${m.channel} senderId= reason=no-senderId`);
12164
12433
  }
12165
12434
  rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
12435
+ const evictIds = /* @__PURE__ */ new Set();
12436
+ if (enumSkipped === 0 && seenIds.size > 0) {
12437
+ for (const sessionId of titleCache.keys()) if (!seenIds.has(sessionId)) evictIds.add(sessionId);
12438
+ }
12439
+ if (titleCacheDir && (cacheUpdates.size > 0 || evictIds.size > 0)) {
12440
+ try {
12441
+ evicted = await saveTitleCacheMerged(titleCacheDir, cacheUpdates, evictIds);
12442
+ } catch (err) {
12443
+ cacheWriteFails += 1;
12444
+ console.error(
12445
+ `[admin-sessions-list] op=title-cache-write-failed dir=${titleCacheDir} code=${errCode(err)} reason=${err instanceof Error ? err.message : String(err)}`
12446
+ );
12447
+ }
12448
+ }
12449
+ const bytesMB = (titleBytes + tailBytes) / (1024 * 1024);
12450
+ console.log(
12451
+ `[admin-sessions-list] op=list-walk enumerated=${enumeratedCount} scoped=${scopedCount} cacheLoad=${cacheLoad.state} cacheEntries=${titleCache.size} cacheDropped=${cacheLoad.dropped} titleCacheHits=${titleCacheHits} bodyScans=${bodyScans} titleReadFails=${titleReadFails} tailReads=${tailReads} tailModelMiss=${tailModelMiss} tailReadFails=${tailReadFails} titleBytesMB=${(titleBytes / (1024 * 1024)).toFixed(3)} bytesMB=${bytesMB.toFixed(3)} cacheWriteFails=${cacheWriteFails} evicted=${evicted} enumSkipped=${enumSkipped} ms=${Date.now() - walkStartedAt}`
12452
+ );
12166
12453
  console.log(
12167
12454
  `[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} channelInList=whatsapp:${channelInList.whatsapp},telegram:${channelInList.telegram},webchat:${channelInList.webchat} channelNameCandidates=${channelNameCandidates} channelNamesResolved=${channelNamesResolved} (operator=${operatorResolvedCount} store=${storeResolvedCount}) unknownChannel=${unknownChannelCount} excludedPublicWebchat=${excludedPublicWebchatCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${scopeAccountId ? scopeAccountId.slice(0, 8) : "unset"}`
12168
12455
  );
@@ -12194,15 +12481,15 @@ var WEBCHAT_REPLY_TOOL = "mcp__webchat-channel__reply";
12194
12481
  var CHANNEL_REPLY_TOOL = "mcp__channel__reply";
12195
12482
  var CHANNEL_REPLY_DOCUMENT_TOOL = "mcp__channel__reply-document";
12196
12483
  var SEND_USER_FILE_TOOL = "SendUserFile";
12197
- var CLI_MARKER_PREFIXES2 = ["<local-command-", "<command-name>", "<command-message>"];
12484
+ var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
12198
12485
  var HARNESS_LIFECYCLE_PREFIXES = ["<task-notification>"];
12199
12486
  var CC_IMAGE_VISION_HINT = /^\[Image:[^\]]*Multiply coordinates by [\d.]+ to map to original image\.\]$/;
12200
12487
  var COMPACT_SUMMARY_PREFIX = "This session is being continued from a previous conversation that ran out of context.";
12201
12488
  function isCompactSummaryRow(row, content) {
12202
12489
  return row.isCompactSummary === true || content !== null && content.startsWith(COMPACT_SUMMARY_PREFIX);
12203
12490
  }
12204
- var CHANNEL_WRAPPER2 = /^<channel\b([^>]*)>\n?([\s\S]*?)\n?<\/channel>$/;
12205
- var SOURCE_ATTR2 = /\bsource="([^"]+)"/;
12491
+ var CHANNEL_WRAPPER = /^<channel\b([^>]*)>\n?([\s\S]*?)\n?<\/channel>$/;
12492
+ var SOURCE_ATTR = /\bsource="([^"]+)"/;
12206
12493
  var SOURCE_MAP = {
12207
12494
  whatsapp: "whatsapp",
12208
12495
  "whatsapp-channel": "whatsapp",
@@ -12212,18 +12499,18 @@ var SOURCE_MAP = {
12212
12499
  "webchat-channel": "webchat"
12213
12500
  };
12214
12501
  function isScheduleSource(text) {
12215
- const m = text.match(CHANNEL_WRAPPER2);
12502
+ const m = text.match(CHANNEL_WRAPPER);
12216
12503
  if (!m) return false;
12217
- return m[1].match(SOURCE_ATTR2)?.[1] === "schedule";
12504
+ return m[1].match(SOURCE_ATTR)?.[1] === "schedule";
12218
12505
  }
12219
12506
  function unwrapChannel(text) {
12220
- const m = text.match(CHANNEL_WRAPPER2);
12507
+ const m = text.match(CHANNEL_WRAPPER);
12221
12508
  if (!m) return { text };
12222
- let source = SOURCE_MAP[m[1].match(SOURCE_ATTR2)?.[1] ?? ""];
12509
+ let source = SOURCE_MAP[m[1].match(SOURCE_ATTR)?.[1] ?? ""];
12223
12510
  let inner = m[2];
12224
- const im = inner.match(CHANNEL_WRAPPER2);
12511
+ const im = inner.match(CHANNEL_WRAPPER);
12225
12512
  if (im) {
12226
- const innerSource = SOURCE_MAP[im[1].match(SOURCE_ATTR2)?.[1] ?? ""];
12513
+ const innerSource = SOURCE_MAP[im[1].match(SOURCE_ATTR)?.[1] ?? ""];
12227
12514
  if (innerSource) {
12228
12515
  source = innerSource;
12229
12516
  inner = im[2];
@@ -12395,7 +12682,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
12395
12682
  }
12396
12683
  if (row.type === "queue-operation" && row.operation === "enqueue") {
12397
12684
  const content = asString(row.content);
12398
- if (content !== null && CHANNEL_WRAPPER2.test(content)) {
12685
+ if (content !== null && CHANNEL_WRAPPER.test(content)) {
12399
12686
  const u = unwrapChannel(content);
12400
12687
  turnCtx.lastChannelSource = u.source;
12401
12688
  if (!isScheduleSource(content)) {
@@ -12428,7 +12715,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
12428
12715
  }
12429
12716
  const text = asString(msg.content);
12430
12717
  if (text === null) continue;
12431
- if (CLI_MARKER_PREFIXES2.some((p) => text.startsWith(p))) continue;
12718
+ if (CLI_MARKER_PREFIXES.some((p) => text.startsWith(p))) continue;
12432
12719
  if (HARNESS_LIFECYCLE_PREFIXES.some((p) => text.startsWith(p))) continue;
12433
12720
  if (CC_IMAGE_VISION_HINT.test(text)) continue;
12434
12721
  const isChannel = row.isMeta === true && typeof row.origin === "object" && row.origin !== null && row.origin.kind === "channel" || // Native Claude Code channels (maxy-lite) journal the delivery twin as a PLAIN
@@ -12436,7 +12723,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
12436
12723
  // `isMeta`/`origin` stamp. Detect it by the wrapper so it is treated as the
12437
12724
  // channel twin and consumes the enqueue row's suppression — otherwise the
12438
12725
  // enqueue row AND this row both render and every channel message doubles.
12439
- CHANNEL_WRAPPER2.test(text);
12726
+ CHANNEL_WRAPPER.test(text);
12440
12727
  if (isChannel) {
12441
12728
  const u = unwrapChannel(text);
12442
12729
  turnCtx.lastChannelSource = u.source;
@@ -12454,7 +12741,7 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
12454
12741
 
12455
12742
  // app/lib/whatsapp-reader/enrich-attachments.ts
12456
12743
  import { readFileSync as readFileSync20, readdirSync as readdirSync13, existsSync as existsSync16, statSync as statSync7, realpathSync as realpathSync5 } from "fs";
12457
- import { basename as basename5, dirname as dirname6, join as join21, resolve as resolve16, sep as sep4 } from "path";
12744
+ import { basename as basename5, dirname as dirname6, join as join22, resolve as resolve16, sep as sep4 } from "path";
12458
12745
  var ADMIN_UPLOAD_PATH = /\/uploads\/(?!public\/)([0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})\//gi;
12459
12746
  function adminAttachmentIds(text) {
12460
12747
  const ids = [];
@@ -12467,7 +12754,7 @@ function adminAttachmentIds(text) {
12467
12754
  function adminAttachmentsFromText(text, uploadsBase) {
12468
12755
  const out = [];
12469
12756
  for (const id of adminAttachmentIds(text)) {
12470
- const meta = readAttachmentMeta(join21(uploadsBase, id));
12757
+ const meta = readAttachmentMeta(join22(uploadsBase, id));
12471
12758
  if (meta) out.push(meta);
12472
12759
  }
12473
12760
  return out;
@@ -12517,7 +12804,7 @@ function claudeUploadAttachmentsFromText(text, sessionId) {
12517
12804
  function readSidecar(dir, attachmentId) {
12518
12805
  let parsed;
12519
12806
  try {
12520
- parsed = JSON.parse(readFileSync20(join21(dir, `${attachmentId}.meta.json`), "utf8"));
12807
+ parsed = JSON.parse(readFileSync20(join22(dir, `${attachmentId}.meta.json`), "utf8"));
12521
12808
  } catch {
12522
12809
  return null;
12523
12810
  }
@@ -12546,7 +12833,7 @@ function listSessionAttachmentsInDir(dir) {
12546
12833
  }
12547
12834
  const sidecars = [];
12548
12835
  for (const name of entries2) {
12549
- const sidecar = readSidecar(join21(dir, name), name);
12836
+ const sidecar = readSidecar(join22(dir, name), name);
12550
12837
  if (sidecar) sidecars.push(sidecar);
12551
12838
  }
12552
12839
  sidecars.sort((a, b) => a.storedAt.localeCompare(b.storedAt));
@@ -12706,25 +12993,59 @@ app5.get("/conversations", requireAdminSession, async (c) => {
12706
12993
  }
12707
12994
  const cfg = claudeConfigDir();
12708
12995
  if (!cfg) return c.json({ conversations: [] });
12709
- const projectsRoot = join22(cfg, "projects");
12996
+ const projectsRoot = join23(cfg, "projects");
12710
12997
  const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
12711
12998
  const rows = [];
12712
12999
  let sessionRowsExcludedUntagged = 0;
13000
+ const account = multiAccount ? validAccounts.find((a) => a.accountId === scopeAccountId) ?? null : resolveAccount();
13001
+ const titleCache = await loadTitleCache(account?.accountDir ?? null);
13002
+ const titleCacheUpdates = /* @__PURE__ */ new Map();
13003
+ let enumeratedCount = 0;
13004
+ let bodyReadCount = 0;
13005
+ let bodyReadFails = 0;
13006
+ let titleCacheHits = 0;
13007
+ let bodyScans = 0;
13008
+ const walkStartedAt = Date.now();
13009
+ const untaggedSenders = /* @__PURE__ */ new Set();
12713
13010
  for (const { path: path3 } of enumerateJsonls(projectsRoot)) {
13011
+ enumeratedCount += 1;
12714
13012
  const sessionId = basename6(path3).replace(/\.jsonl$/, "");
12715
13013
  const projectDir = dirname7(path3);
12716
- const meta = readSidecarMeta(join22(projectDir, `${sessionId}.meta.json`));
13014
+ const meta = readSidecarMeta(join23(projectDir, `${sessionId}.meta.json`));
12717
13015
  if (!isReaderChannelSession(meta.role, meta.channel)) continue;
12718
13016
  if (multiAccount) {
12719
- if (meta.accountId === null) sessionRowsExcludedUntagged += 1;
13017
+ if (meta.accountId === null) {
13018
+ sessionRowsExcludedUntagged += 1;
13019
+ if (meta.senderId) untaggedSenders.add(meta.senderId);
13020
+ }
12720
13021
  if (meta.accountId !== scopeAccountId) continue;
12721
13022
  }
12722
13023
  let body = "";
13024
+ let bodyRead = false;
12723
13025
  try {
12724
13026
  body = readFileSync21(path3, "utf8");
12725
- } catch {
13027
+ bodyRead = true;
13028
+ bodyReadCount += 1;
13029
+ } catch (err) {
13030
+ bodyReadFails += 1;
13031
+ console.error(
13032
+ `[wa-reader] op=body-read-failed sessionId=${sessionId.slice(0, 8)} code=${errCode(err)}`
13033
+ );
13034
+ }
13035
+ let aiTitle = null;
13036
+ if (bodyRead) {
13037
+ const cached3 = titleCache.get(sessionId);
13038
+ if (cached3 && cached3.scannedBytes === Buffer.byteLength(body, "utf8")) {
13039
+ aiTitle = cached3.aiTitle;
13040
+ titleCacheHits += 1;
13041
+ } else {
13042
+ const scanned = scanAiTitleFromBody(body);
13043
+ aiTitle = scanned.aiTitle;
13044
+ titleCacheUpdates.set(sessionId, scanned);
13045
+ bodyScans += 1;
13046
+ }
12726
13047
  }
12727
- const { title } = resolveTitle(body, sessionId, userTitles);
13048
+ const { title } = resolveTitleFromParts(sessionId, userTitles, aiTitle);
12728
13049
  const turns = parseTranscript(body.split("\n"));
12729
13050
  const lastMessageAt = lastTurnTs(turns);
12730
13051
  const modelGated = isModelGated(turns);
@@ -12742,8 +13063,24 @@ app5.get("/conversations", requireAdminSession, async (c) => {
12742
13063
  model: lastAssistantModel(body)
12743
13064
  });
12744
13065
  }
13066
+ if (sessionRowsExcludedUntagged > 0) {
13067
+ console.log(
13068
+ `[wa-reader] op=untagged-sidecars count=${sessionRowsExcludedUntagged} senders=${[...untaggedSenders].sort().join(",")} route=conversations`
13069
+ );
13070
+ }
12745
13071
  const sessionRows = selectReaderChannelSessions(rows).filter((r) => r.channel !== "whatsapp");
12746
- const account = multiAccount ? validAccounts.find((a) => a.accountId === scopeAccountId) ?? null : resolveAccount();
13072
+ if (account && titleCacheUpdates.size > 0) {
13073
+ try {
13074
+ await saveTitleCacheMerged(account.accountDir, titleCacheUpdates);
13075
+ } catch (err) {
13076
+ console.error(
13077
+ `[wa-reader] op=title-cache-write-failed dir=${account.accountDir} reason=${err instanceof Error ? err.message : String(err)}`
13078
+ );
13079
+ }
13080
+ }
13081
+ console.log(
13082
+ `[wa-reader] op=list-walk enumerated=${enumeratedCount} read=${bodyReadCount} readFails=${bodyReadFails} titleCacheHits=${titleCacheHits} bodyScans=${bodyScans} ms=${Date.now() - walkStartedAt}`
13083
+ );
12747
13084
  let users = [];
12748
13085
  if (account) {
12749
13086
  try {
@@ -12844,24 +13181,61 @@ app5.get("/conversations-all", requireAdminSession, async (c) => {
12844
13181
  const { value, state } = await getOrCompute("conversations-all", houseId, async () => {
12845
13182
  const cfg = claudeConfigDir();
12846
13183
  if (!cfg) return { conversations: [] };
12847
- const projectsRoot = join22(cfg, "projects");
13184
+ const projectsRoot = join23(cfg, "projects");
12848
13185
  const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
12849
13186
  const validAccounts = listValidAccounts();
12850
13187
  const validIds = new Set(validAccounts.map((a) => a.accountId));
12851
13188
  const houseIds = new Set(validAccounts.filter((a) => a.config.role === "house").map((a) => a.accountId));
12852
13189
  const rawByAccount = /* @__PURE__ */ new Map();
13190
+ const cachesByAccount = /* @__PURE__ */ new Map();
13191
+ const accountDirById = new Map(validAccounts.map((a) => [a.accountId, a.accountDir]));
13192
+ let enumeratedCount = 0;
13193
+ let bodyReadCount = 0;
13194
+ let bodyReadFails = 0;
13195
+ let titleCacheHits = 0;
13196
+ let bodyScans = 0;
13197
+ const walkStartedAt = Date.now();
13198
+ let untaggedCount = 0;
13199
+ const untaggedSenders = /* @__PURE__ */ new Set();
12853
13200
  for (const { path: path3 } of enumerateJsonls(projectsRoot)) {
13201
+ enumeratedCount += 1;
12854
13202
  const sessionId = basename6(path3).replace(/\.jsonl$/, "");
12855
13203
  const projectDir = dirname7(path3);
12856
- const meta = readSidecarMeta(join22(projectDir, `${sessionId}.meta.json`));
13204
+ const meta = readSidecarMeta(join23(projectDir, `${sessionId}.meta.json`));
12857
13205
  if (!isReaderChannelSession(meta.role, meta.channel)) continue;
12858
- if (meta.accountId === null || !validIds.has(meta.accountId)) continue;
13206
+ if (meta.accountId === null) {
13207
+ untaggedCount += 1;
13208
+ if (meta.senderId) untaggedSenders.add(meta.senderId);
13209
+ continue;
13210
+ }
13211
+ if (!validIds.has(meta.accountId)) continue;
12859
13212
  let body = "";
13213
+ let bodyRead = false;
12860
13214
  try {
12861
13215
  body = readFileSync21(path3, "utf8");
12862
- } catch {
13216
+ bodyRead = true;
13217
+ bodyReadCount += 1;
13218
+ } catch (err) {
13219
+ bodyReadFails += 1;
13220
+ console.error(`[wa-reader] op=body-read-failed sessionId=${sessionId.slice(0, 8)} code=${errCode(err)}`);
13221
+ }
13222
+ let aiTitle = null;
13223
+ if (bodyRead) {
13224
+ let cache3 = cachesByAccount.get(meta.accountId);
13225
+ if (cache3 === void 0) {
13226
+ cache3 = await loadTitleCache(accountDirById.get(meta.accountId) ?? null);
13227
+ cachesByAccount.set(meta.accountId, cache3);
13228
+ }
13229
+ const cached3 = cache3.get(sessionId);
13230
+ if (cached3 && cached3.scannedBytes === Buffer.byteLength(body, "utf8")) {
13231
+ aiTitle = cached3.aiTitle;
13232
+ titleCacheHits += 1;
13233
+ } else {
13234
+ aiTitle = scanAiTitleFromBody(body).aiTitle;
13235
+ bodyScans += 1;
13236
+ }
12863
13237
  }
12864
- const { title } = resolveTitle(body, sessionId, userTitles);
13238
+ const { title } = resolveTitleFromParts(sessionId, userTitles, aiTitle);
12865
13239
  const turns = parseTranscript(body.split("\n"));
12866
13240
  const row = {
12867
13241
  sessionId,
@@ -12879,6 +13253,14 @@ app5.get("/conversations-all", requireAdminSession, async (c) => {
12879
13253
  list.push(row);
12880
13254
  rawByAccount.set(meta.accountId, list);
12881
13255
  }
13256
+ console.log(
13257
+ `[wa-reader] op=list-walk enumerated=${enumeratedCount} read=${bodyReadCount} readFails=${bodyReadFails} titleCacheHits=${titleCacheHits} bodyScans=${bodyScans} ms=${Date.now() - walkStartedAt}`
13258
+ );
13259
+ if (untaggedCount > 0) {
13260
+ console.log(
13261
+ `[wa-reader] op=untagged-sidecars count=${untaggedCount} senders=${[...untaggedSenders].sort().join(",")} route=conversations-all`
13262
+ );
13263
+ }
12882
13264
  let users = [];
12883
13265
  try {
12884
13266
  users = readUsersFile(USERS_FILE) ?? [];
@@ -13018,7 +13400,7 @@ function openTaskKey(turns) {
13018
13400
  }
13019
13401
  function readSubagentMeta(dir, hex) {
13020
13402
  try {
13021
- const m = JSON.parse(readFileSync21(join22(dir, `agent-${hex}.meta.json`), "utf8"));
13403
+ const m = JSON.parse(readFileSync21(join23(dir, `agent-${hex}.meta.json`), "utf8"));
13022
13404
  if (typeof m.agentType === "string" && typeof m.description === "string" && typeof m.toolUseId === "string") {
13023
13405
  return { agentType: m.agentType, description: m.description, toolUseId: m.toolUseId };
13024
13406
  }
@@ -13050,7 +13432,7 @@ function runActivityTick(c) {
13050
13432
  let size = 0;
13051
13433
  let mtimeMs = 0;
13052
13434
  try {
13053
- const st = statSync8(join22(c.subagentsDir, name));
13435
+ const st = statSync8(join23(c.subagentsDir, name));
13054
13436
  size = st.size;
13055
13437
  mtimeMs = st.mtimeMs;
13056
13438
  } catch {
@@ -13095,11 +13477,11 @@ app5.get("/stream", requireAdminSession, (c) => {
13095
13477
  const sessionId = c.req.query("sessionId") ?? "";
13096
13478
  const projectDir = c.req.query("projectDir") ?? "";
13097
13479
  const cfg = claudeConfigDir();
13098
- const projectsRoot = cfg ? resolve17(join22(cfg, "projects")) : null;
13480
+ const projectsRoot = cfg ? resolve17(join23(cfg, "projects")) : null;
13099
13481
  if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
13100
13482
  return c.json({ error: "bad session reference" }, 400);
13101
13483
  }
13102
- const jsonlPath = resolve17(join22(projectDir, `${sessionId}.jsonl`));
13484
+ const jsonlPath = resolve17(join23(projectDir, `${sessionId}.jsonl`));
13103
13485
  if (!jsonlPath.startsWith(projectsRoot + sep5)) {
13104
13486
  return c.json({ error: "bad session reference" }, 400);
13105
13487
  }
@@ -13126,7 +13508,7 @@ data: ${JSON.stringify(turn)}
13126
13508
  let offset = resumeOffset(lastEventId, fileEnd0);
13127
13509
  console.log(`[wa-stream] op=open conn=${connId} sessionId=${sessionId} channel=reader resume=${offset}`);
13128
13510
  const sessionKey = c.req.query("session_key") ?? "";
13129
- const subagentsDir = resolve17(join22(projectDir, sessionId, "subagents"));
13511
+ const subagentsDir = resolve17(join23(projectDir, sessionId, "subagents"));
13130
13512
  console.log(
13131
13513
  `[webchat-activity] op=watch-subagents key=${sessionKey} dir=${subagentsDir} exists=${existsSync17(subagentsDir)}`
13132
13514
  );
@@ -13255,7 +13637,7 @@ app5.get("/directives", requireAdminSession, (c) => {
13255
13637
  const pid = Number(pidPart);
13256
13638
  let len = 0;
13257
13639
  try {
13258
- len = statSync8(join22(dir, name)).size;
13640
+ len = statSync8(join23(dir, name)).size;
13259
13641
  } catch {
13260
13642
  }
13261
13643
  return { name, secs, pid, ts: Number.isFinite(secs) ? new Date(secs * 1e3).toISOString() : null, len };
@@ -13270,7 +13652,7 @@ app5.get("/directive", requireAdminSession, (c) => {
13270
13652
  }
13271
13653
  const dir = directiveStoreDir(sessionId);
13272
13654
  if (!dir) return c.json({ error: "no account" }, 404);
13273
- const path3 = resolve17(join22(dir, name));
13655
+ const path3 = resolve17(join23(dir, name));
13274
13656
  if (!path3.startsWith(dir + sep5)) return c.json({ error: "bad reference" }, 400);
13275
13657
  let body;
13276
13658
  try {
@@ -13328,7 +13710,7 @@ app5.get("/store-stream", requireAdminSession, (c) => {
13328
13710
  console.log(`[wa-reader] op=store-quote msgId=${r.msgKeyId} quoted=${!!q2}`);
13329
13711
  }
13330
13712
  if (r.attachmentId) {
13331
- const meta = readAttachmentMeta(join22(uploadsBase, r.attachmentId));
13713
+ const meta = readAttachmentMeta(join23(uploadsBase, r.attachmentId));
13332
13714
  if (meta) return { ...turn, attachments: [meta] };
13333
13715
  }
13334
13716
  return turn;
@@ -13709,7 +14091,7 @@ var whatsapp_reader_default = app5;
13709
14091
 
13710
14092
  // server/routes/public-reader.ts
13711
14093
  import { statSync as statSync9, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch3, readFileSync as readFileSync22, readdirSync as readdirSync15 } from "fs";
13712
- import { basename as basename7, dirname as dirname8, join as join23, resolve as resolve18, sep as sep6 } from "path";
14094
+ import { basename as basename7, dirname as dirname8, join as join24, resolve as resolve18, sep as sep6 } from "path";
13713
14095
 
13714
14096
  // app/lib/whatsapp-reader/delivered-kinds.ts
13715
14097
  var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
@@ -13783,10 +14165,10 @@ function enumeratePublicRows() {
13783
14165
  const cfg = claudeConfigDir();
13784
14166
  if (!cfg) return [];
13785
14167
  const rows = [];
13786
- for (const { path: path3 } of enumerateJsonls(join23(cfg, "projects"))) {
14168
+ for (const { path: path3 } of enumerateJsonls(join24(cfg, "projects"))) {
13787
14169
  const sessionId = basename7(path3).replace(/\.jsonl$/, "");
13788
14170
  const projectDir = dirname8(path3);
13789
- const meta = readSidecarMeta(join23(projectDir, `${sessionId}.meta.json`));
14171
+ const meta = readSidecarMeta(join24(projectDir, `${sessionId}.meta.json`));
13790
14172
  rows.push({
13791
14173
  sessionId,
13792
14174
  projectDir,
@@ -13862,15 +14244,15 @@ app6.get("/stream", (c) => {
13862
14244
  const sessionId = c.req.query("sessionId") ?? "";
13863
14245
  const projectDir = c.req.query("projectDir") ?? "";
13864
14246
  const cfg = claudeConfigDir();
13865
- const projectsRoot = cfg ? resolve18(join23(cfg, "projects")) : null;
14247
+ const projectsRoot = cfg ? resolve18(join24(cfg, "projects")) : null;
13866
14248
  if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
13867
14249
  return c.json({ error: "bad session reference" }, 400);
13868
14250
  }
13869
- const jsonlPath = resolve18(join23(projectDir, `${sessionId}.jsonl`));
14251
+ const jsonlPath = resolve18(join24(projectDir, `${sessionId}.jsonl`));
13870
14252
  if (!jsonlPath.startsWith(projectsRoot + sep6)) {
13871
14253
  return c.json({ error: "bad session reference" }, 400);
13872
14254
  }
13873
- const meta = readSidecarMeta(join23(projectDir, `${sessionId}.meta.json`));
14255
+ const meta = readSidecarMeta(join24(projectDir, `${sessionId}.meta.json`));
13874
14256
  const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
13875
14257
  const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
13876
14258
  if (!(isPublicWebchat && owns)) {
@@ -14007,16 +14389,16 @@ var public_reader_default = app6;
14007
14389
 
14008
14390
  // server/routes/webchat.ts
14009
14391
  import { basename as basename8, dirname as dirname9 } from "path";
14010
- import { join as join26 } from "path";
14392
+ import { join as join27 } from "path";
14011
14393
  import { existsSync as existsSync19, readdirSync as readdirSync17, readFileSync as readFileSync25, renameSync as renameSync4, statSync as statSync10, writeFileSync as writeFileSync9 } from "fs";
14012
14394
 
14013
14395
  // server/canonical-webchat-override.ts
14014
14396
  import { readFileSync as readFileSync23, writeFileSync as writeFileSync7, renameSync as renameSync2 } from "fs";
14015
- import { join as join24 } from "path";
14397
+ import { join as join25 } from "path";
14016
14398
  var FILE = "canonical-webchat-session.json";
14017
14399
  var UUID2 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
14018
14400
  function canonicalOverridePath(accountDir) {
14019
- return join24(accountDir, FILE);
14401
+ return join25(accountDir, FILE);
14020
14402
  }
14021
14403
  function readRaw(accountDir) {
14022
14404
  try {
@@ -14121,7 +14503,7 @@ function isNewSessionEffortLevel(value) {
14121
14503
 
14122
14504
  // ../services/claude-session-manager/src/sidecar-store.ts
14123
14505
  import { existsSync as existsSync18, mkdirSync as mkdirSync4, readdirSync as readdirSync16, readFileSync as readFileSync24, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync8 } from "fs";
14124
- import { join as join25 } from "path";
14506
+ import { join as join26 } from "path";
14125
14507
  function escapeRegExp(s) {
14126
14508
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
14127
14509
  }
@@ -14129,7 +14511,7 @@ function createSidecarStore(config) {
14129
14511
  const { suffix, validate: validate2 } = config;
14130
14512
  const suffixRe = new RegExp(`${escapeRegExp(suffix)}$`);
14131
14513
  function pathFor(sessionsDir, id) {
14132
- return join25(sessionsDir, `${id}${suffix}`);
14514
+ return join26(sessionsDir, `${id}${suffix}`);
14133
14515
  }
14134
14516
  function write(sessionsDir, id, record) {
14135
14517
  mkdirSync4(sessionsDir, { recursive: true });
@@ -14173,7 +14555,7 @@ function createSidecarStore(config) {
14173
14555
  const out = [];
14174
14556
  for (const name of names) {
14175
14557
  if (!suffixRe.test(name)) continue;
14176
- const path3 = join25(sessionsDir, name);
14558
+ const path3 = join26(sessionsDir, name);
14177
14559
  let raw;
14178
14560
  try {
14179
14561
  raw = readFileSync24(path3, "utf8");
@@ -14250,13 +14632,13 @@ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9
14250
14632
  function locateSession(sessionId) {
14251
14633
  const dir = findSessionProjectDir(sessionId);
14252
14634
  if (!dir) return { projectDir: null, channel: null, accountId: null };
14253
- const meta = readSidecarMeta(join26(dir, `${sessionId}.meta.json`));
14635
+ const meta = readSidecarMeta(join27(dir, `${sessionId}.meta.json`));
14254
14636
  return { projectDir: dir, channel: meta.channel, accountId: meta.accountId };
14255
14637
  }
14256
14638
  function locateSidecar(sessionId) {
14257
14639
  const cfg = claudeConfigDir();
14258
14640
  if (!cfg) return null;
14259
- const projectsRoot = join26(cfg, "projects");
14641
+ const projectsRoot = join27(cfg, "projects");
14260
14642
  let slugs;
14261
14643
  try {
14262
14644
  slugs = readdirSync17(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
@@ -14264,7 +14646,7 @@ function locateSidecar(sessionId) {
14264
14646
  return null;
14265
14647
  }
14266
14648
  for (const slug of slugs) {
14267
- const metaPath = join26(projectsRoot, slug, `${sessionId}.meta.json`);
14649
+ const metaPath = join27(projectsRoot, slug, `${sessionId}.meta.json`);
14268
14650
  if (existsSync19(metaPath)) return readSidecarMeta(metaPath);
14269
14651
  }
14270
14652
  return null;
@@ -14274,7 +14656,7 @@ function readTargetOwner(sessionId) {
14274
14656
  if (sidecar !== null) return { found: true, owner: sidecar.adminUserId };
14275
14657
  const { projectDir } = locateSession(sessionId);
14276
14658
  if (projectDir !== null) {
14277
- return { found: true, owner: readSidecarMeta(join26(projectDir, `${sessionId}.meta.json`)).adminUserId };
14659
+ return { found: true, owner: readSidecarMeta(join27(projectDir, `${sessionId}.meta.json`)).adminUserId };
14278
14660
  }
14279
14661
  return { found: false, owner: null };
14280
14662
  }
@@ -14282,7 +14664,7 @@ function readSourceRowMeta(sessionId) {
14282
14664
  const sidecar = locateSidecar(sessionId);
14283
14665
  if (sidecar !== null) return sidecar;
14284
14666
  const { projectDir } = locateSession(sessionId);
14285
- if (projectDir !== null) return readSidecarMeta(join26(projectDir, `${sessionId}.meta.json`));
14667
+ if (projectDir !== null) return readSidecarMeta(join27(projectDir, `${sessionId}.meta.json`));
14286
14668
  return null;
14287
14669
  }
14288
14670
  function ownedByRequester(owner, requesterUserId, primaryUserId) {
@@ -14295,7 +14677,7 @@ function sessionSidecarExists(sessionId) {
14295
14677
  function jsonlSizeBytes(projectDir, sessionId) {
14296
14678
  if (projectDir === null) return null;
14297
14679
  try {
14298
- return statSync10(join26(projectDir, `${sessionId}.jsonl`)).size;
14680
+ return statSync10(join27(projectDir, `${sessionId}.jsonl`)).size;
14299
14681
  } catch {
14300
14682
  return null;
14301
14683
  }
@@ -14423,10 +14805,10 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId, scopeAccoun
14423
14805
  const cfg = claudeConfigDir();
14424
14806
  if (!cfg) return null;
14425
14807
  let best = null;
14426
- for (const { path: path3, isSubagent, archived } of enumerateJsonls(join26(cfg, "projects"))) {
14808
+ for (const { path: path3, isSubagent, archived } of enumerateJsonls(join27(cfg, "projects"))) {
14427
14809
  if (isSubagent || archived) continue;
14428
14810
  const id = basename8(path3).slice(0, -".jsonl".length);
14429
- const meta = readSidecarMeta(join26(dirname9(path3), `${id}.meta.json`));
14811
+ const meta = readSidecarMeta(join27(dirname9(path3), `${id}.meta.json`));
14430
14812
  if (meta.role !== "admin" || meta.channel !== "webchat") continue;
14431
14813
  if (multiAccount && meta.accountId !== scopeAccountId) continue;
14432
14814
  let mtimeMs;
@@ -14730,7 +15112,7 @@ ${note}` : note;
14730
15112
  console.error(`[webchat:settings] op=${op} outcome=refused value=${value} accountId=none reason=no-account-for-session`);
14731
15113
  return c.json({ error: "account unresolved" }, 503);
14732
15114
  }
14733
- const accountJsonPath = join26(account.accountDir, "account.json");
15115
+ const accountJsonPath = join27(account.accountDir, "account.json");
14734
15116
  try {
14735
15117
  const parsed = JSON.parse(readFileSync25(accountJsonPath, "utf8"));
14736
15118
  if (op === "model") parsed.adminModel = value;
@@ -14778,7 +15160,7 @@ ${note}` : note;
14778
15160
  const cfg2 = claudeConfigDir();
14779
15161
  if (cfg2) {
14780
15162
  const source2 = resolveBridgeSource(
14781
- join26(cfg2, "sessions"),
15163
+ join27(cfg2, "sessions"),
14782
15164
  target,
14783
15165
  (id) => locateSession(id).projectDir !== null
14784
15166
  );
@@ -14805,7 +15187,7 @@ ${note}` : note;
14805
15187
  const cfg = claudeConfigDir();
14806
15188
  let projectDir = null;
14807
15189
  if (cfg) {
14808
- for (const { path: path3 } of enumerateJsonls(join26(cfg, "projects"))) {
15190
+ for (const { path: path3 } of enumerateJsonls(join27(cfg, "projects"))) {
14809
15191
  if (basename8(path3) === `${sessionId}.jsonl`) {
14810
15192
  projectDir = dirname9(path3);
14811
15193
  break;
@@ -14813,7 +15195,7 @@ ${note}` : note;
14813
15195
  }
14814
15196
  }
14815
15197
  if (source === "latest" && requesterUserId !== null) {
14816
- const owner = readSidecarMeta(join26(projectDir ?? "", `${sessionId}.meta.json`)).adminUserId;
15198
+ const owner = readSidecarMeta(join27(projectDir ?? "", `${sessionId}.meta.json`)).adminUserId;
14817
15199
  if (owner !== null && owner !== requesterUserId && requesterUserId !== primaryUserId) {
14818
15200
  console.error(`[webchat:inbound] op=session-resolve-foreign key=${sessionId.slice(0, 8)} owner=${owner.slice(0, 8)} requester=${requesterUserId.slice(0, 8)}`);
14819
15201
  }
@@ -14846,7 +15228,7 @@ import { resolve as resolve19 } from "path";
14846
15228
 
14847
15229
  // app/lib/claude-agent/specialist-roster.ts
14848
15230
  import { existsSync as existsSync20, readFileSync as readFileSync26, readdirSync as readdirSync18 } from "fs";
14849
- import { join as join27 } from "path";
15231
+ import { join as join28 } from "path";
14850
15232
  function field(fm, name) {
14851
15233
  const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
14852
15234
  if (!m) return null;
@@ -14865,7 +15247,7 @@ function readSpecialistRoster(specialistsDir) {
14865
15247
  if (!file.endsWith(".md")) continue;
14866
15248
  let raw;
14867
15249
  try {
14868
- raw = readFileSync26(join27(specialistsDir, file), "utf-8");
15250
+ raw = readFileSync26(join28(specialistsDir, file), "utf-8");
14869
15251
  } catch (err) {
14870
15252
  skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
14871
15253
  continue;
@@ -14982,7 +15364,7 @@ var webchat_greeting_default = app7;
14982
15364
 
14983
15365
  // server/routes/telegram.ts
14984
15366
  import { homedir as homedir2 } from "os";
14985
- import { resolve as resolve20, join as join28 } from "path";
15367
+ import { resolve as resolve20, join as join29 } from "path";
14986
15368
  import { existsSync as existsSync21, readFileSync as readFileSync27 } from "fs";
14987
15369
 
14988
15370
  // app/lib/telegram/gateway/instance.ts
@@ -15042,7 +15424,7 @@ function routeTelegramUpdate(input) {
15042
15424
  var TAG30 = "[telegram-inbound]";
15043
15425
  function configDirName() {
15044
15426
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
15045
- const brandPath = join28(platformRoot5, "config", "brand.json");
15427
+ const brandPath = join29(platformRoot5, "config", "brand.json");
15046
15428
  if (existsSync21(brandPath)) {
15047
15429
  try {
15048
15430
  return JSON.parse(readFileSync27(brandPath, "utf-8")).configDir ?? ".maxy";
@@ -15131,16 +15513,16 @@ app8.post("/", async (c) => {
15131
15513
  var telegram_default = app8;
15132
15514
 
15133
15515
  // server/routes/quickbooks.ts
15134
- import { join as join29 } from "path";
15516
+ import { join as join30 } from "path";
15135
15517
  import { existsSync as existsSync22, readFileSync as readFileSync28, writeFileSync as writeFileSync10, mkdirSync as mkdirSync5, rmSync, renameSync as renameSync5 } from "fs";
15136
15518
  var TAG31 = "[quickbooks]";
15137
15519
  var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
15138
15520
  var STATE_RE = /^[A-Za-z0-9_-]+$/;
15139
15521
  function pendingPath(accountDir, state) {
15140
- return join29(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
15522
+ return join30(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
15141
15523
  }
15142
15524
  function storePath(accountDir) {
15143
- return join29(accountDir, "secrets", "quickbooks.json");
15525
+ return join30(accountDir, "secrets", "quickbooks.json");
15144
15526
  }
15145
15527
  async function completeConsent(args) {
15146
15528
  const { accountDir, code, realmId } = args;
@@ -15207,7 +15589,7 @@ async function completeConsent(args) {
15207
15589
  refreshTokenExpiry: now + (body.x_refresh_token_expires_in ?? 864e4) * 1e3,
15208
15590
  lastRefresh: now
15209
15591
  };
15210
- mkdirSync5(join29(accountDir, "secrets"), { recursive: true });
15592
+ mkdirSync5(join30(accountDir, "secrets"), { recursive: true });
15211
15593
  writeFileSync10(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
15212
15594
  const persisted = JSON.parse(readFileSync28(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
15213
15595
  console.error(`${TAG31} op=token-exchange realmId=${realmId} persisted=${persisted}`);
@@ -15249,7 +15631,7 @@ function claudeBin() {
15249
15631
  }
15250
15632
 
15251
15633
  // server/routes/onboarding.ts
15252
- import { dirname as dirname11, join as join31 } from "path";
15634
+ import { dirname as dirname11, join as join32 } from "path";
15253
15635
 
15254
15636
  // app/lib/claude-keychain.ts
15255
15637
  import { execFileSync as execFileSync3 } from "child_process";
@@ -15379,7 +15761,7 @@ function readHostCredsBlob(service) {
15379
15761
 
15380
15762
  // ../lib/admins-write/src/index.ts
15381
15763
  import { existsSync as existsSync23, readFileSync as readFileSync29, writeFileSync as writeFileSync11, renameSync as renameSync6, mkdirSync as mkdirSync6, readdirSync as readdirSync19, statSync as statSync11, appendFileSync as appendFileSync3 } from "fs";
15382
- import { dirname as dirname10, join as join30 } from "path";
15764
+ import { dirname as dirname10, join as join31 } from "path";
15383
15765
  function id8(value) {
15384
15766
  return value.slice(0, 8);
15385
15767
  }
@@ -15452,7 +15834,7 @@ function writeAdminEntry(input) {
15452
15834
  return result;
15453
15835
  }
15454
15836
  try {
15455
- const accountJsonPath = join30(input.accountDir, "account.json");
15837
+ const accountJsonPath = join31(input.accountDir, "account.json");
15456
15838
  if (!existsSync23(accountJsonPath)) {
15457
15839
  throw new Error(`account.json not found at ${accountJsonPath}`);
15458
15840
  }
@@ -15500,13 +15882,13 @@ function computeAdminStoreDivergence(input) {
15500
15882
  }
15501
15883
  for (const entry of entries2) {
15502
15884
  if (entry.startsWith(".")) continue;
15503
- const accountDir = join30(input.accountsDir, entry);
15885
+ const accountDir = join31(input.accountsDir, entry);
15504
15886
  try {
15505
15887
  if (!statSync11(accountDir).isDirectory()) continue;
15506
15888
  } catch {
15507
15889
  continue;
15508
15890
  }
15509
- const accountJsonPath = join30(accountDir, "account.json");
15891
+ const accountJsonPath = join31(accountDir, "account.json");
15510
15892
  if (!existsSync23(accountJsonPath)) continue;
15511
15893
  let admins = [];
15512
15894
  try {
@@ -15684,7 +16066,7 @@ app10.post("/claude-auth", async (c) => {
15684
16066
  });
15685
16067
  persistKeychainService(
15686
16068
  writebackResult,
15687
- (service) => writeFileSync12(join31(dirname11(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
16069
+ (service) => writeFileSync12(join32(dirname11(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
15688
16070
  (line) => console.log(line)
15689
16071
  );
15690
16072
  if (darwinAuthChild === claudeProc2) darwinAuthChild = null;
@@ -15950,8 +16332,8 @@ var onboarding_default = app10;
15950
16332
 
15951
16333
  // server/routes/client-error.ts
15952
16334
  import { appendFileSync as appendFileSync4, existsSync as existsSync25, renameSync as renameSync8, statSync as statSync12 } from "fs";
15953
- import { join as join32 } from "path";
15954
- var CLIENT_ERRORS_LOG = join32(LOG_DIR, "client-errors.log");
16335
+ import { join as join33 } from "path";
16336
+ var CLIENT_ERRORS_LOG = join33(LOG_DIR, "client-errors.log");
15955
16337
  var MAX_LOG_SIZE = 10 * 1024 * 1024;
15956
16338
  var MAX_BODY_SIZE = 8 * 1024;
15957
16339
  var MAX_STACK_LEN = 2e3;
@@ -16340,12 +16722,12 @@ import { resolve as resolve21, basename as basename9 } from "path";
16340
16722
 
16341
16723
  // app/lib/logs-read-resolve.ts
16342
16724
  import { existsSync as existsSync26 } from "fs";
16343
- import { join as join33 } from "path";
16725
+ import { join as join34 } from "path";
16344
16726
  function resolveSessionLogPaths(filename, logDirs) {
16345
16727
  const tried = [filename];
16346
16728
  const hits = [];
16347
16729
  for (const dir of logDirs) {
16348
- const fullPath = join33(dir, filename);
16730
+ const fullPath = join34(dir, filename);
16349
16731
  if (existsSync26(fullPath)) {
16350
16732
  hits.push({ path: fullPath, dir });
16351
16733
  }
@@ -16527,7 +16909,7 @@ app15.get("/", requireAdminSession, (c) => {
16527
16909
  var claude_info_default = app15;
16528
16910
 
16529
16911
  // server/routes/admin/attachment.ts
16530
- import { readFile as readFile5, readdir as readdir2 } from "fs/promises";
16912
+ import { readFile as readFile6, readdir as readdir2 } from "fs/promises";
16531
16913
  import { existsSync as existsSync28 } from "fs";
16532
16914
  import { resolve as resolve22 } from "path";
16533
16915
  var app16 = new Hono();
@@ -16538,15 +16920,15 @@ function uploadsDirFor2(accountId, attachmentId) {
16538
16920
  app16.get("/:attachmentId", requireAdminSession, async (c) => {
16539
16921
  const attachmentId = c.req.param("attachmentId");
16540
16922
  const cacheKey = c.var.cacheKey;
16541
- const shortId2 = attachmentId.slice(0, 8);
16923
+ const shortId3 = attachmentId.slice(0, 8);
16542
16924
  const shortSession = (c.req.query("session_key") ?? "").slice(0, 8);
16543
16925
  const pinnedAccountId = getAccountIdForSession(cacheKey);
16544
16926
  if (!pinnedAccountId) {
16545
- console.log(`[admin-attachment] op=miss attachmentId=${shortId2} session=${shortSession} status=401 reason=no-account`);
16927
+ console.log(`[admin-attachment] op=miss attachmentId=${shortId3} session=${shortSession} status=401 reason=no-account`);
16546
16928
  return new Response("Unauthorized", { status: 401 });
16547
16929
  }
16548
16930
  if (!ATTACHMENT_ID_RE3.test(attachmentId)) {
16549
- console.log(`[admin-attachment] op=miss attachmentId=${shortId2} session=${shortSession} status=404 reason=bad-id`);
16931
+ console.log(`[admin-attachment] op=miss attachmentId=${shortId3} session=${shortSession} status=404 reason=bad-id`);
16550
16932
  return new Response("Not found", { status: 404 });
16551
16933
  }
16552
16934
  let accountId = pinnedAccountId;
@@ -16566,7 +16948,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
16566
16948
  }
16567
16949
  const shortPinned = pinnedAccountId.slice(0, 8);
16568
16950
  const crossAccountNote = found && accountId !== pinnedAccountId ? ` resolvedAccount=${accountId.slice(0, 8)}` : "";
16569
- console.log(`[admin-attachment] op=lookup attachmentId=${shortId2} session=${shortSession} pinnedAccount=${shortPinned} found=${found}${crossAccountNote}`);
16951
+ console.log(`[admin-attachment] op=lookup attachmentId=${shortId3} session=${shortSession} pinnedAccount=${shortPinned} found=${found}${crossAccountNote}`);
16570
16952
  if (!found) {
16571
16953
  return new Response("Not found", { status: 404 });
16572
16954
  }
@@ -16576,7 +16958,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
16576
16958
  }
16577
16959
  let meta;
16578
16960
  try {
16579
- meta = JSON.parse(await readFile5(metaPath, "utf-8"));
16961
+ meta = JSON.parse(await readFile6(metaPath, "utf-8"));
16580
16962
  } catch {
16581
16963
  return new Response("Not found", { status: 404 });
16582
16964
  }
@@ -16586,11 +16968,11 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
16586
16968
  return new Response("Not found", { status: 404 });
16587
16969
  }
16588
16970
  const filePath = resolve22(dir, dataFile);
16589
- const buffer = await readFile5(filePath);
16971
+ const buffer = await readFile6(filePath);
16590
16972
  const inlineSafe = isInlineSafeMime(meta.mimeType);
16591
16973
  const safeName = meta.filename.replace(/["\\\r\n]/g, "_");
16592
16974
  if (!inlineSafe) {
16593
- console.log(`[admin-attachment] op=served attachmentId=${shortId2} disposition=attachment reason=non-preview-mime mime=${meta.mimeType}`);
16975
+ console.log(`[admin-attachment] op=served attachmentId=${shortId3} disposition=attachment reason=non-preview-mime mime=${meta.mimeType}`);
16594
16976
  }
16595
16977
  return new Response(new Uint8Array(buffer), {
16596
16978
  headers: {
@@ -16604,7 +16986,7 @@ app16.get("/:attachmentId", requireAdminSession, async (c) => {
16604
16986
  var attachment_default = app16;
16605
16987
 
16606
16988
  // server/routes/admin/session-upload.ts
16607
- import { readFile as readFile6 } from "fs/promises";
16989
+ import { readFile as readFile7 } from "fs/promises";
16608
16990
  import { existsSync as existsSync29, statSync as statSync14 } from "fs";
16609
16991
  var app17 = new Hono();
16610
16992
  app17.get("/", requireAdminSession, async (c) => {
@@ -16634,7 +17016,7 @@ app17.get("/", requireAdminSession, async (c) => {
16634
17016
  const inlineSafe = isInlineSafeMime(mimeType);
16635
17017
  const safeName = file.replace(/["\\\r\n]/g, "_");
16636
17018
  console.log(`[session-upload] op=served session=${short2} file=${file} disposition=${inlineSafe ? "inline" : "attachment"} mime=${mimeType}`);
16637
- const buffer = await readFile6(resolution.absolute);
17019
+ const buffer = await readFile7(resolution.absolute);
16638
17020
  return new Response(new Uint8Array(buffer), {
16639
17021
  headers: {
16640
17022
  "Content-Type": mimeType,
@@ -16653,7 +17035,7 @@ import { readdirSync as readdirSync22, readFileSync as readFileSync33, existsSyn
16653
17035
  // ../services/claude-session-manager/src/tool-surface.ts
16654
17036
  import { readFileSync as readFileSync32, readdirSync as readdirSync21, statSync as statSync15, existsSync as existsSync30 } from "fs";
16655
17037
  import { createHash as createHash5 } from "crypto";
16656
- import { join as join34 } from "path";
17038
+ import { join as join35 } from "path";
16657
17039
 
16658
17040
  // ../services/claude-session-manager/src/canonical-tool-names.ts
16659
17041
  function canonicalToolName(plugin, tool) {
@@ -16906,13 +17288,13 @@ function loadToolSurface(pluginsRoots) {
16906
17288
  const riskByTool = /* @__PURE__ */ new Map();
16907
17289
  const manifestPaths = /* @__PURE__ */ new Map();
16908
17290
  const loadOne = (pluginsRoot, plugin) => {
16909
- const pluginDir = join34(pluginsRoot, plugin);
17291
+ const pluginDir = join35(pluginsRoot, plugin);
16910
17292
  try {
16911
17293
  if (!statSync15(pluginDir).isDirectory()) return;
16912
17294
  } catch {
16913
17295
  return;
16914
17296
  }
16915
- const manifestPath = join34(pluginDir, "PLUGIN.md");
17297
+ const manifestPath = join35(pluginDir, "PLUGIN.md");
16916
17298
  if (!existsSync30(manifestPath)) return;
16917
17299
  const raw = readFileSync32(manifestPath, "utf-8");
16918
17300
  const frontmatter = extractFrontmatter(raw, plugin);
@@ -16958,9 +17340,9 @@ function loadToolSurface(pluginsRoots) {
16958
17340
  for (const root of roots) {
16959
17341
  const entries2 = readdirSync21(root).sort();
16960
17342
  for (const plugin of entries2) {
16961
- const pluginDir = join34(root, plugin);
17343
+ const pluginDir = join35(root, plugin);
16962
17344
  loadOne(root, plugin);
16963
- const subRoot = join34(pluginDir, "plugins");
17345
+ const subRoot = join35(pluginDir, "plugins");
16964
17346
  let subEntries;
16965
17347
  try {
16966
17348
  if (!statSync15(subRoot).isDirectory()) continue;
@@ -18228,7 +18610,7 @@ var sessions_default = app19;
18228
18610
 
18229
18611
  // app/lib/claude-agent/spawn-context.ts
18230
18612
  import { existsSync as existsSync33, readFileSync as readFileSync34, readdirSync as readdirSync23, statSync as statSync16 } from "fs";
18231
- import { dirname as dirname12, resolve as resolve24, join as join35 } from "path";
18613
+ import { dirname as dirname12, resolve as resolve24, join as join36 } from "path";
18232
18614
  async function resolveOwnerProfileBlock(accountId, userId) {
18233
18615
  if (!userId) return { ok: false, reason: "missing-user-id" };
18234
18616
  try {
@@ -18269,8 +18651,8 @@ function frontmatterField(manifest, field2) {
18269
18651
  function extractPluginToolDescriptions(pluginDir) {
18270
18652
  const out = /* @__PURE__ */ new Map();
18271
18653
  const candidates = [
18272
- join35(pluginDir, "mcp/dist/index.js"),
18273
- join35(pluginDir, "mcp/src/index.ts")
18654
+ join36(pluginDir, "mcp/dist/index.js"),
18655
+ join36(pluginDir, "mcp/src/index.ts")
18274
18656
  ];
18275
18657
  let raw = null;
18276
18658
  for (const path3 of candidates) {
@@ -18328,7 +18710,7 @@ function listPluginDirs(accountPluginsDir) {
18328
18710
  const platformPlugins = resolve24(PLATFORM_ROOT, "plugins");
18329
18711
  if (existsSync33(platformPlugins)) {
18330
18712
  for (const name of readdirSync23(platformPlugins)) {
18331
- const dir = join35(platformPlugins, name);
18713
+ const dir = join36(platformPlugins, name);
18332
18714
  try {
18333
18715
  if (statSync16(dir).isDirectory()) out.set(name, dir);
18334
18716
  } catch {
@@ -18338,11 +18720,11 @@ function listPluginDirs(accountPluginsDir) {
18338
18720
  const premiumRoot = resolve24(dirname12(PLATFORM_ROOT), "premium-plugins");
18339
18721
  if (existsSync33(premiumRoot)) {
18340
18722
  for (const bundle of readdirSync23(premiumRoot)) {
18341
- const bundlePlugins = join35(premiumRoot, bundle, "plugins");
18723
+ const bundlePlugins = join36(premiumRoot, bundle, "plugins");
18342
18724
  if (!existsSync33(bundlePlugins)) continue;
18343
18725
  try {
18344
18726
  for (const name of readdirSync23(bundlePlugins)) {
18345
- const dir = join35(bundlePlugins, name);
18727
+ const dir = join36(bundlePlugins, name);
18346
18728
  try {
18347
18729
  if (statSync16(dir).isDirectory()) out.set(name, dir);
18348
18730
  } catch {
@@ -18356,7 +18738,7 @@ function listPluginDirs(accountPluginsDir) {
18356
18738
  try {
18357
18739
  for (const name of readdirSync23(accountPluginsDir)) {
18358
18740
  if (out.has(name)) continue;
18359
- const dir = join35(accountPluginsDir, name);
18741
+ const dir = join36(accountPluginsDir, name);
18360
18742
  try {
18361
18743
  if (statSync16(dir).isDirectory()) out.set(name, dir);
18362
18744
  } catch {
@@ -18375,7 +18757,7 @@ function listAccountPluginNames(accountPluginsDir) {
18375
18757
  try {
18376
18758
  return readdirSync23(accountPluginsDir).filter((name) => {
18377
18759
  try {
18378
- return statSync16(join35(accountPluginsDir, name)).isDirectory();
18760
+ return statSync16(join36(accountPluginsDir, name)).isDirectory();
18379
18761
  } catch {
18380
18762
  return false;
18381
18763
  }
@@ -18418,7 +18800,7 @@ function computeActivePlugins(accountId) {
18418
18800
  for (const name of emitNames) {
18419
18801
  const dir = pluginDirs.get(name);
18420
18802
  if (!dir) continue;
18421
- const fm = readFrontmatter(join35(dir, "PLUGIN.md"));
18803
+ const fm = readFrontmatter(join36(dir, "PLUGIN.md"));
18422
18804
  if (!fm) continue;
18423
18805
  const description = frontmatterField(`---
18424
18806
  ${fm}
@@ -18435,7 +18817,7 @@ ${fm}
18435
18817
  `plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
18436
18818
  );
18437
18819
  if (toolNames.length > 0 && descMap.size === 0) {
18438
- const hasSource = existsSync33(join35(dir, "mcp/dist/index.js")) || existsSync33(join35(dir, "mcp/src/index.ts"));
18820
+ const hasSource = existsSync33(join36(dir, "mcp/dist/index.js")) || existsSync33(join36(dir, "mcp/src/index.ts"));
18439
18821
  if (hasSource) {
18440
18822
  console.warn(
18441
18823
  `[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
@@ -18445,7 +18827,7 @@ ${fm}
18445
18827
  const skillPaths = parseSkillPathsFromFrontmatter(fm);
18446
18828
  const skills = [];
18447
18829
  for (const relPath of skillPaths) {
18448
- const skillPath = join35(dir, relPath);
18830
+ const skillPath = join36(dir, relPath);
18449
18831
  const skillFm = readFrontmatter(skillPath);
18450
18832
  if (!skillFm) continue;
18451
18833
  const skillName = frontmatterField(`---
@@ -18489,7 +18871,7 @@ function computeSpecialistDomains(accountId) {
18489
18871
  const out = [];
18490
18872
  for (const file of entries2.sort()) {
18491
18873
  if (!file.endsWith(".md")) continue;
18492
- const fm = readFrontmatter(join35(specialistsDir, file));
18874
+ const fm = readFrontmatter(join36(specialistsDir, file));
18493
18875
  if (!fm) continue;
18494
18876
  const wrapped = `---
18495
18877
  ${fm}
@@ -18885,10 +19267,10 @@ var events_default = app22;
18885
19267
 
18886
19268
  // server/routes/admin/files.ts
18887
19269
  import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync35 } from "fs";
18888
- import { readdir as readdir4, readFile as readFile8, stat as stat7, mkdir as mkdir4, unlink as unlink3, rename as rename2, rmdir } from "fs/promises";
19270
+ import { readdir as readdir4, readFile as readFile9, stat as stat7, mkdir as mkdir4, unlink as unlink4, rename as rename3, rmdir } from "fs/promises";
18889
19271
  import { realpathSync as realpathSync7 } from "fs";
18890
19272
  import { randomUUID as randomUUID10 } from "crypto";
18891
- import { basename as basename11, dirname as dirname13, join as join37, relative as relative5, resolve as resolve27, sep as sep8 } from "path";
19273
+ import { basename as basename11, dirname as dirname13, join as join38, relative as relative5, resolve as resolve27, sep as sep8 } from "path";
18892
19274
  import { Readable as Readable2 } from "stream";
18893
19275
 
18894
19276
  // ../lib/graph-trash/src/index.ts
@@ -19125,7 +19507,7 @@ async function restoreNode(params) {
19125
19507
  }
19126
19508
 
19127
19509
  // app/lib/file-delete-cascade.ts
19128
- var UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
19510
+ var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
19129
19511
  function parseAttachmentPath(relPath) {
19130
19512
  const segments = relPath.split("/").filter(Boolean);
19131
19513
  if (segments.length !== 5) return null;
@@ -19133,7 +19515,7 @@ function parseAttachmentPath(relPath) {
19133
19515
  const accountId = segments[1];
19134
19516
  const attachmentId = segments[3];
19135
19517
  const filename = segments[4];
19136
- if (!UUID_RE3.test(accountId) || !UUID_RE3.test(attachmentId)) return null;
19518
+ if (!UUID_RE4.test(accountId) || !UUID_RE4.test(attachmentId)) return null;
19137
19519
  const dot = filename.lastIndexOf(".");
19138
19520
  if (dot === -1) return null;
19139
19521
  const stem = filename.slice(0, dot);
@@ -19206,7 +19588,7 @@ async function cascadeDeleteDocument(params) {
19206
19588
 
19207
19589
  // app/lib/file-index.ts
19208
19590
  import * as fsp from "fs/promises";
19209
- import { resolve as resolve26, relative as relative4, join as join36, basename as basename10, extname as extname2, sep as sep7 } from "path";
19591
+ import { resolve as resolve26, relative as relative4, join as join37, basename as basename10, extname as extname2, sep as sep7 } from "path";
19210
19592
  import { tmpdir as tmpdir2 } from "os";
19211
19593
  import { execFile as execFile2 } from "child_process";
19212
19594
  import { promisify as promisify2 } from "util";
@@ -19288,7 +19670,7 @@ async function extractPdf(absolute) {
19288
19670
  return stdout.trim();
19289
19671
  }
19290
19672
  async function ocrPdf(absolute) {
19291
- const outPdf = join36(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
19673
+ const outPdf = join37(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
19292
19674
  try {
19293
19675
  await execFileAsync2(
19294
19676
  "ocrmypdf",
@@ -19350,7 +19732,7 @@ async function readDisplayName(absolute) {
19350
19732
  const stem = dot === -1 ? base : base.slice(0, dot);
19351
19733
  if (base === `${stem}.meta.json`) return null;
19352
19734
  try {
19353
- const raw = await fsp.readFile(join36(dir, `${stem}.meta.json`), "utf-8");
19735
+ const raw = await fsp.readFile(join37(dir, `${stem}.meta.json`), "utf-8");
19354
19736
  const meta = JSON.parse(raw);
19355
19737
  const dn = meta.displayName ?? meta.filename;
19356
19738
  return typeof dn === "string" && dn.length > 0 ? dn : null;
@@ -19371,7 +19753,7 @@ async function walkSubtree(root, dataRoot, out) {
19371
19753
  for (const entry of entries2) {
19372
19754
  if (entry.isSymbolicLink()) continue;
19373
19755
  if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
19374
- const abs = join36(root, entry.name);
19756
+ const abs = join37(root, entry.name);
19375
19757
  if (entry.isDirectory()) {
19376
19758
  const sub = await walkSubtree(abs, dataRoot, out);
19377
19759
  if (!sub.clean) clean = false;
@@ -19741,10 +20123,10 @@ function classifyAccountRoot(schemaMd, rootEntries) {
19741
20123
 
19742
20124
  // server/routes/admin/files.ts
19743
20125
  var UPLOAD_TMP_DIR = ".uploads-tmp";
19744
- var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
20126
+ var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
19745
20127
  async function readMeta(absDir, baseName) {
19746
20128
  try {
19747
- const raw = await readFile8(join37(absDir, `${baseName}.meta.json`), "utf8");
20129
+ const raw = await readFile9(join38(absDir, `${baseName}.meta.json`), "utf8");
19748
20130
  const parsed = JSON.parse(raw);
19749
20131
  if (typeof parsed?.filename === "string") {
19750
20132
  return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
@@ -19763,10 +20145,10 @@ async function readAccountNames() {
19763
20145
  return map;
19764
20146
  }
19765
20147
  for (const name of names) {
19766
- if (!UUID_RE4.test(name)) continue;
20148
+ if (!UUID_RE5.test(name)) continue;
19767
20149
  const configPath2 = resolve27(accountsDir, name, "account.json");
19768
20150
  try {
19769
- const raw = await readFile8(configPath2, "utf8");
20151
+ const raw = await readFile9(configPath2, "utf8");
19770
20152
  const parsed = JSON.parse(raw);
19771
20153
  if (typeof parsed?.name === "string" && parsed.name.length > 0) {
19772
20154
  map.set(name, parsed.name);
@@ -19798,8 +20180,8 @@ async function servableFilesIn(dirAbs, uuid) {
19798
20180
  return out;
19799
20181
  }
19800
20182
  async function enrich(absolute, entry, accountNames) {
19801
- if (entry.kind === "directory" && UUID_RE4.test(entry.name)) {
19802
- const dirAbs = join37(absolute, entry.name);
20183
+ if (entry.kind === "directory" && UUID_RE5.test(entry.name)) {
20184
+ const dirAbs = join38(absolute, entry.name);
19803
20185
  const meta = await readMeta(dirAbs, entry.name);
19804
20186
  if (meta?.filename) {
19805
20187
  const servable = await servableFilesIn(dirAbs, entry.name);
@@ -19808,7 +20190,7 @@ async function enrich(absolute, entry, accountNames) {
19808
20190
  let size = null;
19809
20191
  let modifiedAt = entry.modifiedAt;
19810
20192
  try {
19811
- const st = await stat7(join37(dirAbs, innerName));
20193
+ const st = await stat7(join38(dirAbs, innerName));
19812
20194
  size = st.size;
19813
20195
  modifiedAt = st.mtime.toISOString();
19814
20196
  } catch {
@@ -19833,7 +20215,7 @@ async function enrich(absolute, entry, accountNames) {
19833
20215
  if (entry.kind === "file") {
19834
20216
  const dot = entry.name.lastIndexOf(".");
19835
20217
  const base = dot === -1 ? entry.name : entry.name.slice(0, dot);
19836
- if (UUID_RE4.test(base)) {
20218
+ if (UUID_RE5.test(base)) {
19837
20219
  const meta = await readMeta(absolute, base);
19838
20220
  if (meta?.filename) {
19839
20221
  entry.displayName = meta.filename;
@@ -19846,7 +20228,7 @@ async function enrich(absolute, entry, accountNames) {
19846
20228
  function buildDisplayPath(relPath, accountNames) {
19847
20229
  if (relPath === "." || relPath === "") return [];
19848
20230
  return relPath.split("/").filter(Boolean).map((seg) => {
19849
- const dn = UUID_RE4.test(seg) ? accountNames.get(seg) : void 0;
20231
+ const dn = UUID_RE5.test(seg) ? accountNames.get(seg) : void 0;
19850
20232
  return dn ? { name: seg, displayName: dn } : { name: seg };
19851
20233
  });
19852
20234
  }
@@ -19858,13 +20240,13 @@ function parseGroupPath(raw, sessionAccountId) {
19858
20240
  }
19859
20241
  const segs = trimmed.split("/").filter(Boolean);
19860
20242
  if (segs.length !== 3) return null;
19861
- if (segs[0] !== "accounts" || !UUID_RE4.test(segs[1])) return null;
20243
+ if (segs[0] !== "accounts" || !UUID_RE5.test(segs[1])) return null;
19862
20244
  if (segs[2] !== "@home" && segs[2] !== "@system") return null;
19863
20245
  return { view: segs[2].slice(1), accountRel: `accounts/${segs[1]}` };
19864
20246
  }
19865
20247
  function isAccountRoot(relPath) {
19866
20248
  const segs = relPath.split("/").filter(Boolean);
19867
- return segs.length === 2 && segs[0] === "accounts" && UUID_RE4.test(segs[1]);
20249
+ return segs.length === 2 && segs[0] === "accounts" && UUID_RE5.test(segs[1]);
19868
20250
  }
19869
20251
  function sortDirEntries(entries2) {
19870
20252
  entries2.sort((a, b) => {
@@ -19912,11 +20294,11 @@ function isProtectedFromRename(relPath) {
19912
20294
  if (segments.length === 3 && segments[0] === "accounts" && segments[2] === "uploads") {
19913
20295
  return true;
19914
20296
  }
19915
- if (segments.length === 4 && segments[0] === "accounts" && segments[2] === "uploads" && UUID_RE4.test(segments[3])) {
20297
+ if (segments.length === 4 && segments[0] === "accounts" && segments[2] === "uploads" && UUID_RE5.test(segments[3])) {
19916
20298
  return true;
19917
20299
  }
19918
20300
  if (parseAttachmentPath(relPath) !== null) return true;
19919
- if (UUID_RE4.test(base.replace(/\.meta\.json$/, "")) && base.endsWith(".meta.json")) {
20301
+ if (UUID_RE5.test(base.replace(/\.meta\.json$/, "")) && base.endsWith(".meta.json")) {
19920
20302
  return true;
19921
20303
  }
19922
20304
  return false;
@@ -19992,16 +20374,16 @@ app23.get("/", requireAdminSession, async (c) => {
19992
20374
  const isAccountParent = segs.length === 1 && segs[0] === "accounts";
19993
20375
  const entries2 = [];
19994
20376
  for (const name of names) {
19995
- if (UUID_RE4.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
20377
+ if (UUID_RE5.test(name.replace(/\.meta\.json$/, "")) && name.endsWith(".meta.json")) {
19996
20378
  continue;
19997
20379
  }
19998
- if (isAccountParent && UUID_RE4.test(name) && name !== accountId) {
20380
+ if (isAccountParent && UUID_RE5.test(name) && name !== accountId) {
19999
20381
  continue;
20000
20382
  }
20001
20383
  const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
20002
20384
  const protectedEntry = isProtectedFromDeletion(childRel).protected;
20003
20385
  try {
20004
- const entryPath = join37(absolute, name);
20386
+ const entryPath = join38(absolute, name);
20005
20387
  const s = await stat7(entryPath);
20006
20388
  entries2.push({
20007
20389
  name,
@@ -20030,7 +20412,7 @@ app23.get("/", requireAdminSession, async (c) => {
20030
20412
  const displayPath = buildDisplayPath(relPath, accountNames);
20031
20413
  if (groupReq || isAccountRoot(relPath)) {
20032
20414
  const acctId = relPath.split("/")[1] ?? accountId;
20033
- const schemaMd = await readFile8(join37(absolute, "SCHEMA.md"), "utf8").catch(() => null);
20415
+ const schemaMd = await readFile9(join38(absolute, "SCHEMA.md"), "utf8").catch(() => null);
20034
20416
  const groups = classifyAccountRoot(schemaMd, entries2.map((e) => e.name));
20035
20417
  console.error(
20036
20418
  `[data-schema] op=classify account=${acctId} status=${groups.parsed ? "ok" : "parse-failed"} reason=${groups.reason} entries=${entries2.length} home=${groups.home.join(",") || "none"} system=${groups.system.length} unknown=${groups.unknown.join(",") || "none"}`
@@ -20068,7 +20450,7 @@ app23.get("/", requireAdminSession, async (c) => {
20068
20450
  for (const name of homeDirs) {
20069
20451
  const base = byName.get(name);
20070
20452
  try {
20071
- const dirents = await readdir4(join37(absolute, name), { withFileTypes: true });
20453
+ const dirents = await readdir4(join38(absolute, name), { withFileTypes: true });
20072
20454
  const visible = dirents.filter((d) => !d.name.startsWith("."));
20073
20455
  visible.sort((a, b) => {
20074
20456
  const ad = a.isDirectory() ? 0 : 1;
@@ -20133,7 +20515,7 @@ app23.get("/download", requireAdminSession, async (c) => {
20133
20515
  console.error(`[data] op=scratchpad-no-session sessionId="${sessionId.slice(0, 8)}\u2026"`);
20134
20516
  return c.json({ error: "Not found" }, 404);
20135
20517
  }
20136
- const meta = readSidecarMeta(join37(projectDir, `${sessionId}.meta.json`));
20518
+ const meta = readSidecarMeta(join38(projectDir, `${sessionId}.meta.json`));
20137
20519
  if (!meta.accountId || meta.accountId !== accountId) {
20138
20520
  console.error(`[data] account-scope-blocked root="scratchpad" sessionId="${sessionId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
20139
20521
  return c.json({ error: "Not found" }, 404);
@@ -20228,7 +20610,7 @@ async function* walkRegularFiles(dirAbsolute) {
20228
20610
  const dirents = await readdir4(dirAbsolute, { withFileTypes: true });
20229
20611
  for (const d of dirents) {
20230
20612
  if (d.isSymbolicLink()) continue;
20231
- const child = join37(dirAbsolute, d.name);
20613
+ const child = join38(dirAbsolute, d.name);
20232
20614
  if (d.isDirectory()) {
20233
20615
  yield* walkRegularFiles(child);
20234
20616
  continue;
@@ -20257,7 +20639,7 @@ app23.get("/download-zip", requireAdminSession, async (c) => {
20257
20639
  if (entries2.length >= maxFiles) return c.json({ error: `Too many files (max ${maxFiles})` }, 413);
20258
20640
  total += size;
20259
20641
  if (total > maxTotalBytes) return c.json({ error: "Selection too large to zip" }, 413);
20260
- entries2.push({ name: member, data: await readFile8(absolute) });
20642
+ entries2.push({ name: member, data: await readFile9(absolute) });
20261
20643
  return null;
20262
20644
  };
20263
20645
  for (const rawPath of rawPaths) {
@@ -20338,7 +20720,7 @@ async function resolveUploadTarget(c, accountId, uid) {
20338
20720
  const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
20339
20721
  if (!base.ok) return { ok: false, status: base.status, error: base.error };
20340
20722
  const relDir = relpath ? dirname13(relpath) : ".";
20341
- const destRel = relDir === "." ? base.relative : join37(base.relative, relDir);
20723
+ const destRel = relDir === "." ? base.relative : join38(base.relative, relDir);
20342
20724
  if (crossesForeignAccountPartition(destRel, accountId)) {
20343
20725
  console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
20344
20726
  return { ok: false, status: 404, error: "Not found" };
@@ -20410,7 +20792,7 @@ app23.post("/upload", requireAdminSession, async (c) => {
20410
20792
  out.once("close", () => res());
20411
20793
  out.destroy();
20412
20794
  });
20413
- await unlink3(tmpPath).catch(() => {
20795
+ await unlink4(tmpPath).catch(() => {
20414
20796
  });
20415
20797
  const tempRemoved = !existsSync35(tmpPath);
20416
20798
  console.error(`[data-upload] op=cleanup uid=${uid} tempRemoved=${tempRemoved}`);
@@ -20456,7 +20838,7 @@ app23.post("/upload", requireAdminSession, async (c) => {
20456
20838
  out.once("error", rej);
20457
20839
  out.end(() => res());
20458
20840
  });
20459
- await rename2(tmpPath, destPath);
20841
+ await rename3(tmpPath, destPath);
20460
20842
  } catch (err) {
20461
20843
  const message = err instanceof Error ? err.message : String(err);
20462
20844
  console.error(`[data-upload] op=error uid=${uid} err="${message}" token=${token} rel="${relpath ?? ""}"`);
@@ -20484,7 +20866,7 @@ async function discardChunkUpload(uploadId, state) {
20484
20866
  state.out.once("close", () => res());
20485
20867
  state.out.destroy();
20486
20868
  });
20487
- await unlink3(state.tmpPath).catch(() => {
20869
+ await unlink4(state.tmpPath).catch(() => {
20488
20870
  });
20489
20871
  const tempRemoved = !existsSync35(state.tmpPath);
20490
20872
  console.error(`[data-upload] op=cleanup uid=${uploadId} tempRemoved=${tempRemoved}`);
@@ -20612,11 +20994,11 @@ async function acceptChunk(c, uploadId, state, seq, body, ceiling) {
20612
20994
  state.out.once("error", rej);
20613
20995
  state.out.end(() => res());
20614
20996
  });
20615
- await rename2(state.tmpPath, state.destPath);
20997
+ await rename3(state.tmpPath, state.destPath);
20616
20998
  } catch (err) {
20617
20999
  const message = err instanceof Error ? err.message : String(err);
20618
21000
  console.error(`[data-upload] op=error uid=${uploadId} err="${message}" token=${state.token} rel="${state.relpath ?? ""}"`);
20619
- await unlink3(state.tmpPath).catch(() => {
21001
+ await unlink4(state.tmpPath).catch(() => {
20620
21002
  });
20621
21003
  return c.json({ error: message }, 500);
20622
21004
  }
@@ -20668,7 +21050,7 @@ async function sweepStaleUploadTemps() {
20668
21050
  }
20669
21051
  for (const name of entries2) {
20670
21052
  try {
20671
- await unlink3(resolve27(tmpDir, name));
21053
+ await unlink4(resolve27(tmpDir, name));
20672
21054
  removed++;
20673
21055
  } catch {
20674
21056
  }
@@ -20715,17 +21097,17 @@ app23.delete("/", requireAdminSession, async (c) => {
20715
21097
  const dot = base.lastIndexOf(".");
20716
21098
  const stem = dot === -1 ? base : base.slice(0, dot);
20717
21099
  const containerDir = dirname13(absolute);
20718
- const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join37(containerDir, `${stem}.meta.json`) : null;
20719
- const isAttachmentContainer = UUID_RE4.test(stem) && basename11(containerDir) === stem;
20720
- await unlink3(absolute);
21100
+ const sidecarPath = UUID_RE5.test(stem) && base !== `${stem}.meta.json` ? join38(containerDir, `${stem}.meta.json`) : null;
21101
+ const isAttachmentContainer = UUID_RE5.test(stem) && basename11(containerDir) === stem;
21102
+ await unlink4(absolute);
20721
21103
  if (sidecarPath) {
20722
21104
  try {
20723
- await unlink3(sidecarPath);
21105
+ await unlink4(sidecarPath);
20724
21106
  } catch {
20725
21107
  }
20726
21108
  }
20727
21109
  if (isAttachmentContainer) {
20728
- await unlink3(join37(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
21110
+ await unlink4(join38(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
20729
21111
  });
20730
21112
  await rmdir(containerDir).catch(() => {
20731
21113
  });
@@ -20832,7 +21214,7 @@ app23.post("/rename", requireAdminSession, async (c) => {
20832
21214
  if (e.code === "ENOENT") collision = false;
20833
21215
  }
20834
21216
  if (collision) return c.json({ error: "A file or folder with that name already exists" }, 409);
20835
- await rename2(src.absolute, destAbs);
21217
+ await rename3(src.absolute, destAbs);
20836
21218
  } catch (err) {
20837
21219
  const code = err.code;
20838
21220
  if (code === "ENOENT") return c.json({ error: "Not found" }, 404);
@@ -21835,7 +22217,7 @@ function isHiddenByDefault(label) {
21835
22217
  // server/lib/top-level-labels.ts
21836
22218
  var import_dist5 = __toESM(require_dist4(), 1);
21837
22219
  import { readdirSync as readdirSync24, readFileSync as readFileSync36 } from "fs";
21838
- import { join as join38, resolve as resolve28 } from "path";
22220
+ import { join as join39, resolve as resolve28 } from "path";
21839
22221
  var STATIC_TOP_LEVEL_LABELS = Object.freeze(
21840
22222
  /* @__PURE__ */ new Set([
21841
22223
  // Base-schema infra (schema-base.md has no top-level section).
@@ -21939,7 +22321,7 @@ function parseTopLevelLabels(content) {
21939
22321
  }
21940
22322
  function resolveReferencesDir() {
21941
22323
  if (process.env.MAXY_PLATFORM_ROOT) {
21942
- return join38(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
22324
+ return join39(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
21943
22325
  }
21944
22326
  return resolve28(import.meta.dirname, "../../../plugins/memory/references");
21945
22327
  }
@@ -21949,7 +22331,7 @@ function parseTableTopLevelLabels(referencesDir) {
21949
22331
  try {
21950
22332
  const fileNames = readdirSync24(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
21951
22333
  for (const fileName of fileNames) {
21952
- const content = readFileSync36(join38(referencesDir, fileName), "utf-8");
22334
+ const content = readFileSync36(join39(referencesDir, fileName), "utf-8");
21953
22335
  const parsed = parseTopLevelLabels(content);
21954
22336
  if (parsed.length > 0) contributingFiles.push(fileName);
21955
22337
  for (const label of parsed) labels.add(label);
@@ -23288,11 +23670,11 @@ var sidebar_artefacts_default = app30;
23288
23670
 
23289
23671
  // server/channel-session-override.ts
23290
23672
  import { readFileSync as readFileSync37, writeFileSync as writeFileSync14, renameSync as renameSync10 } from "fs";
23291
- import { join as join39 } from "path";
23673
+ import { join as join40 } from "path";
23292
23674
  var FILE2 = "channel-session-override.json";
23293
23675
  var UUID3 = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
23294
23676
  function channelOverridePath(accountDir) {
23295
- return join39(accountDir, FILE2);
23677
+ return join40(accountDir, FILE2);
23296
23678
  }
23297
23679
  function senderKey(channel, senderId) {
23298
23680
  return `${channel}:${senderId}`;
@@ -23688,24 +24070,24 @@ var session_rc_spawn_default = app36;
23688
24070
  import { randomUUID as randomUUID12 } from "crypto";
23689
24071
 
23690
24072
  // server/wa-descriptor.ts
23691
- import { resolve as resolve30, join as join40 } from "path";
24073
+ import { resolve as resolve30, join as join41 } from "path";
23692
24074
  function waGatewayUrl() {
23693
24075
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
23694
24076
  }
23695
24077
  function waServerPath() {
23696
- return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ?? join40(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
24078
+ return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ?? join41(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
23697
24079
  }
23698
24080
  function waChannelDescriptor(senderId) {
23699
24081
  return { senderId, gatewayUrl: waGatewayUrl(), serverPath: waServerPath() };
23700
24082
  }
23701
24083
 
23702
24084
  // server/telegram-descriptor.ts
23703
- import { resolve as resolve31, join as join41 } from "path";
24085
+ import { resolve as resolve31, join as join42 } from "path";
23704
24086
  function telegramGatewayUrl() {
23705
24087
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
23706
24088
  }
23707
24089
  function telegramServerPath() {
23708
- return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join41(__dirname, ".."), "services/telegram-channel/dist/server.js");
24090
+ return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join42(__dirname, ".."), "services/telegram-channel/dist/server.js");
23709
24091
  }
23710
24092
  function telegramChannelDescriptor(senderId) {
23711
24093
  return { senderId, gatewayUrl: telegramGatewayUrl(), serverPath: telegramServerPath() };
@@ -23870,7 +24252,7 @@ app37.post("/", requireAdminSession, async (c) => {
23870
24252
  var session_reseat_default = app37;
23871
24253
 
23872
24254
  // server/routes/admin/system-stats.ts
23873
- import { readFile as readFile9 } from "fs/promises";
24255
+ import { readFile as readFile10 } from "fs/promises";
23874
24256
  import { cpus, loadavg, totalmem, freemem } from "os";
23875
24257
  function parseCpuStat(blob) {
23876
24258
  const line = blob.split("\n", 1)[0] ?? "";
@@ -23914,11 +24296,11 @@ function parseMeminfo(blob) {
23914
24296
  }
23915
24297
  var SAMPLE_DELAY_MS = 100;
23916
24298
  async function sampleLinux() {
23917
- const a = parseCpuStat(await readFile9("/proc/stat", "utf-8"));
24299
+ const a = parseCpuStat(await readFile10("/proc/stat", "utf-8"));
23918
24300
  await new Promise((r) => setTimeout(r, SAMPLE_DELAY_MS));
23919
- const b = parseCpuStat(await readFile9("/proc/stat", "utf-8"));
23920
- const meminfo = parseMeminfo(await readFile9("/proc/meminfo", "utf-8"));
23921
- const loadavgRaw = (await readFile9("/proc/loadavg", "utf-8")).trim();
24301
+ const b = parseCpuStat(await readFile10("/proc/stat", "utf-8"));
24302
+ const meminfo = parseMeminfo(await readFile10("/proc/meminfo", "utf-8"));
24303
+ const loadavgRaw = (await readFile10("/proc/loadavg", "utf-8")).trim();
23922
24304
  const [l1, l5, l15] = loadavgRaw.split(/\s+/, 3).map(Number);
23923
24305
  if (![l1, l5, l15].every(Number.isFinite)) {
23924
24306
  throw new Error(`malformed /proc/loadavg: ${loadavgRaw}`);
@@ -23992,10 +24374,10 @@ var system_stats_default = app38;
23992
24374
 
23993
24375
  // server/routes/admin/health.ts
23994
24376
  import { existsSync as existsSync37, readFileSync as readFileSync38 } from "fs";
23995
- import { resolve as resolve32, join as join42 } from "path";
24377
+ import { resolve as resolve32, join as join43 } from "path";
23996
24378
  var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve32(process.cwd(), "..");
23997
24379
  var brandHostname = "maxy";
23998
- var brandJsonPath = join42(PLATFORM_ROOT6, "config", "brand.json");
24380
+ var brandJsonPath = join43(PLATFORM_ROOT6, "config", "brand.json");
23999
24381
  if (existsSync37(brandJsonPath)) {
24000
24382
  try {
24001
24383
  const brand = JSON.parse(readFileSync38(brandJsonPath, "utf-8"));
@@ -24785,7 +25167,7 @@ var browser_default = app46;
24785
25167
 
24786
25168
  // server/routes/admin/calendar.ts
24787
25169
  import { existsSync as existsSync38 } from "fs";
24788
- import { join as join44 } from "path";
25170
+ import { join as join45 } from "path";
24789
25171
 
24790
25172
  // server/lib/calendar-ics.ts
24791
25173
  var CRLF = "\r\n";
@@ -24885,7 +25267,7 @@ function countVEvents(ics) {
24885
25267
 
24886
25268
  // server/lib/calendar-availability.ts
24887
25269
  import { readFileSync as readFileSync39 } from "fs";
24888
- import { join as join43 } from "path";
25270
+ import { join as join44 } from "path";
24889
25271
  var AVAILABILITY_FILENAME = "calendar-availability.json";
24890
25272
  var REQUIRED_KEYS = [
24891
25273
  "timezone",
@@ -24894,7 +25276,7 @@ var REQUIRED_KEYS = [
24894
25276
  "weekly"
24895
25277
  ];
24896
25278
  function readAvailabilityConfig(accountDir) {
24897
- const path3 = join43(accountDir, AVAILABILITY_FILENAME);
25279
+ const path3 = join44(accountDir, AVAILABILITY_FILENAME);
24898
25280
  let raw;
24899
25281
  try {
24900
25282
  raw = readFileSync39(path3, "utf-8");
@@ -25257,7 +25639,7 @@ app47.get("/booking-link", requireAdminSession, (c) => {
25257
25639
  }
25258
25640
  const id82 = account.accountId.slice(0, 8);
25259
25641
  try {
25260
- if (!existsSync38(join44(account.accountDir, AVAILABILITY_FILENAME))) {
25642
+ if (!existsSync38(join45(account.accountDir, AVAILABILITY_FILENAME))) {
25261
25643
  console.log(`[calendar] op=booking-link accountId=${id82} bookingDomain=none source=availability-config`);
25262
25644
  return c.json({ bookingDomain: null });
25263
25645
  }
@@ -25657,7 +26039,7 @@ async function computeTaskList(accountId) {
25657
26039
  { accountId }
25658
26040
  );
25659
26041
  const graphTotal = totalResult.records.length > 0 ? toNum(totalResult.records[0].get("total")) : 0;
25660
- const open = [];
26042
+ const open3 = [];
25661
26043
  const completed = [];
25662
26044
  let missingTaskId = 0;
25663
26045
  let missingCreatedAt = 0;
@@ -25692,7 +26074,7 @@ async function computeTaskList(accountId) {
25692
26074
  assigneeName
25693
26075
  };
25694
26076
  if (COMPLETED.has(status)) completed.push(row);
25695
- else if (!HIDDEN_FROM_OPEN.has(status)) open.push(row);
26077
+ else if (!HIDDEN_FROM_OPEN.has(status)) open3.push(row);
25696
26078
  }
25697
26079
  const returned = result.records.length;
25698
26080
  if (returned < graphTotal) {
@@ -25701,9 +26083,9 @@ async function computeTaskList(accountId) {
25701
26083
  );
25702
26084
  }
25703
26085
  console.log(
25704
- `${TAG40} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned}`
26086
+ `${TAG40} op=list account=${accountId} returned=${returned} graphTotal=${graphTotal} open=${open3.length} completed=${completed.length} missingTaskId=${missingTaskId} missingCreatedAt=${missingCreatedAt} assigned=${assigned}`
25705
26087
  );
25706
- return { open, completed };
26088
+ return { open: open3, completed };
25707
26089
  } catch (err) {
25708
26090
  console.error(`${TAG40} op=list error="${err instanceof Error ? err.message : String(err)}"`);
25709
26091
  return null;
@@ -25744,14 +26126,14 @@ app51.post("/", requireAdminSession, async (c) => {
25744
26126
  console.error(`${TAG41} op=start taskId=${taskId} accountId=${accountId} result=task-not-found`);
25745
26127
  return c.json({ error: "task-not-found" }, 404);
25746
26128
  }
25747
- const open = await session.run(
26129
+ const open3 = await session.run(
25748
26130
  `MATCH (te:TimeEntry {accountId: $accountId, taskId: $taskId}) WHERE te.endedAt IS NULL
25749
26131
  RETURN te.entryId AS entryId, te.startedAt AS startedAt
25750
26132
  ORDER BY te.startedAt LIMIT 1`,
25751
26133
  { accountId, taskId }
25752
26134
  );
25753
- const priorEntryId = open.records[0]?.get("entryId");
25754
- const priorStartedAt = open.records[0]?.get("startedAt");
26135
+ const priorEntryId = open3.records[0]?.get("entryId");
26136
+ const priorStartedAt = open3.records[0]?.get("startedAt");
25755
26137
  if (priorEntryId) {
25756
26138
  console.log(`${TAG41} op=start taskId=${taskId} accountId=${accountId} result=already-running`);
25757
26139
  invalidate("tasks-list", accountId);
@@ -25799,14 +26181,14 @@ app52.post("/", requireAdminSession, async (c) => {
25799
26181
  const now = (/* @__PURE__ */ new Date()).toISOString();
25800
26182
  const session = getSession();
25801
26183
  try {
25802
- const open = await session.run(
26184
+ const open3 = await session.run(
25803
26185
  `MATCH (te:TimeEntry {taskId: $taskId, accountId: $accountId}) WHERE te.endedAt IS NULL
25804
26186
  RETURN te.entryId AS entryId, te.startedAt AS startedAt
25805
26187
  ORDER BY te.startedAt LIMIT 1`,
25806
26188
  { taskId, accountId }
25807
26189
  );
25808
- const entryId = open.records[0]?.get("entryId");
25809
- const startedAt = open.records[0]?.get("startedAt");
26190
+ const entryId = open3.records[0]?.get("entryId");
26191
+ const startedAt = open3.records[0]?.get("startedAt");
25810
26192
  if (!entryId || !startedAt) {
25811
26193
  const cur = await session.run(
25812
26194
  `MATCH (t:Task {taskId: $taskId, accountId: $accountId})
@@ -26807,7 +27189,7 @@ var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
26807
27189
 
26808
27190
  // app/lib/brand-config.ts
26809
27191
  import { existsSync as existsSync42, readFileSync as readFileSync44 } from "fs";
26810
- import { join as join45 } from "path";
27192
+ import { join as join46 } from "path";
26811
27193
  var cached2 = null;
26812
27194
  var cachedAttempted = false;
26813
27195
  function readBrandConfig() {
@@ -26815,7 +27197,7 @@ function readBrandConfig() {
26815
27197
  cachedAttempted = true;
26816
27198
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
26817
27199
  if (!platformRoot5) return null;
26818
- const brandPath = join45(platformRoot5, "config", "brand.json");
27200
+ const brandPath = join46(platformRoot5, "config", "brand.json");
26819
27201
  if (!existsSync42(brandPath)) return null;
26820
27202
  try {
26821
27203
  cached2 = JSON.parse(readFileSync44(brandPath, "utf-8"));
@@ -27317,7 +27699,7 @@ var visitor_event_default = app65;
27317
27699
  // server/routes/session.ts
27318
27700
  import { resolve as resolve37 } from "path";
27319
27701
  import { existsSync as existsSync43, writeFileSync as writeFileSync16, mkdirSync as mkdirSync10 } from "fs";
27320
- var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
27702
+ var UUID_RE6 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
27321
27703
  function writeBrandingCache(accountId, agentSlug, branding) {
27322
27704
  try {
27323
27705
  const cacheDir = resolve37(MAXY_DIR, "branding-cache", accountId);
@@ -27332,7 +27714,7 @@ function parseVisitorCookie2(cookieHeader) {
27332
27714
  const match = cookieHeader.match(/(?:^|;\s*)maxy_visitor=([^;]*)/);
27333
27715
  if (!match) return null;
27334
27716
  const value = decodeURIComponent(match[1]).trim();
27335
- return UUID_RE5.test(value) ? value : null;
27717
+ return UUID_RE6.test(value) ? value : null;
27336
27718
  }
27337
27719
  function parseAccessSessionId2(cookieHeader) {
27338
27720
  if (!cookieHeader) return null;
@@ -27430,7 +27812,7 @@ app66.post("/", async (c) => {
27430
27812
  );
27431
27813
  }
27432
27814
  }
27433
- if (body.session_key && typeof body.session_key === "string" && UUID_RE5.test(body.session_key)) {
27815
+ if (body.session_key && typeof body.session_key === "string" && UUID_RE6.test(body.session_key)) {
27434
27816
  if (visitorId) {
27435
27817
  const recent = await findRecentConversation(visitorId, accountId, agentSlug).catch(() => null);
27436
27818
  if (recent) {
@@ -27570,9 +27952,9 @@ function computeOpenSlots(config, busy, fromISO, toISO) {
27570
27952
  const weekday = WEEKDAYS[new Date(Date.UTC(y, m - 1, d)).getUTCDay()];
27571
27953
  const windows = config.weekly[weekday] ?? [];
27572
27954
  for (const [openStr, closeStr] of windows) {
27573
- const open = parseHHMM(openStr);
27955
+ const open3 = parseHHMM(openStr);
27574
27956
  const close = parseHHMM(closeStr);
27575
- const openUtc = zonedWallClockToUtc(y, m, d, open.hh, open.mm, tz).getTime();
27957
+ const openUtc = zonedWallClockToUtc(y, m, d, open3.hh, open3.mm, tz).getTime();
27576
27958
  const closeUtc = zonedWallClockToUtc(y, m, d, close.hh, close.mm, tz).getTime();
27577
27959
  for (let s = openUtc; s + durMs <= closeUtc; s += durMs) {
27578
27960
  const slotEnd = s + durMs;
@@ -27659,8 +28041,8 @@ var calendar_public_default = app67;
27659
28041
 
27660
28042
  // server/routes/portal-fetch.ts
27661
28043
  import { createReadStream as createReadStream3 } from "fs";
27662
- import { stat as stat9, readFile as readFile10, realpath } from "fs/promises";
27663
- import { join as join46, resolve as resolve38, sep as sep10 } from "path";
28044
+ import { stat as stat9, readFile as readFile11, realpath } from "fs/promises";
28045
+ import { join as join47, resolve as resolve38, sep as sep10 } from "path";
27664
28046
  import { Readable as Readable3 } from "stream";
27665
28047
  var app68 = new Hono();
27666
28048
  var TAG50 = "[portal-fetch]";
@@ -27716,7 +28098,7 @@ async function readAccountSecret(accountId) {
27716
28098
  const path3 = resolve38(DATA_ROOT, "accounts", accountId, "secrets", "data-portal.env");
27717
28099
  let text;
27718
28100
  try {
27719
- text = await readFile10(path3, "utf8");
28101
+ text = await readFile11(path3, "utf8");
27720
28102
  } catch {
27721
28103
  console.error(`${TAG50} op=no-secret account="${accountId}" path="${path3}"`);
27722
28104
  return "";
@@ -27733,7 +28115,7 @@ function isValidAccountId2(value) {
27733
28115
  }
27734
28116
  async function readExposeFolders2(accountDir) {
27735
28117
  try {
27736
- const cfg = JSON.parse(await readFile10(join46(accountDir, "data-portal.json"), "utf8"));
28118
+ const cfg = JSON.parse(await readFile11(join47(accountDir, "data-portal.json"), "utf8"));
27737
28119
  return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
27738
28120
  } catch {
27739
28121
  return [];
@@ -27742,7 +28124,7 @@ async function readExposeFolders2(accountDir) {
27742
28124
  async function resolveFetchTarget(accountDir, relPath, ownerId) {
27743
28125
  let schemaText = null;
27744
28126
  try {
27745
- schemaText = await readFile10(join46(accountDir, "SCHEMA.md"), "utf8");
28127
+ schemaText = await readFile11(join47(accountDir, "SCHEMA.md"), "utf8");
27746
28128
  } catch {
27747
28129
  schemaText = null;
27748
28130
  }
@@ -27913,7 +28295,7 @@ function startTimeEntryCensus(openSession, opts = {}) {
27913
28295
 
27914
28296
  // app/lib/ledger-census.ts
27915
28297
  import { readdirSync as readdirSync28, readFileSync as readFileSync45, statSync as statSync19 } from "fs";
27916
- import { join as join47 } from "path";
28298
+ import { join as join48 } from "path";
27917
28299
 
27918
28300
  // ../lib/ledger-core/dist/reconcile.js
27919
28301
  var LEDGER_INDEX_NAMES = [
@@ -27967,7 +28349,7 @@ function countWriteRejects24h(logDir, now) {
27967
28349
  }
27968
28350
  let total = 0;
27969
28351
  for (const name of entries2) {
27970
- const path3 = join47(logDir, name);
28352
+ const path3 = join48(logDir, name);
27971
28353
  try {
27972
28354
  if (now - statSync19(path3).mtimeMs > DAY_MS) continue;
27973
28355
  for (const line of readFileSync45(path3, "utf8").split("\n")) {
@@ -28341,7 +28723,7 @@ async function startFileWatcher(opts = {}) {
28341
28723
  }
28342
28724
 
28343
28725
  // app/lib/migrate-uploads.ts
28344
- import { mkdir as mkdir6, readdir as readdir6, rename as rename3, rm as rm3 } from "fs/promises";
28726
+ import { mkdir as mkdir6, readdir as readdir6, rename as rename4, rm as rm3 } from "fs/promises";
28345
28727
  import { dirname as dirname15, relative as relative7, resolve as resolve40 } from "path";
28346
28728
  var ACCOUNT_UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
28347
28729
  async function walkFiles(dir) {
@@ -28375,7 +28757,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
28375
28757
  const suffix = relative7(srcDir, oldAbs);
28376
28758
  const newAbs = resolve40(destDir, suffix);
28377
28759
  await mkdir6(dirname15(newAbs), { recursive: true });
28378
- await rename3(oldAbs, newAbs);
28760
+ await rename4(oldAbs, newAbs);
28379
28761
  moved++;
28380
28762
  const oldRel = relative7(dataRoot, oldAbs);
28381
28763
  const newRel = relative7(dataRoot, newAbs);
@@ -28464,9 +28846,9 @@ async function migrateUploads(opts = {}) {
28464
28846
  }
28465
28847
 
28466
28848
  // app/lib/migrate-admin-webchat-sidecars.ts
28467
- import { readdir as readdir7, readFile as readFile11, rename as rename4, writeFile as writeFile5, unlink as unlink4 } from "fs/promises";
28849
+ import { readdir as readdir7, readFile as readFile12, rename as rename5, writeFile as writeFile6, unlink as unlink5 } from "fs/promises";
28468
28850
  import { existsSync as existsSync44 } from "fs";
28469
- import { join as join48 } from "path";
28851
+ import { join as join49 } from "path";
28470
28852
  var ADMIN_ROLE2 = "admin";
28471
28853
  var WEBCHAT_CHANNEL2 = "webchat";
28472
28854
  var SESSION_META_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
@@ -28477,7 +28859,7 @@ var defaultResolveName = async (_accountId, userId) => {
28477
28859
  async function readRaw3(path3) {
28478
28860
  let raw;
28479
28861
  try {
28480
- raw = await readFile11(path3, "utf8");
28862
+ raw = await readFile12(path3, "utf8");
28481
28863
  } catch {
28482
28864
  return null;
28483
28865
  }
@@ -28491,11 +28873,11 @@ async function readRaw3(path3) {
28491
28873
  async function writeRaw(path3, obj) {
28492
28874
  const tmp = `${path3}.tmp.${process.pid}.${Date.now()}`;
28493
28875
  try {
28494
- await writeFile5(tmp, JSON.stringify(obj, null, 2), "utf8");
28495
- await rename4(tmp, path3);
28876
+ await writeFile6(tmp, JSON.stringify(obj, null, 2), "utf8");
28877
+ await rename5(tmp, path3);
28496
28878
  } catch (err) {
28497
28879
  try {
28498
- if (existsSync44(tmp)) await unlink4(tmp);
28880
+ if (existsSync44(tmp)) await unlink5(tmp);
28499
28881
  } catch {
28500
28882
  }
28501
28883
  throw err;
@@ -28511,7 +28893,7 @@ async function collectLiveSidecars(projectsRoot) {
28511
28893
  }
28512
28894
  for (const slug of slugs) {
28513
28895
  if (!slug.isDirectory()) continue;
28514
- const slugDir = join48(projectsRoot, slug.name);
28896
+ const slugDir = join49(projectsRoot, slug.name);
28515
28897
  let entries2;
28516
28898
  try {
28517
28899
  entries2 = await readdir7(slugDir, { withFileTypes: true });
@@ -28520,9 +28902,9 @@ async function collectLiveSidecars(projectsRoot) {
28520
28902
  }
28521
28903
  for (const entry of entries2) {
28522
28904
  if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
28523
- out.push(join48(slugDir, entry.name));
28905
+ out.push(join49(slugDir, entry.name));
28524
28906
  } else if (entry.isDirectory() && entry.name === "subagents") {
28525
- const subDir = join48(slugDir, entry.name);
28907
+ const subDir = join49(slugDir, entry.name);
28526
28908
  let subs;
28527
28909
  try {
28528
28910
  subs = await readdir7(subDir, { withFileTypes: true });
@@ -28530,7 +28912,7 @@ async function collectLiveSidecars(projectsRoot) {
28530
28912
  continue;
28531
28913
  }
28532
28914
  for (const s of subs) {
28533
- if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join48(subDir, s.name));
28915
+ if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join49(subDir, s.name));
28534
28916
  }
28535
28917
  }
28536
28918
  }
@@ -28542,7 +28924,7 @@ function shortId(path3) {
28542
28924
  return base.slice(0, 8);
28543
28925
  }
28544
28926
  async function migrateAdminWebchatSidecars(opts = {}) {
28545
- const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join48(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
28927
+ const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join49(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
28546
28928
  const usersFile = opts.usersFile ?? USERS_FILE;
28547
28929
  const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
28548
28930
  const resolveName = opts.resolveName ?? defaultResolveName;
@@ -28616,6 +28998,129 @@ async function migrateAdminWebchatSidecars(opts = {}) {
28616
28998
  return result;
28617
28999
  }
28618
29000
 
29001
+ // app/lib/migrate-sidecar-account-ids.ts
29002
+ import { readdir as readdir8, readFile as readFile13, rename as rename6, writeFile as writeFile7, unlink as unlink6 } from "fs/promises";
29003
+ import { existsSync as existsSync45 } from "fs";
29004
+ import { join as join50 } from "path";
29005
+ var SESSION_META_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.meta\.json$/i;
29006
+ function projectSlugForCwd(cwd) {
29007
+ return cwd.replace(/\//g, "-");
29008
+ }
29009
+ async function readRaw4(path3) {
29010
+ let raw;
29011
+ try {
29012
+ raw = await readFile13(path3, "utf8");
29013
+ } catch {
29014
+ return null;
29015
+ }
29016
+ try {
29017
+ const parsed = JSON.parse(raw);
29018
+ return parsed && typeof parsed === "object" ? parsed : null;
29019
+ } catch {
29020
+ return null;
29021
+ }
29022
+ }
29023
+ async function writeRaw2(path3, obj) {
29024
+ const tmp = `${path3}.tmp.${process.pid}.${Date.now()}`;
29025
+ try {
29026
+ await writeFile7(tmp, JSON.stringify(obj, null, 2), "utf8");
29027
+ await rename6(tmp, path3);
29028
+ } catch (err) {
29029
+ try {
29030
+ if (existsSync45(tmp)) await unlink6(tmp);
29031
+ } catch {
29032
+ }
29033
+ throw err;
29034
+ }
29035
+ }
29036
+ function shortId2(path3) {
29037
+ const base = path3.slice(path3.lastIndexOf("/") + 1).replace(/\.meta\.json$/, "");
29038
+ return base.slice(0, 8);
29039
+ }
29040
+ async function collectSidecars(projectsRoot) {
29041
+ const out = [];
29042
+ let slugs;
29043
+ try {
29044
+ slugs = await readdir8(projectsRoot, { withFileTypes: true });
29045
+ } catch {
29046
+ return out;
29047
+ }
29048
+ for (const slug of slugs) {
29049
+ if (!slug.isDirectory()) continue;
29050
+ const slugDir = join50(projectsRoot, slug.name);
29051
+ let entries2;
29052
+ try {
29053
+ entries2 = await readdir8(slugDir, { withFileTypes: true });
29054
+ } catch {
29055
+ continue;
29056
+ }
29057
+ for (const entry of entries2) {
29058
+ if (entry.isFile() && SESSION_META_RE2.test(entry.name)) {
29059
+ out.push({ path: join50(slugDir, entry.name), slug: slug.name });
29060
+ } else if (entry.isDirectory() && (entry.name === "subagents" || entry.name === "archive")) {
29061
+ const subDir = join50(slugDir, entry.name);
29062
+ let subs;
29063
+ try {
29064
+ subs = await readdir8(subDir, { withFileTypes: true });
29065
+ } catch {
29066
+ continue;
29067
+ }
29068
+ for (const s of subs) {
29069
+ if (s.isFile() && SESSION_META_RE2.test(s.name)) {
29070
+ out.push({ path: join50(subDir, s.name), slug: slug.name });
29071
+ }
29072
+ }
29073
+ }
29074
+ }
29075
+ }
29076
+ return out;
29077
+ }
29078
+ async function migrateSidecarAccountIds(opts = {}) {
29079
+ const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join50(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
29080
+ const accounts = opts.accounts ?? listValidAccounts();
29081
+ const result = {
29082
+ scanned: 0,
29083
+ backfilled: 0,
29084
+ skippedHasId: 0,
29085
+ skippedUnknownSlug: 0,
29086
+ verified: 0
29087
+ };
29088
+ if (!projectsRoot) {
29089
+ console.error("[sidecar-account-backfill] skip reason=no-projects-root");
29090
+ return result;
29091
+ }
29092
+ const accountBySlug = /* @__PURE__ */ new Map();
29093
+ for (const a of accounts) accountBySlug.set(projectSlugForCwd(a.accountDir), a.accountId);
29094
+ for (const { path: path3, slug } of await collectSidecars(projectsRoot)) {
29095
+ const raw = await readRaw4(path3);
29096
+ if (!raw) continue;
29097
+ result.scanned++;
29098
+ if (typeof raw.accountId === "string" && raw.accountId.length > 0) {
29099
+ result.skippedHasId++;
29100
+ continue;
29101
+ }
29102
+ const accountId = accountBySlug.get(slug);
29103
+ if (!accountId) {
29104
+ result.skippedUnknownSlug++;
29105
+ console.error(`[sidecar-account-backfill] skip sessionId=${shortId2(path3)} reason=slug-not-in-registry slug=${slug}`);
29106
+ continue;
29107
+ }
29108
+ raw.accountId = accountId;
29109
+ await writeRaw2(path3, raw);
29110
+ result.backfilled++;
29111
+ const back = await readRaw4(path3);
29112
+ if (back && back.accountId === accountId) {
29113
+ result.verified++;
29114
+ } else {
29115
+ console.error(`[sidecar-account-backfill] post-write-verify-failed sessionId=${shortId2(path3)} accountId=${accountId.slice(0, 8)}`);
29116
+ }
29117
+ }
29118
+ console.error(
29119
+ `[sidecar-account-backfill] op=sidecar-account scanned=${result.scanned} backfilled=${result.backfilled} skipped-has-id=${result.skippedHasId} skipped-unknown-slug=${result.skippedUnknownSlug} verified=${result.verified}`
29120
+ );
29121
+ return result;
29122
+ }
29123
+
28619
29124
  // app/lib/whatsapp/gateway/inbound-hub.ts
28620
29125
  var InboundHub = class {
28621
29126
  senders = /* @__PURE__ */ new Map();
@@ -30841,7 +31346,7 @@ function buildTelegramSpawnRequest(input) {
30841
31346
 
30842
31347
  // app/lib/telegram/outbound/send-document.ts
30843
31348
  import { realpathSync as realpathSync10 } from "fs";
30844
- import { readFile as readFile12, stat as stat11 } from "fs/promises";
31349
+ import { readFile as readFile14, stat as stat11 } from "fs/promises";
30845
31350
  import { resolve as resolve42, basename as basename13 } from "path";
30846
31351
  var TAG56 = "[telegram:outbound]";
30847
31352
  var TELEGRAM_DOCUMENT_MAX_BYTES = 50 * 1024 * 1024;
@@ -30891,7 +31396,7 @@ async function sendTelegramDocument(input) {
30891
31396
  };
30892
31397
  }
30893
31398
  const filename = basename13(resolvedPath);
30894
- const buffer = Buffer.from(await readFile12(resolvedPath));
31399
+ const buffer = Buffer.from(await readFile14(resolvedPath));
30895
31400
  const form = new FormData();
30896
31401
  form.append("chat_id", String(chatId));
30897
31402
  if (caption) form.append("caption", caption);
@@ -31245,12 +31750,12 @@ function warnOnChannelAdminBindingDrift() {
31245
31750
  }
31246
31751
 
31247
31752
  // server/lib/booking-site-accounts.ts
31248
- import { existsSync as existsSync45, readFileSync as readFileSync46 } from "fs";
31753
+ import { existsSync as existsSync46, readFileSync as readFileSync46 } from "fs";
31249
31754
  import { resolve as resolve43 } from "path";
31250
31755
  function listBookingSiteAccounts(accounts) {
31251
31756
  return accounts.filter((a) => {
31252
31757
  const availPath = resolve43(a.accountDir, "calendar-availability.json");
31253
- if (!existsSync45(availPath)) return false;
31758
+ if (!existsSync46(availPath)) return false;
31254
31759
  try {
31255
31760
  const cfg = JSON.parse(readFileSync46(availPath, "utf-8"));
31256
31761
  return typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
@@ -31290,7 +31795,7 @@ function broadcastAdminShutdown(reason) {
31290
31795
 
31291
31796
  // ../lib/entitlement/src/index.ts
31292
31797
  import { createPublicKey, createHash as createHash7, verify as cryptoVerify } from "crypto";
31293
- import { existsSync as existsSync46, readFileSync as readFileSync47, statSync as statSync20 } from "fs";
31798
+ import { existsSync as existsSync47, readFileSync as readFileSync47, statSync as statSync20 } from "fs";
31294
31799
  import { resolve as resolve44 } from "path";
31295
31800
 
31296
31801
  // ../lib/entitlement/src/canonicalize.ts
@@ -31339,7 +31844,7 @@ function resolveEntitlement(brand, account) {
31339
31844
  return logResolved(implicitTrust(account), null);
31340
31845
  }
31341
31846
  const entitlementPath = resolve44(brand.configDir, "entitlement.json");
31342
- if (!existsSync46(entitlementPath)) {
31847
+ if (!existsSync47(entitlementPath)) {
31343
31848
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
31344
31849
  }
31345
31850
  const stat12 = statSync20(entitlementPath);
@@ -31530,12 +32035,12 @@ function clientFrom(c) {
31530
32035
  }
31531
32036
  installMediaDownloadGuard();
31532
32037
  var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
31533
- var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join49(PLATFORM_ROOT8, "config", "brand.json") : "";
32038
+ var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join51(PLATFORM_ROOT8, "config", "brand.json") : "";
31534
32039
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
31535
- if (BRAND_JSON_PATH && !existsSync47(BRAND_JSON_PATH)) {
32040
+ if (BRAND_JSON_PATH && !existsSync48(BRAND_JSON_PATH)) {
31536
32041
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
31537
32042
  }
31538
- if (BRAND_JSON_PATH && existsSync47(BRAND_JSON_PATH)) {
32043
+ if (BRAND_JSON_PATH && existsSync48(BRAND_JSON_PATH)) {
31539
32044
  try {
31540
32045
  const parsed = JSON.parse(readFileSync48(BRAND_JSON_PATH, "utf-8"));
31541
32046
  BRAND = { ...BRAND, ...parsed };
@@ -31569,10 +32074,10 @@ var brandLoginOpts = {
31569
32074
  appleTouchIconPath: brandAppIcon512Path,
31570
32075
  themeColor: BRAND.defaultColors?.primary
31571
32076
  };
31572
- var ALIAS_DOMAINS_PATH = join49(homedir4(), BRAND.configDir, "alias-domains.json");
32077
+ var ALIAS_DOMAINS_PATH = join51(homedir4(), BRAND.configDir, "alias-domains.json");
31573
32078
  function loadAliasDomains() {
31574
32079
  try {
31575
- if (!existsSync47(ALIAS_DOMAINS_PATH)) return null;
32080
+ if (!existsSync48(ALIAS_DOMAINS_PATH)) return null;
31576
32081
  const parsed = JSON.parse(readFileSync48(ALIAS_DOMAINS_PATH, "utf-8"));
31577
32082
  if (!Array.isArray(parsed)) {
31578
32083
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
@@ -31648,7 +32153,7 @@ var waGateway = new WaGateway({
31648
32153
  fetchStandingRules: fetchAccountStandingRules,
31649
32154
  resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
31650
32155
  gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
31651
- serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
32156
+ serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
31652
32157
  // Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
31653
32158
  // path-validation scope) is the sender's effective SESSION account, resolved
31654
32159
  // once at the inbound gate and threaded here via the gateway's per-sender doc
@@ -31663,11 +32168,12 @@ var waGateway = new WaGateway({
31663
32168
  caption,
31664
32169
  accountId,
31665
32170
  maxyAccountId,
31666
- platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, ".."))
32171
+ platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, ".."))
31667
32172
  });
31668
32173
  return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
31669
32174
  },
31670
32175
  ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId, ownerSelfPhone, replyContext }) => {
32176
+ warnNonUuidAccount("channel-spawn", effectiveAccountId);
31671
32177
  if (passive) {
31672
32178
  const phoneHash = createHash8("sha256").update(senderId).digest("hex").slice(0, 12);
31673
32179
  const prompt = (text ?? "").trim();
@@ -31716,7 +32222,7 @@ var waGateway = new WaGateway({
31716
32222
  return;
31717
32223
  }
31718
32224
  if (role === "admin") {
31719
- const managesAccount = effectiveAccountId !== accountId ? effectiveAccountId : "none";
32225
+ const managesAccount = managesAccountFor(effectiveAccountId, resolveReadStoreKey(accountId));
31720
32226
  console.error(`[whatsapp-native] op=account-manager-route senderId=${senderId} managesAccount=${managesAccount} effectiveAccount=${effectiveAccountId} source=gate`);
31721
32227
  }
31722
32228
  const req = buildWaSpawnRequest({
@@ -31781,7 +32287,7 @@ function runDuplicateSenderAudit() {
31781
32287
  try {
31782
32288
  const configDir2 = process.env.CLAUDE_CONFIG_DIR;
31783
32289
  if (!configDir2) return;
31784
- const projectsRoot = join49(configDir2, "projects");
32290
+ const projectsRoot = join51(configDir2, "projects");
31785
32291
  const records = [];
31786
32292
  for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
31787
32293
  if (isSubagent || archived) continue;
@@ -32356,7 +32862,7 @@ app69.get("/agent-assets/:slug/:filename", (c) => {
32356
32862
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
32357
32863
  return c.text("Forbidden", 403);
32358
32864
  }
32359
- if (!existsSync47(filePath)) {
32865
+ if (!existsSync48(filePath)) {
32360
32866
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
32361
32867
  return c.text("Not found", 404);
32362
32868
  }
@@ -32386,7 +32892,7 @@ app69.get("/generated/:filename", (c) => {
32386
32892
  console.error(`[generated] serve file=${filename} status=403`);
32387
32893
  return c.text("Forbidden", 403);
32388
32894
  }
32389
- if (!existsSync47(filePath)) {
32895
+ if (!existsSync48(filePath)) {
32390
32896
  console.error(`[generated] serve file=${filename} status=404`);
32391
32897
  return c.text("Not found", 404);
32392
32898
  }
@@ -32406,7 +32912,7 @@ app69.route("/v", visitor_consent_default);
32406
32912
  var htmlCache = /* @__PURE__ */ new Map();
32407
32913
  var brandLogoPath = "/brand/maxy-monochrome.png";
32408
32914
  var brandIconPath = "/brand/maxy-monochrome.png";
32409
- if (BRAND_JSON_PATH && existsSync47(BRAND_JSON_PATH)) {
32915
+ if (BRAND_JSON_PATH && existsSync48(BRAND_JSON_PATH)) {
32410
32916
  try {
32411
32917
  const fullBrand = JSON.parse(readFileSync48(BRAND_JSON_PATH, "utf-8"));
32412
32918
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
@@ -32435,7 +32941,7 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
32435
32941
  var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
32436
32942
  var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
32437
32943
  var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
32438
- (p) => existsSync47(resolve45(process.cwd(), "public", p.replace(/^\//, "")))
32944
+ (p) => existsSync48(resolve45(process.cwd(), "public", p.replace(/^\//, "")))
32439
32945
  );
32440
32946
  var SW_SOURCE = (() => {
32441
32947
  try {
@@ -32447,8 +32953,8 @@ var SW_SOURCE = (() => {
32447
32953
  function readInstalledVersion() {
32448
32954
  try {
32449
32955
  if (!PLATFORM_ROOT8) return "unknown";
32450
- const versionFile = join49(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
32451
- if (!existsSync47(versionFile)) return "unknown";
32956
+ const versionFile = join51(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
32957
+ if (!existsSync48(versionFile)) return "unknown";
32452
32958
  const content = readFileSync48(versionFile, "utf-8").trim();
32453
32959
  return content || "unknown";
32454
32960
  } catch {
@@ -32457,36 +32963,6 @@ function readInstalledVersion() {
32457
32963
  }
32458
32964
  var INSTALLED_VERSION = readInstalledVersion();
32459
32965
  var versionScript = `<script>window.__MAXY_VERSION__=${JSON.stringify(INSTALLED_VERSION)}</script>`;
32460
- var clientErrorReporterScript = `<script>
32461
- (function(){
32462
- var send=function(b){
32463
- try{
32464
- fetch('/api/_client-error',{
32465
- method:'POST',
32466
- headers:{'content-type':'application/json'},
32467
- body:JSON.stringify(Object.assign({url:location.href,ua:navigator.userAgent,version:(window.__MAXY_VERSION__||'unknown')},b)),
32468
- keepalive:true
32469
- }).catch(function(){});
32470
- }catch(e){}
32471
- };
32472
- window.addEventListener('error',function(e){
32473
- var t=e.target;
32474
- if(t&&t!==window&&t.tagName)send({kind:'subresource',tag:t.tagName,url:t.src||t.href||''});
32475
- else send({kind:'uncaught',msg:e.message,filename:e.filename,lineno:e.lineno,colno:e.colno,stack:(e.error&&e.error.stack)||''});
32476
- },true);
32477
- window.addEventListener('unhandledrejection',function(e){
32478
- var r=e.reason;
32479
- send({kind:'unhandled-rejection',msg:String((r&&r.message)||r),stack:(r&&r.stack)||''});
32480
- });
32481
- try{
32482
- new PerformanceObserver(function(list){
32483
- list.getEntries().forEach(function(entry){
32484
- if(entry.responseStatus>=400)send({kind:'subresource',url:entry.name,status:entry.responseStatus});
32485
- });
32486
- }).observe({type:'resource',buffered:true});
32487
- }catch(e){}
32488
- })();
32489
- </script>`;
32490
32966
  function cachedHtml(file) {
32491
32967
  let html = htmlCache.get(file);
32492
32968
  if (!html) {
@@ -32507,12 +32983,12 @@ ${clientErrorReporterScript}
32507
32983
  return html;
32508
32984
  }
32509
32985
  function loadBrandingCache(agentSlug) {
32510
- const configDir2 = join49(homedir4(), BRAND.configDir);
32986
+ const configDir2 = join51(homedir4(), BRAND.configDir);
32511
32987
  try {
32512
32988
  const accountId = getDefaultAccountId();
32513
32989
  if (!accountId) return null;
32514
- const cachePath = join49(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
32515
- if (!existsSync47(cachePath)) return null;
32990
+ const cachePath = join51(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
32991
+ if (!existsSync48(cachePath)) return null;
32516
32992
  return JSON.parse(readFileSync48(cachePath, "utf-8"));
32517
32993
  } catch {
32518
32994
  return null;
@@ -32760,10 +33236,10 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
32760
33236
  var httpServer = serve({ fetch: app69.fetch, port, hostname });
32761
33237
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32762
33238
  {
32763
- const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
33239
+ const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
32764
33240
  const reconcileScript = resolve45(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
32765
33241
  const runReconcile = (ctx) => {
32766
- if (!existsSync47(reconcileScript)) return;
33242
+ if (!existsSync48(reconcileScript)) return;
32767
33243
  try {
32768
33244
  const child = spawn3(process.execPath, [reconcileScript], {
32769
33245
  env: { ...process.env, PLATFORM_ROOT: reconcilePlatformRoot },
@@ -32783,7 +33259,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32783
33259
  detached: true,
32784
33260
  run: runReconcile
32785
33261
  });
32786
- const reconcileStatePath = join49(MAXY_DIR, "booking-reconcile-state.json");
33262
+ const reconcileStatePath = join51(MAXY_DIR, "booking-reconcile-state.json");
32787
33263
  registerLoop({
32788
33264
  name: "calendar-reconcile-liveness",
32789
33265
  intervalMs: 6e5,
@@ -32801,7 +33277,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32801
33277
  }
32802
33278
  {
32803
33279
  const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
32804
- const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
33280
+ const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
32805
33281
  const dreamSweepScript = resolve45(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
32806
33282
  registerLoop({
32807
33283
  name: "dream-cycle-sweep",
@@ -32809,7 +33285,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32809
33285
  firstRunDelayMs: 3e4,
32810
33286
  detached: true,
32811
33287
  run: (ctx) => {
32812
- if (!existsSync47(dreamSweepScript)) return;
33288
+ if (!existsSync48(dreamSweepScript)) return;
32813
33289
  try {
32814
33290
  const child = spawn3(process.execPath, [dreamSweepScript], {
32815
33291
  env: { ...process.env, PLATFORM_ROOT: dreamPlatformRoot },
@@ -32825,11 +33301,11 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32825
33301
  });
32826
33302
  }
32827
33303
  {
32828
- const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
33304
+ const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
32829
33305
  const outlookScript = resolve45(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
32830
33306
  const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
32831
33307
  const runOutlookComplete = (ctx) => {
32832
- if (!existsSync47(outlookScript)) return;
33308
+ if (!existsSync48(outlookScript)) return;
32833
33309
  try {
32834
33310
  const child = spawn3(process.execPath, [outlookScript], {
32835
33311
  env: { ...process.env, PLATFORM_ROOT: outlookPlatformRoot },
@@ -32851,19 +33327,19 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32851
33327
  });
32852
33328
  }
32853
33329
  {
32854
- const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
33330
+ const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
32855
33331
  const strandedAccountsDir = resolve45(auditRoot, "..", "data/accounts");
32856
33332
  const STRANDED_AUDIT_INTERVAL_MS = 3e5;
32857
33333
  const STRANDED_AGE_MS = 16 * 6e4;
32858
33334
  const STRANDED_UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
32859
33335
  const runStrandedAudit = () => {
32860
33336
  try {
32861
- if (!existsSync47(strandedAccountsDir)) return;
33337
+ if (!existsSync48(strandedAccountsDir)) return;
32862
33338
  const now = Date.now();
32863
33339
  for (const name of readdirSync29(strandedAccountsDir)) {
32864
33340
  if (!STRANDED_UUID_RE.test(name)) continue;
32865
33341
  const pendingPath2 = resolve45(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
32866
- if (!existsSync47(pendingPath2)) continue;
33342
+ if (!existsSync48(pendingPath2)) continue;
32867
33343
  const ageMs2 = now - statSync21(pendingPath2).mtimeMs;
32868
33344
  if (ageMs2 > STRANDED_AGE_MS) {
32869
33345
  console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs2 / 1e3)}`);
@@ -32881,7 +33357,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32881
33357
  });
32882
33358
  }
32883
33359
  {
32884
- const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
33360
+ const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
32885
33361
  const googleAccountsDir = resolve45(googleRoot, "..", "data/accounts");
32886
33362
  const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
32887
33363
  const runGooglePendingAuditSafe = () => {
@@ -32900,7 +33376,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32900
33376
  const googleAuditScript = resolve45(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
32901
33377
  const GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS = 36e5;
32902
33378
  const runGoogleAccountAudit = (ctx) => {
32903
- if (!existsSync47(googleAuditScript)) return;
33379
+ if (!existsSync48(googleAuditScript)) return;
32904
33380
  try {
32905
33381
  const child = spawn3(process.execPath, [googleAuditScript], {
32906
33382
  env: { ...process.env, PLATFORM_ROOT: googleRoot },
@@ -32925,7 +33401,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32925
33401
  });
32926
33402
  }
32927
33403
  {
32928
- const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
33404
+ const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
32929
33405
  const STORAGE_AUDIT_INTERVAL_MS = 3e5;
32930
33406
  const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
32931
33407
  console.error(`[storage-audit] error="${err.message}"`);
@@ -32971,7 +33447,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32971
33447
  });
32972
33448
  }
32973
33449
  {
32974
- const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
33450
+ const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
32975
33451
  const publishScript = resolve45(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
32976
33452
  const PUBLISH_INTERVAL_MS = 3e5;
32977
33453
  const bookingAccounts = () => {
@@ -32983,7 +33459,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32983
33459
  }
32984
33460
  };
32985
33461
  const spawnPublish = (account, ctx) => {
32986
- if (!existsSync47(publishScript)) return;
33462
+ if (!existsSync48(publishScript)) return;
32987
33463
  try {
32988
33464
  const child = spawn3(process.execPath, [publishScript], {
32989
33465
  env: {
@@ -33005,7 +33481,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
33005
33481
  const availPath = resolve45(account.accountDir, "calendar-availability.json");
33006
33482
  let hasBookingSite = false;
33007
33483
  try {
33008
- if (existsSync47(availPath)) {
33484
+ if (existsSync48(availPath)) {
33009
33485
  const cfg = JSON.parse(readFileSync48(availPath, "utf-8"));
33010
33486
  hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
33011
33487
  }
@@ -33014,7 +33490,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
33014
33490
  if (!hasBookingSite) return;
33015
33491
  const statePath = resolve45(account.accountDir, "state", "booking-availability", "last-publish.json");
33016
33492
  let lastSuccessAt = null;
33017
- if (existsSync47(statePath)) {
33493
+ if (existsSync48(statePath)) {
33018
33494
  try {
33019
33495
  const rec = JSON.parse(readFileSync48(statePath, "utf-8"));
33020
33496
  lastSuccessAt = rec.lastSuccessAt ?? null;
@@ -33048,12 +33524,12 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
33048
33524
  startTimeEntryCensus(() => getSession());
33049
33525
  startLedgerCensus(() => getSession());
33050
33526
  {
33051
- const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
33527
+ const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..");
33052
33528
  const auditScript = resolve45(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
33053
33529
  const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
33054
33530
  const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
33055
33531
  const runConnectorAudit = (ctx) => {
33056
- if (!existsSync47(auditScript)) return;
33532
+ if (!existsSync48(auditScript)) return;
33057
33533
  try {
33058
33534
  const child = spawn3(process.execPath, [auditScript], {
33059
33535
  env: { ...process.env, PLATFORM_ROOT: auditPlatformRoot, LOG_DIR: auditLogDir },
@@ -33171,7 +33647,7 @@ try {
33171
33647
  var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
33172
33648
  async function runAdminUserReconcileTick() {
33173
33649
  try {
33174
- if (!existsSync47(USERS_FILE)) {
33650
+ if (!existsSync48(USERS_FILE)) {
33175
33651
  console.error("[adminuser-self-heal] skip reason=no-users-file");
33176
33652
  return;
33177
33653
  }
@@ -33222,7 +33698,7 @@ registerLoop({
33222
33698
  });
33223
33699
  var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
33224
33700
  function countUsersRows() {
33225
- if (!existsSync47(USERS_FILE)) return 0;
33701
+ if (!existsSync48(USERS_FILE)) return 0;
33226
33702
  const raw = readFileSync48(USERS_FILE, "utf-8").trim();
33227
33703
  if (!raw) return 0;
33228
33704
  const users = JSON.parse(raw);
@@ -33273,7 +33749,7 @@ registerLoop({
33273
33749
  throw err;
33274
33750
  })
33275
33751
  });
33276
- void migrateAdminWebchatSidecars().catch((err) => console.error(`[sidecar-backfill] failed err="${err instanceof Error ? err.message : String(err)}"`));
33752
+ void migrateAdminWebchatSidecars().catch((err) => console.error(`[sidecar-backfill] failed err="${err instanceof Error ? err.message : String(err)}"`)).then(() => migrateSidecarAccountIds()).catch((err) => console.error(`[sidecar-account-backfill] failed err="${err instanceof Error ? err.message : String(err)}"`));
33277
33753
  try {
33278
33754
  const accounts = enumerateValidAccountIds(getAccountsDirFromEnv());
33279
33755
  console.error(`[graph-health] account-enumeration accounts=${accounts.length}`);
@@ -33356,7 +33832,7 @@ if (bootAccountConfig?.whatsapp) {
33356
33832
  }
33357
33833
  init({
33358
33834
  configDir: configDirForWhatsApp,
33359
- platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..")),
33835
+ platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join51(__dirname, "..")),
33360
33836
  accountConfig: bootAccountConfig,
33361
33837
  onMessage: async (msg) => {
33362
33838
  if (isObserveAccount(msg.accountId)) {