@rubytech/create-sitedesk-code 0.1.507 → 0.1.509

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 (87) hide show
  1. package/dist/index.js +53 -0
  2. package/package.json +2 -2
  3. package/payload/platform/config/brand.json +12 -0
  4. package/payload/platform/docs/superpowers/plans/2026-07-26-task-1926-portal-push-concurrency-guard.md +482 -0
  5. package/payload/platform/docs/superpowers/specs/2026-07-26-task-1926-portal-push-concurrency-guard-design.md +200 -0
  6. package/payload/platform/plugins/admin/PLUGIN.md +10 -5
  7. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +96 -13
  8. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +13 -0
  9. package/payload/platform/plugins/cloudflare/bin/portal-index-push.mjs +68 -28
  10. package/payload/platform/plugins/cloudflare/mcp/__tests__/portal-index-push.test.ts +271 -29
  11. package/payload/platform/plugins/cloudflare/skills/data-portal/schema.sql +5 -4
  12. package/payload/platform/plugins/docs/references/admin-ui.md +95 -12
  13. package/payload/platform/plugins/memory/PLUGIN.md +6 -3
  14. package/payload/platform/scripts/__tests__/check-brand-cache.test.sh +231 -0
  15. package/payload/platform/scripts/__tests__/provision-honours-disabled-agents.test.sh +84 -0
  16. package/payload/platform/scripts/check-brand-cache.sh +138 -0
  17. package/payload/platform/scripts/check-risk-class.mjs +7 -2
  18. package/payload/platform/scripts/check-specialist-tool-surface.mjs +5 -2
  19. package/payload/platform/scripts/lib/canonical-tool-names.mjs +7 -4
  20. package/payload/platform/scripts/lib/provision-account-dir.sh +43 -0
  21. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts +1 -1
  22. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
  23. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +56 -3
  24. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
  25. package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts +19 -5
  26. package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts.map +1 -1
  27. package/payload/platform/services/claude-session-manager/dist/tool-surface.js +50 -11
  28. package/payload/platform/services/claude-session-manager/dist/tool-surface.js.map +1 -1
  29. package/payload/server/maxy-edge.js +15 -10
  30. package/payload/server/public/activity.html +5 -5
  31. package/payload/server/public/agents.html +4 -4
  32. package/payload/server/public/assets/{AdminLoginScreens-YT7jsh_H.js → AdminLoginScreens-8Jk7hnWH.js} +1 -1
  33. package/payload/server/public/assets/{AdminShell-Ckht9hmU.js → AdminShell-BMPEWNZk.js} +1 -1
  34. package/payload/server/public/assets/{activity-DH3Wgc3O.js → activity-ByWYF5dC.js} +1 -1
  35. package/payload/server/public/assets/admin-CnUWbKcx.js +1 -0
  36. package/payload/server/public/assets/agents-C0rTfrYd.js +1 -0
  37. package/payload/server/public/assets/{browser-Bym8QhfA.js → browser-4tTaem8N.js} +1 -1
  38. package/payload/server/public/assets/{calendar-CFnufJOy.js → calendar-BEjnkKG1.js} +1 -1
  39. package/payload/server/public/assets/chat-DBgzjDIE.js +1 -0
  40. package/payload/server/public/assets/chevron-left-DqYv3oFh.js +1 -0
  41. package/payload/server/public/assets/chevron-right-CQfPGsFb.js +1 -0
  42. package/payload/server/public/assets/clock-Dn6FHB51.js +1 -0
  43. package/payload/server/public/assets/data-D_e6Vdfd.js +1 -0
  44. package/payload/server/public/assets/{file-text-zch0E1GJ.js → file-text-DMKw3nIk.js} +1 -1
  45. package/payload/server/public/assets/{graph-BavHLzpV.js → graph-C3vW8lvw.js} +1 -1
  46. package/payload/server/public/assets/{graph-labels-CBwh4g-6.js → graph-labels-BZgd0L6n.js} +1 -1
  47. package/payload/server/public/assets/{maximize-2-bTn_Ozpi.js → maximize-2-la3IBA3M.js} +1 -1
  48. package/payload/server/public/assets/{operator-a4IOwf62.js → operator-RRRdqoRQ.js} +1 -1
  49. package/payload/server/public/assets/{page-3T2mE63b.js → page-BWFHRIAH.js} +1 -1
  50. package/payload/server/public/assets/{page-D6M1CmPe.js → page-DC11gesX.js} +1 -1
  51. package/payload/server/public/assets/{public-B3y_YU1G.js → public-DQbbLHQN.js} +1 -1
  52. package/payload/server/public/assets/{rotate-ccw-BGvzNB1b.js → rotate-ccw-OQD5si8N.js} +1 -1
  53. package/payload/server/public/assets/{routines-C7Dr16am.js → routines-asrBGZUR.js} +1 -1
  54. package/payload/server/public/assets/{skills-DFeb3XO3.js → skills-D4ECwoxa.js} +1 -1
  55. package/payload/server/public/assets/{tasks-CSfnCKJe.js → tasks-U3QdbUsO.js} +1 -1
  56. package/payload/server/public/assets/{time-entry-format-BgZqOOqG.js → time-entry-format-BgdTKgYr.js} +1 -1
  57. package/payload/server/public/assets/{triangle-alert-DBJ7xz_t.js → triangle-alert-Ck_3VhT9.js} +1 -1
  58. package/payload/server/public/assets/{useCopyFeedback-BFOujMl-.js → useCopyFeedback-BdUwyNpa.js} +1 -1
  59. package/payload/server/public/assets/useSubAccountSwitcher-CJKjEPNN.js +9 -0
  60. package/payload/server/public/assets/useSubAccountSwitcher-DOWQXDT8.css +1 -0
  61. package/payload/server/public/assets/{useVoiceRecorder-BP6CpYQD.js → useVoiceRecorder-ChnBrzbZ.js} +1 -1
  62. package/payload/server/public/assets/{wrench-DdaRhfzS.js → wrench-Cpee3C3J.js} +1 -1
  63. package/payload/server/public/brand/fonts/inter-600.woff2 +0 -0
  64. package/payload/server/public/brand/fonts/inter-700.woff2 +0 -0
  65. package/payload/server/public/brand/fonts/inter-800.woff2 +0 -0
  66. package/payload/server/public/brand-defaults.css +22 -1
  67. package/payload/server/public/browser.html +4 -4
  68. package/payload/server/public/calendar.html +7 -7
  69. package/payload/server/public/chat.html +13 -13
  70. package/payload/server/public/data.html +11 -11
  71. package/payload/server/public/graph.html +9 -9
  72. package/payload/server/public/index.html +14 -14
  73. package/payload/server/public/operator.html +14 -14
  74. package/payload/server/public/public.html +13 -13
  75. package/payload/server/public/routines.html +6 -6
  76. package/payload/server/public/skills.html +5 -5
  77. package/payload/server/public/tasks.html +6 -6
  78. package/payload/server/server.js +1139 -427
  79. package/payload/server/public/assets/admin-DetvulAu.js +0 -1
  80. package/payload/server/public/assets/agents-X_IvDHLZ.js +0 -1
  81. package/payload/server/public/assets/chat-wrckyIpw.js +0 -1
  82. package/payload/server/public/assets/chevron-left-Dtk3jEK5.js +0 -1
  83. package/payload/server/public/assets/chevron-right-Dih6IZ8B.js +0 -1
  84. package/payload/server/public/assets/clock-iJCrrmWM.js +0 -1
  85. package/payload/server/public/assets/data-D76--TYs.js +0 -1
  86. package/payload/server/public/assets/useSubAccountSwitcher-0PfRrN6i.js +0 -9
  87. package/payload/server/public/assets/useSubAccountSwitcher-BkQ5tA8A.css +0 -1
@@ -1824,10 +1824,10 @@ var serveStatic = (options = { root: "" }) => {
1824
1824
  };
1825
1825
 
1826
1826
  // server/index.ts
1827
- import { readFileSync as readFileSync47, existsSync as existsSync46, watchFile, readdirSync as readdirSync28, statSync as statSync20 } from "fs";
1827
+ import { readFileSync as readFileSync48, existsSync as existsSync47, watchFile, readdirSync as readdirSync29, statSync as statSync22 } from "fs";
1828
1828
  import { spawn as spawn3 } from "child_process";
1829
- import { createHash as createHash7 } from "crypto";
1830
- import { resolve as resolve45, join as join47, basename as basename14 } from "path";
1829
+ import { createHash as createHash8 } from "crypto";
1830
+ import { resolve as resolve45, join as join49, basename as basename14 } from "path";
1831
1831
  import { homedir as homedir4 } from "os";
1832
1832
 
1833
1833
  // server/lib/route-cache-watchers.ts
@@ -2386,6 +2386,79 @@ async function connectLoop(signal) {
2386
2386
  // server/index.ts
2387
2387
  import { monitorEventLoopDelay } from "perf_hooks";
2388
2388
 
2389
+ // server/lib/event-loop-lag.ts
2390
+ function readAndResetWindow(hist, windowMs) {
2391
+ const toMs = (ns) => Math.round(ns / 1e6);
2392
+ const w = {
2393
+ p50Ms: toMs(hist.percentile(50)),
2394
+ p99Ms: toMs(hist.percentile(99)),
2395
+ maxMs: toMs(hist.max),
2396
+ // Read before the reset.
2397
+ count: hist.count,
2398
+ windowMs
2399
+ };
2400
+ hist.reset();
2401
+ return w;
2402
+ }
2403
+ function formatLagWindow(w) {
2404
+ return `[event-loop] op=lag-window p50=${w.p50Ms} p99=${w.p99Ms} max=${w.maxMs} n=${w.count} windowMs=${w.windowMs}`;
2405
+ }
2406
+
2407
+ // server/lib/static-cache.ts
2408
+ import { statSync as statSync3 } from "fs";
2409
+ import { join as join3 } from "path";
2410
+ var IMMUTABLE = "public, max-age=31536000, immutable";
2411
+ var REVALIDATE = "public, no-cache";
2412
+ function statOrNull(path3) {
2413
+ try {
2414
+ return statSync3(path3);
2415
+ } catch {
2416
+ return null;
2417
+ }
2418
+ }
2419
+ function tryDecodeURI2(str) {
2420
+ try {
2421
+ return decodeURI(str);
2422
+ } catch {
2423
+ return str.replace(/(?:%[0-9A-Fa-f]{2})+/g, (match) => {
2424
+ try {
2425
+ return decodeURI(match);
2426
+ } catch {
2427
+ return match;
2428
+ }
2429
+ });
2430
+ }
2431
+ }
2432
+ function resolveStaticFile(root, reqPath) {
2433
+ const filename = tryDecodeURI2(reqPath);
2434
+ if (/(?:^|[/\\])\.\.(?:$|[/\\])/.test(filename)) return null;
2435
+ let path3 = join3(root, filename);
2436
+ let stats = statOrNull(path3);
2437
+ if (stats?.isDirectory()) {
2438
+ path3 = join3(path3, "index.html");
2439
+ stats = statOrNull(path3);
2440
+ }
2441
+ if (!stats?.isFile()) return null;
2442
+ return { path: path3, stats, filename };
2443
+ }
2444
+ function staticCacheHeaders(root) {
2445
+ return async (c, next) => {
2446
+ if (c.finalized) return next();
2447
+ const hit = resolveStaticFile(root, c.req.path);
2448
+ if (!hit) return next();
2449
+ if (hit.filename.startsWith("/assets/")) {
2450
+ c.header("Cache-Control", IMMUTABLE);
2451
+ return next();
2452
+ }
2453
+ const etag = `"${hit.stats.size}-${hit.stats.mtimeMs}"`;
2454
+ c.header("Cache-Control", REVALIDATE);
2455
+ c.header("Last-Modified", hit.stats.mtime.toUTCString());
2456
+ c.header("ETag", etag);
2457
+ if (c.req.header("If-None-Match") === etag) return c.body(null, 304);
2458
+ return next();
2459
+ };
2460
+ }
2461
+
2389
2462
  // app/lib/whatsapp/inbound/media-download-guard.ts
2390
2463
  var TAG2 = "[media-guard]";
2391
2464
  var inFlight2 = 0;
@@ -2452,14 +2525,14 @@ function installMediaDownloadGuard() {
2452
2525
  }
2453
2526
 
2454
2527
  // app/lib/whatsapp/ingest-audit.ts
2455
- import { readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync3 } from "fs";
2456
- import { join as join4 } from "path";
2528
+ import { readdirSync as readdirSync4, readFileSync as readFileSync4, statSync as statSync4 } from "fs";
2529
+ import { join as join5 } from "path";
2457
2530
 
2458
2531
  // app/lib/whatsapp/ingest-ledger.ts
2459
2532
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, appendFileSync as appendFileSync2, readFileSync as readFileSync3, writeFileSync, readdirSync as readdirSync3 } from "fs";
2460
- import { join as join3 } from "path";
2533
+ import { join as join4 } from "path";
2461
2534
  var TAG3 = "[wa-ingest-ledger]";
2462
- var LEDGER_ROOT = () => join3(process.env.MAXY_DIR_OVERRIDE ?? MAXY_DIR, "data", "whatsapp-ingest-ledger");
2535
+ var LEDGER_ROOT = () => join4(process.env.MAXY_DIR_OVERRIDE ?? MAXY_DIR, "data", "whatsapp-ingest-ledger");
2463
2536
  var ensuredRoots = /* @__PURE__ */ new Set();
2464
2537
  function ledgerFilePath(account) {
2465
2538
  const root = LEDGER_ROOT();
@@ -2467,7 +2540,7 @@ function ledgerFilePath(account) {
2467
2540
  if (!existsSync3(root)) mkdirSync2(root, { recursive: true });
2468
2541
  ensuredRoots.add(root);
2469
2542
  }
2470
- return join3(root, `${account}.jsonl`);
2543
+ return join4(root, `${account}.jsonl`);
2471
2544
  }
2472
2545
  function appendStanza(entry) {
2473
2546
  try {
@@ -2573,16 +2646,16 @@ function readAllConversationsCached(accountId) {
2573
2646
  const out = /* @__PURE__ */ new Map();
2574
2647
  let dir;
2575
2648
  try {
2576
- dir = readdirSync4(join4(STORE_ROOT(), accountId));
2649
+ dir = readdirSync4(join5(STORE_ROOT(), accountId));
2577
2650
  } catch {
2578
2651
  return out;
2579
2652
  }
2580
2653
  for (const file of dir) {
2581
2654
  if (!file.endsWith(".jsonl")) continue;
2582
- const path3 = join4(STORE_ROOT(), accountId, file);
2655
+ const path3 = join5(STORE_ROOT(), accountId, file);
2583
2656
  let stat11;
2584
2657
  try {
2585
- stat11 = statSync3(path3);
2658
+ stat11 = statSync4(path3);
2586
2659
  } catch {
2587
2660
  continue;
2588
2661
  }
@@ -2756,12 +2829,12 @@ function pwaCensus(d) {
2756
2829
  }
2757
2830
 
2758
2831
  // server/webchat-descriptor.ts
2759
- import { resolve as resolve3, join as join5 } from "path";
2832
+ import { resolve as resolve3, join as join6 } from "path";
2760
2833
  function webchatGatewayUrl() {
2761
2834
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
2762
2835
  }
2763
2836
  function webchatServerPath() {
2764
- return process.env.MAXY_WEBCHAT_CHANNEL_SERVER_PATH ?? resolve3(process.env.MAXY_PLATFORM_ROOT ?? join5(__dirname, ".."), "services/webchat-channel/dist/server.js");
2837
+ return process.env.MAXY_WEBCHAT_CHANNEL_SERVER_PATH ?? resolve3(process.env.MAXY_PLATFORM_ROOT ?? join6(__dirname, ".."), "services/webchat-channel/dist/server.js");
2765
2838
  }
2766
2839
  function webchatChannelDescriptor(key) {
2767
2840
  return { key, gatewayUrl: webchatGatewayUrl(), serverPath: webchatServerPath() };
@@ -4983,7 +5056,7 @@ function resolvePlatformAccountId(accountsDir = ACCOUNTS_DIR) {
4983
5056
  }
4984
5057
 
4985
5058
  // app/lib/managed-service.ts
4986
- import { join as join6 } from "path";
5059
+ import { join as join7 } from "path";
4987
5060
  import { readFileSync as readFileSync9 } from "fs";
4988
5061
  function isHouseManagedService(accountsDir = ACCOUNTS_DIR) {
4989
5062
  let houseId;
@@ -4994,7 +5067,7 @@ function isHouseManagedService(accountsDir = ACCOUNTS_DIR) {
4994
5067
  }
4995
5068
  try {
4996
5069
  const cfg = JSON.parse(
4997
- readFileSync9(join6(accountsDir, houseId, "account.json"), "utf-8")
5070
+ readFileSync9(join7(accountsDir, houseId, "account.json"), "utf-8")
4998
5071
  );
4999
5072
  return cfg.managedService === true;
5000
5073
  } catch {
@@ -5008,7 +5081,7 @@ function isCustomerTurnSuppressed(role, managedService) {
5008
5081
  // app/lib/whatsapp/inbound/media.ts
5009
5082
  import { randomUUID as randomUUID4, createHash } from "crypto";
5010
5083
  import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
5011
- import { join as join8 } from "path";
5084
+ import { join as join9 } from "path";
5012
5085
  import {
5013
5086
  downloadMediaMessage,
5014
5087
  downloadContentFromMessage,
@@ -5023,7 +5096,7 @@ import { resolve as resolve7, extname } from "path";
5023
5096
 
5024
5097
  // app/lib/data-path.ts
5025
5098
  import { realpathSync } from "fs";
5026
- import { resolve as resolve6, normalize, sep as sep2, relative, basename, join as join7 } from "path";
5099
+ import { resolve as resolve6, normalize, sep as sep2, relative, basename, join as join8 } from "path";
5027
5100
  var PLATFORM_ROOT3 = process.env.MAXY_PLATFORM_ROOT ?? resolve6(process.cwd(), "../platform");
5028
5101
  var DATA_ROOT = resolve6(PLATFORM_ROOT3, "..", "data");
5029
5102
  var CLAUDE_UPLOADS_ROOT = process.env.CLAUDE_CONFIG_DIR ? resolve6(process.env.CLAUDE_CONFIG_DIR, "uploads") : null;
@@ -5091,7 +5164,7 @@ function scratchpadTmpBase() {
5091
5164
  }
5092
5165
  function sessionScratchpadRoot(projectDir, sessionId) {
5093
5166
  const uid = typeof process.geteuid === "function" ? process.geteuid() : 0;
5094
- return join7(scratchpadTmpBase(), `claude-${uid}`, basename(projectDir), sessionId, "scratchpad");
5167
+ return join8(scratchpadTmpBase(), `claude-${uid}`, basename(projectDir), sessionId, "scratchpad");
5095
5168
  }
5096
5169
  function resolveScratchpadPath(raw, scratchpadRootAbs) {
5097
5170
  return resolveUnderRoot(raw, scratchpadRootAbs, "scratchpad");
@@ -5634,7 +5707,7 @@ async function downloadInboundMedia(msg, sock, opts) {
5634
5707
  if (!res) return void 0;
5635
5708
  await mkdir2(MEDIA_DIR, { recursive: true });
5636
5709
  const ext = mimeToExt(res.mimetype);
5637
- const filePath = join8(MEDIA_DIR, `${randomUUID4()}.${ext}`);
5710
+ const filePath = join9(MEDIA_DIR, `${randomUUID4()}.${ext}`);
5638
5711
  await writeFile2(filePath, res.buffer);
5639
5712
  const sizeKB = (res.buffer.length / 1024).toFixed(0);
5640
5713
  console.error(`${TAG14} media downloaded type=${res.mimetype} size=${sizeKB}KB path=${filePath}`);
@@ -7436,7 +7509,7 @@ var health_default = app;
7436
7509
  // app/lib/stt/voice-note.ts
7437
7510
  import { writeFile as writeFile3, mkdtemp, rm } from "fs/promises";
7438
7511
  import { tmpdir } from "os";
7439
- import { join as join9 } from "path";
7512
+ import { join as join10 } from "path";
7440
7513
 
7441
7514
  // app/lib/stt/audio-mime.ts
7442
7515
  var AUDIO_MIME_TYPES = /* @__PURE__ */ new Set([
@@ -7490,9 +7563,9 @@ async function transcribeVoiceNote(file, source) {
7490
7563
  let tempDir;
7491
7564
  let tempPath;
7492
7565
  try {
7493
- tempDir = await mkdtemp(join9(tmpdir(), "voice-"));
7566
+ tempDir = await mkdtemp(join10(tmpdir(), "voice-"));
7494
7567
  const ext = audioExtension(mimeType);
7495
- tempPath = join9(tempDir, `recording${ext}`);
7568
+ tempPath = join10(tempDir, `recording${ext}`);
7496
7569
  const buffer = Buffer.from(await file.arrayBuffer());
7497
7570
  await writeFile3(tempPath, buffer);
7498
7571
  } catch (err) {
@@ -8068,7 +8141,7 @@ async function sendTelegramText(botToken, chatId, text) {
8068
8141
  }
8069
8142
 
8070
8143
  // server/routes/whatsapp.ts
8071
- import { join as join12, resolve as resolve11 } from "path";
8144
+ import { join as join13, resolve as resolve11 } from "path";
8072
8145
  import { readdirSync as readdirSync7, readFileSync as readFileSync14, existsSync as existsSync8 } from "fs";
8073
8146
 
8074
8147
  // app/lib/whatsapp/login.ts
@@ -8076,7 +8149,7 @@ import { randomUUID as randomUUID6 } from "crypto";
8076
8149
 
8077
8150
  // app/lib/whatsapp/config-persist.ts
8078
8151
  import { readFileSync as readFileSync13, writeFileSync as writeFileSync5, existsSync as existsSync7 } from "fs";
8079
- import { resolve as resolve9, join as join10, dirname as dirname2, basename as basename2 } from "path";
8152
+ import { resolve as resolve9, join as join11, dirname as dirname2, basename as basename2 } from "path";
8080
8153
  var TAG22 = "[whatsapp:config]";
8081
8154
  function configPath(accountDir) {
8082
8155
  return resolve9(accountDir, "account.json");
@@ -8423,7 +8496,7 @@ function setPublicAgent(accountDir, slug) {
8423
8496
  if (!trimmed) {
8424
8497
  return { ok: false, error: "Agent slug cannot be empty." };
8425
8498
  }
8426
- const agentConfigPath = join10(accountDir, "agents", trimmed, "config.json");
8499
+ const agentConfigPath = join11(accountDir, "agents", trimmed, "config.json");
8427
8500
  if (!existsSync7(agentConfigPath)) {
8428
8501
  return { ok: false, error: `Agent "${trimmed}" not found \u2014 no config.json at ${agentConfigPath}. Check the agent slug and try again.` };
8429
8502
  }
@@ -9060,12 +9133,12 @@ function serializeWhatsAppSchema() {
9060
9133
 
9061
9134
  // app/lib/whatsapp/status-reconcile.ts
9062
9135
  import { readdirSync as readdirSync6 } from "fs";
9063
- import { join as join11 } from "path";
9136
+ import { join as join12 } from "path";
9064
9137
  var TAG25 = "[whatsapp:reconcile]";
9065
9138
  var HALF_REGISTERED_MIN_AGE_MS = 5 * 6e4;
9066
9139
  function listCredsAccountIds(credsRoot) {
9067
9140
  try {
9068
- return readdirSync6(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(join11(credsRoot, e.name))).map((e) => e.name);
9141
+ return readdirSync6(credsRoot, { withFileTypes: true }).filter((e) => e.isDirectory() && hasCredsSync(join12(credsRoot, e.name))).map((e) => e.name);
9069
9142
  } catch {
9070
9143
  return [];
9071
9144
  }
@@ -9080,7 +9153,7 @@ function reconcileCredsOnDisk(opts) {
9080
9153
  const entries2 = [];
9081
9154
  for (const accountId of listCredsAccountIds(credsRoot)) {
9082
9155
  if (liveAccountIds.has(accountId)) continue;
9083
- const authDir = join11(credsRoot, accountId);
9156
+ const authDir = join12(credsRoot, accountId);
9084
9157
  const census = credsCensus(authDir);
9085
9158
  if (census.registered && !census.hasAccountSignature) {
9086
9159
  const inFlight3 = activeLoginAccountIds.has(accountId);
@@ -9317,7 +9390,7 @@ app2.get("/status", (c) => {
9317
9390
  const live = getStatus();
9318
9391
  const liveIds = new Set(live.map((a) => a.accountId));
9319
9392
  const activeLoginIds = new Set(listActiveLoginAccountIds());
9320
- const credsRoot = join12(MAXY_DIR, "credentials", "whatsapp");
9393
+ const credsRoot = join13(MAXY_DIR, "credentials", "whatsapp");
9321
9394
  const accountDir = resolveAccount()?.accountDir ?? null;
9322
9395
  const reconciled = reconcileCredsOnDisk({ credsRoot, accountDir, liveAccountIds: liveIds, activeLoginAccountIds: activeLoginIds });
9323
9396
  const cfg = getWhatsAppConfig();
@@ -9354,7 +9427,7 @@ app2.post("/login/start", async (c) => {
9354
9427
  if (!phone) {
9355
9428
  return c.json({ error: 'Missing required field "phone" (E.164, e.g. +441234567890).' }, 400);
9356
9429
  }
9357
- const authDir = join12(MAXY_DIR, "credentials", "whatsapp", accountId);
9430
+ const authDir = join13(MAXY_DIR, "credentials", "whatsapp", accountId);
9358
9431
  const accountDir = resolveAccount()?.accountDir ?? null;
9359
9432
  const result = await startLogin({ accountId, authDir, phone, accountDir, force });
9360
9433
  console.error(`${TAG26} login/start result account=${accountId} hasCode=${!!result.pairingCode}${result.selfPhone ? ` phone=${result.selfPhone}` : ""}`);
@@ -10001,12 +10074,12 @@ var bodyLimit = (options) => {
10001
10074
  };
10002
10075
 
10003
10076
  // server/routes/storage-broker.ts
10004
- import { join as join13, resolve as resolve12 } from "path";
10077
+ import { join as join14, resolve as resolve12 } from "path";
10005
10078
  import { readdirSync as readdirSync8, readFileSync as readFileSync15, existsSync as existsSync9, realpathSync as realpathSync4 } from "fs";
10006
10079
  import { randomUUID as randomUUID7 } from "crypto";
10007
10080
  var app3 = new Hono();
10008
10081
  function platformRoot() {
10009
- return process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? join13(__dirname, "..", "..");
10082
+ return process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? join14(__dirname, "..", "..");
10010
10083
  }
10011
10084
  function caller(c) {
10012
10085
  return c.req.header("x-maxy-caller-account")?.trim() || null;
@@ -10541,7 +10614,7 @@ async function runStorageAudit(root) {
10541
10614
  if (!existsSync9(accountsDir)) return [];
10542
10615
  const files = [];
10543
10616
  for (const accountId of readdirSync8(accountsDir)) {
10544
- const p = join13(accountsDir, accountId, "secrets", "cloudflare.env");
10617
+ const p = join14(accountsDir, accountId, "secrets", "cloudflare.env");
10545
10618
  if (existsSync9(p)) files.push({ accountId, path: p, contents: readFileSync15(p, "utf8") });
10546
10619
  }
10547
10620
  return files;
@@ -10640,7 +10713,7 @@ function discoverPortalAccounts(accountsDir) {
10640
10713
  if (!existsSync9(accountsDir)) return [];
10641
10714
  const found = [];
10642
10715
  for (const accountId of readdirSync8(accountsDir)) {
10643
- const configPath2 = join13(accountsDir, accountId, "data-portal.json");
10716
+ const configPath2 = join14(accountsDir, accountId, "data-portal.json");
10644
10717
  if (!existsSync9(configPath2)) continue;
10645
10718
  try {
10646
10719
  const cfg = JSON.parse(readFileSync15(configPath2, "utf-8"));
@@ -10723,7 +10796,7 @@ async function runDataPortalAudit(root) {
10723
10796
  // server/portal-uploads-pull.ts
10724
10797
  import { existsSync as existsSync10 } from "fs";
10725
10798
  import { mkdir as mkdir3, readFile as readFile2, rename, stat as stat3, unlink as unlink2, writeFile as writeFile4 } from "fs/promises";
10726
- import { basename as basename4, dirname as dirname4, join as join14, relative as relative2, resolve as resolve13, sep as sep3 } from "path";
10799
+ import { basename as basename4, dirname as dirname4, join as join15, relative as relative2, resolve as resolve13, sep as sep3 } from "path";
10727
10800
 
10728
10801
  // ../plugins/cloudflare/bin/schema-exposed-dirs.mjs
10729
10802
  var ONT_START = "<!-- ontology-buckets:start -->";
@@ -10821,19 +10894,19 @@ function resolveDestination(accountDir, row, exposed) {
10821
10894
  if (!segments.every(safeSegment)) return { ok: false, reason: "bad-target" };
10822
10895
  if (!exposed.includes(segments[0])) return { ok: false, reason: "bad-target" };
10823
10896
  root = resolve13(accountDir);
10824
- dir = join14(root, ...segments);
10897
+ dir = join15(root, ...segments);
10825
10898
  } else {
10826
10899
  root = resolve13(accountDir, "uploads");
10827
- dir = join14(root, row.ownerId);
10900
+ dir = join15(root, row.ownerId);
10828
10901
  }
10829
- const final = join14(dir, row.filename);
10902
+ const final = join15(dir, row.filename);
10830
10903
  if (!final.startsWith(root + sep3)) {
10831
10904
  return { ok: false, reason: row.targetPath ? "bad-target" : "bad-filename" };
10832
10905
  }
10833
10906
  return {
10834
10907
  ok: true,
10835
10908
  dir,
10836
- tmp: join14(dir, ".uploads-tmp", row.filename),
10909
+ tmp: join15(dir, ".uploads-tmp", row.filename),
10837
10910
  final,
10838
10911
  relative: relative2(resolve13(accountDir), final).split(sep3).join("/")
10839
10912
  };
@@ -10846,7 +10919,7 @@ function nextFreePath(final) {
10846
10919
  const stem = dot > 0 ? base.slice(0, dot) : base;
10847
10920
  const ext = dot > 0 ? base.slice(dot) : "";
10848
10921
  for (let n = 2; ; n++) {
10849
- const candidate = join14(dir, `${stem} (${n})${ext}`);
10922
+ const candidate = join15(dir, `${stem} (${n})${ext}`);
10850
10923
  if (!existsSync10(candidate)) return candidate;
10851
10924
  }
10852
10925
  }
@@ -10950,7 +11023,7 @@ async function withdrawRow(opts) {
10950
11023
  log2(`${head} removed=false result=bad-path`);
10951
11024
  return false;
10952
11025
  }
10953
- const absolute = join14(resolve13(accountDir), ...segments);
11026
+ const absolute = join15(resolve13(accountDir), ...segments);
10954
11027
  if (!absolute.startsWith(resolve13(accountDir) + sep3)) {
10955
11028
  log2(`${head} removed=false result=bad-path`);
10956
11029
  return false;
@@ -11015,13 +11088,13 @@ function parsePendingRows(raw) {
11015
11088
  async function readExposedDirs(accountDir) {
11016
11089
  let schemaText = null;
11017
11090
  try {
11018
- schemaText = await readFile2(join14(accountDir, "SCHEMA.md"), "utf8");
11091
+ schemaText = await readFile2(join15(accountDir, "SCHEMA.md"), "utf8");
11019
11092
  } catch {
11020
11093
  schemaText = null;
11021
11094
  }
11022
11095
  let exposeFolders = [];
11023
11096
  try {
11024
- const cfg = JSON.parse(await readFile2(join14(accountDir, "data-portal.json"), "utf8"));
11097
+ const cfg = JSON.parse(await readFile2(join15(accountDir, "data-portal.json"), "utf8"));
11025
11098
  exposeFolders = Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
11026
11099
  } catch {
11027
11100
  exposeFolders = [];
@@ -11046,7 +11119,7 @@ async function runPortalUploadsPull(root) {
11046
11119
  console.error(`${TAG27} op=malformed account=${portal.accountId} rows=${malformed}`);
11047
11120
  }
11048
11121
  if (rows.length === 0) continue;
11049
- const accountDir = join14(accountsRoot, portal.accountId);
11122
+ const accountDir = join15(accountsRoot, portal.accountId);
11050
11123
  const r = await pullAccount({
11051
11124
  accountDir,
11052
11125
  accountId: portal.accountId,
@@ -11079,7 +11152,7 @@ async function runPortalUploadsPull(root) {
11079
11152
  import { readFile as readFile3, readdir, stat as stat4 } from "fs/promises";
11080
11153
  import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync6 } from "fs";
11081
11154
  import { execFileSync as execFileSync2 } from "child_process";
11082
- import { join as join15, resolve as resolve14 } from "path";
11155
+ import { join as join16, resolve as resolve14 } from "path";
11083
11156
  import { fileURLToPath } from "url";
11084
11157
 
11085
11158
  // ../plugins/cloudflare/bin/d1-http.mjs
@@ -11155,7 +11228,7 @@ function readEnvFile(path3) {
11155
11228
  }
11156
11229
  async function readExposeFolders(accountDir) {
11157
11230
  try {
11158
- const cfg = JSON.parse(await readFile3(join15(accountDir, "data-portal.json"), "utf8"));
11231
+ const cfg = JSON.parse(await readFile3(join16(accountDir, "data-portal.json"), "utf8"));
11159
11232
  return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
11160
11233
  } catch {
11161
11234
  return [];
@@ -11166,12 +11239,12 @@ async function walkExposed(accountDir, exposed) {
11166
11239
  async function walk(rel) {
11167
11240
  let entries2;
11168
11241
  try {
11169
- entries2 = await readdir(join15(accountDir, rel), { withFileTypes: true });
11242
+ entries2 = await readdir(join16(accountDir, rel), { withFileTypes: true });
11170
11243
  } catch {
11171
11244
  return;
11172
11245
  }
11173
11246
  try {
11174
- const st = await stat4(join15(accountDir, rel));
11247
+ const st = await stat4(join16(accountDir, rel));
11175
11248
  out.push({ relPath: rel, sizeBytes: 0, modifiedAt: st.mtime.toISOString(), isDir: true });
11176
11249
  } catch {
11177
11250
  }
@@ -11182,7 +11255,7 @@ async function walkExposed(accountDir, exposed) {
11182
11255
  await walk(childRel);
11183
11256
  } else if (e.isFile()) {
11184
11257
  try {
11185
- const st = await stat4(join15(accountDir, childRel));
11258
+ const st = await stat4(join16(accountDir, childRel));
11186
11259
  out.push({
11187
11260
  relPath: childRel,
11188
11261
  sizeBytes: st.size,
@@ -11201,7 +11274,7 @@ async function pushAccount(opts) {
11201
11274
  const { accountDir, accountId, client, log: log2, nowIso } = opts;
11202
11275
  let schemaText = null;
11203
11276
  try {
11204
- schemaText = await readFile3(join15(accountDir, "SCHEMA.md"), "utf8");
11277
+ schemaText = await readFile3(join16(accountDir, "SCHEMA.md"), "utf8");
11205
11278
  } catch {
11206
11279
  schemaText = null;
11207
11280
  }
@@ -11231,19 +11304,11 @@ async function pushAccount(opts) {
11231
11304
  [accountId]
11232
11305
  );
11233
11306
  const current = Number(state[0]?.currentGeneration ?? 0);
11234
- const next = current + 1;
11235
- const orphan = await client.query(
11236
- "SELECT COUNT(*) AS n FROM directory WHERE accountId = ? AND generation = ?",
11237
- [accountId, next]
11307
+ const staged = await client.query(
11308
+ "SELECT MAX(generation) AS g FROM directory WHERE accountId = ?",
11309
+ [accountId]
11238
11310
  );
11239
- const orphanCount = Number(orphan[0]?.n ?? 0);
11240
- if (orphanCount > 0) {
11241
- await client.query("DELETE FROM directory WHERE accountId = ? AND generation = ?", [
11242
- accountId,
11243
- next
11244
- ]);
11245
- log2(`${TAG28} op=stage-clear account=${accountId} generation=${next} cleared=${orphanCount}`);
11246
- }
11311
+ const next = Math.max(current, Number(staged[0]?.g ?? 0)) + 1;
11247
11312
  for (const row of rows) {
11248
11313
  await client.query(
11249
11314
  "INSERT INTO directory (accountId, relPath, sizeBytes, modifiedAt, indexedAt, isDir, generation) VALUES (?, ?, ?, ?, ?, ?, ?)",
@@ -11252,12 +11317,29 @@ async function pushAccount(opts) {
11252
11317
  }
11253
11318
  log2(`${TAG28} op=stage account=${accountId} generation=${next} inserted=${rows.length}`);
11254
11319
  await client.query(
11255
- "INSERT INTO directory_state (accountId, currentGeneration) VALUES (?, ?) ON CONFLICT (accountId) DO UPDATE SET currentGeneration = excluded.currentGeneration",
11320
+ "INSERT INTO directory_state (accountId, currentGeneration) VALUES (?, ?) ON CONFLICT (accountId) DO UPDATE SET currentGeneration = excluded.currentGeneration WHERE excluded.currentGeneration > directory_state.currentGeneration",
11256
11321
  [accountId, next]
11257
11322
  );
11323
+ const flipped = await client.query(
11324
+ "SELECT currentGeneration FROM directory_state WHERE accountId = ?",
11325
+ [accountId]
11326
+ );
11327
+ const pointer = Number(flipped[0]?.currentGeneration ?? 0);
11328
+ if (pointer !== next) {
11329
+ log2(
11330
+ `${TAG28} op=stage-contended account=${accountId} generation=${next} pointer=${pointer} action=superseded`
11331
+ );
11332
+ return {
11333
+ exposed: r.exposed,
11334
+ rows: rows.length,
11335
+ schemaPresent: true,
11336
+ generation: next,
11337
+ superseded: true
11338
+ };
11339
+ }
11258
11340
  log2(`${TAG28} op=flip account=${accountId} generation=${next}`);
11259
11341
  try {
11260
- await client.query("DELETE FROM directory WHERE accountId = ? AND generation != ?", [
11342
+ await client.query("DELETE FROM directory WHERE accountId = ? AND generation < ?", [
11261
11343
  accountId,
11262
11344
  next
11263
11345
  ]);
@@ -11309,9 +11391,9 @@ async function portalAccounts(accountsRoot) {
11309
11391
  return out;
11310
11392
  }
11311
11393
  for (const accountId of names) {
11312
- const accountDir = join15(accountsRoot, accountId);
11394
+ const accountDir = join16(accountsRoot, accountId);
11313
11395
  try {
11314
- const cfg = JSON.parse(await readFile3(join15(accountDir, "data-portal.json"), "utf8"));
11396
+ const cfg = JSON.parse(await readFile3(join16(accountDir, "data-portal.json"), "utf8"));
11315
11397
  if (typeof cfg?.portalDbName === "string" && cfg.portalDbName) {
11316
11398
  const exposeFolders = Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
11317
11399
  out.push({ accountDir, accountId, dbName: cfg.portalDbName, exposeFolders });
@@ -11324,11 +11406,11 @@ async function portalAccounts(accountsRoot) {
11324
11406
  return out;
11325
11407
  }
11326
11408
  function resolveCloudflareCredentials(platformRoot5) {
11327
- const houseEnvPath = join15(platformRoot5, "config", "cloudflare-house.env");
11409
+ const houseEnvPath = join16(platformRoot5, "config", "cloudflare-house.env");
11328
11410
  const house = readEnvFile(houseEnvPath);
11329
11411
  if (!house.CLOUDFLARE_API_TOKEN) return { error: "no-house-cloudflare-credential" };
11330
11412
  if (!house.CLOUDFLARE_ACCOUNT_ID) return { error: "no-house-cloudflare-account-id" };
11331
- const cfTokenSh = join15(platformRoot5, "plugins", "cloudflare", "bin", "cf-token.sh");
11413
+ const cfTokenSh = join16(platformRoot5, "plugins", "cloudflare", "bin", "cf-token.sh");
11332
11414
  if (!existsSync11(cfTokenSh)) return { error: "cf-token-sh-missing" };
11333
11415
  let keyName;
11334
11416
  try {
@@ -11434,17 +11516,17 @@ async function runPortalIndexPush(root) {
11434
11516
  }
11435
11517
 
11436
11518
  // server/google-pending-audit.ts
11437
- import { existsSync as existsSync12, readdirSync as readdirSync9, statSync as statSync4 } from "fs";
11438
- import { join as join16 } from "path";
11519
+ import { existsSync as existsSync12, readdirSync as readdirSync9, statSync as statSync5 } from "fs";
11520
+ import { join as join17 } from "path";
11439
11521
  var GOOGLE_PENDING_LIFETIME_SEC = 600;
11440
11522
  var UUID_RE2 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
11441
- function runGooglePendingAudit(accountsDir, nowMs, emit, readMtimeMs = (path3) => statSync4(path3).mtimeMs) {
11523
+ function runGooglePendingAudit(accountsDir, nowMs, emit, readMtimeMs = (path3) => statSync5(path3).mtimeMs) {
11442
11524
  let scanned = 0;
11443
11525
  let stranded = 0;
11444
11526
  if (existsSync12(accountsDir)) {
11445
11527
  for (const accountId of readdirSync9(accountsDir)) {
11446
11528
  if (!UUID_RE2.test(accountId)) continue;
11447
- const pendingPath2 = join16(accountsDir, accountId, "secrets", "google", "pending-oauth.enc");
11529
+ const pendingPath2 = join17(accountsDir, accountId, "secrets", "google", "pending-oauth.enc");
11448
11530
  try {
11449
11531
  if (!existsSync12(pendingPath2)) continue;
11450
11532
  const ageSec = Math.max(0, Math.floor((nowMs - readMtimeMs(pendingPath2)) / 1e3));
@@ -11501,19 +11583,19 @@ function runReconcileLivenessAudit(statePath, nowMs, intervalMs, emit) {
11501
11583
  }
11502
11584
 
11503
11585
  // server/routes/whatsapp-reader.ts
11504
- import { readFileSync as readFileSync21, watch as watch2, statSync as statSync8, openSync, readSync, closeSync, existsSync as existsSync17, readdirSync as readdirSync14, realpathSync as realpathSync6 } from "fs";
11505
- import { basename as basename6, dirname as dirname7, isAbsolute, join as join21, relative as relative3, resolve as resolve17, sep as sep5 } from "path";
11586
+ import { readFileSync as readFileSync21, watch as watch2, statSync as statSync9, openSync, readSync, closeSync, existsSync as existsSync17, readdirSync as readdirSync14, realpathSync as realpathSync6 } from "fs";
11587
+ import { basename as basename6, dirname as dirname7, isAbsolute, join as join22, relative as relative3, resolve as resolve17, sep as sep5 } from "path";
11506
11588
 
11507
11589
  // server/routes/admin/sidebar-sessions.ts
11508
- import { readdirSync as readdirSync12, readFileSync as readFileSync19, statSync as statSync6 } from "fs";
11509
- import { dirname as dirname5, join as join19, resolve as resolve15 } from "path";
11590
+ import { readdirSync as readdirSync12, readFileSync as readFileSync19, statSync as statSync7 } from "fs";
11591
+ import { dirname as dirname5, join as join20, resolve as resolve15 } from "path";
11510
11592
 
11511
11593
  // ../services/claude-session-manager/src/jsonl-path.ts
11512
11594
  import { existsSync as existsSync14, readdirSync as readdirSync10 } from "fs";
11513
11595
  import { homedir } from "os";
11514
- import { join as join17 } from "path";
11596
+ import { join as join18 } from "path";
11515
11597
  function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
11516
- const projectsRoot = join17(claudeConfigDir2, "projects");
11598
+ const projectsRoot = join18(claudeConfigDir2, "projects");
11517
11599
  if (!existsSync14(projectsRoot)) return null;
11518
11600
  let slugs;
11519
11601
  try {
@@ -11523,9 +11605,9 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
11523
11605
  }
11524
11606
  const basename15 = `${sessionId}.jsonl`;
11525
11607
  for (const slug of slugs) {
11526
- const live = join17(projectsRoot, slug, basename15);
11608
+ const live = join18(projectsRoot, slug, basename15);
11527
11609
  if (existsSync14(live)) return live;
11528
- const archived = join17(projectsRoot, slug, "archive", basename15);
11610
+ const archived = join18(projectsRoot, slug, "archive", basename15);
11529
11611
  if (existsSync14(archived)) return archived;
11530
11612
  }
11531
11613
  return null;
@@ -11533,8 +11615,8 @@ function findExistingJsonlForSessionId(claudeConfigDir2, sessionId) {
11533
11615
 
11534
11616
  // app/lib/admin-identity/pin-validator.ts
11535
11617
  import { createHash as createHash3 } from "crypto";
11536
- import { existsSync as existsSync15, readFileSync as readFileSync18, readdirSync as readdirSync11, statSync as statSync5 } from "fs";
11537
- import { join as join18 } from "path";
11618
+ import { existsSync as existsSync15, readFileSync as readFileSync18, readdirSync as readdirSync11, statSync as statSync6 } from "fs";
11619
+ import { join as join19 } from "path";
11538
11620
  function hashPin(pin) {
11539
11621
  return createHash3("sha256").update(pin).digest("hex");
11540
11622
  }
@@ -11665,7 +11747,7 @@ function enumerateJsonls(projectsRoot) {
11665
11747
  throw err;
11666
11748
  }
11667
11749
  for (const slug of slugs) {
11668
- const slugDir = join19(projectsRoot, slug);
11750
+ const slugDir = join20(projectsRoot, slug);
11669
11751
  let entries2;
11670
11752
  try {
11671
11753
  entries2 = readdirSync12(slugDir, { withFileTypes: true });
@@ -11676,9 +11758,9 @@ function enumerateJsonls(projectsRoot) {
11676
11758
  }
11677
11759
  for (const entry of entries2) {
11678
11760
  if (entry.isFile() && SESSION_ID_RE.test(entry.name)) {
11679
- out.push({ path: join19(slugDir, entry.name), isSubagent: false, archived: false });
11761
+ out.push({ path: join20(slugDir, entry.name), isSubagent: false, archived: false });
11680
11762
  } else if (entry.isDirectory() && entry.name === "subagents") {
11681
- const subDir = join19(slugDir, entry.name);
11763
+ const subDir = join20(slugDir, entry.name);
11682
11764
  let subEntries;
11683
11765
  try {
11684
11766
  subEntries = readdirSync12(subDir, { withFileTypes: true });
@@ -11689,11 +11771,11 @@ function enumerateJsonls(projectsRoot) {
11689
11771
  }
11690
11772
  for (const sub of subEntries) {
11691
11773
  if (sub.isFile() && SESSION_ID_RE.test(sub.name)) {
11692
- out.push({ path: join19(subDir, sub.name), isSubagent: true, archived: false });
11774
+ out.push({ path: join20(subDir, sub.name), isSubagent: true, archived: false });
11693
11775
  }
11694
11776
  }
11695
11777
  } else if (entry.isDirectory() && entry.name === "archive") {
11696
- const archiveDir = join19(slugDir, entry.name);
11778
+ const archiveDir = join20(slugDir, entry.name);
11697
11779
  let archiveEntries;
11698
11780
  try {
11699
11781
  archiveEntries = readdirSync12(archiveDir, { withFileTypes: true });
@@ -11704,7 +11786,7 @@ function enumerateJsonls(projectsRoot) {
11704
11786
  }
11705
11787
  for (const arc of archiveEntries) {
11706
11788
  if (arc.isFile() && SESSION_ID_RE.test(arc.name)) {
11707
- out.push({ path: join19(archiveDir, arc.name), isSubagent: false, archived: true });
11789
+ out.push({ path: join20(archiveDir, arc.name), isSubagent: false, archived: true });
11708
11790
  }
11709
11791
  }
11710
11792
  }
@@ -11737,7 +11819,7 @@ async function fetchLiveSessions() {
11737
11819
  function loadUserTitles(accountDir) {
11738
11820
  const out = /* @__PURE__ */ new Map();
11739
11821
  if (!accountDir) return out;
11740
- const path3 = join19(accountDir, "session-titles.json");
11822
+ const path3 = join20(accountDir, "session-titles.json");
11741
11823
  let raw;
11742
11824
  try {
11743
11825
  raw = readFileSync19(path3, "utf8");
@@ -11877,7 +11959,7 @@ async function computeSessionList(scopeAccountId) {
11877
11959
  console.error("[admin-sessions-list] CLAUDE_CONFIG_DIR not set; returning empty list");
11878
11960
  return { sessions: [], accountId: scopeAccountId };
11879
11961
  }
11880
- const projectsRoot = join19(configDir2, "projects");
11962
+ const projectsRoot = join20(configDir2, "projects");
11881
11963
  const jsonls = enumerateJsonls(projectsRoot);
11882
11964
  const liveSessions = await fetchLiveSessions();
11883
11965
  const accountDir = scopeAccountId ? resolve15(ACCOUNTS_DIR, scopeAccountId) : null;
@@ -11922,7 +12004,7 @@ async function computeSessionList(scopeAccountId) {
11922
12004
  let mtimeMs;
11923
12005
  try {
11924
12006
  body = readFileSync19(path3, "utf8");
11925
- mtimeMs = statSync6(path3).mtimeMs;
12007
+ mtimeMs = statSync7(path3).mtimeMs;
11926
12008
  } catch {
11927
12009
  continue;
11928
12010
  }
@@ -11930,7 +12012,7 @@ async function computeSessionList(scopeAccountId) {
11930
12012
  const pid = live ? liveSessions.get(sessionId) ?? null : null;
11931
12013
  const resolved = resolveTitle(body, sessionId, userTitles);
11932
12014
  titleSourceCounts[resolved.source] += 1;
11933
- const metaPath = join19(projectDir, `${sessionId}.meta.json`);
12015
+ const metaPath = join20(projectDir, `${sessionId}.meta.json`);
11934
12016
  const { bridgeIds, role, channel: sidecarChannel, senderId, personId, adminUserId, accountId: rowAccountId } = readSidecarMeta(metaPath);
11935
12017
  if (multiAccount) {
11936
12018
  if (rowAccountId === null) untaggedCount += 1;
@@ -12332,8 +12414,8 @@ function parseTranscript(lines, queuedPendingSuppress = /* @__PURE__ */ new Map(
12332
12414
  }
12333
12415
 
12334
12416
  // app/lib/whatsapp-reader/enrich-attachments.ts
12335
- import { readFileSync as readFileSync20, readdirSync as readdirSync13, existsSync as existsSync16, statSync as statSync7, realpathSync as realpathSync5 } from "fs";
12336
- import { basename as basename5, dirname as dirname6, join as join20, resolve as resolve16, sep as sep4 } from "path";
12417
+ import { readFileSync as readFileSync20, readdirSync as readdirSync13, existsSync as existsSync16, statSync as statSync8, realpathSync as realpathSync5 } from "fs";
12418
+ import { basename as basename5, dirname as dirname6, join as join21, resolve as resolve16, sep as sep4 } from "path";
12337
12419
  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;
12338
12420
  function adminAttachmentIds(text) {
12339
12421
  const ids = [];
@@ -12346,7 +12428,7 @@ function adminAttachmentIds(text) {
12346
12428
  function adminAttachmentsFromText(text, uploadsBase) {
12347
12429
  const out = [];
12348
12430
  for (const id of adminAttachmentIds(text)) {
12349
- const meta = readAttachmentMeta(join20(uploadsBase, id));
12431
+ const meta = readAttachmentMeta(join21(uploadsBase, id));
12350
12432
  if (meta) out.push(meta);
12351
12433
  }
12352
12434
  return out;
@@ -12383,7 +12465,7 @@ function claudeUploadAttachmentsFromText(text, sessionId) {
12383
12465
  attachmentId: filename,
12384
12466
  filename,
12385
12467
  mimeType: detectMimeType(filename),
12386
- sizeBytes: statSync7(real).size,
12468
+ sizeBytes: statSync8(real).size,
12387
12469
  source: "claude-upload"
12388
12470
  });
12389
12471
  accepted.push(m[0]);
@@ -12396,7 +12478,7 @@ function claudeUploadAttachmentsFromText(text, sessionId) {
12396
12478
  function readSidecar(dir, attachmentId) {
12397
12479
  let parsed;
12398
12480
  try {
12399
- parsed = JSON.parse(readFileSync20(join20(dir, `${attachmentId}.meta.json`), "utf8"));
12481
+ parsed = JSON.parse(readFileSync20(join21(dir, `${attachmentId}.meta.json`), "utf8"));
12400
12482
  } catch {
12401
12483
  return null;
12402
12484
  }
@@ -12425,7 +12507,7 @@ function listSessionAttachmentsInDir(dir) {
12425
12507
  }
12426
12508
  const sidecars = [];
12427
12509
  for (const name of entries2) {
12428
- const sidecar = readSidecar(join20(dir, name), name);
12510
+ const sidecar = readSidecar(join21(dir, name), name);
12429
12511
  if (sidecar) sidecars.push(sidecar);
12430
12512
  }
12431
12513
  sidecars.sort((a, b) => a.storedAt.localeCompare(b.storedAt));
@@ -12585,14 +12667,14 @@ app5.get("/conversations", requireAdminSession, async (c) => {
12585
12667
  }
12586
12668
  const cfg = claudeConfigDir();
12587
12669
  if (!cfg) return c.json({ conversations: [] });
12588
- const projectsRoot = join21(cfg, "projects");
12670
+ const projectsRoot = join22(cfg, "projects");
12589
12671
  const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
12590
12672
  const rows = [];
12591
12673
  let sessionRowsExcludedUntagged = 0;
12592
12674
  for (const { path: path3 } of enumerateJsonls(projectsRoot)) {
12593
12675
  const sessionId = basename6(path3).replace(/\.jsonl$/, "");
12594
12676
  const projectDir = dirname7(path3);
12595
- const meta = readSidecarMeta(join21(projectDir, `${sessionId}.meta.json`));
12677
+ const meta = readSidecarMeta(join22(projectDir, `${sessionId}.meta.json`));
12596
12678
  if (!isReaderChannelSession(meta.role, meta.channel)) continue;
12597
12679
  if (multiAccount) {
12598
12680
  if (meta.accountId === null) sessionRowsExcludedUntagged += 1;
@@ -12723,7 +12805,7 @@ app5.get("/conversations-all", requireAdminSession, async (c) => {
12723
12805
  const { value, state } = await getOrCompute("conversations-all", houseId, async () => {
12724
12806
  const cfg = claudeConfigDir();
12725
12807
  if (!cfg) return { conversations: [] };
12726
- const projectsRoot = join21(cfg, "projects");
12808
+ const projectsRoot = join22(cfg, "projects");
12727
12809
  const userTitles = loadUserTitles(ACCOUNTS_DIR ?? null);
12728
12810
  const validAccounts = listValidAccounts();
12729
12811
  const validIds = new Set(validAccounts.map((a) => a.accountId));
@@ -12732,7 +12814,7 @@ app5.get("/conversations-all", requireAdminSession, async (c) => {
12732
12814
  for (const { path: path3 } of enumerateJsonls(projectsRoot)) {
12733
12815
  const sessionId = basename6(path3).replace(/\.jsonl$/, "");
12734
12816
  const projectDir = dirname7(path3);
12735
- const meta = readSidecarMeta(join21(projectDir, `${sessionId}.meta.json`));
12817
+ const meta = readSidecarMeta(join22(projectDir, `${sessionId}.meta.json`));
12736
12818
  if (!isReaderChannelSession(meta.role, meta.channel)) continue;
12737
12819
  if (meta.accountId === null || !validIds.has(meta.accountId)) continue;
12738
12820
  let body = "";
@@ -12803,7 +12885,7 @@ app5.get("/conversations-all", requireAdminSession, async (c) => {
12803
12885
  return c.json(value);
12804
12886
  });
12805
12887
  function readFrom(path3, from) {
12806
- const end = statSync8(path3).size;
12888
+ const end = statSync9(path3).size;
12807
12889
  if (end <= from) return { buf: Buffer.alloc(0), end: from };
12808
12890
  const fd = openSync(path3, "r");
12809
12891
  try {
@@ -12897,7 +12979,7 @@ function openTaskKey(turns) {
12897
12979
  }
12898
12980
  function readSubagentMeta(dir, hex) {
12899
12981
  try {
12900
- const m = JSON.parse(readFileSync21(join21(dir, `agent-${hex}.meta.json`), "utf8"));
12982
+ const m = JSON.parse(readFileSync21(join22(dir, `agent-${hex}.meta.json`), "utf8"));
12901
12983
  if (typeof m.agentType === "string" && typeof m.description === "string" && typeof m.toolUseId === "string") {
12902
12984
  return { agentType: m.agentType, description: m.description, toolUseId: m.toolUseId };
12903
12985
  }
@@ -12929,7 +13011,7 @@ function runActivityTick(c) {
12929
13011
  let size = 0;
12930
13012
  let mtimeMs = 0;
12931
13013
  try {
12932
- const st = statSync8(join21(c.subagentsDir, name));
13014
+ const st = statSync9(join22(c.subagentsDir, name));
12933
13015
  size = st.size;
12934
13016
  mtimeMs = st.mtimeMs;
12935
13017
  } catch {
@@ -12974,11 +13056,11 @@ app5.get("/stream", requireAdminSession, (c) => {
12974
13056
  const sessionId = c.req.query("sessionId") ?? "";
12975
13057
  const projectDir = c.req.query("projectDir") ?? "";
12976
13058
  const cfg = claudeConfigDir();
12977
- const projectsRoot = cfg ? resolve17(join21(cfg, "projects")) : null;
13059
+ const projectsRoot = cfg ? resolve17(join22(cfg, "projects")) : null;
12978
13060
  if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
12979
13061
  return c.json({ error: "bad session reference" }, 400);
12980
13062
  }
12981
- const jsonlPath = resolve17(join21(projectDir, `${sessionId}.jsonl`));
13063
+ const jsonlPath = resolve17(join22(projectDir, `${sessionId}.jsonl`));
12982
13064
  if (!jsonlPath.startsWith(projectsRoot + sep5)) {
12983
13065
  return c.json({ error: "bad session reference" }, 400);
12984
13066
  }
@@ -12997,7 +13079,7 @@ data: ${JSON.stringify(turn)}
12997
13079
  start(controller) {
12998
13080
  const fileEnd0 = (() => {
12999
13081
  try {
13000
- return statSync8(jsonlPath).size;
13082
+ return statSync9(jsonlPath).size;
13001
13083
  } catch {
13002
13084
  return 0;
13003
13085
  }
@@ -13005,7 +13087,7 @@ data: ${JSON.stringify(turn)}
13005
13087
  let offset = resumeOffset(lastEventId, fileEnd0);
13006
13088
  console.log(`[wa-stream] op=open conn=${connId} sessionId=${sessionId} channel=reader resume=${offset}`);
13007
13089
  const sessionKey = c.req.query("session_key") ?? "";
13008
- const subagentsDir = resolve17(join21(projectDir, sessionId, "subagents"));
13090
+ const subagentsDir = resolve17(join22(projectDir, sessionId, "subagents"));
13009
13091
  console.log(
13010
13092
  `[webchat-activity] op=watch-subagents key=${sessionKey} dir=${subagentsDir} exists=${existsSync17(subagentsDir)}`
13011
13093
  );
@@ -13134,7 +13216,7 @@ app5.get("/directives", requireAdminSession, (c) => {
13134
13216
  const pid = Number(pidPart);
13135
13217
  let len = 0;
13136
13218
  try {
13137
- len = statSync8(join21(dir, name)).size;
13219
+ len = statSync9(join22(dir, name)).size;
13138
13220
  } catch {
13139
13221
  }
13140
13222
  return { name, secs, pid, ts: Number.isFinite(secs) ? new Date(secs * 1e3).toISOString() : null, len };
@@ -13149,7 +13231,7 @@ app5.get("/directive", requireAdminSession, (c) => {
13149
13231
  }
13150
13232
  const dir = directiveStoreDir(sessionId);
13151
13233
  if (!dir) return c.json({ error: "no account" }, 404);
13152
- const path3 = resolve17(join21(dir, name));
13234
+ const path3 = resolve17(join22(dir, name));
13153
13235
  if (!path3.startsWith(dir + sep5)) return c.json({ error: "bad reference" }, 400);
13154
13236
  let body;
13155
13237
  try {
@@ -13207,7 +13289,7 @@ app5.get("/store-stream", requireAdminSession, (c) => {
13207
13289
  console.log(`[wa-reader] op=store-quote msgId=${r.msgKeyId} quoted=${!!q2}`);
13208
13290
  }
13209
13291
  if (r.attachmentId) {
13210
- const meta = readAttachmentMeta(join21(uploadsBase, r.attachmentId));
13292
+ const meta = readAttachmentMeta(join22(uploadsBase, r.attachmentId));
13211
13293
  if (meta) return { ...turn, attachments: [meta] };
13212
13294
  }
13213
13295
  return turn;
@@ -13240,7 +13322,7 @@ data: ${JSON.stringify(payload)}
13240
13322
  };
13241
13323
  const fileEnd0 = (() => {
13242
13324
  try {
13243
- return statSync8(file).size;
13325
+ return statSync9(file).size;
13244
13326
  } catch {
13245
13327
  return 0;
13246
13328
  }
@@ -13458,7 +13540,7 @@ app5.post("/reply", requireAdminSession, async (c) => {
13458
13540
  const absolute = resolved.absolute;
13459
13541
  let size = -1;
13460
13542
  try {
13461
- const st = statSync8(absolute);
13543
+ const st = statSync9(absolute);
13462
13544
  size = st.isFile() ? st.size : -1;
13463
13545
  } catch {
13464
13546
  size = -1;
@@ -13587,8 +13669,8 @@ app5.post("/reply", requireAdminSession, async (c) => {
13587
13669
  var whatsapp_reader_default = app5;
13588
13670
 
13589
13671
  // server/routes/public-reader.ts
13590
- import { statSync as statSync9, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch3, readFileSync as readFileSync22, readdirSync as readdirSync15 } from "fs";
13591
- import { basename as basename7, dirname as dirname8, join as join22, resolve as resolve18, sep as sep6 } from "path";
13672
+ import { statSync as statSync10, openSync as openSync2, readSync as readSync2, closeSync as closeSync2, watch as watch3, readFileSync as readFileSync22, readdirSync as readdirSync15 } from "fs";
13673
+ import { basename as basename7, dirname as dirname8, join as join23, resolve as resolve18, sep as sep6 } from "path";
13592
13674
 
13593
13675
  // app/lib/whatsapp-reader/delivered-kinds.ts
13594
13676
  var PUBLIC_DELIVERED_KINDS = /* @__PURE__ */ new Set([
@@ -13662,10 +13744,10 @@ function enumeratePublicRows() {
13662
13744
  const cfg = claudeConfigDir();
13663
13745
  if (!cfg) return [];
13664
13746
  const rows = [];
13665
- for (const { path: path3 } of enumerateJsonls(join22(cfg, "projects"))) {
13747
+ for (const { path: path3 } of enumerateJsonls(join23(cfg, "projects"))) {
13666
13748
  const sessionId = basename7(path3).replace(/\.jsonl$/, "");
13667
13749
  const projectDir = dirname8(path3);
13668
- const meta = readSidecarMeta(join22(projectDir, `${sessionId}.meta.json`));
13750
+ const meta = readSidecarMeta(join23(projectDir, `${sessionId}.meta.json`));
13669
13751
  rows.push({
13670
13752
  sessionId,
13671
13753
  projectDir,
@@ -13721,7 +13803,7 @@ function enrichPublicAttachments(turns, sessionAttachments, cursor) {
13721
13803
  }
13722
13804
  }
13723
13805
  function readFrom2(path3, from) {
13724
- const end = statSync9(path3).size;
13806
+ const end = statSync10(path3).size;
13725
13807
  if (end <= from) return { buf: Buffer.alloc(0), end: from };
13726
13808
  const fd = openSync2(path3, "r");
13727
13809
  try {
@@ -13741,15 +13823,15 @@ app6.get("/stream", (c) => {
13741
13823
  const sessionId = c.req.query("sessionId") ?? "";
13742
13824
  const projectDir = c.req.query("projectDir") ?? "";
13743
13825
  const cfg = claudeConfigDir();
13744
- const projectsRoot = cfg ? resolve18(join22(cfg, "projects")) : null;
13826
+ const projectsRoot = cfg ? resolve18(join23(cfg, "projects")) : null;
13745
13827
  if (!cfg || !projectsRoot || !SESSION_ID_RE2.test(sessionId)) {
13746
13828
  return c.json({ error: "bad session reference" }, 400);
13747
13829
  }
13748
- const jsonlPath = resolve18(join22(projectDir, `${sessionId}.jsonl`));
13830
+ const jsonlPath = resolve18(join23(projectDir, `${sessionId}.jsonl`));
13749
13831
  if (!jsonlPath.startsWith(projectsRoot + sep6)) {
13750
13832
  return c.json({ error: "bad session reference" }, 400);
13751
13833
  }
13752
- const meta = readSidecarMeta(join22(projectDir, `${sessionId}.meta.json`));
13834
+ const meta = readSidecarMeta(join23(projectDir, `${sessionId}.meta.json`));
13753
13835
  const isPublicWebchat = meta.role === "public" && meta.channel === "webchat";
13754
13836
  const owns = visitor.kind === "person" ? meta.personId === visitor.personId : meta.personId === null && meta.visitorId === visitor.visitorId;
13755
13837
  if (!(isPublicWebchat && owns)) {
@@ -13886,16 +13968,16 @@ var public_reader_default = app6;
13886
13968
 
13887
13969
  // server/routes/webchat.ts
13888
13970
  import { basename as basename8, dirname as dirname9 } from "path";
13889
- import { join as join25 } from "path";
13890
- import { existsSync as existsSync19, readdirSync as readdirSync17, readFileSync as readFileSync25, renameSync as renameSync4, statSync as statSync10, writeFileSync as writeFileSync9 } from "fs";
13971
+ import { join as join26 } from "path";
13972
+ import { existsSync as existsSync19, readdirSync as readdirSync17, readFileSync as readFileSync25, renameSync as renameSync4, statSync as statSync11, writeFileSync as writeFileSync9 } from "fs";
13891
13973
 
13892
13974
  // server/canonical-webchat-override.ts
13893
13975
  import { readFileSync as readFileSync23, writeFileSync as writeFileSync7, renameSync as renameSync2 } from "fs";
13894
- import { join as join23 } from "path";
13976
+ import { join as join24 } from "path";
13895
13977
  var FILE = "canonical-webchat-session.json";
13896
13978
  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}$/;
13897
13979
  function canonicalOverridePath(accountDir) {
13898
- return join23(accountDir, FILE);
13980
+ return join24(accountDir, FILE);
13899
13981
  }
13900
13982
  function readRaw(accountDir) {
13901
13983
  try {
@@ -13975,7 +14057,7 @@ function isNewSessionEffortLevel(value) {
13975
14057
 
13976
14058
  // ../services/claude-session-manager/src/sidecar-store.ts
13977
14059
  import { existsSync as existsSync18, mkdirSync as mkdirSync4, readdirSync as readdirSync16, readFileSync as readFileSync24, renameSync as renameSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync8 } from "fs";
13978
- import { join as join24 } from "path";
14060
+ import { join as join25 } from "path";
13979
14061
  function escapeRegExp(s) {
13980
14062
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
13981
14063
  }
@@ -13983,7 +14065,7 @@ function createSidecarStore(config) {
13983
14065
  const { suffix, validate: validate2 } = config;
13984
14066
  const suffixRe = new RegExp(`${escapeRegExp(suffix)}$`);
13985
14067
  function pathFor(sessionsDir, id) {
13986
- return join24(sessionsDir, `${id}${suffix}`);
14068
+ return join25(sessionsDir, `${id}${suffix}`);
13987
14069
  }
13988
14070
  function write(sessionsDir, id, record) {
13989
14071
  mkdirSync4(sessionsDir, { recursive: true });
@@ -14027,7 +14109,7 @@ function createSidecarStore(config) {
14027
14109
  const out = [];
14028
14110
  for (const name of names) {
14029
14111
  if (!suffixRe.test(name)) continue;
14030
- const path3 = join24(sessionsDir, name);
14112
+ const path3 = join25(sessionsDir, name);
14031
14113
  let raw;
14032
14114
  try {
14033
14115
  raw = readFileSync24(path3, "utf8");
@@ -14104,13 +14186,13 @@ var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9
14104
14186
  function locateSession(sessionId) {
14105
14187
  const dir = findSessionProjectDir(sessionId);
14106
14188
  if (!dir) return { projectDir: null, channel: null, accountId: null };
14107
- const meta = readSidecarMeta(join25(dir, `${sessionId}.meta.json`));
14189
+ const meta = readSidecarMeta(join26(dir, `${sessionId}.meta.json`));
14108
14190
  return { projectDir: dir, channel: meta.channel, accountId: meta.accountId };
14109
14191
  }
14110
14192
  function locateSidecar(sessionId) {
14111
14193
  const cfg = claudeConfigDir();
14112
14194
  if (!cfg) return null;
14113
- const projectsRoot = join25(cfg, "projects");
14195
+ const projectsRoot = join26(cfg, "projects");
14114
14196
  let slugs;
14115
14197
  try {
14116
14198
  slugs = readdirSync17(projectsRoot, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
@@ -14118,7 +14200,7 @@ function locateSidecar(sessionId) {
14118
14200
  return null;
14119
14201
  }
14120
14202
  for (const slug of slugs) {
14121
- const metaPath = join25(projectsRoot, slug, `${sessionId}.meta.json`);
14203
+ const metaPath = join26(projectsRoot, slug, `${sessionId}.meta.json`);
14122
14204
  if (existsSync19(metaPath)) return readSidecarMeta(metaPath);
14123
14205
  }
14124
14206
  return null;
@@ -14128,7 +14210,7 @@ function readTargetOwner(sessionId) {
14128
14210
  if (sidecar !== null) return { found: true, owner: sidecar.adminUserId };
14129
14211
  const { projectDir } = locateSession(sessionId);
14130
14212
  if (projectDir !== null) {
14131
- return { found: true, owner: readSidecarMeta(join25(projectDir, `${sessionId}.meta.json`)).adminUserId };
14213
+ return { found: true, owner: readSidecarMeta(join26(projectDir, `${sessionId}.meta.json`)).adminUserId };
14132
14214
  }
14133
14215
  return { found: false, owner: null };
14134
14216
  }
@@ -14136,7 +14218,7 @@ function readSourceRowMeta(sessionId) {
14136
14218
  const sidecar = locateSidecar(sessionId);
14137
14219
  if (sidecar !== null) return sidecar;
14138
14220
  const { projectDir } = locateSession(sessionId);
14139
- if (projectDir !== null) return readSidecarMeta(join25(projectDir, `${sessionId}.meta.json`));
14221
+ if (projectDir !== null) return readSidecarMeta(join26(projectDir, `${sessionId}.meta.json`));
14140
14222
  return null;
14141
14223
  }
14142
14224
  function ownedByRequester(owner, requesterUserId, primaryUserId) {
@@ -14149,7 +14231,7 @@ function sessionSidecarExists(sessionId) {
14149
14231
  function jsonlSizeBytes(projectDir, sessionId) {
14150
14232
  if (projectDir === null) return null;
14151
14233
  try {
14152
- return statSync10(join25(projectDir, `${sessionId}.jsonl`)).size;
14234
+ return statSync11(join26(projectDir, `${sessionId}.jsonl`)).size;
14153
14235
  } catch {
14154
14236
  return null;
14155
14237
  }
@@ -14285,15 +14367,15 @@ function latestAdminWebchatSessionId(requesterUserId, primaryUserId, scopeAccoun
14285
14367
  const cfg = claudeConfigDir();
14286
14368
  if (!cfg) return null;
14287
14369
  let best = null;
14288
- for (const { path: path3, isSubagent, archived } of enumerateJsonls(join25(cfg, "projects"))) {
14370
+ for (const { path: path3, isSubagent, archived } of enumerateJsonls(join26(cfg, "projects"))) {
14289
14371
  if (isSubagent || archived) continue;
14290
14372
  const id = basename8(path3).slice(0, -".jsonl".length);
14291
- const meta = readSidecarMeta(join25(dirname9(path3), `${id}.meta.json`));
14373
+ const meta = readSidecarMeta(join26(dirname9(path3), `${id}.meta.json`));
14292
14374
  if (meta.role !== "admin" || meta.channel !== "webchat") continue;
14293
14375
  if (multiAccount && meta.accountId !== scopeAccountId) continue;
14294
14376
  let mtimeMs;
14295
14377
  try {
14296
- mtimeMs = statSync10(path3).mtimeMs;
14378
+ mtimeMs = statSync11(path3).mtimeMs;
14297
14379
  } catch {
14298
14380
  continue;
14299
14381
  }
@@ -14601,7 +14683,7 @@ ${note}` : note;
14601
14683
  console.error(`[webchat:settings] op=${op} outcome=refused value=${value} reason=account-unresolved`);
14602
14684
  return c.json({ error: "account unresolved" }, 503);
14603
14685
  }
14604
- const accountJsonPath = join25(account.accountDir, "account.json");
14686
+ const accountJsonPath = join26(account.accountDir, "account.json");
14605
14687
  try {
14606
14688
  const parsed = JSON.parse(readFileSync25(accountJsonPath, "utf8"));
14607
14689
  if (op === "model") parsed.adminModel = value;
@@ -14649,7 +14731,7 @@ ${note}` : note;
14649
14731
  const cfg2 = claudeConfigDir();
14650
14732
  if (cfg2) {
14651
14733
  const source2 = resolveBridgeSource(
14652
- join25(cfg2, "sessions"),
14734
+ join26(cfg2, "sessions"),
14653
14735
  target,
14654
14736
  (id) => locateSession(id).projectDir !== null
14655
14737
  );
@@ -14681,7 +14763,7 @@ ${note}` : note;
14681
14763
  const cfg = claudeConfigDir();
14682
14764
  let projectDir = null;
14683
14765
  if (cfg) {
14684
- for (const { path: path3 } of enumerateJsonls(join25(cfg, "projects"))) {
14766
+ for (const { path: path3 } of enumerateJsonls(join26(cfg, "projects"))) {
14685
14767
  if (basename8(path3) === `${sessionId}.jsonl`) {
14686
14768
  projectDir = dirname9(path3);
14687
14769
  break;
@@ -14689,7 +14771,7 @@ ${note}` : note;
14689
14771
  }
14690
14772
  }
14691
14773
  if (source === "latest" && requesterUserId !== null) {
14692
- const owner = readSidecarMeta(join25(projectDir ?? "", `${sessionId}.meta.json`)).adminUserId;
14774
+ const owner = readSidecarMeta(join26(projectDir ?? "", `${sessionId}.meta.json`)).adminUserId;
14693
14775
  if (owner !== null && owner !== requesterUserId && requesterUserId !== primaryUserId) {
14694
14776
  console.error(`[webchat:inbound] op=session-resolve-foreign key=${sessionId.slice(0, 8)} owner=${owner.slice(0, 8)} requester=${requesterUserId.slice(0, 8)}`);
14695
14777
  }
@@ -14722,7 +14804,7 @@ import { resolve as resolve19 } from "path";
14722
14804
 
14723
14805
  // app/lib/claude-agent/specialist-roster.ts
14724
14806
  import { existsSync as existsSync20, readFileSync as readFileSync26, readdirSync as readdirSync18 } from "fs";
14725
- import { join as join26 } from "path";
14807
+ import { join as join27 } from "path";
14726
14808
  function field(fm, name) {
14727
14809
  const m = fm.match(new RegExp(`^${name}:\\s*(.*?)\\r?$`, "m"));
14728
14810
  if (!m) return null;
@@ -14741,7 +14823,7 @@ function readSpecialistRoster(specialistsDir) {
14741
14823
  if (!file.endsWith(".md")) continue;
14742
14824
  let raw;
14743
14825
  try {
14744
- raw = readFileSync26(join26(specialistsDir, file), "utf-8");
14826
+ raw = readFileSync26(join27(specialistsDir, file), "utf-8");
14745
14827
  } catch (err) {
14746
14828
  skipped.push({ file, reason: err instanceof Error ? err.message : String(err) });
14747
14829
  continue;
@@ -14858,7 +14940,7 @@ var webchat_greeting_default = app7;
14858
14940
 
14859
14941
  // server/routes/telegram.ts
14860
14942
  import { homedir as homedir2 } from "os";
14861
- import { resolve as resolve20, join as join27 } from "path";
14943
+ import { resolve as resolve20, join as join28 } from "path";
14862
14944
  import { existsSync as existsSync21, readFileSync as readFileSync27 } from "fs";
14863
14945
 
14864
14946
  // app/lib/telegram/gateway/instance.ts
@@ -14918,7 +15000,7 @@ function routeTelegramUpdate(input) {
14918
15000
  var TAG30 = "[telegram-inbound]";
14919
15001
  function configDirName() {
14920
15002
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? resolve20(process.cwd(), "..");
14921
- const brandPath = join27(platformRoot5, "config", "brand.json");
15003
+ const brandPath = join28(platformRoot5, "config", "brand.json");
14922
15004
  if (existsSync21(brandPath)) {
14923
15005
  try {
14924
15006
  return JSON.parse(readFileSync27(brandPath, "utf-8")).configDir ?? ".maxy";
@@ -15007,16 +15089,16 @@ app8.post("/", async (c) => {
15007
15089
  var telegram_default = app8;
15008
15090
 
15009
15091
  // server/routes/quickbooks.ts
15010
- import { join as join28 } from "path";
15092
+ import { join as join29 } from "path";
15011
15093
  import { existsSync as existsSync22, readFileSync as readFileSync28, writeFileSync as writeFileSync10, mkdirSync as mkdirSync5, rmSync, renameSync as renameSync5 } from "fs";
15012
15094
  var TAG31 = "[quickbooks]";
15013
15095
  var INTUIT_TOKEN_URL = "https://oauth.platform.intuit.com/oauth2/v1/tokens/bearer";
15014
15096
  var STATE_RE = /^[A-Za-z0-9_-]+$/;
15015
15097
  function pendingPath(accountDir, state) {
15016
- return join28(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
15098
+ return join29(accountDir, "secrets", "quickbooks-pending", `${state}.json`);
15017
15099
  }
15018
15100
  function storePath(accountDir) {
15019
- return join28(accountDir, "secrets", "quickbooks.json");
15101
+ return join29(accountDir, "secrets", "quickbooks.json");
15020
15102
  }
15021
15103
  async function completeConsent(args) {
15022
15104
  const { accountDir, code, realmId } = args;
@@ -15083,7 +15165,7 @@ async function completeConsent(args) {
15083
15165
  refreshTokenExpiry: now + (body.x_refresh_token_expires_in ?? 864e4) * 1e3,
15084
15166
  lastRefresh: now
15085
15167
  };
15086
- mkdirSync5(join28(accountDir, "secrets"), { recursive: true });
15168
+ mkdirSync5(join29(accountDir, "secrets"), { recursive: true });
15087
15169
  writeFileSync10(storePath(accountDir), JSON.stringify(store2, null, 2), { mode: 384 });
15088
15170
  const persisted = JSON.parse(readFileSync28(storePath(accountDir), "utf-8")).connections?.[realmId]?.refreshToken === body.refresh_token;
15089
15171
  console.error(`${TAG31} op=token-exchange realmId=${realmId} persisted=${persisted}`);
@@ -15125,7 +15207,7 @@ function claudeBin() {
15125
15207
  }
15126
15208
 
15127
15209
  // server/routes/onboarding.ts
15128
- import { dirname as dirname11, join as join30 } from "path";
15210
+ import { dirname as dirname11, join as join31 } from "path";
15129
15211
 
15130
15212
  // app/lib/claude-keychain.ts
15131
15213
  import { execFileSync as execFileSync3 } from "child_process";
@@ -15254,8 +15336,8 @@ function readHostCredsBlob(service) {
15254
15336
  }
15255
15337
 
15256
15338
  // ../lib/admins-write/src/index.ts
15257
- 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";
15258
- import { dirname as dirname10, join as join29 } from "path";
15339
+ import { existsSync as existsSync23, readFileSync as readFileSync29, writeFileSync as writeFileSync11, renameSync as renameSync6, mkdirSync as mkdirSync6, readdirSync as readdirSync19, statSync as statSync12, appendFileSync as appendFileSync3 } from "fs";
15340
+ import { dirname as dirname10, join as join30 } from "path";
15259
15341
  function id8(value) {
15260
15342
  return value.slice(0, 8);
15261
15343
  }
@@ -15328,7 +15410,7 @@ function writeAdminEntry(input) {
15328
15410
  return result;
15329
15411
  }
15330
15412
  try {
15331
- const accountJsonPath = join29(input.accountDir, "account.json");
15413
+ const accountJsonPath = join30(input.accountDir, "account.json");
15332
15414
  if (!existsSync23(accountJsonPath)) {
15333
15415
  throw new Error(`account.json not found at ${accountJsonPath}`);
15334
15416
  }
@@ -15376,13 +15458,13 @@ function computeAdminStoreDivergence(input) {
15376
15458
  }
15377
15459
  for (const entry of entries2) {
15378
15460
  if (entry.startsWith(".")) continue;
15379
- const accountDir = join29(input.accountsDir, entry);
15461
+ const accountDir = join30(input.accountsDir, entry);
15380
15462
  try {
15381
- if (!statSync11(accountDir).isDirectory()) continue;
15463
+ if (!statSync12(accountDir).isDirectory()) continue;
15382
15464
  } catch {
15383
15465
  continue;
15384
15466
  }
15385
- const accountJsonPath = join29(accountDir, "account.json");
15467
+ const accountJsonPath = join30(accountDir, "account.json");
15386
15468
  if (!existsSync23(accountJsonPath)) continue;
15387
15469
  let admins = [];
15388
15470
  try {
@@ -15560,7 +15642,7 @@ app10.post("/claude-auth", async (c) => {
15560
15642
  });
15561
15643
  persistKeychainService(
15562
15644
  writebackResult,
15563
- (service) => writeFileSync12(join30(dirname11(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
15645
+ (service) => writeFileSync12(join31(dirname11(CLAUDE_CREDENTIALS_FILE), ".keychain-service"), service, { mode: 384 }),
15564
15646
  (line) => console.log(line)
15565
15647
  );
15566
15648
  if (darwinAuthChild === claudeProc2) darwinAuthChild = null;
@@ -15825,9 +15907,9 @@ ${body.newPin}
15825
15907
  var onboarding_default = app10;
15826
15908
 
15827
15909
  // server/routes/client-error.ts
15828
- import { appendFileSync as appendFileSync4, existsSync as existsSync25, renameSync as renameSync8, statSync as statSync12 } from "fs";
15829
- import { join as join31 } from "path";
15830
- var CLIENT_ERRORS_LOG = join31(LOG_DIR, "client-errors.log");
15910
+ import { appendFileSync as appendFileSync4, existsSync as existsSync25, renameSync as renameSync8, statSync as statSync13 } from "fs";
15911
+ import { join as join32 } from "path";
15912
+ var CLIENT_ERRORS_LOG = join32(LOG_DIR, "client-errors.log");
15831
15913
  var MAX_LOG_SIZE = 10 * 1024 * 1024;
15832
15914
  var MAX_BODY_SIZE = 8 * 1024;
15833
15915
  var MAX_STACK_LEN = 2e3;
@@ -15885,7 +15967,7 @@ function stackHead(stack) {
15885
15967
  function rotateIfNeeded() {
15886
15968
  try {
15887
15969
  if (!existsSync25(CLIENT_ERRORS_LOG)) return;
15888
- const stats = statSync12(CLIENT_ERRORS_LOG);
15970
+ const stats = statSync13(CLIENT_ERRORS_LOG);
15889
15971
  if (stats.size < MAX_LOG_SIZE) return;
15890
15972
  renameSync8(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
15891
15973
  } catch (err) {
@@ -15971,7 +16053,7 @@ app11.post("/", async (c) => {
15971
16053
  const safe = typeof v === "string" ? truncate(v, 200) : typeof v === "number" || typeof v === "boolean" ? String(v) : JSON.stringify(v).slice(0, 200);
15972
16054
  return `${k}=${safe}`;
15973
16055
  }).join(" ");
15974
- const TAGGED_PREFIX_SOURCES = /* @__PURE__ */ new Set(["stream-log-click", "pwa", "graph-settle"]);
16056
+ const TAGGED_PREFIX_SOURCES = /* @__PURE__ */ new Set(["stream-log-click", "pwa", "graph-settle", "dashboard-load"]);
15975
16057
  if (TAGGED_PREFIX_SOURCES.has(source)) {
15976
16058
  console.log(
15977
16059
  `[${source}] ts=${ts} ip=${ip} version=${version || "unknown"}${extra ? " " + extra : ""}`
@@ -16211,17 +16293,17 @@ app13.get("/", requireAdminSession, async (c) => {
16211
16293
  var accounts_default = app13;
16212
16294
 
16213
16295
  // server/routes/admin/logs.ts
16214
- import { existsSync as existsSync27, readdirSync as readdirSync20, readFileSync as readFileSync31, statSync as statSync13 } from "fs";
16296
+ import { existsSync as existsSync27, readdirSync as readdirSync20, readFileSync as readFileSync31, statSync as statSync14 } from "fs";
16215
16297
  import { resolve as resolve21, basename as basename9 } from "path";
16216
16298
 
16217
16299
  // app/lib/logs-read-resolve.ts
16218
16300
  import { existsSync as existsSync26 } from "fs";
16219
- import { join as join32 } from "path";
16301
+ import { join as join33 } from "path";
16220
16302
  function resolveSessionLogPaths(filename, logDirs) {
16221
16303
  const tried = [filename];
16222
16304
  const hits = [];
16223
16305
  for (const dir of logDirs) {
16224
- const fullPath = join32(dir, filename);
16306
+ const fullPath = join33(dir, filename);
16225
16307
  if (existsSync26(fullPath)) {
16226
16308
  hits.push({ path: fullPath, dir });
16227
16309
  }
@@ -16251,7 +16333,7 @@ app14.get("/", async (c) => {
16251
16333
  searched.push(filePath);
16252
16334
  try {
16253
16335
  const buffer = readFileSync31(filePath);
16254
- const onDiskBytes = statSync13(filePath).size;
16336
+ const onDiskBytes = statSync14(filePath).size;
16255
16337
  const headers = {
16256
16338
  "Content-Type": "text/plain; charset=utf-8",
16257
16339
  "Content-Length": String(buffer.byteLength)
@@ -16316,7 +16398,7 @@ app14.get("/", async (c) => {
16316
16398
  try {
16317
16399
  const filename = basename9(hit.path);
16318
16400
  const buffer = readFileSync31(hit.path);
16319
- const onDiskBytes = statSync13(hit.path).size;
16401
+ const onDiskBytes = statSync14(hit.path).size;
16320
16402
  const headers = {
16321
16403
  "Content-Type": "text/plain; charset=utf-8",
16322
16404
  "Content-Length": String(buffer.byteLength)
@@ -16359,7 +16441,7 @@ app14.get("/", async (c) => {
16359
16441
  console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
16360
16442
  continue;
16361
16443
  }
16362
- files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync13(resolve21(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
16444
+ files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync14(resolve21(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
16363
16445
  seen.add(name);
16364
16446
  try {
16365
16447
  const content = readFileSync31(resolve21(dir, name));
@@ -16479,7 +16561,7 @@ var attachment_default = app16;
16479
16561
 
16480
16562
  // server/routes/admin/session-upload.ts
16481
16563
  import { readFile as readFile5 } from "fs/promises";
16482
- import { existsSync as existsSync29, statSync as statSync14 } from "fs";
16564
+ import { existsSync as existsSync29, statSync as statSync15 } from "fs";
16483
16565
  var app17 = new Hono();
16484
16566
  app17.get("/", requireAdminSession, async (c) => {
16485
16567
  const cacheKey = c.var.cacheKey;
@@ -16500,7 +16582,7 @@ app17.get("/", requireAdminSession, async (c) => {
16500
16582
  return c.json({ error: "Not found" }, 404);
16501
16583
  }
16502
16584
  const resolution = resolveClaudeUploadsPath(`${sessionId}/${file}`);
16503
- if (!resolution.ok || !existsSync29(resolution.absolute) || !statSync14(resolution.absolute).isFile()) {
16585
+ if (!resolution.ok || !existsSync29(resolution.absolute) || !statSync15(resolution.absolute).isFile()) {
16504
16586
  console.log(`[session-upload] op=miss session=${short2} file=${file} status=404 reason=absent`);
16505
16587
  return c.json({ error: "Not found" }, 404);
16506
16588
  }
@@ -16522,7 +16604,7 @@ var session_upload_default = app17;
16522
16604
 
16523
16605
  // server/routes/admin/agents.ts
16524
16606
  import { resolve as resolve23 } from "path";
16525
- import { readdirSync as readdirSync21, readFileSync as readFileSync32, existsSync as existsSync30, rmSync as rmSync2 } from "fs";
16607
+ import { readdirSync as readdirSync22, readFileSync as readFileSync33, existsSync as existsSync31, rmSync as rmSync2, renameSync as renameSync9, mkdirSync as mkdirSync7, writeFileSync as writeFileSync13 } from "fs";
16526
16608
 
16527
16609
  // server/routes/admin/_account-scope.ts
16528
16610
  function accountDirForSession(cacheKey) {
@@ -16549,12 +16631,390 @@ async function authorizeAccountWrite(c, accountId) {
16549
16631
  return { ok: true, via: "session" };
16550
16632
  }
16551
16633
 
16634
+ // ../services/claude-session-manager/src/tool-surface.ts
16635
+ import { readFileSync as readFileSync32, readdirSync as readdirSync21, statSync as statSync16, existsSync as existsSync30 } from "fs";
16636
+ import { createHash as createHash5 } from "crypto";
16637
+ import { join as join34 } from "path";
16638
+
16639
+ // ../services/claude-session-manager/src/canonical-tool-names.ts
16640
+ function canonicalToolName(plugin, tool) {
16641
+ return `mcp__plugin_${plugin}_${plugin}__${tool}`;
16642
+ }
16643
+ function qualifyShortToolName(plugin, tool) {
16644
+ return `mcp__${plugin}__${tool}`;
16645
+ }
16646
+
16647
+ // ../services/claude-session-manager/src/tool-surface.ts
16648
+ var RISK_CLASSES = ["read", "write_local", "exec", "external"];
16649
+ var ToolSurfaceError = class extends Error {
16650
+ constructor(reason, detail) {
16651
+ super(`${reason}: ${detail}`);
16652
+ this.reason = reason;
16653
+ this.detail = detail;
16654
+ this.name = "ToolSurfaceError";
16655
+ }
16656
+ };
16657
+ var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/;
16658
+ function extractFrontmatter(raw, pluginDir) {
16659
+ const m = raw.match(FRONTMATTER_RE);
16660
+ if (!m) {
16661
+ throw new ToolSurfaceError("frontmatter-missing", `${pluginDir}/PLUGIN.md has no '---' delimited frontmatter`);
16662
+ }
16663
+ return m[1];
16664
+ }
16665
+ function parseToolsBlock(frontmatter, pluginDir) {
16666
+ const lines = frontmatter.split(/\r?\n/);
16667
+ let i = 0;
16668
+ while (i < lines.length) {
16669
+ const line = lines[i];
16670
+ if (/^tools:\s*\[\s*\]\s*$/.test(line)) return [];
16671
+ if (/^tools:\s*$/.test(line)) {
16672
+ i++;
16673
+ break;
16674
+ }
16675
+ i++;
16676
+ }
16677
+ if (i >= lines.length) return [];
16678
+ const out = [];
16679
+ let current = null;
16680
+ const flush = () => {
16681
+ if (!current) return;
16682
+ if (typeof current.name !== "string" || current.name.length === 0) {
16683
+ throw new ToolSurfaceError("tool-name-missing", `${pluginDir}/PLUGIN.md has a tool entry with no name`);
16684
+ }
16685
+ if (typeof current.publicAllowlist !== "boolean") {
16686
+ if (current.publicAllowlist === void 0) {
16687
+ throw new ToolSurfaceError(
16688
+ "public-allowlist-missing",
16689
+ `${pluginDir}/${current.name} \u2014 every tool must declare publicAllowlist: <true|false>`
16690
+ );
16691
+ }
16692
+ throw new ToolSurfaceError(
16693
+ "public-allowlist-not-boolean",
16694
+ `${pluginDir}/${current.name} \u2014 publicAllowlist must be a YAML boolean (true|false), got ${JSON.stringify(current.publicAllowlist)}`
16695
+ );
16696
+ }
16697
+ if (typeof current.adminAllowlist !== "boolean") {
16698
+ if (current.adminAllowlist === void 0) {
16699
+ throw new ToolSurfaceError(
16700
+ "admin-allowlist-missing",
16701
+ `${pluginDir}/${current.name} \u2014 every tool must declare adminAllowlist: <true|false>`
16702
+ );
16703
+ }
16704
+ throw new ToolSurfaceError(
16705
+ "admin-allowlist-not-boolean",
16706
+ `${pluginDir}/${current.name} \u2014 adminAllowlist must be a YAML boolean (true|false), got ${JSON.stringify(current.adminAllowlist)}`
16707
+ );
16708
+ }
16709
+ if (current.riskClass === void 0) {
16710
+ throw new ToolSurfaceError(
16711
+ "risk-class-missing",
16712
+ `${pluginDir}/${current.name} \u2014 every tool must declare riskClass: <${RISK_CLASSES.join("|")}>`
16713
+ );
16714
+ }
16715
+ if (!RISK_CLASSES.includes(current.riskClass)) {
16716
+ throw new ToolSurfaceError(
16717
+ "risk-class-invalid",
16718
+ `${pluginDir}/${current.name} \u2014 riskClass must be one of ${RISK_CLASSES.join("|")}, got ${JSON.stringify(current.riskClass)}`
16719
+ );
16720
+ }
16721
+ out.push(current);
16722
+ current = null;
16723
+ };
16724
+ for (; i < lines.length; i++) {
16725
+ const line = lines[i];
16726
+ if (line.length === 0) continue;
16727
+ if (/^[A-Za-z_]/.test(line)) break;
16728
+ const newEntry = line.match(/^\s+-\s+name:\s*(.+?)\s*$/);
16729
+ if (newEntry) {
16730
+ flush();
16731
+ current = { name: newEntry[1] };
16732
+ continue;
16733
+ }
16734
+ const orphanListItem = line.match(/^\s+-\s+(?!name:)/);
16735
+ if (orphanListItem) {
16736
+ throw new ToolSurfaceError("tool-name-missing", `${pluginDir}/PLUGIN.md tool entry lacks a name field`);
16737
+ }
16738
+ const publicAllow = line.match(/^\s+publicAllowlist:\s*(.+?)\s*$/);
16739
+ if (publicAllow && current) {
16740
+ const v = publicAllow[1].trim();
16741
+ if (v === "true") current.publicAllowlist = true;
16742
+ else if (v === "false") current.publicAllowlist = false;
16743
+ else current.publicAllowlist = v;
16744
+ continue;
16745
+ }
16746
+ const adminAllow = line.match(/^\s+adminAllowlist:\s*(.+?)\s*$/);
16747
+ if (adminAllow && current) {
16748
+ const v = adminAllow[1].trim();
16749
+ if (v === "true") current.adminAllowlist = true;
16750
+ else if (v === "false") current.adminAllowlist = false;
16751
+ else current.adminAllowlist = v;
16752
+ continue;
16753
+ }
16754
+ const risk = line.match(/^\s+riskClass:\s*(.+?)\s*$/);
16755
+ if (risk && current) {
16756
+ current.riskClass = risk[1].trim();
16757
+ continue;
16758
+ }
16759
+ }
16760
+ flush();
16761
+ return out;
16762
+ }
16763
+ function parseHiddenBlock(frontmatter, pluginDir) {
16764
+ const lines = frontmatter.split(/\r?\n/);
16765
+ let i = 0;
16766
+ while (i < lines.length) {
16767
+ if (/^hidden:\s*$/.test(lines[i])) {
16768
+ i++;
16769
+ break;
16770
+ }
16771
+ i++;
16772
+ }
16773
+ if (i >= lines.length) return [];
16774
+ const out = [];
16775
+ let current = null;
16776
+ const flush = () => {
16777
+ if (!current) return;
16778
+ if (current.riskClass === void 0) {
16779
+ throw new ToolSurfaceError(
16780
+ "risk-class-missing",
16781
+ `${pluginDir}/${current.name} \u2014 every hidden tool must declare riskClass: <${RISK_CLASSES.join("|")}>`
16782
+ );
16783
+ }
16784
+ if (!RISK_CLASSES.includes(current.riskClass)) {
16785
+ throw new ToolSurfaceError(
16786
+ "risk-class-invalid",
16787
+ `${pluginDir}/${current.name} \u2014 hidden riskClass must be one of ${RISK_CLASSES.join("|")}, got ${JSON.stringify(current.riskClass)}`
16788
+ );
16789
+ }
16790
+ out.push(current);
16791
+ current = null;
16792
+ };
16793
+ for (; i < lines.length; i++) {
16794
+ const line = lines[i];
16795
+ if (line.length === 0) continue;
16796
+ if (/^[A-Za-z_]/.test(line)) break;
16797
+ const newEntry = line.match(/^\s+-\s+name:\s*(.+?)\s*$/);
16798
+ if (newEntry) {
16799
+ flush();
16800
+ current = { name: newEntry[1] };
16801
+ continue;
16802
+ }
16803
+ const bareItem = line.match(/^\s+-\s+(.+?)\s*$/);
16804
+ if (bareItem) {
16805
+ throw new ToolSurfaceError(
16806
+ "hidden-tool-name-missing",
16807
+ `${pluginDir}/PLUGIN.md hidden entry "${bareItem[1]}" is a bare name \u2014 declare it as "- name: ${bareItem[1]}" with a riskClass`
16808
+ );
16809
+ }
16810
+ const risk = line.match(/^\s+riskClass:\s*(.+?)\s*$/);
16811
+ if (risk && current) {
16812
+ current.riskClass = risk[1].trim();
16813
+ continue;
16814
+ }
16815
+ }
16816
+ flush();
16817
+ return out;
16818
+ }
16819
+ function parseMcpBlock(frontmatter, pluginDir) {
16820
+ const lines = frontmatter.split(/\r?\n/);
16821
+ let i = 0;
16822
+ while (i < lines.length) {
16823
+ if (/^mcp:\s*$/.test(lines[i])) {
16824
+ i++;
16825
+ break;
16826
+ }
16827
+ i++;
16828
+ }
16829
+ if (i >= lines.length) return null;
16830
+ let command = null;
16831
+ const args = [];
16832
+ const env = {};
16833
+ let envHasEntry = false;
16834
+ let mode = "top";
16835
+ for (; i < lines.length; i++) {
16836
+ const line = lines[i];
16837
+ if (line.length === 0) continue;
16838
+ if (/^[A-Za-z_]/.test(line)) break;
16839
+ const topCommand = line.match(/^\s\s(command):\s*(.+?)\s*$/);
16840
+ const topArgsHeader = line.match(/^\s\s(args):\s*$/);
16841
+ const topEnvHeader = line.match(/^\s\s(env):\s*$/);
16842
+ if (topCommand) {
16843
+ command = topCommand[2];
16844
+ mode = "top";
16845
+ continue;
16846
+ }
16847
+ if (topArgsHeader) {
16848
+ mode = "args";
16849
+ continue;
16850
+ }
16851
+ if (topEnvHeader) {
16852
+ mode = "env";
16853
+ continue;
16854
+ }
16855
+ if (mode === "args") {
16856
+ const item = line.match(/^\s+-\s+(.+?)\s*$/);
16857
+ if (item) {
16858
+ args.push(item[1]);
16859
+ continue;
16860
+ }
16861
+ }
16862
+ if (mode === "env") {
16863
+ const kv = line.match(/^\s+([A-Za-z_][A-Za-z0-9_]*):\s*(.+?)\s*$/);
16864
+ if (kv) {
16865
+ env[kv[1]] = kv[2];
16866
+ envHasEntry = true;
16867
+ continue;
16868
+ }
16869
+ }
16870
+ }
16871
+ if (command === null) {
16872
+ throw new ToolSurfaceError("mcp-command-missing", `${pluginDir}/PLUGIN.md mcp: block has no command`);
16873
+ }
16874
+ const desc = { command, args };
16875
+ if (envHasEntry) desc.env = env;
16876
+ return desc;
16877
+ }
16878
+ function loadToolSurface(pluginsRoots) {
16879
+ const roots = Array.isArray(pluginsRoots) ? pluginsRoots : [pluginsRoots];
16880
+ for (const r of roots) {
16881
+ if (!existsSync30(r)) throw new ToolSurfaceError("plugins-root-missing", r);
16882
+ }
16883
+ const admin = /* @__PURE__ */ new Set();
16884
+ const pub = /* @__PURE__ */ new Set();
16885
+ const all = /* @__PURE__ */ new Set();
16886
+ const mcpServers = /* @__PURE__ */ new Map();
16887
+ const riskByTool = /* @__PURE__ */ new Map();
16888
+ const manifestPaths = /* @__PURE__ */ new Map();
16889
+ const loadOne = (pluginsRoot, plugin) => {
16890
+ const pluginDir = join34(pluginsRoot, plugin);
16891
+ try {
16892
+ if (!statSync16(pluginDir).isDirectory()) return;
16893
+ } catch {
16894
+ return;
16895
+ }
16896
+ const manifestPath = join34(pluginDir, "PLUGIN.md");
16897
+ if (!existsSync30(manifestPath)) return;
16898
+ const raw = readFileSync32(manifestPath, "utf-8");
16899
+ const frontmatter = extractFrontmatter(raw, plugin);
16900
+ const tools = parseToolsBlock(frontmatter, plugin);
16901
+ if (tools.length === 0) return;
16902
+ const mcp = parseMcpBlock(frontmatter, plugin);
16903
+ if (!mcp) {
16904
+ throw new ToolSurfaceError(
16905
+ "mcp-block-missing",
16906
+ `${plugin}/PLUGIN.md declares tools but no mcp: block; spawns would --allowed-tools mcp__${plugin}__* with no registered server`
16907
+ );
16908
+ }
16909
+ if (mcpServers.has(plugin)) {
16910
+ const priorPath = manifestPaths.get(plugin);
16911
+ if (!priorPath) {
16912
+ throw new ToolSurfaceError(
16913
+ "mcp-plugin-duplicate-no-prior-path",
16914
+ `${plugin}: mcpServers has entry but manifestPaths is missing \u2014 invariant violated, both maps must be written together`
16915
+ );
16916
+ }
16917
+ const priorSha = createHash5("sha256").update(readFileSync32(priorPath)).digest("hex").slice(0, 8);
16918
+ const newSha = createHash5("sha256").update(raw).digest("hex").slice(0, 8);
16919
+ throw new ToolSurfaceError(
16920
+ "mcp-plugin-duplicate",
16921
+ `${plugin} declared by more than one plugins root: ${priorPath} (sha=${priorSha}) vs ${manifestPath} (sha=${newSha})`
16922
+ );
16923
+ }
16924
+ mcpServers.set(plugin, mcp);
16925
+ manifestPaths.set(plugin, manifestPath);
16926
+ for (const t of tools) {
16927
+ const canonical = canonicalToolName(plugin, t.name);
16928
+ all.add(canonical);
16929
+ riskByTool.set(canonical, t.riskClass);
16930
+ if (t.adminAllowlist) admin.add(canonical);
16931
+ if (t.publicAllowlist) pub.add(qualifyShortToolName(plugin, t.name));
16932
+ }
16933
+ for (const h of parseHiddenBlock(frontmatter, plugin)) {
16934
+ const canonical = canonicalToolName(plugin, h.name);
16935
+ all.add(canonical);
16936
+ riskByTool.set(canonical, h.riskClass);
16937
+ }
16938
+ };
16939
+ for (const root of roots) {
16940
+ const entries2 = readdirSync21(root).sort();
16941
+ for (const plugin of entries2) {
16942
+ const pluginDir = join34(root, plugin);
16943
+ loadOne(root, plugin);
16944
+ const subRoot = join34(pluginDir, "plugins");
16945
+ let subEntries;
16946
+ try {
16947
+ if (!statSync16(subRoot).isDirectory()) continue;
16948
+ subEntries = readdirSync21(subRoot).sort();
16949
+ } catch {
16950
+ continue;
16951
+ }
16952
+ for (const sub of subEntries) {
16953
+ loadOne(subRoot, sub);
16954
+ }
16955
+ }
16956
+ }
16957
+ return { admin, public: pub, all, mcpServers, riskByTool };
16958
+ }
16959
+
16960
+ // server/lib/agent-risk.ts
16961
+ var BUILTIN_TOOL_RISK = {
16962
+ Bash: "exec",
16963
+ Task: "exec",
16964
+ Skill: "exec",
16965
+ Edit: "write_local",
16966
+ MultiEdit: "write_local",
16967
+ Write: "write_local",
16968
+ Read: "read",
16969
+ Glob: "read",
16970
+ Grep: "read",
16971
+ WebFetch: "external",
16972
+ WebSearch: "external"
16973
+ };
16974
+ var SEVERITY = {
16975
+ read: 0,
16976
+ write_local: 1,
16977
+ exec: 2,
16978
+ external: 2
16979
+ };
16980
+ var AGENT_CLASS = {
16981
+ read: "green",
16982
+ write_local: "amber",
16983
+ exec: "red",
16984
+ external: "red"
16985
+ };
16986
+ function agentRiskClass(tools, riskByTool) {
16987
+ const byTool = [];
16988
+ const unresolved = [];
16989
+ let worst = null;
16990
+ let riskiestTool = null;
16991
+ for (const tool of tools) {
16992
+ const cls = BUILTIN_TOOL_RISK[tool] ?? riskByTool.get(tool) ?? null;
16993
+ byTool.push({ tool, risk: cls });
16994
+ if (cls === null) {
16995
+ unresolved.push(tool);
16996
+ continue;
16997
+ }
16998
+ if (worst === null || SEVERITY[cls] > SEVERITY[worst]) {
16999
+ worst = cls;
17000
+ riskiestTool = tool;
17001
+ }
17002
+ }
17003
+ if (unresolved.length > 0) {
17004
+ return { risk: "red", riskiestTool: unresolved[0], unresolved, byTool };
17005
+ }
17006
+ if (worst === null) {
17007
+ return { risk: "red", riskiestTool: null, unresolved, byTool };
17008
+ }
17009
+ return { risk: AGENT_CLASS[worst], riskiestTool, unresolved, byTool };
17010
+ }
17011
+
16552
17012
  // server/routes/admin/agents.ts
16553
17013
  var SLUG_UNSAFE = (s) => s.includes("/") || s.includes("..") || s.includes("\\");
16554
17014
  function subdirs(dir) {
16555
- if (!existsSync30(dir)) return [];
17015
+ if (!existsSync31(dir)) return [];
16556
17016
  try {
16557
- return readdirSync21(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
17017
+ return readdirSync22(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
16558
17018
  } catch {
16559
17019
  return [];
16560
17020
  }
@@ -16569,34 +17029,148 @@ function splitFrontmatter(text) {
16569
17029
  }
16570
17030
  return { fm, body: text.slice(m[0].length) };
16571
17031
  }
16572
- function listSpecialists(accountDir) {
17032
+ var SPECIALISTS_DIR = ["specialists", "agents"];
17033
+ var QUARANTINE_DIR = ["specialists", "agents-disabled"];
17034
+ var DISABLED_STORE = "agents-disabled.json";
17035
+ function loadRiskSurface() {
17036
+ const roots = [resolve23(PLATFORM_ROOT, "plugins"), resolve23(PLATFORM_ROOT, "..", "premium-plugins")].filter((r) => existsSync31(r));
17037
+ try {
17038
+ return { riskByTool: loadToolSurface(roots).riskByTool, failed: null };
17039
+ } catch (err) {
17040
+ const msg = err instanceof Error ? err.message : String(err);
17041
+ console.error(`[admin/agents] op=risk-surface status=load-failed reason="${msg}"`);
17042
+ return { riskByTool: /* @__PURE__ */ new Map(), failed: msg };
17043
+ }
17044
+ }
17045
+ function readDisabledStoreStrict(accountDir) {
17046
+ const p = resolve23(accountDir, DISABLED_STORE);
17047
+ if (!existsSync31(p)) return /* @__PURE__ */ new Set();
17048
+ const parsed = JSON.parse(readFileSync33(p, "utf-8"));
17049
+ if (!Array.isArray(parsed.disabled)) throw new Error("disabled is not an array");
17050
+ return new Set(parsed.disabled.filter((x) => typeof x === "string"));
17051
+ }
17052
+ function readDisabledStore(accountDir) {
17053
+ try {
17054
+ return readDisabledStoreStrict(accountDir);
17055
+ } catch (err) {
17056
+ const msg = err instanceof Error ? err.message : String(err);
17057
+ console.error(`[admin/agents] op=disabled-store status=parse-failed reason="${msg}"`);
17058
+ return /* @__PURE__ */ new Set();
17059
+ }
17060
+ }
17061
+ function shippedSourceDirs(accountDir) {
17062
+ return [
17063
+ resolve23(accountDir, ...SPECIALISTS_DIR),
17064
+ resolve23(accountDir, ...QUARANTINE_DIR),
17065
+ resolve23(PLATFORM_ROOT, "templates", "specialists", "agents")
17066
+ ];
17067
+ }
17068
+ function writeDisabledStore(accountDir, disabled) {
17069
+ writeFileSync13(
17070
+ resolve23(accountDir, DISABLED_STORE),
17071
+ `${JSON.stringify({ disabled: [...disabled].sort() }, null, 2)}
17072
+ `,
17073
+ { mode: 384 }
17074
+ );
17075
+ }
17076
+ function listShipped(accountDir, riskByTool, disabled, riskSurfaceFailed) {
17077
+ const dirs = shippedSourceDirs(accountDir);
17078
+ const names = /* @__PURE__ */ new Set();
17079
+ for (const dir of dirs) {
17080
+ if (!existsSync31(dir)) continue;
17081
+ try {
17082
+ for (const entry of readdirSync22(dir)) if (entry.endsWith(".md")) names.add(entry);
17083
+ } catch (err) {
17084
+ console.error(`[admin/agents] op=list-shipped read-failed dir=${dir} error="${err}"`);
17085
+ }
17086
+ }
17087
+ const shipped = [];
17088
+ let shippedSkipped = 0;
17089
+ for (const filename of [...names].sort()) {
17090
+ const source = dirs.find((d) => existsSync31(resolve23(d, filename)));
17091
+ if (!source) continue;
17092
+ try {
17093
+ const { fm } = splitFrontmatter(readFileSync33(resolve23(source, filename), "utf-8"));
17094
+ if (!fm.name) {
17095
+ shippedSkipped++;
17096
+ console.error(`[admin/agents] op=list-shipped-skip file=${filename} reason=no-name`);
17097
+ continue;
17098
+ }
17099
+ const tools = parseToolsLine(fm.tools);
17100
+ const r = classify(tools, riskByTool, riskSurfaceFailed);
17101
+ shipped.push({
17102
+ slug: filename.replace(/\.md$/, ""),
17103
+ displayName: fm.name,
17104
+ kind: "specialist",
17105
+ origin: "shipped",
17106
+ plugin: "",
17107
+ description: fm.description ?? "",
17108
+ risk: r.risk,
17109
+ riskiestTool: r.riskiestTool,
17110
+ unresolved: r.unresolved,
17111
+ toolCount: tools.length,
17112
+ // The DIRECTORY is the ground truth, not the store. `spawn-context.ts`
17113
+ // reads the live dir, so a file found in quarantine is not dispatchable
17114
+ // whatever the JSON says, and a file found live IS dispatchable even if
17115
+ // the store claims otherwise. The store only answers for a bundled-only
17116
+ // agent, which has no account copy in either directory to look at.
17117
+ disabled: source === dirs[1] || source === dirs[2] && disabled.has(filename)
17118
+ });
17119
+ } catch (err) {
17120
+ shippedSkipped++;
17121
+ console.error(`[admin/agents] op=list-shipped-skip file=${filename} error="${err}"`);
17122
+ }
17123
+ }
17124
+ return { shipped, shippedSkipped };
17125
+ }
17126
+ function parseToolsLine(raw) {
17127
+ return raw ? raw.split(",").map((t) => t.trim()).filter(Boolean) : [];
17128
+ }
17129
+ function classify(tools, riskByTool, riskSurfaceFailed) {
17130
+ if (riskSurfaceFailed) {
17131
+ return { risk: "red", riskiestTool: null, unresolved: [], byTool: tools.map((t) => ({ tool: t, risk: null })) };
17132
+ }
17133
+ return agentRiskClass(tools, riskByTool);
17134
+ }
17135
+ function listSpecialists(accountDir, riskByTool, riskSurfaceFailed) {
16573
17136
  const pluginsDir = resolve23(accountDir, "plugins");
16574
17137
  const specialists = [];
16575
17138
  let specialistsSkipped = 0;
16576
17139
  for (const plugin of subdirs(pluginsDir).sort()) {
16577
17140
  const agentsDirP = resolve23(pluginsDir, plugin, "agents");
16578
- if (!existsSync30(agentsDirP)) continue;
17141
+ if (!existsSync31(agentsDirP)) continue;
16579
17142
  let entries2;
16580
17143
  try {
16581
- entries2 = readdirSync21(agentsDirP, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
17144
+ entries2 = readdirSync22(agentsDirP, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
16582
17145
  } catch {
16583
17146
  continue;
16584
17147
  }
16585
17148
  for (const entry of entries2) {
16586
17149
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
16587
17150
  try {
16588
- const { fm } = splitFrontmatter(readFileSync32(resolve23(agentsDirP, entry.name), "utf-8"));
17151
+ const { fm } = splitFrontmatter(readFileSync33(resolve23(agentsDirP, entry.name), "utf-8"));
16589
17152
  if (!fm.name) {
16590
17153
  specialistsSkipped++;
16591
17154
  console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry.name}`);
16592
17155
  continue;
16593
17156
  }
17157
+ const specialistTools = parseToolsLine(fm.tools);
17158
+ const r = classify(specialistTools, riskByTool, riskSurfaceFailed);
16594
17159
  specialists.push({
16595
17160
  slug: entry.name.replace(/\.md$/, ""),
16596
17161
  displayName: fm.name,
16597
17162
  kind: "specialist",
17163
+ origin: "specialist",
16598
17164
  plugin,
16599
- description: fm.description ?? ""
17165
+ description: fm.description ?? "",
17166
+ risk: r.risk,
17167
+ riskiestTool: r.riskiestTool,
17168
+ unresolved: r.unresolved,
17169
+ toolCount: specialistTools.length,
17170
+ // A user-created specialist lives under the account plugins tree,
17171
+ // which provisioning never rewrites, so the quarantine mechanism
17172
+ // does not apply to it.
17173
+ disabled: false
16600
17174
  });
16601
17175
  } catch {
16602
17176
  specialistsSkipped++;
@@ -16619,24 +17193,31 @@ app18.get("/", requireAdminSession, (c) => {
16619
17193
  console.error("[admin/agents] op=list auth-rejected reason=no-account-for-session");
16620
17194
  return c.json({ error: "Account not found for session" }, 401);
16621
17195
  }
17196
+ const { riskByTool, failed: riskSurfaceFailed } = loadRiskSurface();
17197
+ const disabled = readDisabledStore(account.accountDir);
16622
17198
  const agents = [];
16623
17199
  let skipped = 0;
16624
17200
  const agentsDir = resolve23(account.accountDir, "agents");
16625
- if (existsSync30(agentsDir)) {
17201
+ if (existsSync31(agentsDir)) {
16626
17202
  try {
16627
- const entries2 = readdirSync21(agentsDir, { withFileTypes: true });
17203
+ const entries2 = readdirSync22(agentsDir, { withFileTypes: true });
16628
17204
  for (const entry of entries2.sort((a, b) => a.name.localeCompare(b.name))) {
16629
17205
  if (!entry.isDirectory()) continue;
16630
17206
  if (entry.name === "admin") continue;
16631
17207
  const configPath2 = resolve23(agentsDir, entry.name, "config.json");
16632
- if (!existsSync30(configPath2)) continue;
17208
+ if (!existsSync31(configPath2)) continue;
16633
17209
  try {
16634
- const config = JSON.parse(readFileSync32(configPath2, "utf-8"));
17210
+ const config = JSON.parse(readFileSync33(configPath2, "utf-8"));
16635
17211
  agents.push({
16636
17212
  slug: entry.name,
16637
17213
  displayName: config.displayName ?? entry.name,
16638
17214
  status: config.status ?? "unknown",
16639
- kind: "public"
17215
+ kind: "public",
17216
+ origin: "public",
17217
+ risk: null,
17218
+ riskiestTool: null,
17219
+ unresolved: [],
17220
+ disabled: false
16640
17221
  });
16641
17222
  } catch {
16642
17223
  skipped++;
@@ -16647,9 +17228,25 @@ app18.get("/", requireAdminSession, (c) => {
16647
17228
  console.error(`[admin/agents] failed to scan agents directory: ${err}`);
16648
17229
  }
16649
17230
  }
16650
- const { specialists, specialistsSkipped } = listSpecialists(account.accountDir);
16651
- console.log(`[admin/agents] op=list accountId=${account.accountId.slice(0, 8)} agents=${agents.length} specialists=${specialists.length} skipped=${skipped} specialistsSkipped=${specialistsSkipped}`);
16652
- return c.json({ agents: [...agents, ...specialists], accountId: account.accountId, skipped, specialistsSkipped });
17231
+ const { specialists, specialistsSkipped } = listSpecialists(account.accountDir, riskByTool, riskSurfaceFailed !== null);
17232
+ const { shipped, shippedSkipped } = listShipped(account.accountDir, riskByTool, disabled, riskSurfaceFailed !== null);
17233
+ const rows = [...agents, ...specialists, ...shipped];
17234
+ const acct = account.accountId.slice(0, 8);
17235
+ for (const row of rows) {
17236
+ if (row.risk === null) continue;
17237
+ console.log(
17238
+ `[admin/agents] op=classify account=${acct} agent=${row.slug} origin=${row.origin} risk=${row.risk} riskiestTool=${row.riskiestTool ?? "none"} tools=${row.toolCount} unresolved=${row.unresolved.length > 0 ? row.unresolved.join(",") : "none"} disabled=${row.disabled}`
17239
+ );
17240
+ }
17241
+ console.log(`[admin/agents] op=list accountId=${acct} agents=${agents.length} specialists=${specialists.length} shipped=${shipped.length} skipped=${skipped} specialistsSkipped=${specialistsSkipped} shippedSkipped=${shippedSkipped}`);
17242
+ return c.json({
17243
+ agents: rows,
17244
+ accountId: account.accountId,
17245
+ skipped,
17246
+ specialistsSkipped,
17247
+ shippedSkipped,
17248
+ riskSurfaceFailed: riskSurfaceFailed !== null
17249
+ });
16653
17250
  });
16654
17251
  app18.get("/:slug", requireAdminSession, (c) => {
16655
17252
  const slug = c.req.param("slug");
@@ -16659,34 +17256,72 @@ app18.get("/:slug", requireAdminSession, (c) => {
16659
17256
  return c.json({ error: "Account not found for session" }, 401);
16660
17257
  }
16661
17258
  if (SLUG_UNSAFE(slug)) return c.json({ error: "Invalid agent slug" }, 400);
17259
+ if (c.req.query("origin") === "shipped") {
17260
+ const dirs = shippedSourceDirs(account.accountDir);
17261
+ const source = dirs.find((d) => existsSync31(resolve23(d, `${slug}.md`)));
17262
+ if (!source) return c.json({ error: "Agent not found" }, 404);
17263
+ const { fm, body } = splitFrontmatter(readFileSync33(resolve23(source, `${slug}.md`), "utf-8"));
17264
+ const { riskByTool, failed } = loadRiskSurface();
17265
+ const tools = parseToolsLine(fm.tools);
17266
+ const r = classify(tools, riskByTool, failed !== null);
17267
+ console.log(`[admin/agents] op=detail accountId=${account.accountId.slice(0, 8)} slug=${slug} kind=specialist origin=shipped risk=${r.risk}`);
17268
+ return c.json({
17269
+ agent: {
17270
+ kind: "specialist",
17271
+ origin: "shipped",
17272
+ slug,
17273
+ displayName: fm.name ?? slug,
17274
+ description: fm.description ?? "",
17275
+ summary: fm.summary ?? "",
17276
+ model: fm.model ?? null,
17277
+ tools,
17278
+ systemPrompt: body.trim(),
17279
+ skills: [],
17280
+ risk: r.risk,
17281
+ riskiestTool: r.riskiestTool,
17282
+ unresolved: r.unresolved,
17283
+ byTool: r.byTool,
17284
+ disabled: readDisabledStore(account.accountDir).has(`${slug}.md`)
17285
+ }
17286
+ });
17287
+ }
16662
17288
  const pluginParam = c.req.query("plugin");
16663
17289
  if (pluginParam) {
16664
17290
  if (SLUG_UNSAFE(pluginParam)) return c.json({ error: "Invalid plugin" }, 400);
16665
17291
  const file = resolve23(account.accountDir, "plugins", pluginParam, "agents", `${slug}.md`);
16666
- if (!existsSync30(file)) return c.json({ error: "Agent not found" }, 404);
16667
- const { fm, body } = splitFrontmatter(readFileSync32(file, "utf-8"));
17292
+ if (!existsSync31(file)) return c.json({ error: "Agent not found" }, 404);
17293
+ const { fm, body } = splitFrontmatter(readFileSync33(file, "utf-8"));
16668
17294
  const skills = subdirs(resolve23(account.accountDir, "plugins", pluginParam, "skills"));
16669
- console.log(`[admin/agents] op=detail accountId=${account.accountId.slice(0, 8)} slug=${slug} kind=specialist plugin=${pluginParam}`);
17295
+ const { riskByTool, failed } = loadRiskSurface();
17296
+ const tools = parseToolsLine(fm.tools);
17297
+ const r = classify(tools, riskByTool, failed !== null);
17298
+ console.log(`[admin/agents] op=detail accountId=${account.accountId.slice(0, 8)} slug=${slug} kind=specialist plugin=${pluginParam} risk=${r.risk}`);
16670
17299
  return c.json({
16671
17300
  agent: {
16672
17301
  kind: "specialist",
17302
+ origin: "specialist",
16673
17303
  slug,
16674
17304
  displayName: fm.name ?? slug,
16675
17305
  description: fm.description ?? "",
16676
17306
  summary: fm.summary ?? "",
16677
17307
  model: fm.model ?? null,
16678
- tools: fm.tools ? fm.tools.split(",").map((t) => t.trim()).filter(Boolean) : [],
17308
+ tools,
16679
17309
  systemPrompt: body.trim(),
16680
- skills
17310
+ skills,
17311
+ risk: r.risk,
17312
+ riskiestTool: r.riskiestTool,
17313
+ unresolved: r.unresolved,
17314
+ byTool: r.byTool,
17315
+ disabled: false
16681
17316
  }
16682
17317
  });
16683
17318
  }
16684
17319
  const agentDir = resolve23(account.accountDir, "agents", slug);
16685
17320
  const configPath2 = resolve23(agentDir, "config.json");
16686
- if (!existsSync30(configPath2)) return c.json({ error: "Agent not found" }, 404);
17321
+ if (!existsSync31(configPath2)) return c.json({ error: "Agent not found" }, 404);
16687
17322
  let config;
16688
17323
  try {
16689
- config = JSON.parse(readFileSync32(configPath2, "utf-8"));
17324
+ config = JSON.parse(readFileSync33(configPath2, "utf-8"));
16690
17325
  } catch {
16691
17326
  console.error(`[admin/agents] op=detail slug=${slug} error="config.json parse failed"`);
16692
17327
  return c.json({ error: "Agent config unreadable" }, 500);
@@ -16696,8 +17331,8 @@ app18.get("/:slug", requireAdminSession, (c) => {
16696
17331
  for (const { file, key } of OWNED_DOCS) {
16697
17332
  const p = resolve23(agentDir, file);
16698
17333
  try {
16699
- if (existsSync30(p)) {
16700
- docs[key] = readFileSync32(p, "utf-8");
17334
+ if (existsSync31(p)) {
17335
+ docs[key] = readFileSync33(p, "utf-8");
16701
17336
  present[key] = true;
16702
17337
  } else {
16703
17338
  docs[key] = "";
@@ -16726,6 +17361,84 @@ app18.get("/:slug", requireAdminSession, (c) => {
16726
17361
  }
16727
17362
  });
16728
17363
  });
17364
+ async function resolveWritableAccount(c, op, slug) {
17365
+ const accountIdParam = c.req.query("accountId") ?? "";
17366
+ if (!accountIdParam) {
17367
+ console.error(`[admin/agents] op=${op} rejected reason=missing-accountId slug=${slug}`);
17368
+ return { status: 400, error: "accountId is required" };
17369
+ }
17370
+ const account = validateAccountId2(accountIdParam);
17371
+ if (!account) {
17372
+ console.error(`[admin/agents] op=${op} rejected reason=unknown-accountId accountId=${accountIdParam.slice(0, 8)} slug=${slug}`);
17373
+ return { status: 400, error: "Unknown accountId" };
17374
+ }
17375
+ const authz = await authorizeAccountWrite(c, account.accountId);
17376
+ if (!authz.ok) {
17377
+ console.error(`[admin/agents] op=${op} rejected reason=${authz.reason} accountId=${account.accountId.slice(0, 8)} slug=${slug}`);
17378
+ return { status: 403, error: "Not authorized for this account" };
17379
+ }
17380
+ return account;
17381
+ }
17382
+ app18.post("/:slug/disable", async (c) => {
17383
+ const slug = c.req.param("slug");
17384
+ if (SLUG_UNSAFE(slug)) return c.json({ error: "Invalid agent slug" }, 400);
17385
+ const resolved = await resolveWritableAccount(c, "disable", slug);
17386
+ if ("status" in resolved) return c.json({ error: resolved.error }, resolved.status);
17387
+ const filename = `${slug}.md`;
17388
+ const live = resolve23(resolved.accountDir, ...SPECIALISTS_DIR, filename);
17389
+ const quarantined = resolve23(resolved.accountDir, ...QUARANTINE_DIR, filename);
17390
+ if (!shippedSourceDirs(resolved.accountDir).some((d) => existsSync31(resolve23(d, filename)))) {
17391
+ console.error(`[admin/agents] op=disable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=failed reason=not-a-shipped-agent`);
17392
+ return c.json({ error: "Only a shipped agent can be disabled" }, 404);
17393
+ }
17394
+ let moved = false;
17395
+ try {
17396
+ const disabled = readDisabledStoreStrict(resolved.accountDir);
17397
+ if (existsSync31(live)) {
17398
+ mkdirSync7(resolve23(resolved.accountDir, ...QUARANTINE_DIR), { recursive: true });
17399
+ renameSync9(live, quarantined);
17400
+ moved = true;
17401
+ }
17402
+ disabled.add(filename);
17403
+ writeDisabledStore(resolved.accountDir, disabled);
17404
+ } catch (err) {
17405
+ const msg = err instanceof Error ? err.message : String(err);
17406
+ console.error(`[admin/agents] op=disable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=failed reason="${msg}"`);
17407
+ return c.json({ error: `Disable failed, disabled store unreadable or unwritable: ${msg}` }, 500);
17408
+ }
17409
+ console.log(`[admin/agents] op=disable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=ok moved=${moved}`);
17410
+ return c.json({ ok: true, moved });
17411
+ });
17412
+ app18.post("/:slug/enable", async (c) => {
17413
+ const slug = c.req.param("slug");
17414
+ if (SLUG_UNSAFE(slug)) return c.json({ error: "Invalid agent slug" }, 400);
17415
+ const resolved = await resolveWritableAccount(c, "enable", slug);
17416
+ if ("status" in resolved) return c.json({ error: resolved.error }, resolved.status);
17417
+ const filename = `${slug}.md`;
17418
+ const live = resolve23(resolved.accountDir, ...SPECIALISTS_DIR, filename);
17419
+ const quarantined = resolve23(resolved.accountDir, ...QUARANTINE_DIR, filename);
17420
+ let restored = false;
17421
+ try {
17422
+ const disabled = readDisabledStoreStrict(resolved.accountDir);
17423
+ if (!existsSync31(quarantined) && !disabled.has(filename)) {
17424
+ console.error(`[admin/agents] op=enable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=failed reason=not-disabled`);
17425
+ return c.json({ error: "This agent is not disabled" }, 404);
17426
+ }
17427
+ if (existsSync31(quarantined)) {
17428
+ mkdirSync7(resolve23(resolved.accountDir, ...SPECIALISTS_DIR), { recursive: true });
17429
+ renameSync9(quarantined, live);
17430
+ restored = true;
17431
+ }
17432
+ disabled.delete(filename);
17433
+ writeDisabledStore(resolved.accountDir, disabled);
17434
+ } catch (err) {
17435
+ const msg = err instanceof Error ? err.message : String(err);
17436
+ console.error(`[admin/agents] op=enable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=failed reason="${msg}"`);
17437
+ return c.json({ error: `Enable failed: ${msg}` }, 500);
17438
+ }
17439
+ console.log(`[admin/agents] op=enable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=ok restored=${restored}`);
17440
+ return c.json({ ok: true, restored });
17441
+ });
16729
17442
  app18.delete("/:slug", async (c) => {
16730
17443
  const slug = c.req.param("slug");
16731
17444
  if (slug === "admin") {
@@ -16750,7 +17463,7 @@ app18.delete("/:slug", async (c) => {
16750
17463
  return c.json({ error: "Not authorized for this account" }, 403);
16751
17464
  }
16752
17465
  const agentDir = resolve23(account.accountDir, "agents", slug);
16753
- if (!existsSync30(agentDir)) {
17466
+ if (!existsSync31(agentDir)) {
16754
17467
  return c.json({ error: "Agent not found" }, 404);
16755
17468
  }
16756
17469
  try {
@@ -16793,7 +17506,7 @@ app18.post("/:slug/project", async (c) => {
16793
17506
  return c.json({ error: "Not authorized for this account" }, 403);
16794
17507
  }
16795
17508
  const agentDir = resolve23(account.accountDir, "agents", slug);
16796
- if (!existsSync30(agentDir)) {
17509
+ if (!existsSync31(agentDir)) {
16797
17510
  return c.json({ error: "Agent not found on disk" }, 404);
16798
17511
  }
16799
17512
  try {
@@ -16809,7 +17522,7 @@ var agents_default = app18;
16809
17522
  // server/routes/admin/sessions.ts
16810
17523
  import crypto2 from "crypto";
16811
17524
  import { resolve as resolvePath } from "path";
16812
- import { existsSync as existsSync31, mkdirSync as mkdirSync7, createWriteStream } from "fs";
17525
+ import { existsSync as existsSync32, mkdirSync as mkdirSync8, createWriteStream } from "fs";
16813
17526
 
16814
17527
  // ../lib/admin-conversation-purge/src/index.ts
16815
17528
  async function purgeAdminConversationJsonls(args) {
@@ -16956,7 +17669,7 @@ var pickComponentBytes = (..._args) => null;
16956
17669
  function openResumeStreamLog(accountId, sessionId) {
16957
17670
  const dir = resolvePath(ACCOUNTS_DIR, accountId, "resume-logs");
16958
17671
  try {
16959
- mkdirSync7(dir, { recursive: true });
17672
+ mkdirSync8(dir, { recursive: true });
16960
17673
  } catch {
16961
17674
  }
16962
17675
  return createWriteStream(resolvePath(dir, `${sessionId}.log`), { flags: "a" });
@@ -16969,7 +17682,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
16969
17682
  let reason = null;
16970
17683
  if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
16971
17684
  else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
16972
- else if (!existsSync31(a.storagePath)) reason = "missing-file";
17685
+ else if (!existsSync32(a.storagePath)) reason = "missing-file";
16973
17686
  if (reason) {
16974
17687
  invalid++;
16975
17688
  try {
@@ -17495,8 +18208,8 @@ app19.put("/:id/label", requireAdminSession, async (c) => {
17495
18208
  var sessions_default = app19;
17496
18209
 
17497
18210
  // app/lib/claude-agent/spawn-context.ts
17498
- import { existsSync as existsSync32, readFileSync as readFileSync33, readdirSync as readdirSync22, statSync as statSync15 } from "fs";
17499
- import { dirname as dirname12, resolve as resolve24, join as join33 } from "path";
18211
+ import { existsSync as existsSync33, readFileSync as readFileSync34, readdirSync as readdirSync23, statSync as statSync17 } from "fs";
18212
+ import { dirname as dirname12, resolve as resolve24, join as join35 } from "path";
17500
18213
  async function resolveOwnerProfileBlock(accountId, userId) {
17501
18214
  if (!userId) return { ok: false, reason: "missing-user-id" };
17502
18215
  try {
@@ -17537,14 +18250,14 @@ function frontmatterField(manifest, field2) {
17537
18250
  function extractPluginToolDescriptions(pluginDir) {
17538
18251
  const out = /* @__PURE__ */ new Map();
17539
18252
  const candidates = [
17540
- join33(pluginDir, "mcp/dist/index.js"),
17541
- join33(pluginDir, "mcp/src/index.ts")
18253
+ join35(pluginDir, "mcp/dist/index.js"),
18254
+ join35(pluginDir, "mcp/src/index.ts")
17542
18255
  ];
17543
18256
  let raw = null;
17544
18257
  for (const path3 of candidates) {
17545
- if (!existsSync32(path3)) continue;
18258
+ if (!existsSync33(path3)) continue;
17546
18259
  try {
17547
- raw = readFileSync33(path3, "utf-8");
18260
+ raw = readFileSync34(path3, "utf-8");
17548
18261
  break;
17549
18262
  } catch {
17550
18263
  }
@@ -17594,25 +18307,25 @@ function parseSkillPathsFromFrontmatter(fm) {
17594
18307
  function listPluginDirs(accountPluginsDir) {
17595
18308
  const out = /* @__PURE__ */ new Map();
17596
18309
  const platformPlugins = resolve24(PLATFORM_ROOT, "plugins");
17597
- if (existsSync32(platformPlugins)) {
17598
- for (const name of readdirSync22(platformPlugins)) {
17599
- const dir = join33(platformPlugins, name);
18310
+ if (existsSync33(platformPlugins)) {
18311
+ for (const name of readdirSync23(platformPlugins)) {
18312
+ const dir = join35(platformPlugins, name);
17600
18313
  try {
17601
- if (statSync15(dir).isDirectory()) out.set(name, dir);
18314
+ if (statSync17(dir).isDirectory()) out.set(name, dir);
17602
18315
  } catch {
17603
18316
  }
17604
18317
  }
17605
18318
  }
17606
18319
  const premiumRoot = resolve24(dirname12(PLATFORM_ROOT), "premium-plugins");
17607
- if (existsSync32(premiumRoot)) {
17608
- for (const bundle of readdirSync22(premiumRoot)) {
17609
- const bundlePlugins = join33(premiumRoot, bundle, "plugins");
17610
- if (!existsSync32(bundlePlugins)) continue;
18320
+ if (existsSync33(premiumRoot)) {
18321
+ for (const bundle of readdirSync23(premiumRoot)) {
18322
+ const bundlePlugins = join35(premiumRoot, bundle, "plugins");
18323
+ if (!existsSync33(bundlePlugins)) continue;
17611
18324
  try {
17612
- for (const name of readdirSync22(bundlePlugins)) {
17613
- const dir = join33(bundlePlugins, name);
18325
+ for (const name of readdirSync23(bundlePlugins)) {
18326
+ const dir = join35(bundlePlugins, name);
17614
18327
  try {
17615
- if (statSync15(dir).isDirectory()) out.set(name, dir);
18328
+ if (statSync17(dir).isDirectory()) out.set(name, dir);
17616
18329
  } catch {
17617
18330
  }
17618
18331
  }
@@ -17620,13 +18333,13 @@ function listPluginDirs(accountPluginsDir) {
17620
18333
  }
17621
18334
  }
17622
18335
  }
17623
- if (accountPluginsDir && existsSync32(accountPluginsDir)) {
18336
+ if (accountPluginsDir && existsSync33(accountPluginsDir)) {
17624
18337
  try {
17625
- for (const name of readdirSync22(accountPluginsDir)) {
18338
+ for (const name of readdirSync23(accountPluginsDir)) {
17626
18339
  if (out.has(name)) continue;
17627
- const dir = join33(accountPluginsDir, name);
18340
+ const dir = join35(accountPluginsDir, name);
17628
18341
  try {
17629
- if (statSync15(dir).isDirectory()) out.set(name, dir);
18342
+ if (statSync17(dir).isDirectory()) out.set(name, dir);
17630
18343
  } catch {
17631
18344
  }
17632
18345
  }
@@ -17639,11 +18352,11 @@ function accountPluginsDirFor(accountId) {
17639
18352
  return resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "plugins");
17640
18353
  }
17641
18354
  function listAccountPluginNames(accountPluginsDir) {
17642
- if (!existsSync32(accountPluginsDir)) return [];
18355
+ if (!existsSync33(accountPluginsDir)) return [];
17643
18356
  try {
17644
- return readdirSync22(accountPluginsDir).filter((name) => {
18357
+ return readdirSync23(accountPluginsDir).filter((name) => {
17645
18358
  try {
17646
- return statSync15(join33(accountPluginsDir, name)).isDirectory();
18359
+ return statSync17(join35(accountPluginsDir, name)).isDirectory();
17647
18360
  } catch {
17648
18361
  return false;
17649
18362
  }
@@ -17654,9 +18367,9 @@ function listAccountPluginNames(accountPluginsDir) {
17654
18367
  }
17655
18368
  function readEnabledPlugins(accountId) {
17656
18369
  const accountFile = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17657
- if (!existsSync32(accountFile)) return /* @__PURE__ */ new Set();
18370
+ if (!existsSync33(accountFile)) return /* @__PURE__ */ new Set();
17658
18371
  try {
17659
- const parsed = JSON.parse(readFileSync33(accountFile, "utf-8"));
18372
+ const parsed = JSON.parse(readFileSync34(accountFile, "utf-8"));
17660
18373
  return new Set(
17661
18374
  Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
17662
18375
  );
@@ -17665,10 +18378,10 @@ function readEnabledPlugins(accountId) {
17665
18378
  }
17666
18379
  }
17667
18380
  function readFrontmatter(path3) {
17668
- if (!existsSync32(path3)) return null;
18381
+ if (!existsSync33(path3)) return null;
17669
18382
  let raw;
17670
18383
  try {
17671
- raw = readFileSync33(path3, "utf-8");
18384
+ raw = readFileSync34(path3, "utf-8");
17672
18385
  } catch {
17673
18386
  return null;
17674
18387
  }
@@ -17686,7 +18399,7 @@ function computeActivePlugins(accountId) {
17686
18399
  for (const name of emitNames) {
17687
18400
  const dir = pluginDirs.get(name);
17688
18401
  if (!dir) continue;
17689
- const fm = readFrontmatter(join33(dir, "PLUGIN.md"));
18402
+ const fm = readFrontmatter(join35(dir, "PLUGIN.md"));
17690
18403
  if (!fm) continue;
17691
18404
  const description = frontmatterField(`---
17692
18405
  ${fm}
@@ -17703,7 +18416,7 @@ ${fm}
17703
18416
  `plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
17704
18417
  );
17705
18418
  if (toolNames.length > 0 && descMap.size === 0) {
17706
- const hasSource = existsSync32(join33(dir, "mcp/dist/index.js")) || existsSync32(join33(dir, "mcp/src/index.ts"));
18419
+ const hasSource = existsSync33(join35(dir, "mcp/dist/index.js")) || existsSync33(join35(dir, "mcp/src/index.ts"));
17707
18420
  if (hasSource) {
17708
18421
  console.warn(
17709
18422
  `[spawn-context] WARN plugin=${name} mcp source present but tool-description regex matched zero entries \u2014 SDK upgrade may have changed the registration shape`
@@ -17713,7 +18426,7 @@ ${fm}
17713
18426
  const skillPaths = parseSkillPathsFromFrontmatter(fm);
17714
18427
  const skills = [];
17715
18428
  for (const relPath of skillPaths) {
17716
- const skillPath = join33(dir, relPath);
18429
+ const skillPath = join35(dir, relPath);
17717
18430
  const skillFm = readFrontmatter(skillPath);
17718
18431
  if (!skillFm) continue;
17719
18432
  const skillName = frontmatterField(`---
@@ -17730,10 +18443,10 @@ ${skillFm}
17730
18443
  }
17731
18444
  function computeSpecialistDomains(accountId) {
17732
18445
  const specialistsDir = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
17733
- if (!existsSync32(specialistsDir)) return [];
18446
+ if (!existsSync33(specialistsDir)) return [];
17734
18447
  let entries2;
17735
18448
  try {
17736
- entries2 = readdirSync22(specialistsDir);
18449
+ entries2 = readdirSync23(specialistsDir);
17737
18450
  } catch {
17738
18451
  return [];
17739
18452
  }
@@ -17757,7 +18470,7 @@ function computeSpecialistDomains(accountId) {
17757
18470
  const out = [];
17758
18471
  for (const file of entries2.sort()) {
17759
18472
  if (!file.endsWith(".md")) continue;
17760
- const fm = readFrontmatter(join33(specialistsDir, file));
18473
+ const fm = readFrontmatter(join35(specialistsDir, file));
17761
18474
  if (!fm) continue;
17762
18475
  const wrapped = `---
17763
18476
  ${fm}
@@ -17776,10 +18489,10 @@ ${fm}
17776
18489
  }
17777
18490
  function computeDormantPlugins(accountId) {
17778
18491
  const accountFile = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17779
- if (!existsSync32(accountFile)) return [];
18492
+ if (!existsSync33(accountFile)) return [];
17780
18493
  let enabled;
17781
18494
  try {
17782
- const raw = readFileSync33(accountFile, "utf-8");
18495
+ const raw = readFileSync34(accountFile, "utf-8");
17783
18496
  const parsed = JSON.parse(raw);
17784
18497
  enabled = new Set(
17785
18498
  Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
@@ -17791,10 +18504,10 @@ function computeDormantPlugins(accountId) {
17791
18504
  return [];
17792
18505
  }
17793
18506
  const pluginsDir = resolve24(PLATFORM_ROOT, "plugins");
17794
- if (!existsSync32(pluginsDir)) return [];
18507
+ if (!existsSync33(pluginsDir)) return [];
17795
18508
  let entries2;
17796
18509
  try {
17797
- entries2 = readdirSync22(pluginsDir);
18510
+ entries2 = readdirSync23(pluginsDir);
17798
18511
  } catch {
17799
18512
  return [];
17800
18513
  }
@@ -17802,10 +18515,10 @@ function computeDormantPlugins(accountId) {
17802
18515
  for (const name of entries2) {
17803
18516
  if (enabled.has(name)) continue;
17804
18517
  const manifestPath = resolve24(pluginsDir, name, "PLUGIN.md");
17805
- if (!existsSync32(manifestPath)) continue;
18518
+ if (!existsSync33(manifestPath)) continue;
17806
18519
  let manifest;
17807
18520
  try {
17808
- manifest = readFileSync33(manifestPath, "utf-8");
18521
+ manifest = readFileSync34(manifestPath, "utf-8");
17809
18522
  } catch {
17810
18523
  continue;
17811
18524
  }
@@ -17819,13 +18532,13 @@ function computeDormantPlugins(accountId) {
17819
18532
  }
17820
18533
 
17821
18534
  // server/routes/admin/claude-sessions.ts
17822
- import { existsSync as existsSync33, readFileSync as readFileSync34 } from "fs";
18535
+ import { existsSync as existsSync34, readFileSync as readFileSync35 } from "fs";
17823
18536
  import { resolve as resolve25 } from "path";
17824
18537
  function readTunnelState(brandConfigDir) {
17825
18538
  const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
17826
- if (!existsSync33(statePath)) return null;
18539
+ if (!existsSync34(statePath)) return null;
17827
18540
  try {
17828
- const parsed = JSON.parse(readFileSync34(statePath, "utf-8"));
18541
+ const parsed = JSON.parse(readFileSync35(statePath, "utf-8"));
17829
18542
  const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
17830
18543
  const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
17831
18544
  const domain = typeof parsed.domain === "string" ? parsed.domain : null;
@@ -17839,7 +18552,7 @@ function resolveTunnelUrl() {
17839
18552
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
17840
18553
  let brand;
17841
18554
  try {
17842
- brand = JSON.parse(readFileSync34(resolve25(platformRoot5, "config", "brand.json"), "utf-8"));
18555
+ brand = JSON.parse(readFileSync35(resolve25(platformRoot5, "config", "brand.json"), "utf-8"));
17843
18556
  } catch {
17844
18557
  return null;
17845
18558
  }
@@ -18152,11 +18865,11 @@ app22.get("/", requireAdminSession, async (c) => {
18152
18865
  var events_default = app22;
18153
18866
 
18154
18867
  // server/routes/admin/files.ts
18155
- import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync34 } from "fs";
18868
+ import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync35 } from "fs";
18156
18869
  import { readdir as readdir4, readFile as readFile7, stat as stat6, mkdir as mkdir4, unlink as unlink3, rename as rename2, rmdir } from "fs/promises";
18157
18870
  import { realpathSync as realpathSync7 } from "fs";
18158
18871
  import { randomUUID as randomUUID10 } from "crypto";
18159
- import { basename as basename11, dirname as dirname13, join as join35, relative as relative5, resolve as resolve27, sep as sep8 } from "path";
18872
+ import { basename as basename11, dirname as dirname13, join as join37, relative as relative5, resolve as resolve27, sep as sep8 } from "path";
18160
18873
  import { Readable as Readable2 } from "stream";
18161
18874
 
18162
18875
  // ../lib/graph-trash/src/index.ts
@@ -18474,7 +19187,7 @@ async function cascadeDeleteDocument(params) {
18474
19187
 
18475
19188
  // app/lib/file-index.ts
18476
19189
  import * as fsp from "fs/promises";
18477
- import { resolve as resolve26, relative as relative4, join as join34, basename as basename10, extname as extname2, sep as sep7 } from "path";
19190
+ import { resolve as resolve26, relative as relative4, join as join36, basename as basename10, extname as extname2, sep as sep7 } from "path";
18478
19191
  import { tmpdir as tmpdir2 } from "os";
18479
19192
  import { execFile as execFile2 } from "child_process";
18480
19193
  import { promisify as promisify2 } from "util";
@@ -18556,7 +19269,7 @@ async function extractPdf(absolute) {
18556
19269
  return stdout.trim();
18557
19270
  }
18558
19271
  async function ocrPdf(absolute) {
18559
- const outPdf = join34(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
19272
+ const outPdf = join36(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
18560
19273
  try {
18561
19274
  await execFileAsync2(
18562
19275
  "ocrmypdf",
@@ -18618,7 +19331,7 @@ async function readDisplayName(absolute) {
18618
19331
  const stem = dot === -1 ? base : base.slice(0, dot);
18619
19332
  if (base === `${stem}.meta.json`) return null;
18620
19333
  try {
18621
- const raw = await fsp.readFile(join34(dir, `${stem}.meta.json`), "utf-8");
19334
+ const raw = await fsp.readFile(join36(dir, `${stem}.meta.json`), "utf-8");
18622
19335
  const meta = JSON.parse(raw);
18623
19336
  const dn = meta.displayName ?? meta.filename;
18624
19337
  return typeof dn === "string" && dn.length > 0 ? dn : null;
@@ -18639,7 +19352,7 @@ async function walkSubtree(root, dataRoot, out) {
18639
19352
  for (const entry of entries2) {
18640
19353
  if (entry.isSymbolicLink()) continue;
18641
19354
  if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
18642
- const abs = join34(root, entry.name);
19355
+ const abs = join36(root, entry.name);
18643
19356
  if (entry.isDirectory()) {
18644
19357
  const sub = await walkSubtree(abs, dataRoot, out);
18645
19358
  if (!sub.clean) clean = false;
@@ -19012,7 +19725,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
19012
19725
  var UUID_RE4 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
19013
19726
  async function readMeta(absDir, baseName) {
19014
19727
  try {
19015
- const raw = await readFile7(join35(absDir, `${baseName}.meta.json`), "utf8");
19728
+ const raw = await readFile7(join37(absDir, `${baseName}.meta.json`), "utf8");
19016
19729
  const parsed = JSON.parse(raw);
19017
19730
  if (typeof parsed?.filename === "string") {
19018
19731
  return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
@@ -19067,7 +19780,7 @@ async function servableFilesIn(dirAbs, uuid) {
19067
19780
  }
19068
19781
  async function enrich(absolute, entry, accountNames) {
19069
19782
  if (entry.kind === "directory" && UUID_RE4.test(entry.name)) {
19070
- const dirAbs = join35(absolute, entry.name);
19783
+ const dirAbs = join37(absolute, entry.name);
19071
19784
  const meta = await readMeta(dirAbs, entry.name);
19072
19785
  if (meta?.filename) {
19073
19786
  const servable = await servableFilesIn(dirAbs, entry.name);
@@ -19076,7 +19789,7 @@ async function enrich(absolute, entry, accountNames) {
19076
19789
  let size = null;
19077
19790
  let modifiedAt = entry.modifiedAt;
19078
19791
  try {
19079
- const st = await stat6(join35(dirAbs, innerName));
19792
+ const st = await stat6(join37(dirAbs, innerName));
19080
19793
  size = st.size;
19081
19794
  modifiedAt = st.mtime.toISOString();
19082
19795
  } catch {
@@ -19269,7 +19982,7 @@ app23.get("/", requireAdminSession, async (c) => {
19269
19982
  const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
19270
19983
  const protectedEntry = isProtectedFromDeletion(childRel).protected;
19271
19984
  try {
19272
- const entryPath = join35(absolute, name);
19985
+ const entryPath = join37(absolute, name);
19273
19986
  const s = await stat6(entryPath);
19274
19987
  entries2.push({
19275
19988
  name,
@@ -19298,7 +20011,7 @@ app23.get("/", requireAdminSession, async (c) => {
19298
20011
  const displayPath = buildDisplayPath(relPath, accountNames);
19299
20012
  if (groupReq || isAccountRoot(relPath)) {
19300
20013
  const acctId = relPath.split("/")[1] ?? accountId;
19301
- const schemaMd = await readFile7(join35(absolute, "SCHEMA.md"), "utf8").catch(() => null);
20014
+ const schemaMd = await readFile7(join37(absolute, "SCHEMA.md"), "utf8").catch(() => null);
19302
20015
  const groups = classifyAccountRoot(schemaMd, entries2.map((e) => e.name));
19303
20016
  console.error(
19304
20017
  `[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"}`
@@ -19336,7 +20049,7 @@ app23.get("/", requireAdminSession, async (c) => {
19336
20049
  for (const name of homeDirs) {
19337
20050
  const base = byName.get(name);
19338
20051
  try {
19339
- const dirents = await readdir4(join35(absolute, name), { withFileTypes: true });
20052
+ const dirents = await readdir4(join37(absolute, name), { withFileTypes: true });
19340
20053
  const visible = dirents.filter((d) => !d.name.startsWith("."));
19341
20054
  visible.sort((a, b) => {
19342
20055
  const ad = a.isDirectory() ? 0 : 1;
@@ -19401,7 +20114,7 @@ app23.get("/download", requireAdminSession, async (c) => {
19401
20114
  console.error(`[data] op=scratchpad-no-session sessionId="${sessionId.slice(0, 8)}\u2026"`);
19402
20115
  return c.json({ error: "Not found" }, 404);
19403
20116
  }
19404
- const meta = readSidecarMeta(join35(projectDir, `${sessionId}.meta.json`));
20117
+ const meta = readSidecarMeta(join37(projectDir, `${sessionId}.meta.json`));
19405
20118
  if (!meta.accountId || meta.accountId !== accountId) {
19406
20119
  console.error(`[data] account-scope-blocked root="scratchpad" sessionId="${sessionId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
19407
20120
  return c.json({ error: "Not found" }, 404);
@@ -19496,7 +20209,7 @@ async function* walkRegularFiles(dirAbsolute) {
19496
20209
  const dirents = await readdir4(dirAbsolute, { withFileTypes: true });
19497
20210
  for (const d of dirents) {
19498
20211
  if (d.isSymbolicLink()) continue;
19499
- const child = join35(dirAbsolute, d.name);
20212
+ const child = join37(dirAbsolute, d.name);
19500
20213
  if (d.isDirectory()) {
19501
20214
  yield* walkRegularFiles(child);
19502
20215
  continue;
@@ -19606,7 +20319,7 @@ async function resolveUploadTarget(c, accountId, uid) {
19606
20319
  const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
19607
20320
  if (!base.ok) return { ok: false, status: base.status, error: base.error };
19608
20321
  const relDir = relpath ? dirname13(relpath) : ".";
19609
- const destRel = relDir === "." ? base.relative : join35(base.relative, relDir);
20322
+ const destRel = relDir === "." ? base.relative : join37(base.relative, relDir);
19610
20323
  if (crossesForeignAccountPartition(destRel, accountId)) {
19611
20324
  console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
19612
20325
  return { ok: false, status: 404, error: "Not found" };
@@ -19680,7 +20393,7 @@ app23.post("/upload", requireAdminSession, async (c) => {
19680
20393
  });
19681
20394
  await unlink3(tmpPath).catch(() => {
19682
20395
  });
19683
- const tempRemoved = !existsSync34(tmpPath);
20396
+ const tempRemoved = !existsSync35(tmpPath);
19684
20397
  console.error(`[data-upload] op=cleanup uid=${uid} tempRemoved=${tempRemoved}`);
19685
20398
  };
19686
20399
  const reader = body.getReader();
@@ -19754,7 +20467,7 @@ async function discardChunkUpload(uploadId, state) {
19754
20467
  });
19755
20468
  await unlink3(state.tmpPath).catch(() => {
19756
20469
  });
19757
- const tempRemoved = !existsSync34(state.tmpPath);
20470
+ const tempRemoved = !existsSync35(state.tmpPath);
19758
20471
  console.error(`[data-upload] op=cleanup uid=${uploadId} tempRemoved=${tempRemoved}`);
19759
20472
  }
19760
20473
  async function writeChunkBody(body, out, alreadyReceived, ceiling) {
@@ -19983,7 +20696,7 @@ app23.delete("/", requireAdminSession, async (c) => {
19983
20696
  const dot = base.lastIndexOf(".");
19984
20697
  const stem = dot === -1 ? base : base.slice(0, dot);
19985
20698
  const containerDir = dirname13(absolute);
19986
- const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join35(containerDir, `${stem}.meta.json`) : null;
20699
+ const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join37(containerDir, `${stem}.meta.json`) : null;
19987
20700
  const isAttachmentContainer = UUID_RE4.test(stem) && basename11(containerDir) === stem;
19988
20701
  await unlink3(absolute);
19989
20702
  if (sidecarPath) {
@@ -19993,7 +20706,7 @@ app23.delete("/", requireAdminSession, async (c) => {
19993
20706
  }
19994
20707
  }
19995
20708
  if (isAttachmentContainer) {
19996
- await unlink3(join35(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
20709
+ await unlink3(join37(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
19997
20710
  });
19998
20711
  await rmdir(containerDir).catch(() => {
19999
20712
  });
@@ -20172,7 +20885,7 @@ function applyBacklinkBoost(hits) {
20172
20885
  }
20173
20886
 
20174
20887
  // ../lib/graph-search/src/dedup.ts
20175
- import { createHash as createHash5 } from "crypto";
20888
+ import { createHash as createHash6 } from "crypto";
20176
20889
  var DEFAULT_LAYERS = [
20177
20890
  "nodeId",
20178
20891
  "slug",
@@ -20199,7 +20912,7 @@ function readContentHash(props) {
20199
20912
  const content = props["content"];
20200
20913
  const source = typeof compiled === "string" && compiled.length > 0 ? compiled : typeof content === "string" && content.length > 0 ? content : null;
20201
20914
  if (source === null) return null;
20202
- return createHash5("sha256").update(source).digest("hex").slice(0, 16);
20915
+ return createHash6("sha256").update(source).digest("hex").slice(0, 16);
20203
20916
  }
20204
20917
  function dedup(hits, layers = DEFAULT_LAYERS) {
20205
20918
  const sorted = [...hits].sort((a, b) => b.score - a.score);
@@ -21102,8 +21815,8 @@ function isHiddenByDefault(label) {
21102
21815
 
21103
21816
  // server/lib/top-level-labels.ts
21104
21817
  var import_dist5 = __toESM(require_dist4(), 1);
21105
- import { readdirSync as readdirSync23, readFileSync as readFileSync35 } from "fs";
21106
- import { join as join36, resolve as resolve28 } from "path";
21818
+ import { readdirSync as readdirSync24, readFileSync as readFileSync36 } from "fs";
21819
+ import { join as join38, resolve as resolve28 } from "path";
21107
21820
  var STATIC_TOP_LEVEL_LABELS = Object.freeze(
21108
21821
  /* @__PURE__ */ new Set([
21109
21822
  // Base-schema infra (schema-base.md has no top-level section).
@@ -21207,7 +21920,7 @@ function parseTopLevelLabels(content) {
21207
21920
  }
21208
21921
  function resolveReferencesDir() {
21209
21922
  if (process.env.MAXY_PLATFORM_ROOT) {
21210
- return join36(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
21923
+ return join38(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
21211
21924
  }
21212
21925
  return resolve28(import.meta.dirname, "../../../plugins/memory/references");
21213
21926
  }
@@ -21215,9 +21928,9 @@ function parseTableTopLevelLabels(referencesDir) {
21215
21928
  const labels = /* @__PURE__ */ new Set();
21216
21929
  const contributingFiles = [];
21217
21930
  try {
21218
- const fileNames = readdirSync23(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
21931
+ const fileNames = readdirSync24(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
21219
21932
  for (const fileName of fileNames) {
21220
- const content = readFileSync35(join36(referencesDir, fileName), "utf-8");
21933
+ const content = readFileSync36(join38(referencesDir, fileName), "utf-8");
21221
21934
  const parsed = parseTopLevelLabels(content);
21222
21935
  if (parsed.length > 0) contributingFiles.push(fileName);
21223
21936
  for (const label of parsed) labels.add(label);
@@ -22375,7 +23088,7 @@ var graph_default_view_default = app29;
22375
23088
  // server/routes/admin/sidebar-artefacts.ts
22376
23089
  import { readdir as readdir5, stat as stat7 } from "fs/promises";
22377
23090
  import { resolve as resolve29, relative as relative6, isAbsolute as isAbsolute2, sep as sep9, basename as basename12 } from "path";
22378
- import { existsSync as existsSync35 } from "fs";
23091
+ import { existsSync as existsSync36 } from "fs";
22379
23092
  var LIMIT = 50;
22380
23093
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
22381
23094
  function toDataRootRelPath(absPath) {
@@ -22487,7 +23200,7 @@ async function fetchAgentTemplateRows(accountDir) {
22487
23200
  async function unionSpecialistFilenames(overrideDir, bundledDir) {
22488
23201
  const names = /* @__PURE__ */ new Set();
22489
23202
  for (const dir of [overrideDir, bundledDir]) {
22490
- if (!existsSync35(dir)) continue;
23203
+ if (!existsSync36(dir)) continue;
22491
23204
  try {
22492
23205
  const entries2 = await readdir5(dir);
22493
23206
  for (const entry of entries2) {
@@ -22502,7 +23215,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
22502
23215
  }
22503
23216
  async function readAgentTemplateRow(inp) {
22504
23217
  let chosenPath = null;
22505
- if (existsSync35(inp.overridePath)) {
23218
+ if (existsSync36(inp.overridePath)) {
22506
23219
  try {
22507
23220
  validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
22508
23221
  chosenPath = inp.overridePath;
@@ -22513,7 +23226,7 @@ async function readAgentTemplateRow(inp) {
22513
23226
  );
22514
23227
  return null;
22515
23228
  }
22516
- } else if (existsSync35(inp.bundledPath)) {
23229
+ } else if (existsSync36(inp.bundledPath)) {
22517
23230
  if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
22518
23231
  console.error(
22519
23232
  `[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
@@ -22555,19 +23268,19 @@ function isWithin(target, root) {
22555
23268
  var sidebar_artefacts_default = app30;
22556
23269
 
22557
23270
  // server/channel-session-override.ts
22558
- import { readFileSync as readFileSync36, writeFileSync as writeFileSync13, renameSync as renameSync9 } from "fs";
22559
- import { join as join37 } from "path";
23271
+ import { readFileSync as readFileSync37, writeFileSync as writeFileSync14, renameSync as renameSync10 } from "fs";
23272
+ import { join as join39 } from "path";
22560
23273
  var FILE2 = "channel-session-override.json";
22561
23274
  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}$/;
22562
23275
  function channelOverridePath(accountDir) {
22563
- return join37(accountDir, FILE2);
23276
+ return join39(accountDir, FILE2);
22564
23277
  }
22565
23278
  function senderKey(channel, senderId) {
22566
23279
  return `${channel}:${senderId}`;
22567
23280
  }
22568
23281
  function readRaw2(accountDir) {
22569
23282
  try {
22570
- return JSON.parse(readFileSync36(channelOverridePath(accountDir), "utf8"));
23283
+ return JSON.parse(readFileSync37(channelOverridePath(accountDir), "utf8"));
22571
23284
  } catch {
22572
23285
  return null;
22573
23286
  }
@@ -22589,8 +23302,8 @@ function writeChannelOverrideId(accountDir, channel, senderId, sessionId) {
22589
23302
  bySender[senderKey(channel, senderId)] = sessionId;
22590
23303
  const path3 = channelOverridePath(accountDir);
22591
23304
  const tmp = `${path3}.${process.pid}.tmp`;
22592
- writeFileSync13(tmp, JSON.stringify({ bySender }, null, 2), "utf8");
22593
- renameSync9(tmp, path3);
23305
+ writeFileSync14(tmp, JSON.stringify({ bySender }, null, 2), "utf8");
23306
+ renameSync10(tmp, path3);
22594
23307
  }
22595
23308
  function clearChannelOverrideForSession(accountDir, sessionId) {
22596
23309
  const raw = readRaw2(accountDir);
@@ -22605,8 +23318,8 @@ function clearChannelOverrideForSession(accountDir, sessionId) {
22605
23318
  if (cleared.length === 0) return [];
22606
23319
  const path3 = channelOverridePath(accountDir);
22607
23320
  const tmp = `${path3}.${process.pid}.tmp`;
22608
- writeFileSync13(tmp, JSON.stringify({ bySender: kept }, null, 2), "utf8");
22609
- renameSync9(tmp, path3);
23321
+ writeFileSync14(tmp, JSON.stringify({ bySender: kept }, null, 2), "utf8");
23322
+ renameSync10(tmp, path3);
22610
23323
  return cleared;
22611
23324
  }
22612
23325
 
@@ -22956,24 +23669,24 @@ var session_rc_spawn_default = app36;
22956
23669
  import { randomUUID as randomUUID12 } from "crypto";
22957
23670
 
22958
23671
  // server/wa-descriptor.ts
22959
- import { resolve as resolve30, join as join38 } from "path";
23672
+ import { resolve as resolve30, join as join40 } from "path";
22960
23673
  function waGatewayUrl() {
22961
23674
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
22962
23675
  }
22963
23676
  function waServerPath() {
22964
- return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ?? join38(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
23677
+ return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ?? join40(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
22965
23678
  }
22966
23679
  function waChannelDescriptor(senderId) {
22967
23680
  return { senderId, gatewayUrl: waGatewayUrl(), serverPath: waServerPath() };
22968
23681
  }
22969
23682
 
22970
23683
  // server/telegram-descriptor.ts
22971
- import { resolve as resolve31, join as join39 } from "path";
23684
+ import { resolve as resolve31, join as join41 } from "path";
22972
23685
  function telegramGatewayUrl() {
22973
23686
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
22974
23687
  }
22975
23688
  function telegramServerPath() {
22976
- return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, ".."), "services/telegram-channel/dist/server.js");
23689
+ return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join41(__dirname, ".."), "services/telegram-channel/dist/server.js");
22977
23690
  }
22978
23691
  function telegramChannelDescriptor(senderId) {
22979
23692
  return { senderId, gatewayUrl: telegramGatewayUrl(), serverPath: telegramServerPath() };
@@ -23257,14 +23970,14 @@ app38.get("/", async (c) => {
23257
23970
  var system_stats_default = app38;
23258
23971
 
23259
23972
  // server/routes/admin/health.ts
23260
- import { existsSync as existsSync36, readFileSync as readFileSync37 } from "fs";
23261
- import { resolve as resolve32, join as join40 } from "path";
23973
+ import { existsSync as existsSync37, readFileSync as readFileSync38 } from "fs";
23974
+ import { resolve as resolve32, join as join42 } from "path";
23262
23975
  var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve32(process.cwd(), "..");
23263
23976
  var brandHostname = "maxy";
23264
- var brandJsonPath = join40(PLATFORM_ROOT6, "config", "brand.json");
23265
- if (existsSync36(brandJsonPath)) {
23977
+ var brandJsonPath = join42(PLATFORM_ROOT6, "config", "brand.json");
23978
+ if (existsSync37(brandJsonPath)) {
23266
23979
  try {
23267
- const brand = JSON.parse(readFileSync37(brandJsonPath, "utf-8"));
23980
+ const brand = JSON.parse(readFileSync38(brandJsonPath, "utf-8"));
23268
23981
  if (brand.hostname) brandHostname = brand.hostname;
23269
23982
  } catch {
23270
23983
  }
@@ -23273,8 +23986,8 @@ var VERSION_FILE = resolve32(PLATFORM_ROOT6, `config/.${brandHostname}-version`)
23273
23986
  var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
23274
23987
  var PROBE_TIMEOUT_MS = 1e3;
23275
23988
  function readVersion() {
23276
- if (!existsSync36(VERSION_FILE)) return "unknown";
23277
- return readFileSync37(VERSION_FILE, "utf-8").trim() || "unknown";
23989
+ if (!existsSync37(VERSION_FILE)) return "unknown";
23990
+ return readFileSync38(VERSION_FILE, "utf-8").trim() || "unknown";
23278
23991
  }
23279
23992
  async function probeConversationDb() {
23280
23993
  let session;
@@ -24050,8 +24763,8 @@ app46.post("/launch", requireAdminSession, async (c) => {
24050
24763
  var browser_default = app46;
24051
24764
 
24052
24765
  // server/routes/admin/calendar.ts
24053
- import { existsSync as existsSync37 } from "fs";
24054
- import { join as join42 } from "path";
24766
+ import { existsSync as existsSync38 } from "fs";
24767
+ import { join as join44 } from "path";
24055
24768
 
24056
24769
  // server/lib/calendar-ics.ts
24057
24770
  var CRLF = "\r\n";
@@ -24150,8 +24863,8 @@ function countVEvents(ics) {
24150
24863
  }
24151
24864
 
24152
24865
  // server/lib/calendar-availability.ts
24153
- import { readFileSync as readFileSync38 } from "fs";
24154
- import { join as join41 } from "path";
24866
+ import { readFileSync as readFileSync39 } from "fs";
24867
+ import { join as join43 } from "path";
24155
24868
  var AVAILABILITY_FILENAME = "calendar-availability.json";
24156
24869
  var REQUIRED_KEYS = [
24157
24870
  "timezone",
@@ -24160,10 +24873,10 @@ var REQUIRED_KEYS = [
24160
24873
  "weekly"
24161
24874
  ];
24162
24875
  function readAvailabilityConfig(accountDir) {
24163
- const path3 = join41(accountDir, AVAILABILITY_FILENAME);
24876
+ const path3 = join43(accountDir, AVAILABILITY_FILENAME);
24164
24877
  let raw;
24165
24878
  try {
24166
- raw = readFileSync38(path3, "utf-8");
24879
+ raw = readFileSync39(path3, "utf-8");
24167
24880
  } catch {
24168
24881
  throw new Error(`availability not configured: ${path3} not found`);
24169
24882
  }
@@ -24522,7 +25235,7 @@ app47.get("/booking-link", requireAdminSession, (c) => {
24522
25235
  console.error('[calendar] op=booking-link-fail err="no account configured"');
24523
25236
  return c.json({ bookingDomain: null });
24524
25237
  }
24525
- if (!existsSync37(join42(account.accountDir, AVAILABILITY_FILENAME))) {
25238
+ if (!existsSync38(join44(account.accountDir, AVAILABILITY_FILENAME))) {
24526
25239
  console.log("[calendar] op=booking-link bookingDomain=none source=availability-config");
24527
25240
  return c.json({ bookingDomain: null });
24528
25241
  }
@@ -24724,7 +25437,7 @@ app48.delete("/:eventId", requireAdminSession, async (c) => {
24724
25437
  var routines_default = app48;
24725
25438
 
24726
25439
  // server/routes/admin/skills.ts
24727
- import { existsSync as existsSync38, readdirSync as readdirSync24, readFileSync as readFileSync39, rmSync as rmSync3 } from "fs";
25440
+ import { existsSync as existsSync39, readdirSync as readdirSync25, readFileSync as readFileSync40, rmSync as rmSync3 } from "fs";
24728
25441
  import { resolve as resolve33 } from "path";
24729
25442
  var app49 = new Hono();
24730
25443
  var NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
@@ -24748,9 +25461,9 @@ function stripQuotes(s) {
24748
25461
  return s;
24749
25462
  }
24750
25463
  function subdirs2(dir) {
24751
- if (!existsSync38(dir)) return [];
25464
+ if (!existsSync39(dir)) return [];
24752
25465
  try {
24753
- return readdirSync24(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
25466
+ return readdirSync25(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
24754
25467
  } catch {
24755
25468
  return [];
24756
25469
  }
@@ -24771,11 +25484,11 @@ app49.get("/", requireAdminSession, async (c) => {
24771
25484
  const skillsDir = resolve33(pluginsDir, plugin, "skills");
24772
25485
  for (const skill of subdirs2(skillsDir)) {
24773
25486
  const skillMd = resolve33(skillsDir, skill, "SKILL.md");
24774
- if (!existsSync38(skillMd)) continue;
25487
+ if (!existsSync39(skillMd)) continue;
24775
25488
  try {
24776
- const { frontmatter } = splitSkillMd(readFileSync39(skillMd, "utf-8"));
25489
+ const { frontmatter } = splitSkillMd(readFileSync40(skillMd, "utf-8"));
24777
25490
  const refsDir = resolve33(skillsDir, skill, "references");
24778
- const refCount = existsSync38(refsDir) ? readdirSync24(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).length : 0;
25491
+ const refCount = existsSync39(refsDir) ? readdirSync25(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).length : 0;
24779
25492
  skills.push({ plugin, skill, description: frontmatter.description, refCount });
24780
25493
  } catch (err) {
24781
25494
  console.error(`[admin:skills] op=list-skip plugin=${plugin} skill=${skill} reason="${err instanceof Error ? err.message : String(err)}"`);
@@ -24799,13 +25512,13 @@ app49.get("/:plugin/:skill", requireAdminSession, async (c) => {
24799
25512
  }
24800
25513
  const skillDir = resolve33(acct.accountDir, "plugins", plugin, "skills", skill);
24801
25514
  const skillMd = resolve33(skillDir, "SKILL.md");
24802
- const found = existsSync38(skillMd);
25515
+ const found = existsSync39(skillMd);
24803
25516
  console.log(`[admin:skills] op=get plugin=${plugin} skill=${skill} found=${found}`);
24804
25517
  if (!found) return c.json({ error: "Skill not found" }, 404);
24805
25518
  try {
24806
- const { frontmatter, body } = splitSkillMd(readFileSync39(skillMd, "utf-8"));
25519
+ const { frontmatter, body } = splitSkillMd(readFileSync40(skillMd, "utf-8"));
24807
25520
  const refsDir = resolve33(skillDir, "references");
24808
- const references = existsSync38(refsDir) ? readdirSync24(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).sort() : [];
25521
+ const references = existsSync39(refsDir) ? readdirSync25(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).sort() : [];
24809
25522
  return c.json({ skill: { plugin, skill, frontmatter, body, references } });
24810
25523
  } catch (err) {
24811
25524
  const message = err instanceof Error ? err.message : String(err);
@@ -24825,7 +25538,7 @@ app49.delete("/:plugin/:skill", requireAdminSession, async (c) => {
24825
25538
  const pluginDir = resolve33(acct.accountDir, "plugins", plugin);
24826
25539
  const skillsDir = resolve33(pluginDir, "skills");
24827
25540
  const skillDir = resolve33(skillsDir, skill);
24828
- if (!existsSync38(resolve33(skillDir, "SKILL.md"))) {
25541
+ if (!existsSync39(resolve33(skillDir, "SKILL.md"))) {
24829
25542
  console.error(`[admin:skills] op=delete outcome=rejected reason=not-found plugin=${plugin} skill=${skill}`);
24830
25543
  return c.json({ error: "Skill not found" }, 404);
24831
25544
  }
@@ -24833,7 +25546,7 @@ app49.delete("/:plugin/:skill", requireAdminSession, async (c) => {
24833
25546
  rmSync3(skillDir, { recursive: true, force: true });
24834
25547
  const pluginDirRemoved = subdirs2(skillsDir).length === 0;
24835
25548
  if (pluginDirRemoved) rmSync3(pluginDir, { recursive: true, force: true });
24836
- const skillDirGone = !existsSync38(skillDir);
25549
+ const skillDirGone = !existsSync39(skillDir);
24837
25550
  if (!skillDirGone) {
24838
25551
  console.error(`[admin:skills] op=delete plugin=${plugin} skill=${skill} outcome=rejected reason=rm-incomplete skillDirGone=false`);
24839
25552
  return c.json({ error: "Delete did not remove the skill directory" }, 503);
@@ -25243,20 +25956,20 @@ app54.post("/", requireAdminSession, async (c) => {
25243
25956
  var task_time_adjust_default = app54;
25244
25957
 
25245
25958
  // app/lib/admin-roster.ts
25246
- import { existsSync as existsSync39, readdirSync as readdirSync25, readFileSync as readFileSync40 } from "fs";
25959
+ import { existsSync as existsSync40, readdirSync as readdirSync26, readFileSync as readFileSync41 } from "fs";
25247
25960
  import { resolve as resolve34 } from "path";
25248
25961
  function readHouseAdminUserIds(accountsDir = ACCOUNTS_DIR) {
25249
25962
  let entries2;
25250
25963
  try {
25251
- entries2 = readdirSync25(accountsDir);
25964
+ entries2 = readdirSync26(accountsDir);
25252
25965
  } catch {
25253
25966
  return [];
25254
25967
  }
25255
25968
  for (const entry of entries2) {
25256
25969
  const cfgPath = resolve34(accountsDir, entry, "account.json");
25257
- if (!existsSync39(cfgPath)) continue;
25970
+ if (!existsSync40(cfgPath)) continue;
25258
25971
  try {
25259
- const cfg = JSON.parse(readFileSync40(cfgPath, "utf-8"));
25972
+ const cfg = JSON.parse(readFileSync41(cfgPath, "utf-8"));
25260
25973
  if (cfg.role !== "house") continue;
25261
25974
  if (!Array.isArray(cfg.admins)) return [];
25262
25975
  return cfg.admins.map(
@@ -25435,7 +26148,7 @@ app56.get("/", requireAdminSession, async (c) => {
25435
26148
  var admin_users_list_default = app56;
25436
26149
 
25437
26150
  // server/routes/admin/activity.ts
25438
- import { readdirSync as readdirSync26 } from "fs";
26151
+ import { readdirSync as readdirSync27 } from "fs";
25439
26152
  var app57 = new Hono();
25440
26153
  var TAG47 = "[activity]";
25441
26154
  function resolveHouseAccountId(accounts) {
@@ -25451,7 +26164,7 @@ function requestToken() {
25451
26164
  var short = (id) => id ? id.slice(0, 8) : "unset";
25452
26165
  function countAccountDirsOnDisk() {
25453
26166
  try {
25454
- return readdirSync26(ACCOUNTS_DIR, { withFileTypes: true }).filter(
26167
+ return readdirSync27(ACCOUNTS_DIR, { withFileTypes: true }).filter(
25455
26168
  (e) => e.isDirectory() && !e.name.startsWith(".")
25456
26169
  ).length;
25457
26170
  } catch {
@@ -25855,7 +26568,7 @@ app61.route("/request-magic-link", request_magic_link_default);
25855
26568
  var access_default = app61;
25856
26569
 
25857
26570
  // server/routes/sites.ts
25858
- import { existsSync as existsSync40, readFileSync as readFileSync41, realpathSync as realpathSync8, statSync as statSync17 } from "fs";
26571
+ import { existsSync as existsSync41, readFileSync as readFileSync42, realpathSync as realpathSync8, statSync as statSync19 } from "fs";
25859
26572
  import { resolve as resolve36 } from "path";
25860
26573
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
25861
26574
  var MIME = {
@@ -25921,7 +26634,7 @@ app62.get("/:rel{.*}", (c) => {
25921
26634
  }
25922
26635
  let stat11;
25923
26636
  try {
25924
- stat11 = existsSync40(filePath) ? statSync17(filePath) : null;
26637
+ stat11 = existsSync41(filePath) ? statSync19(filePath) : null;
25925
26638
  } catch {
25926
26639
  stat11 = null;
25927
26640
  }
@@ -25940,7 +26653,7 @@ app62.get("/:rel{.*}", (c) => {
25940
26653
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
25941
26654
  return c.text("Forbidden", 403);
25942
26655
  }
25943
- if (!existsSync40(filePath)) {
26656
+ if (!existsSync41(filePath)) {
25944
26657
  console.error(`[sites] not-found path=${reqPath} status=404`);
25945
26658
  return c.text("Not found", 404);
25946
26659
  }
@@ -25959,7 +26672,7 @@ app62.get("/:rel{.*}", (c) => {
25959
26672
  }
25960
26673
  let body;
25961
26674
  try {
25962
- body = readFileSync41(realPath);
26675
+ body = readFileSync42(realPath);
25963
26676
  } catch (err) {
25964
26677
  const code = err?.code;
25965
26678
  if (code === "EISDIR") {
@@ -25995,7 +26708,7 @@ var sites_default = app62;
25995
26708
 
25996
26709
  // app/lib/visitor-token.ts
25997
26710
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
25998
- import { mkdirSync as mkdirSync8, readFileSync as readFileSync42, writeFileSync as writeFileSync14 } from "fs";
26711
+ import { mkdirSync as mkdirSync9, readFileSync as readFileSync43, writeFileSync as writeFileSync15 } from "fs";
25999
26712
  import { dirname as dirname14 } from "path";
26000
26713
  var TOKEN_PREFIX = "v1.";
26001
26714
  var SECRET_BYTES = 32;
@@ -26004,7 +26717,7 @@ var cachedSecret = null;
26004
26717
  function getSecret() {
26005
26718
  if (cachedSecret) return cachedSecret;
26006
26719
  try {
26007
- const hex2 = readFileSync42(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
26720
+ const hex2 = readFileSync43(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
26008
26721
  if (hex2.length === SECRET_BYTES * 2) {
26009
26722
  cachedSecret = Buffer.from(hex2, "hex");
26010
26723
  return cachedSecret;
@@ -26013,12 +26726,12 @@ function getSecret() {
26013
26726
  }
26014
26727
  const fresh = randomBytes(SECRET_BYTES).toString("hex");
26015
26728
  try {
26016
- mkdirSync8(dirname14(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
26017
- writeFileSync14(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
26729
+ mkdirSync9(dirname14(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
26730
+ writeFileSync15(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
26018
26731
  console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
26019
26732
  } catch {
26020
26733
  }
26021
- const hex = readFileSync42(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
26734
+ const hex = readFileSync43(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
26022
26735
  cachedSecret = Buffer.from(hex, "hex");
26023
26736
  return cachedSecret;
26024
26737
  }
@@ -26071,8 +26784,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
26071
26784
  var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
26072
26785
 
26073
26786
  // app/lib/brand-config.ts
26074
- import { existsSync as existsSync41, readFileSync as readFileSync43 } from "fs";
26075
- import { join as join43 } from "path";
26787
+ import { existsSync as existsSync42, readFileSync as readFileSync44 } from "fs";
26788
+ import { join as join45 } from "path";
26076
26789
  var cached2 = null;
26077
26790
  var cachedAttempted = false;
26078
26791
  function readBrandConfig() {
@@ -26080,10 +26793,10 @@ function readBrandConfig() {
26080
26793
  cachedAttempted = true;
26081
26794
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
26082
26795
  if (!platformRoot5) return null;
26083
- const brandPath = join43(platformRoot5, "config", "brand.json");
26084
- if (!existsSync41(brandPath)) return null;
26796
+ const brandPath = join45(platformRoot5, "config", "brand.json");
26797
+ if (!existsSync42(brandPath)) return null;
26085
26798
  try {
26086
- cached2 = JSON.parse(readFileSync43(brandPath, "utf-8"));
26799
+ cached2 = JSON.parse(readFileSync44(brandPath, "utf-8"));
26087
26800
  return cached2;
26088
26801
  } catch {
26089
26802
  return null;
@@ -26581,13 +27294,13 @@ var visitor_event_default = app65;
26581
27294
 
26582
27295
  // server/routes/session.ts
26583
27296
  import { resolve as resolve37 } from "path";
26584
- import { existsSync as existsSync42, writeFileSync as writeFileSync15, mkdirSync as mkdirSync9 } from "fs";
27297
+ import { existsSync as existsSync43, writeFileSync as writeFileSync16, mkdirSync as mkdirSync10 } from "fs";
26585
27298
  var UUID_RE5 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
26586
27299
  function writeBrandingCache(accountId, agentSlug, branding) {
26587
27300
  try {
26588
27301
  const cacheDir = resolve37(MAXY_DIR, "branding-cache", accountId);
26589
- mkdirSync9(cacheDir, { recursive: true });
26590
- writeFileSync15(resolve37(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
27302
+ mkdirSync10(cacheDir, { recursive: true });
27303
+ writeFileSync16(resolve37(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
26591
27304
  } catch (err) {
26592
27305
  console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
26593
27306
  }
@@ -26665,7 +27378,7 @@ app66.post("/", async (c) => {
26665
27378
  let agentConfig = null;
26666
27379
  if (account) {
26667
27380
  const agentDir = resolve37(account.accountDir, "agents", agentSlug);
26668
- if (!existsSync42(agentDir) || !existsSync42(resolve37(agentDir, "config.json"))) {
27381
+ if (!existsSync43(agentDir) || !existsSync43(resolve37(agentDir, "config.json"))) {
26669
27382
  return c.json({ error: "Agent not found" }, 404);
26670
27383
  }
26671
27384
  agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
@@ -26925,7 +27638,7 @@ var calendar_public_default = app67;
26925
27638
  // server/routes/portal-fetch.ts
26926
27639
  import { createReadStream as createReadStream3 } from "fs";
26927
27640
  import { stat as stat8, readFile as readFile9, realpath } from "fs/promises";
26928
- import { join as join44, resolve as resolve38, sep as sep10 } from "path";
27641
+ import { join as join46, resolve as resolve38, sep as sep10 } from "path";
26929
27642
  import { Readable as Readable3 } from "stream";
26930
27643
  var app68 = new Hono();
26931
27644
  var TAG50 = "[portal-fetch]";
@@ -26998,7 +27711,7 @@ function isValidAccountId2(value) {
26998
27711
  }
26999
27712
  async function readExposeFolders2(accountDir) {
27000
27713
  try {
27001
- const cfg = JSON.parse(await readFile9(join44(accountDir, "data-portal.json"), "utf8"));
27714
+ const cfg = JSON.parse(await readFile9(join46(accountDir, "data-portal.json"), "utf8"));
27002
27715
  return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
27003
27716
  } catch {
27004
27717
  return [];
@@ -27007,7 +27720,7 @@ async function readExposeFolders2(accountDir) {
27007
27720
  async function resolveFetchTarget(accountDir, relPath, ownerId) {
27008
27721
  let schemaText = null;
27009
27722
  try {
27010
- schemaText = await readFile9(join44(accountDir, "SCHEMA.md"), "utf8");
27723
+ schemaText = await readFile9(join46(accountDir, "SCHEMA.md"), "utf8");
27011
27724
  } catch {
27012
27725
  schemaText = null;
27013
27726
  }
@@ -27177,8 +27890,8 @@ function startTimeEntryCensus(openSession, opts = {}) {
27177
27890
  }
27178
27891
 
27179
27892
  // app/lib/ledger-census.ts
27180
- import { readdirSync as readdirSync27, readFileSync as readFileSync44, statSync as statSync18 } from "fs";
27181
- import { join as join45 } from "path";
27893
+ import { readdirSync as readdirSync28, readFileSync as readFileSync45, statSync as statSync20 } from "fs";
27894
+ import { join as join47 } from "path";
27182
27895
 
27183
27896
  // ../lib/ledger-core/dist/reconcile.js
27184
27897
  var LEDGER_INDEX_NAMES = [
@@ -27226,16 +27939,16 @@ var DAY_MS = 864e5;
27226
27939
  function countWriteRejects24h(logDir, now) {
27227
27940
  let entries2;
27228
27941
  try {
27229
- entries2 = readdirSync27(logDir).filter((f) => f.startsWith("mcp-ledger-") && f.endsWith(".log"));
27942
+ entries2 = readdirSync28(logDir).filter((f) => f.startsWith("mcp-ledger-") && f.endsWith(".log"));
27230
27943
  } catch {
27231
27944
  return 0;
27232
27945
  }
27233
27946
  let total = 0;
27234
27947
  for (const name of entries2) {
27235
- const path3 = join45(logDir, name);
27948
+ const path3 = join47(logDir, name);
27236
27949
  try {
27237
- if (now - statSync18(path3).mtimeMs > DAY_MS) continue;
27238
- for (const line of readFileSync44(path3, "utf8").split("\n")) {
27950
+ if (now - statSync20(path3).mtimeMs > DAY_MS) continue;
27951
+ for (const line of readFileSync45(path3, "utf8").split("\n")) {
27239
27952
  if (line.includes("[graph-write] reject")) total += 1;
27240
27953
  }
27241
27954
  } catch {
@@ -27730,8 +28443,8 @@ async function migrateUploads(opts = {}) {
27730
28443
 
27731
28444
  // app/lib/migrate-admin-webchat-sidecars.ts
27732
28445
  import { readdir as readdir7, readFile as readFile10, rename as rename4, writeFile as writeFile5, unlink as unlink4 } from "fs/promises";
27733
- import { existsSync as existsSync43 } from "fs";
27734
- import { join as join46 } from "path";
28446
+ import { existsSync as existsSync44 } from "fs";
28447
+ import { join as join48 } from "path";
27735
28448
  var ADMIN_ROLE2 = "admin";
27736
28449
  var WEBCHAT_CHANNEL2 = "webchat";
27737
28450
  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;
@@ -27760,7 +28473,7 @@ async function writeRaw(path3, obj) {
27760
28473
  await rename4(tmp, path3);
27761
28474
  } catch (err) {
27762
28475
  try {
27763
- if (existsSync43(tmp)) await unlink4(tmp);
28476
+ if (existsSync44(tmp)) await unlink4(tmp);
27764
28477
  } catch {
27765
28478
  }
27766
28479
  throw err;
@@ -27776,7 +28489,7 @@ async function collectLiveSidecars(projectsRoot) {
27776
28489
  }
27777
28490
  for (const slug of slugs) {
27778
28491
  if (!slug.isDirectory()) continue;
27779
- const slugDir = join46(projectsRoot, slug.name);
28492
+ const slugDir = join48(projectsRoot, slug.name);
27780
28493
  let entries2;
27781
28494
  try {
27782
28495
  entries2 = await readdir7(slugDir, { withFileTypes: true });
@@ -27785,9 +28498,9 @@ async function collectLiveSidecars(projectsRoot) {
27785
28498
  }
27786
28499
  for (const entry of entries2) {
27787
28500
  if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
27788
- out.push(join46(slugDir, entry.name));
28501
+ out.push(join48(slugDir, entry.name));
27789
28502
  } else if (entry.isDirectory() && entry.name === "subagents") {
27790
- const subDir = join46(slugDir, entry.name);
28503
+ const subDir = join48(slugDir, entry.name);
27791
28504
  let subs;
27792
28505
  try {
27793
28506
  subs = await readdir7(subDir, { withFileTypes: true });
@@ -27795,7 +28508,7 @@ async function collectLiveSidecars(projectsRoot) {
27795
28508
  continue;
27796
28509
  }
27797
28510
  for (const s of subs) {
27798
- if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join46(subDir, s.name));
28511
+ if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join48(subDir, s.name));
27799
28512
  }
27800
28513
  }
27801
28514
  }
@@ -27807,7 +28520,7 @@ function shortId(path3) {
27807
28520
  return base.slice(0, 8);
27808
28521
  }
27809
28522
  async function migrateAdminWebchatSidecars(opts = {}) {
27810
- const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join46(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
28523
+ const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join48(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
27811
28524
  const usersFile = opts.usersFile ?? USERS_FILE;
27812
28525
  const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
27813
28526
  const resolveName = opts.resolveName ?? defaultResolveName;
@@ -30510,14 +31223,14 @@ function warnOnChannelAdminBindingDrift() {
30510
31223
  }
30511
31224
 
30512
31225
  // server/lib/booking-site-accounts.ts
30513
- import { existsSync as existsSync44, readFileSync as readFileSync45 } from "fs";
31226
+ import { existsSync as existsSync45, readFileSync as readFileSync46 } from "fs";
30514
31227
  import { resolve as resolve43 } from "path";
30515
31228
  function listBookingSiteAccounts(accounts) {
30516
31229
  return accounts.filter((a) => {
30517
31230
  const availPath = resolve43(a.accountDir, "calendar-availability.json");
30518
- if (!existsSync44(availPath)) return false;
31231
+ if (!existsSync45(availPath)) return false;
30519
31232
  try {
30520
- const cfg = JSON.parse(readFileSync45(availPath, "utf-8"));
31233
+ const cfg = JSON.parse(readFileSync46(availPath, "utf-8"));
30521
31234
  return typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
30522
31235
  } catch {
30523
31236
  return false;
@@ -30554,8 +31267,8 @@ function broadcastAdminShutdown(reason) {
30554
31267
  }
30555
31268
 
30556
31269
  // ../lib/entitlement/src/index.ts
30557
- import { createPublicKey, createHash as createHash6, verify as cryptoVerify } from "crypto";
30558
- import { existsSync as existsSync45, readFileSync as readFileSync46, statSync as statSync19 } from "fs";
31270
+ import { createPublicKey, createHash as createHash7, verify as cryptoVerify } from "crypto";
31271
+ import { existsSync as existsSync46, readFileSync as readFileSync47, statSync as statSync21 } from "fs";
30559
31272
  import { resolve as resolve44 } from "path";
30560
31273
 
30561
31274
  // ../lib/entitlement/src/canonicalize.ts
@@ -30604,10 +31317,10 @@ function resolveEntitlement(brand, account) {
30604
31317
  return logResolved(implicitTrust(account), null);
30605
31318
  }
30606
31319
  const entitlementPath = resolve44(brand.configDir, "entitlement.json");
30607
- if (!existsSync45(entitlementPath)) {
31320
+ if (!existsSync46(entitlementPath)) {
30608
31321
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
30609
31322
  }
30610
- const stat11 = statSync19(entitlementPath);
31323
+ const stat11 = statSync21(entitlementPath);
30611
31324
  const key = memoKey(stat11.mtimeMs, account);
30612
31325
  if (memo && memo.key === key) {
30613
31326
  return memo.result;
@@ -30619,13 +31332,13 @@ function resolveEntitlement(brand, account) {
30619
31332
  function verifyAndResolve(brand, entitlementPath, account) {
30620
31333
  let pubkeyPem;
30621
31334
  try {
30622
- pubkeyPem = readFileSync46(pubkeyPath(brand), "utf-8");
31335
+ pubkeyPem = readFileSync47(pubkeyPath(brand), "utf-8");
30623
31336
  } catch (err) {
30624
31337
  return logResolved(anonymousFallback("pubkey-missing"), {
30625
31338
  reason: "pubkey-missing"
30626
31339
  });
30627
31340
  }
30628
- const pubkeyHash = createHash6("sha256").update(pubkeyPem).digest("hex");
31341
+ const pubkeyHash = createHash7("sha256").update(pubkeyPem).digest("hex");
30629
31342
  if (pubkeyHash !== PUBKEY_SHA256) {
30630
31343
  return logResolved(anonymousFallback("pubkey-tamper"), {
30631
31344
  reason: "pubkey-tamper"
@@ -30633,7 +31346,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
30633
31346
  }
30634
31347
  let envelope;
30635
31348
  try {
30636
- envelope = JSON.parse(readFileSync46(entitlementPath, "utf-8"));
31349
+ envelope = JSON.parse(readFileSync47(entitlementPath, "utf-8"));
30637
31350
  } catch {
30638
31351
  return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
30639
31352
  }
@@ -30795,14 +31508,14 @@ function clientFrom(c) {
30795
31508
  }
30796
31509
  installMediaDownloadGuard();
30797
31510
  var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
30798
- var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join47(PLATFORM_ROOT8, "config", "brand.json") : "";
31511
+ var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join49(PLATFORM_ROOT8, "config", "brand.json") : "";
30799
31512
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
30800
- if (BRAND_JSON_PATH && !existsSync46(BRAND_JSON_PATH)) {
31513
+ if (BRAND_JSON_PATH && !existsSync47(BRAND_JSON_PATH)) {
30801
31514
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
30802
31515
  }
30803
- if (BRAND_JSON_PATH && existsSync46(BRAND_JSON_PATH)) {
31516
+ if (BRAND_JSON_PATH && existsSync47(BRAND_JSON_PATH)) {
30804
31517
  try {
30805
- const parsed = JSON.parse(readFileSync47(BRAND_JSON_PATH, "utf-8"));
31518
+ const parsed = JSON.parse(readFileSync48(BRAND_JSON_PATH, "utf-8"));
30806
31519
  BRAND = { ...BRAND, ...parsed };
30807
31520
  } catch (err) {
30808
31521
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -30834,11 +31547,11 @@ var brandLoginOpts = {
30834
31547
  appleTouchIconPath: brandAppIcon512Path,
30835
31548
  themeColor: BRAND.defaultColors?.primary
30836
31549
  };
30837
- var ALIAS_DOMAINS_PATH = join47(homedir4(), BRAND.configDir, "alias-domains.json");
31550
+ var ALIAS_DOMAINS_PATH = join49(homedir4(), BRAND.configDir, "alias-domains.json");
30838
31551
  function loadAliasDomains() {
30839
31552
  try {
30840
- if (!existsSync46(ALIAS_DOMAINS_PATH)) return null;
30841
- const parsed = JSON.parse(readFileSync47(ALIAS_DOMAINS_PATH, "utf-8"));
31553
+ if (!existsSync47(ALIAS_DOMAINS_PATH)) return null;
31554
+ const parsed = JSON.parse(readFileSync48(ALIAS_DOMAINS_PATH, "utf-8"));
30842
31555
  if (!Array.isArray(parsed)) {
30843
31556
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
30844
31557
  return null;
@@ -30913,7 +31626,7 @@ var waGateway = new WaGateway({
30913
31626
  fetchStandingRules: fetchAccountStandingRules,
30914
31627
  resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
30915
31628
  gatewayUrl: `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`,
30916
- serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
31629
+ serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
30917
31630
  // Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
30918
31631
  // path-validation scope) is the sender's effective SESSION account, resolved
30919
31632
  // once at the inbound gate and threaded here via the gateway's per-sender doc
@@ -30928,13 +31641,13 @@ var waGateway = new WaGateway({
30928
31641
  caption,
30929
31642
  accountId,
30930
31643
  maxyAccountId,
30931
- platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."))
31644
+ platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, ".."))
30932
31645
  });
30933
31646
  return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
30934
31647
  },
30935
31648
  ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId, ownerSelfPhone, replyContext }) => {
30936
31649
  if (passive) {
30937
- const phoneHash = createHash7("sha256").update(senderId).digest("hex").slice(0, 12);
31650
+ const phoneHash = createHash8("sha256").update(senderId).digest("hex").slice(0, 12);
30938
31651
  const prompt = (text ?? "").trim();
30939
31652
  if (prompt.length === 0) {
30940
31653
  console.error(`[wa-passive] op=dropped account=${effectiveAccountId} phoneHash=${phoneHash} msgId=${msgId ?? "none"} reason=empty-text`);
@@ -31046,7 +31759,7 @@ function runDuplicateSenderAudit() {
31046
31759
  try {
31047
31760
  const configDir2 = process.env.CLAUDE_CONFIG_DIR;
31048
31761
  if (!configDir2) return;
31049
- const projectsRoot = join47(configDir2, "projects");
31762
+ const projectsRoot = join49(configDir2, "projects");
31050
31763
  const records = [];
31051
31764
  for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
31052
31765
  if (isSubagent || archived) continue;
@@ -31621,14 +32334,14 @@ app69.get("/agent-assets/:slug/:filename", (c) => {
31621
32334
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
31622
32335
  return c.text("Forbidden", 403);
31623
32336
  }
31624
- if (!existsSync46(filePath)) {
32337
+ if (!existsSync47(filePath)) {
31625
32338
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
31626
32339
  return c.text("Not found", 404);
31627
32340
  }
31628
32341
  const ext = "." + filename.split(".").pop()?.toLowerCase();
31629
32342
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
31630
32343
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
31631
- const body = readFileSync47(filePath);
32344
+ const body = readFileSync48(filePath);
31632
32345
  return c.body(body, 200, {
31633
32346
  "Content-Type": contentType,
31634
32347
  "Cache-Control": "public, max-age=3600"
@@ -31651,14 +32364,14 @@ app69.get("/generated/:filename", (c) => {
31651
32364
  console.error(`[generated] serve file=${filename} status=403`);
31652
32365
  return c.text("Forbidden", 403);
31653
32366
  }
31654
- if (!existsSync46(filePath)) {
32367
+ if (!existsSync47(filePath)) {
31655
32368
  console.error(`[generated] serve file=${filename} status=404`);
31656
32369
  return c.text("Not found", 404);
31657
32370
  }
31658
32371
  const ext = "." + filename.split(".").pop()?.toLowerCase();
31659
32372
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
31660
32373
  console.log(`[generated] serve file=${filename} status=200`);
31661
- const body = readFileSync47(filePath);
32374
+ const body = readFileSync48(filePath);
31662
32375
  return c.body(body, 200, {
31663
32376
  "Content-Type": contentType,
31664
32377
  "Cache-Control": "public, max-age=86400"
@@ -31671,9 +32384,9 @@ app69.route("/v", visitor_consent_default);
31671
32384
  var htmlCache = /* @__PURE__ */ new Map();
31672
32385
  var brandLogoPath = "/brand/maxy-monochrome.png";
31673
32386
  var brandIconPath = "/brand/maxy-monochrome.png";
31674
- if (BRAND_JSON_PATH && existsSync46(BRAND_JSON_PATH)) {
32387
+ if (BRAND_JSON_PATH && existsSync47(BRAND_JSON_PATH)) {
31675
32388
  try {
31676
- const fullBrand = JSON.parse(readFileSync47(BRAND_JSON_PATH, "utf-8"));
32389
+ const fullBrand = JSON.parse(readFileSync48(BRAND_JSON_PATH, "utf-8"));
31677
32390
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
31678
32391
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
31679
32392
  } catch {
@@ -31700,11 +32413,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
31700
32413
  var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
31701
32414
  var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
31702
32415
  var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
31703
- (p) => existsSync46(resolve45(process.cwd(), "public", p.replace(/^\//, "")))
32416
+ (p) => existsSync47(resolve45(process.cwd(), "public", p.replace(/^\//, "")))
31704
32417
  );
31705
32418
  var SW_SOURCE = (() => {
31706
32419
  try {
31707
- return readFileSync47(resolve45(process.cwd(), "public", "sw.js"), "utf-8");
32420
+ return readFileSync48(resolve45(process.cwd(), "public", "sw.js"), "utf-8");
31708
32421
  } catch {
31709
32422
  return null;
31710
32423
  }
@@ -31712,9 +32425,9 @@ var SW_SOURCE = (() => {
31712
32425
  function readInstalledVersion() {
31713
32426
  try {
31714
32427
  if (!PLATFORM_ROOT8) return "unknown";
31715
- const versionFile = join47(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
31716
- if (!existsSync46(versionFile)) return "unknown";
31717
- const content = readFileSync47(versionFile, "utf-8").trim();
32428
+ const versionFile = join49(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
32429
+ if (!existsSync47(versionFile)) return "unknown";
32430
+ const content = readFileSync48(versionFile, "utf-8").trim();
31718
32431
  return content || "unknown";
31719
32432
  } catch {
31720
32433
  return "unknown";
@@ -31755,7 +32468,7 @@ var clientErrorReporterScript = `<script>
31755
32468
  function cachedHtml(file) {
31756
32469
  let html = htmlCache.get(file);
31757
32470
  if (!html) {
31758
- html = readFileSync47(resolve45(process.cwd(), "public", file), "utf-8");
32471
+ html = readFileSync48(resolve45(process.cwd(), "public", file), "utf-8");
31759
32472
  const productNameEsc = escapeHtml(BRAND.productName);
31760
32473
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
31761
32474
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -31772,13 +32485,13 @@ ${clientErrorReporterScript}
31772
32485
  return html;
31773
32486
  }
31774
32487
  function loadBrandingCache(agentSlug) {
31775
- const configDir2 = join47(homedir4(), BRAND.configDir);
32488
+ const configDir2 = join49(homedir4(), BRAND.configDir);
31776
32489
  try {
31777
32490
  const accountId = getDefaultAccountId();
31778
32491
  if (!accountId) return null;
31779
- const cachePath = join47(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
31780
- if (!existsSync46(cachePath)) return null;
31781
- return JSON.parse(readFileSync47(cachePath, "utf-8"));
32492
+ const cachePath = join49(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
32493
+ if (!existsSync47(cachePath)) return null;
32494
+ return JSON.parse(readFileSync48(cachePath, "utf-8"));
31782
32495
  } catch {
31783
32496
  return null;
31784
32497
  }
@@ -31873,7 +32586,7 @@ app69.use("/vnc-popout.html", logViewerFetch);
31873
32586
  app69.get("/vnc-popout.html", (c) => {
31874
32587
  let html = htmlCache.get("vnc-popout.html");
31875
32588
  if (!html) {
31876
- html = readFileSync47(resolve45(process.cwd(), "public", "vnc-popout.html"), "utf-8");
32589
+ html = readFileSync48(resolve45(process.cwd(), "public", "vnc-popout.html"), "utf-8");
31877
32590
  const name = escapeHtml(BRAND.productName);
31878
32591
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
31879
32592
  html = html.replace("</head>", ` ${brandScript}
@@ -32007,6 +32720,7 @@ if (brandFaviconPath !== "/favicon.ico") {
32007
32720
  return c.redirect(brandFaviconPath, 302);
32008
32721
  });
32009
32722
  }
32723
+ app69.use("/*", staticCacheHeaders("./public"));
32010
32724
  app69.use("/*", serveStatic({ root: "./public" }));
32011
32725
  app69.all("*", (c) => {
32012
32726
  const host = (c.req.header("host") ?? "").split(":")[0];
@@ -32025,10 +32739,10 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
32025
32739
  var httpServer = serve({ fetch: app69.fetch, port, hostname });
32026
32740
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32027
32741
  {
32028
- const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32742
+ const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
32029
32743
  const reconcileScript = resolve45(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
32030
32744
  const runReconcile = (ctx) => {
32031
- if (!existsSync46(reconcileScript)) return;
32745
+ if (!existsSync47(reconcileScript)) return;
32032
32746
  try {
32033
32747
  const child = spawn3(process.execPath, [reconcileScript], {
32034
32748
  env: { ...process.env, PLATFORM_ROOT: reconcilePlatformRoot },
@@ -32048,7 +32762,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32048
32762
  detached: true,
32049
32763
  run: runReconcile
32050
32764
  });
32051
- const reconcileStatePath = join47(MAXY_DIR, "booking-reconcile-state.json");
32765
+ const reconcileStatePath = join49(MAXY_DIR, "booking-reconcile-state.json");
32052
32766
  registerLoop({
32053
32767
  name: "calendar-reconcile-liveness",
32054
32768
  intervalMs: 6e5,
@@ -32066,7 +32780,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32066
32780
  }
32067
32781
  {
32068
32782
  const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
32069
- const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32783
+ const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
32070
32784
  const dreamSweepScript = resolve45(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
32071
32785
  registerLoop({
32072
32786
  name: "dream-cycle-sweep",
@@ -32074,7 +32788,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32074
32788
  firstRunDelayMs: 3e4,
32075
32789
  detached: true,
32076
32790
  run: (ctx) => {
32077
- if (!existsSync46(dreamSweepScript)) return;
32791
+ if (!existsSync47(dreamSweepScript)) return;
32078
32792
  try {
32079
32793
  const child = spawn3(process.execPath, [dreamSweepScript], {
32080
32794
  env: { ...process.env, PLATFORM_ROOT: dreamPlatformRoot },
@@ -32090,11 +32804,11 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32090
32804
  });
32091
32805
  }
32092
32806
  {
32093
- const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32807
+ const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
32094
32808
  const outlookScript = resolve45(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
32095
32809
  const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
32096
32810
  const runOutlookComplete = (ctx) => {
32097
- if (!existsSync46(outlookScript)) return;
32811
+ if (!existsSync47(outlookScript)) return;
32098
32812
  try {
32099
32813
  const child = spawn3(process.execPath, [outlookScript], {
32100
32814
  env: { ...process.env, PLATFORM_ROOT: outlookPlatformRoot },
@@ -32116,20 +32830,20 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32116
32830
  });
32117
32831
  }
32118
32832
  {
32119
- const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32833
+ const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
32120
32834
  const strandedAccountsDir = resolve45(auditRoot, "..", "data/accounts");
32121
32835
  const STRANDED_AUDIT_INTERVAL_MS = 3e5;
32122
32836
  const STRANDED_AGE_MS = 16 * 6e4;
32123
32837
  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;
32124
32838
  const runStrandedAudit = () => {
32125
32839
  try {
32126
- if (!existsSync46(strandedAccountsDir)) return;
32840
+ if (!existsSync47(strandedAccountsDir)) return;
32127
32841
  const now = Date.now();
32128
- for (const name of readdirSync28(strandedAccountsDir)) {
32842
+ for (const name of readdirSync29(strandedAccountsDir)) {
32129
32843
  if (!STRANDED_UUID_RE.test(name)) continue;
32130
32844
  const pendingPath2 = resolve45(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
32131
- if (!existsSync46(pendingPath2)) continue;
32132
- const ageMs2 = now - statSync20(pendingPath2).mtimeMs;
32845
+ if (!existsSync47(pendingPath2)) continue;
32846
+ const ageMs2 = now - statSync22(pendingPath2).mtimeMs;
32133
32847
  if (ageMs2 > STRANDED_AGE_MS) {
32134
32848
  console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs2 / 1e3)}`);
32135
32849
  }
@@ -32146,7 +32860,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32146
32860
  });
32147
32861
  }
32148
32862
  {
32149
- const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32863
+ const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
32150
32864
  const googleAccountsDir = resolve45(googleRoot, "..", "data/accounts");
32151
32865
  const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
32152
32866
  const runGooglePendingAuditSafe = () => {
@@ -32165,7 +32879,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32165
32879
  const googleAuditScript = resolve45(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
32166
32880
  const GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS = 36e5;
32167
32881
  const runGoogleAccountAudit = (ctx) => {
32168
- if (!existsSync46(googleAuditScript)) return;
32882
+ if (!existsSync47(googleAuditScript)) return;
32169
32883
  try {
32170
32884
  const child = spawn3(process.execPath, [googleAuditScript], {
32171
32885
  env: { ...process.env, PLATFORM_ROOT: googleRoot },
@@ -32190,7 +32904,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32190
32904
  });
32191
32905
  }
32192
32906
  {
32193
- const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32907
+ const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
32194
32908
  const STORAGE_AUDIT_INTERVAL_MS = 3e5;
32195
32909
  const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
32196
32910
  console.error(`[storage-audit] error="${err.message}"`);
@@ -32236,7 +32950,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32236
32950
  });
32237
32951
  }
32238
32952
  {
32239
- const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32953
+ const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
32240
32954
  const publishScript = resolve45(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
32241
32955
  const PUBLISH_INTERVAL_MS = 3e5;
32242
32956
  const bookingAccounts = () => {
@@ -32248,7 +32962,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32248
32962
  }
32249
32963
  };
32250
32964
  const spawnPublish = (account, ctx) => {
32251
- if (!existsSync46(publishScript)) return;
32965
+ if (!existsSync47(publishScript)) return;
32252
32966
  try {
32253
32967
  const child = spawn3(process.execPath, [publishScript], {
32254
32968
  env: {
@@ -32270,8 +32984,8 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32270
32984
  const availPath = resolve45(account.accountDir, "calendar-availability.json");
32271
32985
  let hasBookingSite = false;
32272
32986
  try {
32273
- if (existsSync46(availPath)) {
32274
- const cfg = JSON.parse(readFileSync47(availPath, "utf-8"));
32987
+ if (existsSync47(availPath)) {
32988
+ const cfg = JSON.parse(readFileSync48(availPath, "utf-8"));
32275
32989
  hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
32276
32990
  }
32277
32991
  } catch {
@@ -32279,9 +32993,9 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32279
32993
  if (!hasBookingSite) return;
32280
32994
  const statePath = resolve45(account.accountDir, "state", "booking-availability", "last-publish.json");
32281
32995
  let lastSuccessAt = null;
32282
- if (existsSync46(statePath)) {
32996
+ if (existsSync47(statePath)) {
32283
32997
  try {
32284
- const rec = JSON.parse(readFileSync47(statePath, "utf-8"));
32998
+ const rec = JSON.parse(readFileSync48(statePath, "utf-8"));
32285
32999
  lastSuccessAt = rec.lastSuccessAt ?? null;
32286
33000
  } catch {
32287
33001
  console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
@@ -32313,12 +33027,12 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32313
33027
  startTimeEntryCensus(() => getSession());
32314
33028
  startLedgerCensus(() => getSession());
32315
33029
  {
32316
- const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
33030
+ const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..");
32317
33031
  const auditScript = resolve45(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
32318
33032
  const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
32319
33033
  const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
32320
33034
  const runConnectorAudit = (ctx) => {
32321
- if (!existsSync46(auditScript)) return;
33035
+ if (!existsSync47(auditScript)) return;
32322
33036
  try {
32323
33037
  const child = spawn3(process.execPath, [auditScript], {
32324
33038
  env: { ...process.env, PLATFORM_ROOT: auditPlatformRoot, LOG_DIR: auditLogDir },
@@ -32358,19 +33072,17 @@ startAuthHealthHeartbeat();
32358
33072
  {
32359
33073
  const loopHist = monitorEventLoopDelay({ resolution: 50 });
32360
33074
  loopHist.enable();
32361
- const LOG_THRESHOLD_MS = 1e3;
33075
+ const LOUD_THRESHOLD_MS = 1e3;
32362
33076
  const WINDOW_MS2 = 3e4;
32363
33077
  registerLoop({
32364
33078
  name: "event-loop-lag",
32365
33079
  intervalMs: WINDOW_MS2,
32366
33080
  run: () => {
32367
- const maxMs = loopHist.max / 1e6;
32368
- const p99Ms = loopHist.percentile(99) / 1e6;
32369
- loopHist.reset();
32370
- if (maxMs >= LOG_THRESHOLD_MS) {
32371
- console.error(`[event-loop] lag p99=${Math.round(p99Ms)} max=${Math.round(maxMs)} window=${WINDOW_MS2 / 1e3}s`);
32372
- }
32373
- return `p99 ${Math.round(p99Ms)}ms, max ${Math.round(maxMs)}ms`;
33081
+ const w = readAndResetWindow(loopHist, WINDOW_MS2);
33082
+ const line = formatLagWindow(w);
33083
+ if (w.maxMs >= LOUD_THRESHOLD_MS) console.error(line);
33084
+ else console.log(line);
33085
+ return `p99 ${w.p99Ms}ms, max ${w.maxMs}ms`;
32374
33086
  }
32375
33087
  });
32376
33088
  }
@@ -32438,11 +33150,11 @@ try {
32438
33150
  var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
32439
33151
  async function runAdminUserReconcileTick() {
32440
33152
  try {
32441
- if (!existsSync46(USERS_FILE)) {
33153
+ if (!existsSync47(USERS_FILE)) {
32442
33154
  console.error("[adminuser-self-heal] skip reason=no-users-file");
32443
33155
  return;
32444
33156
  }
32445
- const usersRaw = readFileSync47(USERS_FILE, "utf-8").trim();
33157
+ const usersRaw = readFileSync48(USERS_FILE, "utf-8").trim();
32446
33158
  if (!usersRaw) {
32447
33159
  console.error("[adminuser-self-heal] skip reason=empty-users-file");
32448
33160
  return;
@@ -32489,8 +33201,8 @@ registerLoop({
32489
33201
  });
32490
33202
  var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
32491
33203
  function countUsersRows() {
32492
- if (!existsSync46(USERS_FILE)) return 0;
32493
- const raw = readFileSync47(USERS_FILE, "utf-8").trim();
33204
+ if (!existsSync47(USERS_FILE)) return 0;
33205
+ const raw = readFileSync48(USERS_FILE, "utf-8").trim();
32494
33206
  if (!raw) return 0;
32495
33207
  const users = JSON.parse(raw);
32496
33208
  return users.filter((u) => typeof u.userId === "string").length;
@@ -32623,7 +33335,7 @@ if (bootAccountConfig?.whatsapp) {
32623
33335
  }
32624
33336
  init({
32625
33337
  configDir: configDirForWhatsApp,
32626
- platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..")),
33338
+ platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join49(__dirname, "..")),
32627
33339
  accountConfig: bootAccountConfig,
32628
33340
  onMessage: async (msg) => {
32629
33341
  if (isObserveAccount(msg.accountId)) {