@rubytech/create-sitedesk-code 0.1.507 → 0.1.508

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 (78) hide show
  1. package/package.json +2 -2
  2. package/payload/platform/config/brand.json +12 -0
  3. package/payload/platform/plugins/admin/PLUGIN.md +10 -5
  4. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +91 -13
  5. package/payload/platform/plugins/admin/skills/whats-new/SKILL.md +7 -0
  6. package/payload/platform/plugins/docs/references/admin-ui.md +90 -12
  7. package/payload/platform/plugins/memory/PLUGIN.md +6 -3
  8. package/payload/platform/scripts/__tests__/provision-honours-disabled-agents.test.sh +84 -0
  9. package/payload/platform/scripts/check-risk-class.mjs +7 -2
  10. package/payload/platform/scripts/check-specialist-tool-surface.mjs +5 -2
  11. package/payload/platform/scripts/lib/canonical-tool-names.mjs +7 -4
  12. package/payload/platform/scripts/lib/provision-account-dir.sh +43 -0
  13. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts +1 -1
  14. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.d.ts.map +1 -1
  15. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js +56 -3
  16. package/payload/platform/services/claude-session-manager/dist/account-dir-schema-reconcile.js.map +1 -1
  17. package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts +19 -5
  18. package/payload/platform/services/claude-session-manager/dist/tool-surface.d.ts.map +1 -1
  19. package/payload/platform/services/claude-session-manager/dist/tool-surface.js +50 -11
  20. package/payload/platform/services/claude-session-manager/dist/tool-surface.js.map +1 -1
  21. package/payload/server/public/activity.html +5 -5
  22. package/payload/server/public/agents.html +4 -4
  23. package/payload/server/public/assets/{AdminLoginScreens-YT7jsh_H.js → AdminLoginScreens-DKeCt1uf.js} +1 -1
  24. package/payload/server/public/assets/{AdminShell-Ckht9hmU.js → AdminShell-HeELCCjJ.js} +1 -1
  25. package/payload/server/public/assets/{activity-DH3Wgc3O.js → activity-BEIDAxDA.js} +1 -1
  26. package/payload/server/public/assets/admin-C0-WU1sf.js +1 -0
  27. package/payload/server/public/assets/agents-DjUvMFTj.js +1 -0
  28. package/payload/server/public/assets/{browser-Bym8QhfA.js → browser-GkVTGqlb.js} +1 -1
  29. package/payload/server/public/assets/{calendar-CFnufJOy.js → calendar-CSqJeFEg.js} +1 -1
  30. package/payload/server/public/assets/chat-C0Ps84U5.js +1 -0
  31. package/payload/server/public/assets/chevron-left-DQ2uNlu9.js +1 -0
  32. package/payload/server/public/assets/chevron-right-C4QCiRGD.js +1 -0
  33. package/payload/server/public/assets/clock-BEeQ7JxX.js +1 -0
  34. package/payload/server/public/assets/data-CGuNfym7.js +1 -0
  35. package/payload/server/public/assets/{file-text-zch0E1GJ.js → file-text-DiscM2pP.js} +1 -1
  36. package/payload/server/public/assets/{graph-BavHLzpV.js → graph-CRP5DM8C.js} +1 -1
  37. package/payload/server/public/assets/{graph-labels-CBwh4g-6.js → graph-labels-Du-6KoBE.js} +1 -1
  38. package/payload/server/public/assets/{maximize-2-bTn_Ozpi.js → maximize-2-D-H_uIV-.js} +1 -1
  39. package/payload/server/public/assets/{operator-a4IOwf62.js → operator-D5rA76YY.js} +1 -1
  40. package/payload/server/public/assets/{page-3T2mE63b.js → page-CHK1415C.js} +1 -1
  41. package/payload/server/public/assets/{page-D6M1CmPe.js → page-DZE3H_n4.js} +1 -1
  42. package/payload/server/public/assets/{public-B3y_YU1G.js → public-DFHXVkdD.js} +1 -1
  43. package/payload/server/public/assets/{rotate-ccw-BGvzNB1b.js → rotate-ccw-CesEJsuO.js} +1 -1
  44. package/payload/server/public/assets/{routines-C7Dr16am.js → routines-DYMYY_r8.js} +1 -1
  45. package/payload/server/public/assets/{skills-DFeb3XO3.js → skills-67jtJ16D.js} +1 -1
  46. package/payload/server/public/assets/{tasks-CSfnCKJe.js → tasks-D2C2a-uk.js} +1 -1
  47. package/payload/server/public/assets/{time-entry-format-BgZqOOqG.js → time-entry-format-BixTGQAd.js} +1 -1
  48. package/payload/server/public/assets/{triangle-alert-DBJ7xz_t.js → triangle-alert-Co9RWb9q.js} +1 -1
  49. package/payload/server/public/assets/{useCopyFeedback-BFOujMl-.js → useCopyFeedback-7zwf9_w4.js} +1 -1
  50. package/payload/server/public/assets/useSubAccountSwitcher-Bg72hdQ8.js +9 -0
  51. package/payload/server/public/assets/useSubAccountSwitcher-DE4v5_Fz.css +1 -0
  52. package/payload/server/public/assets/{useVoiceRecorder-BP6CpYQD.js → useVoiceRecorder-CZDDiwMD.js} +1 -1
  53. package/payload/server/public/assets/{wrench-DdaRhfzS.js → wrench-CjQqdj4P.js} +1 -1
  54. package/payload/server/public/brand/fonts/inter-600.woff2 +0 -0
  55. package/payload/server/public/brand/fonts/inter-700.woff2 +0 -0
  56. package/payload/server/public/brand/fonts/inter-800.woff2 +0 -0
  57. package/payload/server/public/brand-defaults.css +22 -1
  58. package/payload/server/public/browser.html +4 -4
  59. package/payload/server/public/calendar.html +7 -7
  60. package/payload/server/public/chat.html +13 -13
  61. package/payload/server/public/data.html +11 -11
  62. package/payload/server/public/graph.html +9 -9
  63. package/payload/server/public/index.html +14 -14
  64. package/payload/server/public/operator.html +14 -14
  65. package/payload/server/public/public.html +13 -13
  66. package/payload/server/public/routines.html +6 -6
  67. package/payload/server/public/skills.html +5 -5
  68. package/payload/server/public/tasks.html +6 -6
  69. package/payload/server/server.js +882 -251
  70. package/payload/server/public/assets/admin-DetvulAu.js +0 -1
  71. package/payload/server/public/assets/agents-X_IvDHLZ.js +0 -1
  72. package/payload/server/public/assets/chat-wrckyIpw.js +0 -1
  73. package/payload/server/public/assets/chevron-left-Dtk3jEK5.js +0 -1
  74. package/payload/server/public/assets/chevron-right-Dih6IZ8B.js +0 -1
  75. package/payload/server/public/assets/clock-iJCrrmWM.js +0 -1
  76. package/payload/server/public/assets/data-D76--TYs.js +0 -1
  77. package/payload/server/public/assets/useSubAccountSwitcher-0PfRrN6i.js +0 -9
  78. 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 statSync21 } 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 join48, basename as basename14 } from "path";
1831
1831
  import { homedir as homedir4 } from "os";
1832
1832
 
1833
1833
  // server/lib/route-cache-watchers.ts
@@ -16522,7 +16522,7 @@ var session_upload_default = app17;
16522
16522
 
16523
16523
  // server/routes/admin/agents.ts
16524
16524
  import { resolve as resolve23 } from "path";
16525
- import { readdirSync as readdirSync21, readFileSync as readFileSync32, existsSync as existsSync30, rmSync as rmSync2 } from "fs";
16525
+ 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
16526
 
16527
16527
  // server/routes/admin/_account-scope.ts
16528
16528
  function accountDirForSession(cacheKey) {
@@ -16549,12 +16549,390 @@ async function authorizeAccountWrite(c, accountId) {
16549
16549
  return { ok: true, via: "session" };
16550
16550
  }
16551
16551
 
16552
+ // ../services/claude-session-manager/src/tool-surface.ts
16553
+ import { readFileSync as readFileSync32, readdirSync as readdirSync21, statSync as statSync15, existsSync as existsSync30 } from "fs";
16554
+ import { createHash as createHash5 } from "crypto";
16555
+ import { join as join33 } from "path";
16556
+
16557
+ // ../services/claude-session-manager/src/canonical-tool-names.ts
16558
+ function canonicalToolName(plugin, tool) {
16559
+ return `mcp__plugin_${plugin}_${plugin}__${tool}`;
16560
+ }
16561
+ function qualifyShortToolName(plugin, tool) {
16562
+ return `mcp__${plugin}__${tool}`;
16563
+ }
16564
+
16565
+ // ../services/claude-session-manager/src/tool-surface.ts
16566
+ var RISK_CLASSES = ["read", "write_local", "exec", "external"];
16567
+ var ToolSurfaceError = class extends Error {
16568
+ constructor(reason, detail) {
16569
+ super(`${reason}: ${detail}`);
16570
+ this.reason = reason;
16571
+ this.detail = detail;
16572
+ this.name = "ToolSurfaceError";
16573
+ }
16574
+ };
16575
+ var FRONTMATTER_RE = /^---\r?\n([\s\S]*?)\r?\n---/;
16576
+ function extractFrontmatter(raw, pluginDir) {
16577
+ const m = raw.match(FRONTMATTER_RE);
16578
+ if (!m) {
16579
+ throw new ToolSurfaceError("frontmatter-missing", `${pluginDir}/PLUGIN.md has no '---' delimited frontmatter`);
16580
+ }
16581
+ return m[1];
16582
+ }
16583
+ function parseToolsBlock(frontmatter, pluginDir) {
16584
+ const lines = frontmatter.split(/\r?\n/);
16585
+ let i = 0;
16586
+ while (i < lines.length) {
16587
+ const line = lines[i];
16588
+ if (/^tools:\s*\[\s*\]\s*$/.test(line)) return [];
16589
+ if (/^tools:\s*$/.test(line)) {
16590
+ i++;
16591
+ break;
16592
+ }
16593
+ i++;
16594
+ }
16595
+ if (i >= lines.length) return [];
16596
+ const out = [];
16597
+ let current = null;
16598
+ const flush = () => {
16599
+ if (!current) return;
16600
+ if (typeof current.name !== "string" || current.name.length === 0) {
16601
+ throw new ToolSurfaceError("tool-name-missing", `${pluginDir}/PLUGIN.md has a tool entry with no name`);
16602
+ }
16603
+ if (typeof current.publicAllowlist !== "boolean") {
16604
+ if (current.publicAllowlist === void 0) {
16605
+ throw new ToolSurfaceError(
16606
+ "public-allowlist-missing",
16607
+ `${pluginDir}/${current.name} \u2014 every tool must declare publicAllowlist: <true|false>`
16608
+ );
16609
+ }
16610
+ throw new ToolSurfaceError(
16611
+ "public-allowlist-not-boolean",
16612
+ `${pluginDir}/${current.name} \u2014 publicAllowlist must be a YAML boolean (true|false), got ${JSON.stringify(current.publicAllowlist)}`
16613
+ );
16614
+ }
16615
+ if (typeof current.adminAllowlist !== "boolean") {
16616
+ if (current.adminAllowlist === void 0) {
16617
+ throw new ToolSurfaceError(
16618
+ "admin-allowlist-missing",
16619
+ `${pluginDir}/${current.name} \u2014 every tool must declare adminAllowlist: <true|false>`
16620
+ );
16621
+ }
16622
+ throw new ToolSurfaceError(
16623
+ "admin-allowlist-not-boolean",
16624
+ `${pluginDir}/${current.name} \u2014 adminAllowlist must be a YAML boolean (true|false), got ${JSON.stringify(current.adminAllowlist)}`
16625
+ );
16626
+ }
16627
+ if (current.riskClass === void 0) {
16628
+ throw new ToolSurfaceError(
16629
+ "risk-class-missing",
16630
+ `${pluginDir}/${current.name} \u2014 every tool must declare riskClass: <${RISK_CLASSES.join("|")}>`
16631
+ );
16632
+ }
16633
+ if (!RISK_CLASSES.includes(current.riskClass)) {
16634
+ throw new ToolSurfaceError(
16635
+ "risk-class-invalid",
16636
+ `${pluginDir}/${current.name} \u2014 riskClass must be one of ${RISK_CLASSES.join("|")}, got ${JSON.stringify(current.riskClass)}`
16637
+ );
16638
+ }
16639
+ out.push(current);
16640
+ current = null;
16641
+ };
16642
+ for (; i < lines.length; i++) {
16643
+ const line = lines[i];
16644
+ if (line.length === 0) continue;
16645
+ if (/^[A-Za-z_]/.test(line)) break;
16646
+ const newEntry = line.match(/^\s+-\s+name:\s*(.+?)\s*$/);
16647
+ if (newEntry) {
16648
+ flush();
16649
+ current = { name: newEntry[1] };
16650
+ continue;
16651
+ }
16652
+ const orphanListItem = line.match(/^\s+-\s+(?!name:)/);
16653
+ if (orphanListItem) {
16654
+ throw new ToolSurfaceError("tool-name-missing", `${pluginDir}/PLUGIN.md tool entry lacks a name field`);
16655
+ }
16656
+ const publicAllow = line.match(/^\s+publicAllowlist:\s*(.+?)\s*$/);
16657
+ if (publicAllow && current) {
16658
+ const v = publicAllow[1].trim();
16659
+ if (v === "true") current.publicAllowlist = true;
16660
+ else if (v === "false") current.publicAllowlist = false;
16661
+ else current.publicAllowlist = v;
16662
+ continue;
16663
+ }
16664
+ const adminAllow = line.match(/^\s+adminAllowlist:\s*(.+?)\s*$/);
16665
+ if (adminAllow && current) {
16666
+ const v = adminAllow[1].trim();
16667
+ if (v === "true") current.adminAllowlist = true;
16668
+ else if (v === "false") current.adminAllowlist = false;
16669
+ else current.adminAllowlist = v;
16670
+ continue;
16671
+ }
16672
+ const risk = line.match(/^\s+riskClass:\s*(.+?)\s*$/);
16673
+ if (risk && current) {
16674
+ current.riskClass = risk[1].trim();
16675
+ continue;
16676
+ }
16677
+ }
16678
+ flush();
16679
+ return out;
16680
+ }
16681
+ function parseHiddenBlock(frontmatter, pluginDir) {
16682
+ const lines = frontmatter.split(/\r?\n/);
16683
+ let i = 0;
16684
+ while (i < lines.length) {
16685
+ if (/^hidden:\s*$/.test(lines[i])) {
16686
+ i++;
16687
+ break;
16688
+ }
16689
+ i++;
16690
+ }
16691
+ if (i >= lines.length) return [];
16692
+ const out = [];
16693
+ let current = null;
16694
+ const flush = () => {
16695
+ if (!current) return;
16696
+ if (current.riskClass === void 0) {
16697
+ throw new ToolSurfaceError(
16698
+ "risk-class-missing",
16699
+ `${pluginDir}/${current.name} \u2014 every hidden tool must declare riskClass: <${RISK_CLASSES.join("|")}>`
16700
+ );
16701
+ }
16702
+ if (!RISK_CLASSES.includes(current.riskClass)) {
16703
+ throw new ToolSurfaceError(
16704
+ "risk-class-invalid",
16705
+ `${pluginDir}/${current.name} \u2014 hidden riskClass must be one of ${RISK_CLASSES.join("|")}, got ${JSON.stringify(current.riskClass)}`
16706
+ );
16707
+ }
16708
+ out.push(current);
16709
+ current = null;
16710
+ };
16711
+ for (; i < lines.length; i++) {
16712
+ const line = lines[i];
16713
+ if (line.length === 0) continue;
16714
+ if (/^[A-Za-z_]/.test(line)) break;
16715
+ const newEntry = line.match(/^\s+-\s+name:\s*(.+?)\s*$/);
16716
+ if (newEntry) {
16717
+ flush();
16718
+ current = { name: newEntry[1] };
16719
+ continue;
16720
+ }
16721
+ const bareItem = line.match(/^\s+-\s+(.+?)\s*$/);
16722
+ if (bareItem) {
16723
+ throw new ToolSurfaceError(
16724
+ "hidden-tool-name-missing",
16725
+ `${pluginDir}/PLUGIN.md hidden entry "${bareItem[1]}" is a bare name \u2014 declare it as "- name: ${bareItem[1]}" with a riskClass`
16726
+ );
16727
+ }
16728
+ const risk = line.match(/^\s+riskClass:\s*(.+?)\s*$/);
16729
+ if (risk && current) {
16730
+ current.riskClass = risk[1].trim();
16731
+ continue;
16732
+ }
16733
+ }
16734
+ flush();
16735
+ return out;
16736
+ }
16737
+ function parseMcpBlock(frontmatter, pluginDir) {
16738
+ const lines = frontmatter.split(/\r?\n/);
16739
+ let i = 0;
16740
+ while (i < lines.length) {
16741
+ if (/^mcp:\s*$/.test(lines[i])) {
16742
+ i++;
16743
+ break;
16744
+ }
16745
+ i++;
16746
+ }
16747
+ if (i >= lines.length) return null;
16748
+ let command = null;
16749
+ const args = [];
16750
+ const env = {};
16751
+ let envHasEntry = false;
16752
+ let mode = "top";
16753
+ for (; i < lines.length; i++) {
16754
+ const line = lines[i];
16755
+ if (line.length === 0) continue;
16756
+ if (/^[A-Za-z_]/.test(line)) break;
16757
+ const topCommand = line.match(/^\s\s(command):\s*(.+?)\s*$/);
16758
+ const topArgsHeader = line.match(/^\s\s(args):\s*$/);
16759
+ const topEnvHeader = line.match(/^\s\s(env):\s*$/);
16760
+ if (topCommand) {
16761
+ command = topCommand[2];
16762
+ mode = "top";
16763
+ continue;
16764
+ }
16765
+ if (topArgsHeader) {
16766
+ mode = "args";
16767
+ continue;
16768
+ }
16769
+ if (topEnvHeader) {
16770
+ mode = "env";
16771
+ continue;
16772
+ }
16773
+ if (mode === "args") {
16774
+ const item = line.match(/^\s+-\s+(.+?)\s*$/);
16775
+ if (item) {
16776
+ args.push(item[1]);
16777
+ continue;
16778
+ }
16779
+ }
16780
+ if (mode === "env") {
16781
+ const kv = line.match(/^\s+([A-Za-z_][A-Za-z0-9_]*):\s*(.+?)\s*$/);
16782
+ if (kv) {
16783
+ env[kv[1]] = kv[2];
16784
+ envHasEntry = true;
16785
+ continue;
16786
+ }
16787
+ }
16788
+ }
16789
+ if (command === null) {
16790
+ throw new ToolSurfaceError("mcp-command-missing", `${pluginDir}/PLUGIN.md mcp: block has no command`);
16791
+ }
16792
+ const desc = { command, args };
16793
+ if (envHasEntry) desc.env = env;
16794
+ return desc;
16795
+ }
16796
+ function loadToolSurface(pluginsRoots) {
16797
+ const roots = Array.isArray(pluginsRoots) ? pluginsRoots : [pluginsRoots];
16798
+ for (const r of roots) {
16799
+ if (!existsSync30(r)) throw new ToolSurfaceError("plugins-root-missing", r);
16800
+ }
16801
+ const admin = /* @__PURE__ */ new Set();
16802
+ const pub = /* @__PURE__ */ new Set();
16803
+ const all = /* @__PURE__ */ new Set();
16804
+ const mcpServers = /* @__PURE__ */ new Map();
16805
+ const riskByTool = /* @__PURE__ */ new Map();
16806
+ const manifestPaths = /* @__PURE__ */ new Map();
16807
+ const loadOne = (pluginsRoot, plugin) => {
16808
+ const pluginDir = join33(pluginsRoot, plugin);
16809
+ try {
16810
+ if (!statSync15(pluginDir).isDirectory()) return;
16811
+ } catch {
16812
+ return;
16813
+ }
16814
+ const manifestPath = join33(pluginDir, "PLUGIN.md");
16815
+ if (!existsSync30(manifestPath)) return;
16816
+ const raw = readFileSync32(manifestPath, "utf-8");
16817
+ const frontmatter = extractFrontmatter(raw, plugin);
16818
+ const tools = parseToolsBlock(frontmatter, plugin);
16819
+ if (tools.length === 0) return;
16820
+ const mcp = parseMcpBlock(frontmatter, plugin);
16821
+ if (!mcp) {
16822
+ throw new ToolSurfaceError(
16823
+ "mcp-block-missing",
16824
+ `${plugin}/PLUGIN.md declares tools but no mcp: block; spawns would --allowed-tools mcp__${plugin}__* with no registered server`
16825
+ );
16826
+ }
16827
+ if (mcpServers.has(plugin)) {
16828
+ const priorPath = manifestPaths.get(plugin);
16829
+ if (!priorPath) {
16830
+ throw new ToolSurfaceError(
16831
+ "mcp-plugin-duplicate-no-prior-path",
16832
+ `${plugin}: mcpServers has entry but manifestPaths is missing \u2014 invariant violated, both maps must be written together`
16833
+ );
16834
+ }
16835
+ const priorSha = createHash5("sha256").update(readFileSync32(priorPath)).digest("hex").slice(0, 8);
16836
+ const newSha = createHash5("sha256").update(raw).digest("hex").slice(0, 8);
16837
+ throw new ToolSurfaceError(
16838
+ "mcp-plugin-duplicate",
16839
+ `${plugin} declared by more than one plugins root: ${priorPath} (sha=${priorSha}) vs ${manifestPath} (sha=${newSha})`
16840
+ );
16841
+ }
16842
+ mcpServers.set(plugin, mcp);
16843
+ manifestPaths.set(plugin, manifestPath);
16844
+ for (const t of tools) {
16845
+ const canonical = canonicalToolName(plugin, t.name);
16846
+ all.add(canonical);
16847
+ riskByTool.set(canonical, t.riskClass);
16848
+ if (t.adminAllowlist) admin.add(canonical);
16849
+ if (t.publicAllowlist) pub.add(qualifyShortToolName(plugin, t.name));
16850
+ }
16851
+ for (const h of parseHiddenBlock(frontmatter, plugin)) {
16852
+ const canonical = canonicalToolName(plugin, h.name);
16853
+ all.add(canonical);
16854
+ riskByTool.set(canonical, h.riskClass);
16855
+ }
16856
+ };
16857
+ for (const root of roots) {
16858
+ const entries2 = readdirSync21(root).sort();
16859
+ for (const plugin of entries2) {
16860
+ const pluginDir = join33(root, plugin);
16861
+ loadOne(root, plugin);
16862
+ const subRoot = join33(pluginDir, "plugins");
16863
+ let subEntries;
16864
+ try {
16865
+ if (!statSync15(subRoot).isDirectory()) continue;
16866
+ subEntries = readdirSync21(subRoot).sort();
16867
+ } catch {
16868
+ continue;
16869
+ }
16870
+ for (const sub of subEntries) {
16871
+ loadOne(subRoot, sub);
16872
+ }
16873
+ }
16874
+ }
16875
+ return { admin, public: pub, all, mcpServers, riskByTool };
16876
+ }
16877
+
16878
+ // server/lib/agent-risk.ts
16879
+ var BUILTIN_TOOL_RISK = {
16880
+ Bash: "exec",
16881
+ Task: "exec",
16882
+ Skill: "exec",
16883
+ Edit: "write_local",
16884
+ MultiEdit: "write_local",
16885
+ Write: "write_local",
16886
+ Read: "read",
16887
+ Glob: "read",
16888
+ Grep: "read",
16889
+ WebFetch: "external",
16890
+ WebSearch: "external"
16891
+ };
16892
+ var SEVERITY = {
16893
+ read: 0,
16894
+ write_local: 1,
16895
+ exec: 2,
16896
+ external: 2
16897
+ };
16898
+ var AGENT_CLASS = {
16899
+ read: "green",
16900
+ write_local: "amber",
16901
+ exec: "red",
16902
+ external: "red"
16903
+ };
16904
+ function agentRiskClass(tools, riskByTool) {
16905
+ const byTool = [];
16906
+ const unresolved = [];
16907
+ let worst = null;
16908
+ let worstTool = null;
16909
+ for (const tool of tools) {
16910
+ const cls = BUILTIN_TOOL_RISK[tool] ?? riskByTool.get(tool) ?? null;
16911
+ byTool.push({ tool, risk: cls });
16912
+ if (cls === null) {
16913
+ unresolved.push(tool);
16914
+ continue;
16915
+ }
16916
+ if (worst === null || SEVERITY[cls] > SEVERITY[worst]) {
16917
+ worst = cls;
16918
+ worstTool = tool;
16919
+ }
16920
+ }
16921
+ if (unresolved.length > 0) {
16922
+ return { risk: "red", worstTool: unresolved[0], unresolved, byTool };
16923
+ }
16924
+ if (worst === null) {
16925
+ return { risk: "red", worstTool: null, unresolved, byTool };
16926
+ }
16927
+ return { risk: AGENT_CLASS[worst], worstTool, unresolved, byTool };
16928
+ }
16929
+
16552
16930
  // server/routes/admin/agents.ts
16553
16931
  var SLUG_UNSAFE = (s) => s.includes("/") || s.includes("..") || s.includes("\\");
16554
16932
  function subdirs(dir) {
16555
- if (!existsSync30(dir)) return [];
16933
+ if (!existsSync31(dir)) return [];
16556
16934
  try {
16557
- return readdirSync21(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
16935
+ return readdirSync22(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
16558
16936
  } catch {
16559
16937
  return [];
16560
16938
  }
@@ -16569,34 +16947,148 @@ function splitFrontmatter(text) {
16569
16947
  }
16570
16948
  return { fm, body: text.slice(m[0].length) };
16571
16949
  }
16572
- function listSpecialists(accountDir) {
16950
+ var SPECIALISTS_DIR = ["specialists", "agents"];
16951
+ var QUARANTINE_DIR = ["specialists", "agents-disabled"];
16952
+ var DISABLED_STORE = "agents-disabled.json";
16953
+ function loadRiskSurface() {
16954
+ const roots = [resolve23(PLATFORM_ROOT, "plugins"), resolve23(PLATFORM_ROOT, "..", "premium-plugins")].filter((r) => existsSync31(r));
16955
+ try {
16956
+ return { riskByTool: loadToolSurface(roots).riskByTool, failed: null };
16957
+ } catch (err) {
16958
+ const msg = err instanceof Error ? err.message : String(err);
16959
+ console.error(`[admin/agents] op=risk-surface status=load-failed reason="${msg}"`);
16960
+ return { riskByTool: /* @__PURE__ */ new Map(), failed: msg };
16961
+ }
16962
+ }
16963
+ function readDisabledStoreStrict(accountDir) {
16964
+ const p = resolve23(accountDir, DISABLED_STORE);
16965
+ if (!existsSync31(p)) return /* @__PURE__ */ new Set();
16966
+ const parsed = JSON.parse(readFileSync33(p, "utf-8"));
16967
+ if (!Array.isArray(parsed.disabled)) throw new Error("disabled is not an array");
16968
+ return new Set(parsed.disabled.filter((x) => typeof x === "string"));
16969
+ }
16970
+ function readDisabledStore(accountDir) {
16971
+ try {
16972
+ return readDisabledStoreStrict(accountDir);
16973
+ } catch (err) {
16974
+ const msg = err instanceof Error ? err.message : String(err);
16975
+ console.error(`[admin/agents] op=disabled-store status=parse-failed reason="${msg}"`);
16976
+ return /* @__PURE__ */ new Set();
16977
+ }
16978
+ }
16979
+ function shippedSourceDirs(accountDir) {
16980
+ return [
16981
+ resolve23(accountDir, ...SPECIALISTS_DIR),
16982
+ resolve23(accountDir, ...QUARANTINE_DIR),
16983
+ resolve23(PLATFORM_ROOT, "templates", "specialists", "agents")
16984
+ ];
16985
+ }
16986
+ function writeDisabledStore(accountDir, disabled) {
16987
+ writeFileSync13(
16988
+ resolve23(accountDir, DISABLED_STORE),
16989
+ `${JSON.stringify({ disabled: [...disabled].sort() }, null, 2)}
16990
+ `,
16991
+ { mode: 384 }
16992
+ );
16993
+ }
16994
+ function listShipped(accountDir, riskByTool, disabled, riskSurfaceFailed) {
16995
+ const dirs = shippedSourceDirs(accountDir);
16996
+ const names = /* @__PURE__ */ new Set();
16997
+ for (const dir of dirs) {
16998
+ if (!existsSync31(dir)) continue;
16999
+ try {
17000
+ for (const entry of readdirSync22(dir)) if (entry.endsWith(".md")) names.add(entry);
17001
+ } catch (err) {
17002
+ console.error(`[admin/agents] op=list-shipped read-failed dir=${dir} error="${err}"`);
17003
+ }
17004
+ }
17005
+ const shipped = [];
17006
+ let shippedSkipped = 0;
17007
+ for (const filename of [...names].sort()) {
17008
+ const source = dirs.find((d) => existsSync31(resolve23(d, filename)));
17009
+ if (!source) continue;
17010
+ try {
17011
+ const { fm } = splitFrontmatter(readFileSync33(resolve23(source, filename), "utf-8"));
17012
+ if (!fm.name) {
17013
+ shippedSkipped++;
17014
+ console.error(`[admin/agents] op=list-shipped-skip file=${filename} reason=no-name`);
17015
+ continue;
17016
+ }
17017
+ const tools = parseToolsLine(fm.tools);
17018
+ const r = classify(tools, riskByTool, riskSurfaceFailed);
17019
+ shipped.push({
17020
+ slug: filename.replace(/\.md$/, ""),
17021
+ displayName: fm.name,
17022
+ kind: "specialist",
17023
+ origin: "shipped",
17024
+ plugin: "",
17025
+ description: fm.description ?? "",
17026
+ risk: r.risk,
17027
+ worstTool: r.worstTool,
17028
+ unresolved: r.unresolved,
17029
+ toolCount: tools.length,
17030
+ // The DIRECTORY is the ground truth, not the store. `spawn-context.ts`
17031
+ // reads the live dir, so a file found in quarantine is not dispatchable
17032
+ // whatever the JSON says, and a file found live IS dispatchable even if
17033
+ // the store claims otherwise. The store only answers for a bundled-only
17034
+ // agent, which has no account copy in either directory to look at.
17035
+ disabled: source === dirs[1] || source === dirs[2] && disabled.has(filename)
17036
+ });
17037
+ } catch (err) {
17038
+ shippedSkipped++;
17039
+ console.error(`[admin/agents] op=list-shipped-skip file=${filename} error="${err}"`);
17040
+ }
17041
+ }
17042
+ return { shipped, shippedSkipped };
17043
+ }
17044
+ function parseToolsLine(raw) {
17045
+ return raw ? raw.split(",").map((t) => t.trim()).filter(Boolean) : [];
17046
+ }
17047
+ function classify(tools, riskByTool, riskSurfaceFailed) {
17048
+ if (riskSurfaceFailed) {
17049
+ return { risk: "red", worstTool: null, unresolved: [], byTool: tools.map((t) => ({ tool: t, risk: null })) };
17050
+ }
17051
+ return agentRiskClass(tools, riskByTool);
17052
+ }
17053
+ function listSpecialists(accountDir, riskByTool, riskSurfaceFailed) {
16573
17054
  const pluginsDir = resolve23(accountDir, "plugins");
16574
17055
  const specialists = [];
16575
17056
  let specialistsSkipped = 0;
16576
17057
  for (const plugin of subdirs(pluginsDir).sort()) {
16577
17058
  const agentsDirP = resolve23(pluginsDir, plugin, "agents");
16578
- if (!existsSync30(agentsDirP)) continue;
17059
+ if (!existsSync31(agentsDirP)) continue;
16579
17060
  let entries2;
16580
17061
  try {
16581
- entries2 = readdirSync21(agentsDirP, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
17062
+ entries2 = readdirSync22(agentsDirP, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
16582
17063
  } catch {
16583
17064
  continue;
16584
17065
  }
16585
17066
  for (const entry of entries2) {
16586
17067
  if (!entry.isFile() || !entry.name.endsWith(".md")) continue;
16587
17068
  try {
16588
- const { fm } = splitFrontmatter(readFileSync32(resolve23(agentsDirP, entry.name), "utf-8"));
17069
+ const { fm } = splitFrontmatter(readFileSync33(resolve23(agentsDirP, entry.name), "utf-8"));
16589
17070
  if (!fm.name) {
16590
17071
  specialistsSkipped++;
16591
17072
  console.error(`[admin/agents] op=list-specialist-skip plugin=${plugin} file=${entry.name}`);
16592
17073
  continue;
16593
17074
  }
17075
+ const specialistTools = parseToolsLine(fm.tools);
17076
+ const r = classify(specialistTools, riskByTool, riskSurfaceFailed);
16594
17077
  specialists.push({
16595
17078
  slug: entry.name.replace(/\.md$/, ""),
16596
17079
  displayName: fm.name,
16597
17080
  kind: "specialist",
17081
+ origin: "specialist",
16598
17082
  plugin,
16599
- description: fm.description ?? ""
17083
+ description: fm.description ?? "",
17084
+ risk: r.risk,
17085
+ worstTool: r.worstTool,
17086
+ unresolved: r.unresolved,
17087
+ toolCount: specialistTools.length,
17088
+ // A user-created specialist lives under the account plugins tree,
17089
+ // which provisioning never rewrites, so the quarantine mechanism
17090
+ // does not apply to it.
17091
+ disabled: false
16600
17092
  });
16601
17093
  } catch {
16602
17094
  specialistsSkipped++;
@@ -16619,24 +17111,31 @@ app18.get("/", requireAdminSession, (c) => {
16619
17111
  console.error("[admin/agents] op=list auth-rejected reason=no-account-for-session");
16620
17112
  return c.json({ error: "Account not found for session" }, 401);
16621
17113
  }
17114
+ const { riskByTool, failed: riskSurfaceFailed } = loadRiskSurface();
17115
+ const disabled = readDisabledStore(account.accountDir);
16622
17116
  const agents = [];
16623
17117
  let skipped = 0;
16624
17118
  const agentsDir = resolve23(account.accountDir, "agents");
16625
- if (existsSync30(agentsDir)) {
17119
+ if (existsSync31(agentsDir)) {
16626
17120
  try {
16627
- const entries2 = readdirSync21(agentsDir, { withFileTypes: true });
17121
+ const entries2 = readdirSync22(agentsDir, { withFileTypes: true });
16628
17122
  for (const entry of entries2.sort((a, b) => a.name.localeCompare(b.name))) {
16629
17123
  if (!entry.isDirectory()) continue;
16630
17124
  if (entry.name === "admin") continue;
16631
17125
  const configPath2 = resolve23(agentsDir, entry.name, "config.json");
16632
- if (!existsSync30(configPath2)) continue;
17126
+ if (!existsSync31(configPath2)) continue;
16633
17127
  try {
16634
- const config = JSON.parse(readFileSync32(configPath2, "utf-8"));
17128
+ const config = JSON.parse(readFileSync33(configPath2, "utf-8"));
16635
17129
  agents.push({
16636
17130
  slug: entry.name,
16637
17131
  displayName: config.displayName ?? entry.name,
16638
17132
  status: config.status ?? "unknown",
16639
- kind: "public"
17133
+ kind: "public",
17134
+ origin: "public",
17135
+ risk: null,
17136
+ worstTool: null,
17137
+ unresolved: [],
17138
+ disabled: false
16640
17139
  });
16641
17140
  } catch {
16642
17141
  skipped++;
@@ -16647,9 +17146,25 @@ app18.get("/", requireAdminSession, (c) => {
16647
17146
  console.error(`[admin/agents] failed to scan agents directory: ${err}`);
16648
17147
  }
16649
17148
  }
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 });
17149
+ const { specialists, specialistsSkipped } = listSpecialists(account.accountDir, riskByTool, riskSurfaceFailed !== null);
17150
+ const { shipped, shippedSkipped } = listShipped(account.accountDir, riskByTool, disabled, riskSurfaceFailed !== null);
17151
+ const rows = [...agents, ...specialists, ...shipped];
17152
+ const acct = account.accountId.slice(0, 8);
17153
+ for (const row of rows) {
17154
+ if (row.risk === null) continue;
17155
+ console.log(
17156
+ `[admin/agents] op=classify account=${acct} agent=${row.slug} origin=${row.origin} risk=${row.risk} worstTool=${row.worstTool ?? "none"} tools=${row.toolCount} unresolved=${row.unresolved.length > 0 ? row.unresolved.join(",") : "none"} disabled=${row.disabled}`
17157
+ );
17158
+ }
17159
+ console.log(`[admin/agents] op=list accountId=${acct} agents=${agents.length} specialists=${specialists.length} shipped=${shipped.length} skipped=${skipped} specialistsSkipped=${specialistsSkipped} shippedSkipped=${shippedSkipped}`);
17160
+ return c.json({
17161
+ agents: rows,
17162
+ accountId: account.accountId,
17163
+ skipped,
17164
+ specialistsSkipped,
17165
+ shippedSkipped,
17166
+ riskSurfaceFailed: riskSurfaceFailed !== null
17167
+ });
16653
17168
  });
16654
17169
  app18.get("/:slug", requireAdminSession, (c) => {
16655
17170
  const slug = c.req.param("slug");
@@ -16659,34 +17174,72 @@ app18.get("/:slug", requireAdminSession, (c) => {
16659
17174
  return c.json({ error: "Account not found for session" }, 401);
16660
17175
  }
16661
17176
  if (SLUG_UNSAFE(slug)) return c.json({ error: "Invalid agent slug" }, 400);
17177
+ if (c.req.query("origin") === "shipped") {
17178
+ const dirs = shippedSourceDirs(account.accountDir);
17179
+ const source = dirs.find((d) => existsSync31(resolve23(d, `${slug}.md`)));
17180
+ if (!source) return c.json({ error: "Agent not found" }, 404);
17181
+ const { fm, body } = splitFrontmatter(readFileSync33(resolve23(source, `${slug}.md`), "utf-8"));
17182
+ const { riskByTool, failed } = loadRiskSurface();
17183
+ const tools = parseToolsLine(fm.tools);
17184
+ const r = classify(tools, riskByTool, failed !== null);
17185
+ console.log(`[admin/agents] op=detail accountId=${account.accountId.slice(0, 8)} slug=${slug} kind=specialist origin=shipped risk=${r.risk}`);
17186
+ return c.json({
17187
+ agent: {
17188
+ kind: "specialist",
17189
+ origin: "shipped",
17190
+ slug,
17191
+ displayName: fm.name ?? slug,
17192
+ description: fm.description ?? "",
17193
+ summary: fm.summary ?? "",
17194
+ model: fm.model ?? null,
17195
+ tools,
17196
+ systemPrompt: body.trim(),
17197
+ skills: [],
17198
+ risk: r.risk,
17199
+ worstTool: r.worstTool,
17200
+ unresolved: r.unresolved,
17201
+ byTool: r.byTool,
17202
+ disabled: readDisabledStore(account.accountDir).has(`${slug}.md`)
17203
+ }
17204
+ });
17205
+ }
16662
17206
  const pluginParam = c.req.query("plugin");
16663
17207
  if (pluginParam) {
16664
17208
  if (SLUG_UNSAFE(pluginParam)) return c.json({ error: "Invalid plugin" }, 400);
16665
17209
  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"));
17210
+ if (!existsSync31(file)) return c.json({ error: "Agent not found" }, 404);
17211
+ const { fm, body } = splitFrontmatter(readFileSync33(file, "utf-8"));
16668
17212
  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}`);
17213
+ const { riskByTool, failed } = loadRiskSurface();
17214
+ const tools = parseToolsLine(fm.tools);
17215
+ const r = classify(tools, riskByTool, failed !== null);
17216
+ console.log(`[admin/agents] op=detail accountId=${account.accountId.slice(0, 8)} slug=${slug} kind=specialist plugin=${pluginParam} risk=${r.risk}`);
16670
17217
  return c.json({
16671
17218
  agent: {
16672
17219
  kind: "specialist",
17220
+ origin: "specialist",
16673
17221
  slug,
16674
17222
  displayName: fm.name ?? slug,
16675
17223
  description: fm.description ?? "",
16676
17224
  summary: fm.summary ?? "",
16677
17225
  model: fm.model ?? null,
16678
- tools: fm.tools ? fm.tools.split(",").map((t) => t.trim()).filter(Boolean) : [],
17226
+ tools,
16679
17227
  systemPrompt: body.trim(),
16680
- skills
17228
+ skills,
17229
+ risk: r.risk,
17230
+ worstTool: r.worstTool,
17231
+ unresolved: r.unresolved,
17232
+ byTool: r.byTool,
17233
+ disabled: false
16681
17234
  }
16682
17235
  });
16683
17236
  }
16684
17237
  const agentDir = resolve23(account.accountDir, "agents", slug);
16685
17238
  const configPath2 = resolve23(agentDir, "config.json");
16686
- if (!existsSync30(configPath2)) return c.json({ error: "Agent not found" }, 404);
17239
+ if (!existsSync31(configPath2)) return c.json({ error: "Agent not found" }, 404);
16687
17240
  let config;
16688
17241
  try {
16689
- config = JSON.parse(readFileSync32(configPath2, "utf-8"));
17242
+ config = JSON.parse(readFileSync33(configPath2, "utf-8"));
16690
17243
  } catch {
16691
17244
  console.error(`[admin/agents] op=detail slug=${slug} error="config.json parse failed"`);
16692
17245
  return c.json({ error: "Agent config unreadable" }, 500);
@@ -16696,8 +17249,8 @@ app18.get("/:slug", requireAdminSession, (c) => {
16696
17249
  for (const { file, key } of OWNED_DOCS) {
16697
17250
  const p = resolve23(agentDir, file);
16698
17251
  try {
16699
- if (existsSync30(p)) {
16700
- docs[key] = readFileSync32(p, "utf-8");
17252
+ if (existsSync31(p)) {
17253
+ docs[key] = readFileSync33(p, "utf-8");
16701
17254
  present[key] = true;
16702
17255
  } else {
16703
17256
  docs[key] = "";
@@ -16726,6 +17279,84 @@ app18.get("/:slug", requireAdminSession, (c) => {
16726
17279
  }
16727
17280
  });
16728
17281
  });
17282
+ async function resolveWritableAccount(c, op, slug) {
17283
+ const accountIdParam = c.req.query("accountId") ?? "";
17284
+ if (!accountIdParam) {
17285
+ console.error(`[admin/agents] op=${op} rejected reason=missing-accountId slug=${slug}`);
17286
+ return { status: 400, error: "accountId is required" };
17287
+ }
17288
+ const account = validateAccountId2(accountIdParam);
17289
+ if (!account) {
17290
+ console.error(`[admin/agents] op=${op} rejected reason=unknown-accountId accountId=${accountIdParam.slice(0, 8)} slug=${slug}`);
17291
+ return { status: 400, error: "Unknown accountId" };
17292
+ }
17293
+ const authz = await authorizeAccountWrite(c, account.accountId);
17294
+ if (!authz.ok) {
17295
+ console.error(`[admin/agents] op=${op} rejected reason=${authz.reason} accountId=${account.accountId.slice(0, 8)} slug=${slug}`);
17296
+ return { status: 403, error: "Not authorized for this account" };
17297
+ }
17298
+ return account;
17299
+ }
17300
+ app18.post("/:slug/disable", async (c) => {
17301
+ const slug = c.req.param("slug");
17302
+ if (SLUG_UNSAFE(slug)) return c.json({ error: "Invalid agent slug" }, 400);
17303
+ const resolved = await resolveWritableAccount(c, "disable", slug);
17304
+ if ("status" in resolved) return c.json({ error: resolved.error }, resolved.status);
17305
+ const filename = `${slug}.md`;
17306
+ const live = resolve23(resolved.accountDir, ...SPECIALISTS_DIR, filename);
17307
+ const quarantined = resolve23(resolved.accountDir, ...QUARANTINE_DIR, filename);
17308
+ if (!shippedSourceDirs(resolved.accountDir).some((d) => existsSync31(resolve23(d, filename)))) {
17309
+ console.error(`[admin/agents] op=disable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=failed reason=not-a-shipped-agent`);
17310
+ return c.json({ error: "Only a shipped agent can be disabled" }, 404);
17311
+ }
17312
+ let moved = false;
17313
+ try {
17314
+ const disabled = readDisabledStoreStrict(resolved.accountDir);
17315
+ if (existsSync31(live)) {
17316
+ mkdirSync7(resolve23(resolved.accountDir, ...QUARANTINE_DIR), { recursive: true });
17317
+ renameSync9(live, quarantined);
17318
+ moved = true;
17319
+ }
17320
+ disabled.add(filename);
17321
+ writeDisabledStore(resolved.accountDir, disabled);
17322
+ } catch (err) {
17323
+ const msg = err instanceof Error ? err.message : String(err);
17324
+ console.error(`[admin/agents] op=disable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=failed reason="${msg}"`);
17325
+ return c.json({ error: `Disable failed, disabled store unreadable or unwritable: ${msg}` }, 500);
17326
+ }
17327
+ console.log(`[admin/agents] op=disable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=ok moved=${moved}`);
17328
+ return c.json({ ok: true, moved });
17329
+ });
17330
+ app18.post("/:slug/enable", async (c) => {
17331
+ const slug = c.req.param("slug");
17332
+ if (SLUG_UNSAFE(slug)) return c.json({ error: "Invalid agent slug" }, 400);
17333
+ const resolved = await resolveWritableAccount(c, "enable", slug);
17334
+ if ("status" in resolved) return c.json({ error: resolved.error }, resolved.status);
17335
+ const filename = `${slug}.md`;
17336
+ const live = resolve23(resolved.accountDir, ...SPECIALISTS_DIR, filename);
17337
+ const quarantined = resolve23(resolved.accountDir, ...QUARANTINE_DIR, filename);
17338
+ let restored = false;
17339
+ try {
17340
+ const disabled = readDisabledStoreStrict(resolved.accountDir);
17341
+ if (!existsSync31(quarantined) && !disabled.has(filename)) {
17342
+ console.error(`[admin/agents] op=enable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=failed reason=not-disabled`);
17343
+ return c.json({ error: "This agent is not disabled" }, 404);
17344
+ }
17345
+ if (existsSync31(quarantined)) {
17346
+ mkdirSync7(resolve23(resolved.accountDir, ...SPECIALISTS_DIR), { recursive: true });
17347
+ renameSync9(quarantined, live);
17348
+ restored = true;
17349
+ }
17350
+ disabled.delete(filename);
17351
+ writeDisabledStore(resolved.accountDir, disabled);
17352
+ } catch (err) {
17353
+ const msg = err instanceof Error ? err.message : String(err);
17354
+ console.error(`[admin/agents] op=enable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=failed reason="${msg}"`);
17355
+ return c.json({ error: `Enable failed: ${msg}` }, 500);
17356
+ }
17357
+ console.log(`[admin/agents] op=enable accountId=${resolved.accountId.slice(0, 8)} slug=${slug} outcome=ok restored=${restored}`);
17358
+ return c.json({ ok: true, restored });
17359
+ });
16729
17360
  app18.delete("/:slug", async (c) => {
16730
17361
  const slug = c.req.param("slug");
16731
17362
  if (slug === "admin") {
@@ -16750,7 +17381,7 @@ app18.delete("/:slug", async (c) => {
16750
17381
  return c.json({ error: "Not authorized for this account" }, 403);
16751
17382
  }
16752
17383
  const agentDir = resolve23(account.accountDir, "agents", slug);
16753
- if (!existsSync30(agentDir)) {
17384
+ if (!existsSync31(agentDir)) {
16754
17385
  return c.json({ error: "Agent not found" }, 404);
16755
17386
  }
16756
17387
  try {
@@ -16793,7 +17424,7 @@ app18.post("/:slug/project", async (c) => {
16793
17424
  return c.json({ error: "Not authorized for this account" }, 403);
16794
17425
  }
16795
17426
  const agentDir = resolve23(account.accountDir, "agents", slug);
16796
- if (!existsSync30(agentDir)) {
17427
+ if (!existsSync31(agentDir)) {
16797
17428
  return c.json({ error: "Agent not found on disk" }, 404);
16798
17429
  }
16799
17430
  try {
@@ -16809,7 +17440,7 @@ var agents_default = app18;
16809
17440
  // server/routes/admin/sessions.ts
16810
17441
  import crypto2 from "crypto";
16811
17442
  import { resolve as resolvePath } from "path";
16812
- import { existsSync as existsSync31, mkdirSync as mkdirSync7, createWriteStream } from "fs";
17443
+ import { existsSync as existsSync32, mkdirSync as mkdirSync8, createWriteStream } from "fs";
16813
17444
 
16814
17445
  // ../lib/admin-conversation-purge/src/index.ts
16815
17446
  async function purgeAdminConversationJsonls(args) {
@@ -16956,7 +17587,7 @@ var pickComponentBytes = (..._args) => null;
16956
17587
  function openResumeStreamLog(accountId, sessionId) {
16957
17588
  const dir = resolvePath(ACCOUNTS_DIR, accountId, "resume-logs");
16958
17589
  try {
16959
- mkdirSync7(dir, { recursive: true });
17590
+ mkdirSync8(dir, { recursive: true });
16960
17591
  } catch {
16961
17592
  }
16962
17593
  return createWriteStream(resolvePath(dir, `${sessionId}.log`), { flags: "a" });
@@ -16969,7 +17600,7 @@ function validateAndShapeAttachments(raws, conversationAccountId, sessionId, mes
16969
17600
  let reason = null;
16970
17601
  if (!a.attachmentId || !a.filename || !a.mimeType || !a.storagePath) reason = "schema-fail";
16971
17602
  else if (a.accountId !== conversationAccountId) reason = "account-mismatch";
16972
- else if (!existsSync31(a.storagePath)) reason = "missing-file";
17603
+ else if (!existsSync32(a.storagePath)) reason = "missing-file";
16973
17604
  if (reason) {
16974
17605
  invalid++;
16975
17606
  try {
@@ -17495,8 +18126,8 @@ app19.put("/:id/label", requireAdminSession, async (c) => {
17495
18126
  var sessions_default = app19;
17496
18127
 
17497
18128
  // 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";
18129
+ import { existsSync as existsSync33, readFileSync as readFileSync34, readdirSync as readdirSync23, statSync as statSync16 } from "fs";
18130
+ import { dirname as dirname12, resolve as resolve24, join as join34 } from "path";
17500
18131
  async function resolveOwnerProfileBlock(accountId, userId) {
17501
18132
  if (!userId) return { ok: false, reason: "missing-user-id" };
17502
18133
  try {
@@ -17537,14 +18168,14 @@ function frontmatterField(manifest, field2) {
17537
18168
  function extractPluginToolDescriptions(pluginDir) {
17538
18169
  const out = /* @__PURE__ */ new Map();
17539
18170
  const candidates = [
17540
- join33(pluginDir, "mcp/dist/index.js"),
17541
- join33(pluginDir, "mcp/src/index.ts")
18171
+ join34(pluginDir, "mcp/dist/index.js"),
18172
+ join34(pluginDir, "mcp/src/index.ts")
17542
18173
  ];
17543
18174
  let raw = null;
17544
18175
  for (const path3 of candidates) {
17545
- if (!existsSync32(path3)) continue;
18176
+ if (!existsSync33(path3)) continue;
17546
18177
  try {
17547
- raw = readFileSync33(path3, "utf-8");
18178
+ raw = readFileSync34(path3, "utf-8");
17548
18179
  break;
17549
18180
  } catch {
17550
18181
  }
@@ -17594,25 +18225,25 @@ function parseSkillPathsFromFrontmatter(fm) {
17594
18225
  function listPluginDirs(accountPluginsDir) {
17595
18226
  const out = /* @__PURE__ */ new Map();
17596
18227
  const platformPlugins = resolve24(PLATFORM_ROOT, "plugins");
17597
- if (existsSync32(platformPlugins)) {
17598
- for (const name of readdirSync22(platformPlugins)) {
17599
- const dir = join33(platformPlugins, name);
18228
+ if (existsSync33(platformPlugins)) {
18229
+ for (const name of readdirSync23(platformPlugins)) {
18230
+ const dir = join34(platformPlugins, name);
17600
18231
  try {
17601
- if (statSync15(dir).isDirectory()) out.set(name, dir);
18232
+ if (statSync16(dir).isDirectory()) out.set(name, dir);
17602
18233
  } catch {
17603
18234
  }
17604
18235
  }
17605
18236
  }
17606
18237
  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;
18238
+ if (existsSync33(premiumRoot)) {
18239
+ for (const bundle of readdirSync23(premiumRoot)) {
18240
+ const bundlePlugins = join34(premiumRoot, bundle, "plugins");
18241
+ if (!existsSync33(bundlePlugins)) continue;
17611
18242
  try {
17612
- for (const name of readdirSync22(bundlePlugins)) {
17613
- const dir = join33(bundlePlugins, name);
18243
+ for (const name of readdirSync23(bundlePlugins)) {
18244
+ const dir = join34(bundlePlugins, name);
17614
18245
  try {
17615
- if (statSync15(dir).isDirectory()) out.set(name, dir);
18246
+ if (statSync16(dir).isDirectory()) out.set(name, dir);
17616
18247
  } catch {
17617
18248
  }
17618
18249
  }
@@ -17620,13 +18251,13 @@ function listPluginDirs(accountPluginsDir) {
17620
18251
  }
17621
18252
  }
17622
18253
  }
17623
- if (accountPluginsDir && existsSync32(accountPluginsDir)) {
18254
+ if (accountPluginsDir && existsSync33(accountPluginsDir)) {
17624
18255
  try {
17625
- for (const name of readdirSync22(accountPluginsDir)) {
18256
+ for (const name of readdirSync23(accountPluginsDir)) {
17626
18257
  if (out.has(name)) continue;
17627
- const dir = join33(accountPluginsDir, name);
18258
+ const dir = join34(accountPluginsDir, name);
17628
18259
  try {
17629
- if (statSync15(dir).isDirectory()) out.set(name, dir);
18260
+ if (statSync16(dir).isDirectory()) out.set(name, dir);
17630
18261
  } catch {
17631
18262
  }
17632
18263
  }
@@ -17639,11 +18270,11 @@ function accountPluginsDirFor(accountId) {
17639
18270
  return resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "plugins");
17640
18271
  }
17641
18272
  function listAccountPluginNames(accountPluginsDir) {
17642
- if (!existsSync32(accountPluginsDir)) return [];
18273
+ if (!existsSync33(accountPluginsDir)) return [];
17643
18274
  try {
17644
- return readdirSync22(accountPluginsDir).filter((name) => {
18275
+ return readdirSync23(accountPluginsDir).filter((name) => {
17645
18276
  try {
17646
- return statSync15(join33(accountPluginsDir, name)).isDirectory();
18277
+ return statSync16(join34(accountPluginsDir, name)).isDirectory();
17647
18278
  } catch {
17648
18279
  return false;
17649
18280
  }
@@ -17654,9 +18285,9 @@ function listAccountPluginNames(accountPluginsDir) {
17654
18285
  }
17655
18286
  function readEnabledPlugins(accountId) {
17656
18287
  const accountFile = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17657
- if (!existsSync32(accountFile)) return /* @__PURE__ */ new Set();
18288
+ if (!existsSync33(accountFile)) return /* @__PURE__ */ new Set();
17658
18289
  try {
17659
- const parsed = JSON.parse(readFileSync33(accountFile, "utf-8"));
18290
+ const parsed = JSON.parse(readFileSync34(accountFile, "utf-8"));
17660
18291
  return new Set(
17661
18292
  Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
17662
18293
  );
@@ -17665,10 +18296,10 @@ function readEnabledPlugins(accountId) {
17665
18296
  }
17666
18297
  }
17667
18298
  function readFrontmatter(path3) {
17668
- if (!existsSync32(path3)) return null;
18299
+ if (!existsSync33(path3)) return null;
17669
18300
  let raw;
17670
18301
  try {
17671
- raw = readFileSync33(path3, "utf-8");
18302
+ raw = readFileSync34(path3, "utf-8");
17672
18303
  } catch {
17673
18304
  return null;
17674
18305
  }
@@ -17686,7 +18317,7 @@ function computeActivePlugins(accountId) {
17686
18317
  for (const name of emitNames) {
17687
18318
  const dir = pluginDirs.get(name);
17688
18319
  if (!dir) continue;
17689
- const fm = readFrontmatter(join33(dir, "PLUGIN.md"));
18320
+ const fm = readFrontmatter(join34(dir, "PLUGIN.md"));
17690
18321
  if (!fm) continue;
17691
18322
  const description = frontmatterField(`---
17692
18323
  ${fm}
@@ -17703,7 +18334,7 @@ ${fm}
17703
18334
  `plugin-manifest-tool-coverage plugin=${name} tools=${tools.length} with-desc=${withDesc}`
17704
18335
  );
17705
18336
  if (toolNames.length > 0 && descMap.size === 0) {
17706
- const hasSource = existsSync32(join33(dir, "mcp/dist/index.js")) || existsSync32(join33(dir, "mcp/src/index.ts"));
18337
+ const hasSource = existsSync33(join34(dir, "mcp/dist/index.js")) || existsSync33(join34(dir, "mcp/src/index.ts"));
17707
18338
  if (hasSource) {
17708
18339
  console.warn(
17709
18340
  `[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 +18344,7 @@ ${fm}
17713
18344
  const skillPaths = parseSkillPathsFromFrontmatter(fm);
17714
18345
  const skills = [];
17715
18346
  for (const relPath of skillPaths) {
17716
- const skillPath = join33(dir, relPath);
18347
+ const skillPath = join34(dir, relPath);
17717
18348
  const skillFm = readFrontmatter(skillPath);
17718
18349
  if (!skillFm) continue;
17719
18350
  const skillName = frontmatterField(`---
@@ -17730,10 +18361,10 @@ ${skillFm}
17730
18361
  }
17731
18362
  function computeSpecialistDomains(accountId) {
17732
18363
  const specialistsDir = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "specialists", "agents");
17733
- if (!existsSync32(specialistsDir)) return [];
18364
+ if (!existsSync33(specialistsDir)) return [];
17734
18365
  let entries2;
17735
18366
  try {
17736
- entries2 = readdirSync22(specialistsDir);
18367
+ entries2 = readdirSync23(specialistsDir);
17737
18368
  } catch {
17738
18369
  return [];
17739
18370
  }
@@ -17757,7 +18388,7 @@ function computeSpecialistDomains(accountId) {
17757
18388
  const out = [];
17758
18389
  for (const file of entries2.sort()) {
17759
18390
  if (!file.endsWith(".md")) continue;
17760
- const fm = readFrontmatter(join33(specialistsDir, file));
18391
+ const fm = readFrontmatter(join34(specialistsDir, file));
17761
18392
  if (!fm) continue;
17762
18393
  const wrapped = `---
17763
18394
  ${fm}
@@ -17776,10 +18407,10 @@ ${fm}
17776
18407
  }
17777
18408
  function computeDormantPlugins(accountId) {
17778
18409
  const accountFile = resolve24(PLATFORM_ROOT, "..", "data/accounts", accountId, "account.json");
17779
- if (!existsSync32(accountFile)) return [];
18410
+ if (!existsSync33(accountFile)) return [];
17780
18411
  let enabled;
17781
18412
  try {
17782
- const raw = readFileSync33(accountFile, "utf-8");
18413
+ const raw = readFileSync34(accountFile, "utf-8");
17783
18414
  const parsed = JSON.parse(raw);
17784
18415
  enabled = new Set(
17785
18416
  Array.isArray(parsed.enabledPlugins) ? parsed.enabledPlugins.filter((p) => typeof p === "string") : []
@@ -17791,10 +18422,10 @@ function computeDormantPlugins(accountId) {
17791
18422
  return [];
17792
18423
  }
17793
18424
  const pluginsDir = resolve24(PLATFORM_ROOT, "plugins");
17794
- if (!existsSync32(pluginsDir)) return [];
18425
+ if (!existsSync33(pluginsDir)) return [];
17795
18426
  let entries2;
17796
18427
  try {
17797
- entries2 = readdirSync22(pluginsDir);
18428
+ entries2 = readdirSync23(pluginsDir);
17798
18429
  } catch {
17799
18430
  return [];
17800
18431
  }
@@ -17802,10 +18433,10 @@ function computeDormantPlugins(accountId) {
17802
18433
  for (const name of entries2) {
17803
18434
  if (enabled.has(name)) continue;
17804
18435
  const manifestPath = resolve24(pluginsDir, name, "PLUGIN.md");
17805
- if (!existsSync32(manifestPath)) continue;
18436
+ if (!existsSync33(manifestPath)) continue;
17806
18437
  let manifest;
17807
18438
  try {
17808
- manifest = readFileSync33(manifestPath, "utf-8");
18439
+ manifest = readFileSync34(manifestPath, "utf-8");
17809
18440
  } catch {
17810
18441
  continue;
17811
18442
  }
@@ -17819,13 +18450,13 @@ function computeDormantPlugins(accountId) {
17819
18450
  }
17820
18451
 
17821
18452
  // server/routes/admin/claude-sessions.ts
17822
- import { existsSync as existsSync33, readFileSync as readFileSync34 } from "fs";
18453
+ import { existsSync as existsSync34, readFileSync as readFileSync35 } from "fs";
17823
18454
  import { resolve as resolve25 } from "path";
17824
18455
  function readTunnelState(brandConfigDir) {
17825
18456
  const statePath = `${process.env.HOME ?? ""}/${brandConfigDir}/cloudflared/tunnel.state`;
17826
- if (!existsSync33(statePath)) return null;
18457
+ if (!existsSync34(statePath)) return null;
17827
18458
  try {
17828
- const parsed = JSON.parse(readFileSync34(statePath, "utf-8"));
18459
+ const parsed = JSON.parse(readFileSync35(statePath, "utf-8"));
17829
18460
  const tunnelId = typeof parsed.tunnelId === "string" ? parsed.tunnelId : null;
17830
18461
  const tunnelName = typeof parsed.tunnelName === "string" ? parsed.tunnelName : null;
17831
18462
  const domain = typeof parsed.domain === "string" ? parsed.domain : null;
@@ -17839,7 +18470,7 @@ function resolveTunnelUrl() {
17839
18470
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT ?? process.env.PLATFORM_ROOT ?? resolve25(process.cwd(), "..");
17840
18471
  let brand;
17841
18472
  try {
17842
- brand = JSON.parse(readFileSync34(resolve25(platformRoot5, "config", "brand.json"), "utf-8"));
18473
+ brand = JSON.parse(readFileSync35(resolve25(platformRoot5, "config", "brand.json"), "utf-8"));
17843
18474
  } catch {
17844
18475
  return null;
17845
18476
  }
@@ -18152,11 +18783,11 @@ app22.get("/", requireAdminSession, async (c) => {
18152
18783
  var events_default = app22;
18153
18784
 
18154
18785
  // server/routes/admin/files.ts
18155
- import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync34 } from "fs";
18786
+ import { createReadStream as createReadStream2, createWriteStream as createWriteStream2, existsSync as existsSync35 } from "fs";
18156
18787
  import { readdir as readdir4, readFile as readFile7, stat as stat6, mkdir as mkdir4, unlink as unlink3, rename as rename2, rmdir } from "fs/promises";
18157
18788
  import { realpathSync as realpathSync7 } from "fs";
18158
18789
  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";
18790
+ import { basename as basename11, dirname as dirname13, join as join36, relative as relative5, resolve as resolve27, sep as sep8 } from "path";
18160
18791
  import { Readable as Readable2 } from "stream";
18161
18792
 
18162
18793
  // ../lib/graph-trash/src/index.ts
@@ -18474,7 +19105,7 @@ async function cascadeDeleteDocument(params) {
18474
19105
 
18475
19106
  // app/lib/file-index.ts
18476
19107
  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";
19108
+ import { resolve as resolve26, relative as relative4, join as join35, basename as basename10, extname as extname2, sep as sep7 } from "path";
18478
19109
  import { tmpdir as tmpdir2 } from "os";
18479
19110
  import { execFile as execFile2 } from "child_process";
18480
19111
  import { promisify as promisify2 } from "util";
@@ -18556,7 +19187,7 @@ async function extractPdf(absolute) {
18556
19187
  return stdout.trim();
18557
19188
  }
18558
19189
  async function ocrPdf(absolute) {
18559
- const outPdf = join34(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
19190
+ const outPdf = join35(tmpdir2(), `file-index-ocr-${process.pid}-${Date.now()}.pdf`);
18560
19191
  try {
18561
19192
  await execFileAsync2(
18562
19193
  "ocrmypdf",
@@ -18618,7 +19249,7 @@ async function readDisplayName(absolute) {
18618
19249
  const stem = dot === -1 ? base : base.slice(0, dot);
18619
19250
  if (base === `${stem}.meta.json`) return null;
18620
19251
  try {
18621
- const raw = await fsp.readFile(join34(dir, `${stem}.meta.json`), "utf-8");
19252
+ const raw = await fsp.readFile(join35(dir, `${stem}.meta.json`), "utf-8");
18622
19253
  const meta = JSON.parse(raw);
18623
19254
  const dn = meta.displayName ?? meta.filename;
18624
19255
  return typeof dn === "string" && dn.length > 0 ? dn : null;
@@ -18639,7 +19270,7 @@ async function walkSubtree(root, dataRoot, out) {
18639
19270
  for (const entry of entries2) {
18640
19271
  if (entry.isSymbolicLink()) continue;
18641
19272
  if (entry.isDirectory() && entry.name === ".uploads-tmp") continue;
18642
- const abs = join34(root, entry.name);
19273
+ const abs = join35(root, entry.name);
18643
19274
  if (entry.isDirectory()) {
18644
19275
  const sub = await walkSubtree(abs, dataRoot, out);
18645
19276
  if (!sub.clean) clean = false;
@@ -19012,7 +19643,7 @@ var UPLOAD_TMP_DIR = ".uploads-tmp";
19012
19643
  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
19644
  async function readMeta(absDir, baseName) {
19014
19645
  try {
19015
- const raw = await readFile7(join35(absDir, `${baseName}.meta.json`), "utf8");
19646
+ const raw = await readFile7(join36(absDir, `${baseName}.meta.json`), "utf8");
19016
19647
  const parsed = JSON.parse(raw);
19017
19648
  if (typeof parsed?.filename === "string") {
19018
19649
  return { filename: parsed.filename, mimeType: typeof parsed.mimeType === "string" ? parsed.mimeType : void 0 };
@@ -19067,7 +19698,7 @@ async function servableFilesIn(dirAbs, uuid) {
19067
19698
  }
19068
19699
  async function enrich(absolute, entry, accountNames) {
19069
19700
  if (entry.kind === "directory" && UUID_RE4.test(entry.name)) {
19070
- const dirAbs = join35(absolute, entry.name);
19701
+ const dirAbs = join36(absolute, entry.name);
19071
19702
  const meta = await readMeta(dirAbs, entry.name);
19072
19703
  if (meta?.filename) {
19073
19704
  const servable = await servableFilesIn(dirAbs, entry.name);
@@ -19076,7 +19707,7 @@ async function enrich(absolute, entry, accountNames) {
19076
19707
  let size = null;
19077
19708
  let modifiedAt = entry.modifiedAt;
19078
19709
  try {
19079
- const st = await stat6(join35(dirAbs, innerName));
19710
+ const st = await stat6(join36(dirAbs, innerName));
19080
19711
  size = st.size;
19081
19712
  modifiedAt = st.mtime.toISOString();
19082
19713
  } catch {
@@ -19269,7 +19900,7 @@ app23.get("/", requireAdminSession, async (c) => {
19269
19900
  const childRel = relPath === "" || relPath === "." ? name : `${relPath}/${name}`;
19270
19901
  const protectedEntry = isProtectedFromDeletion(childRel).protected;
19271
19902
  try {
19272
- const entryPath = join35(absolute, name);
19903
+ const entryPath = join36(absolute, name);
19273
19904
  const s = await stat6(entryPath);
19274
19905
  entries2.push({
19275
19906
  name,
@@ -19298,7 +19929,7 @@ app23.get("/", requireAdminSession, async (c) => {
19298
19929
  const displayPath = buildDisplayPath(relPath, accountNames);
19299
19930
  if (groupReq || isAccountRoot(relPath)) {
19300
19931
  const acctId = relPath.split("/")[1] ?? accountId;
19301
- const schemaMd = await readFile7(join35(absolute, "SCHEMA.md"), "utf8").catch(() => null);
19932
+ const schemaMd = await readFile7(join36(absolute, "SCHEMA.md"), "utf8").catch(() => null);
19302
19933
  const groups = classifyAccountRoot(schemaMd, entries2.map((e) => e.name));
19303
19934
  console.error(
19304
19935
  `[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 +19967,7 @@ app23.get("/", requireAdminSession, async (c) => {
19336
19967
  for (const name of homeDirs) {
19337
19968
  const base = byName.get(name);
19338
19969
  try {
19339
- const dirents = await readdir4(join35(absolute, name), { withFileTypes: true });
19970
+ const dirents = await readdir4(join36(absolute, name), { withFileTypes: true });
19340
19971
  const visible = dirents.filter((d) => !d.name.startsWith("."));
19341
19972
  visible.sort((a, b) => {
19342
19973
  const ad = a.isDirectory() ? 0 : 1;
@@ -19401,7 +20032,7 @@ app23.get("/download", requireAdminSession, async (c) => {
19401
20032
  console.error(`[data] op=scratchpad-no-session sessionId="${sessionId.slice(0, 8)}\u2026"`);
19402
20033
  return c.json({ error: "Not found" }, 404);
19403
20034
  }
19404
- const meta = readSidecarMeta(join35(projectDir, `${sessionId}.meta.json`));
20035
+ const meta = readSidecarMeta(join36(projectDir, `${sessionId}.meta.json`));
19405
20036
  if (!meta.accountId || meta.accountId !== accountId) {
19406
20037
  console.error(`[data] account-scope-blocked root="scratchpad" sessionId="${sessionId.slice(0, 8)}\u2026" account=${accountId.slice(0, 8)}\u2026`);
19407
20038
  return c.json({ error: "Not found" }, 404);
@@ -19496,7 +20127,7 @@ async function* walkRegularFiles(dirAbsolute) {
19496
20127
  const dirents = await readdir4(dirAbsolute, { withFileTypes: true });
19497
20128
  for (const d of dirents) {
19498
20129
  if (d.isSymbolicLink()) continue;
19499
- const child = join35(dirAbsolute, d.name);
20130
+ const child = join36(dirAbsolute, d.name);
19500
20131
  if (d.isDirectory()) {
19501
20132
  yield* walkRegularFiles(child);
19502
20133
  continue;
@@ -19606,7 +20237,7 @@ async function resolveUploadTarget(c, accountId, uid) {
19606
20237
  const base = resolveOwnAccountWrite(rawDir, accountId, "POST /api/admin/files/upload");
19607
20238
  if (!base.ok) return { ok: false, status: base.status, error: base.error };
19608
20239
  const relDir = relpath ? dirname13(relpath) : ".";
19609
- const destRel = relDir === "." ? base.relative : join35(base.relative, relDir);
20240
+ const destRel = relDir === "." ? base.relative : join36(base.relative, relDir);
19610
20241
  if (crossesForeignAccountPartition(destRel, accountId)) {
19611
20242
  console.error(`[data] account-scope-blocked endpoint="POST /api/admin/files/upload" path="${destRel}" account=${accountId.slice(0, 8)}\u2026`);
19612
20243
  return { ok: false, status: 404, error: "Not found" };
@@ -19680,7 +20311,7 @@ app23.post("/upload", requireAdminSession, async (c) => {
19680
20311
  });
19681
20312
  await unlink3(tmpPath).catch(() => {
19682
20313
  });
19683
- const tempRemoved = !existsSync34(tmpPath);
20314
+ const tempRemoved = !existsSync35(tmpPath);
19684
20315
  console.error(`[data-upload] op=cleanup uid=${uid} tempRemoved=${tempRemoved}`);
19685
20316
  };
19686
20317
  const reader = body.getReader();
@@ -19754,7 +20385,7 @@ async function discardChunkUpload(uploadId, state) {
19754
20385
  });
19755
20386
  await unlink3(state.tmpPath).catch(() => {
19756
20387
  });
19757
- const tempRemoved = !existsSync34(state.tmpPath);
20388
+ const tempRemoved = !existsSync35(state.tmpPath);
19758
20389
  console.error(`[data-upload] op=cleanup uid=${uploadId} tempRemoved=${tempRemoved}`);
19759
20390
  }
19760
20391
  async function writeChunkBody(body, out, alreadyReceived, ceiling) {
@@ -19983,7 +20614,7 @@ app23.delete("/", requireAdminSession, async (c) => {
19983
20614
  const dot = base.lastIndexOf(".");
19984
20615
  const stem = dot === -1 ? base : base.slice(0, dot);
19985
20616
  const containerDir = dirname13(absolute);
19986
- const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join35(containerDir, `${stem}.meta.json`) : null;
20617
+ const sidecarPath = UUID_RE4.test(stem) && base !== `${stem}.meta.json` ? join36(containerDir, `${stem}.meta.json`) : null;
19987
20618
  const isAttachmentContainer = UUID_RE4.test(stem) && basename11(containerDir) === stem;
19988
20619
  await unlink3(absolute);
19989
20620
  if (sidecarPath) {
@@ -19993,7 +20624,7 @@ app23.delete("/", requireAdminSession, async (c) => {
19993
20624
  }
19994
20625
  }
19995
20626
  if (isAttachmentContainer) {
19996
- await unlink3(join35(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
20627
+ await unlink3(join36(containerDir, `${stem}${EXTRACTED_TEXT_SUFFIX}`)).catch(() => {
19997
20628
  });
19998
20629
  await rmdir(containerDir).catch(() => {
19999
20630
  });
@@ -20172,7 +20803,7 @@ function applyBacklinkBoost(hits) {
20172
20803
  }
20173
20804
 
20174
20805
  // ../lib/graph-search/src/dedup.ts
20175
- import { createHash as createHash5 } from "crypto";
20806
+ import { createHash as createHash6 } from "crypto";
20176
20807
  var DEFAULT_LAYERS = [
20177
20808
  "nodeId",
20178
20809
  "slug",
@@ -20199,7 +20830,7 @@ function readContentHash(props) {
20199
20830
  const content = props["content"];
20200
20831
  const source = typeof compiled === "string" && compiled.length > 0 ? compiled : typeof content === "string" && content.length > 0 ? content : null;
20201
20832
  if (source === null) return null;
20202
- return createHash5("sha256").update(source).digest("hex").slice(0, 16);
20833
+ return createHash6("sha256").update(source).digest("hex").slice(0, 16);
20203
20834
  }
20204
20835
  function dedup(hits, layers = DEFAULT_LAYERS) {
20205
20836
  const sorted = [...hits].sort((a, b) => b.score - a.score);
@@ -21102,8 +21733,8 @@ function isHiddenByDefault(label) {
21102
21733
 
21103
21734
  // server/lib/top-level-labels.ts
21104
21735
  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";
21736
+ import { readdirSync as readdirSync24, readFileSync as readFileSync36 } from "fs";
21737
+ import { join as join37, resolve as resolve28 } from "path";
21107
21738
  var STATIC_TOP_LEVEL_LABELS = Object.freeze(
21108
21739
  /* @__PURE__ */ new Set([
21109
21740
  // Base-schema infra (schema-base.md has no top-level section).
@@ -21207,7 +21838,7 @@ function parseTopLevelLabels(content) {
21207
21838
  }
21208
21839
  function resolveReferencesDir() {
21209
21840
  if (process.env.MAXY_PLATFORM_ROOT) {
21210
- return join36(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
21841
+ return join37(process.env.MAXY_PLATFORM_ROOT, "plugins", "memory", "references");
21211
21842
  }
21212
21843
  return resolve28(import.meta.dirname, "../../../plugins/memory/references");
21213
21844
  }
@@ -21215,9 +21846,9 @@ function parseTableTopLevelLabels(referencesDir) {
21215
21846
  const labels = /* @__PURE__ */ new Set();
21216
21847
  const contributingFiles = [];
21217
21848
  try {
21218
- const fileNames = readdirSync23(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
21849
+ const fileNames = readdirSync24(referencesDir).filter((f) => f.startsWith("schema-") && f.endsWith(".md")).sort();
21219
21850
  for (const fileName of fileNames) {
21220
- const content = readFileSync35(join36(referencesDir, fileName), "utf-8");
21851
+ const content = readFileSync36(join37(referencesDir, fileName), "utf-8");
21221
21852
  const parsed = parseTopLevelLabels(content);
21222
21853
  if (parsed.length > 0) contributingFiles.push(fileName);
21223
21854
  for (const label of parsed) labels.add(label);
@@ -22375,7 +23006,7 @@ var graph_default_view_default = app29;
22375
23006
  // server/routes/admin/sidebar-artefacts.ts
22376
23007
  import { readdir as readdir5, stat as stat7 } from "fs/promises";
22377
23008
  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";
23009
+ import { existsSync as existsSync36 } from "fs";
22379
23010
  var LIMIT = 50;
22380
23011
  var ADMIN_AGENT_FILES = ["IDENTITY.md", "SOUL.md", "KNOWLEDGE.md"];
22381
23012
  function toDataRootRelPath(absPath) {
@@ -22487,7 +23118,7 @@ async function fetchAgentTemplateRows(accountDir) {
22487
23118
  async function unionSpecialistFilenames(overrideDir, bundledDir) {
22488
23119
  const names = /* @__PURE__ */ new Set();
22489
23120
  for (const dir of [overrideDir, bundledDir]) {
22490
- if (!existsSync35(dir)) continue;
23121
+ if (!existsSync36(dir)) continue;
22491
23122
  try {
22492
23123
  const entries2 = await readdir5(dir);
22493
23124
  for (const entry of entries2) {
@@ -22502,7 +23133,7 @@ async function unionSpecialistFilenames(overrideDir, bundledDir) {
22502
23133
  }
22503
23134
  async function readAgentTemplateRow(inp) {
22504
23135
  let chosenPath = null;
22505
- if (existsSync35(inp.overridePath)) {
23136
+ if (existsSync36(inp.overridePath)) {
22506
23137
  try {
22507
23138
  validateFilePathInAccount(inp.overridePath, inp.overrideRoot);
22508
23139
  chosenPath = inp.overridePath;
@@ -22513,7 +23144,7 @@ async function readAgentTemplateRow(inp) {
22513
23144
  );
22514
23145
  return null;
22515
23146
  }
22516
- } else if (existsSync35(inp.bundledPath)) {
23147
+ } else if (existsSync36(inp.bundledPath)) {
22517
23148
  if (!isWithin(inp.bundledPath, inp.bundledRoot)) {
22518
23149
  console.error(
22519
23150
  `[admin/sidebar-artefacts] agent-template-read-failed agent=${inp.displayName} kind=${inp.logName} error="bundled path outside PLATFORM_ROOT"`
@@ -22555,19 +23186,19 @@ function isWithin(target, root) {
22555
23186
  var sidebar_artefacts_default = app30;
22556
23187
 
22557
23188
  // 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";
23189
+ import { readFileSync as readFileSync37, writeFileSync as writeFileSync14, renameSync as renameSync10 } from "fs";
23190
+ import { join as join38 } from "path";
22560
23191
  var FILE2 = "channel-session-override.json";
22561
23192
  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
23193
  function channelOverridePath(accountDir) {
22563
- return join37(accountDir, FILE2);
23194
+ return join38(accountDir, FILE2);
22564
23195
  }
22565
23196
  function senderKey(channel, senderId) {
22566
23197
  return `${channel}:${senderId}`;
22567
23198
  }
22568
23199
  function readRaw2(accountDir) {
22569
23200
  try {
22570
- return JSON.parse(readFileSync36(channelOverridePath(accountDir), "utf8"));
23201
+ return JSON.parse(readFileSync37(channelOverridePath(accountDir), "utf8"));
22571
23202
  } catch {
22572
23203
  return null;
22573
23204
  }
@@ -22589,8 +23220,8 @@ function writeChannelOverrideId(accountDir, channel, senderId, sessionId) {
22589
23220
  bySender[senderKey(channel, senderId)] = sessionId;
22590
23221
  const path3 = channelOverridePath(accountDir);
22591
23222
  const tmp = `${path3}.${process.pid}.tmp`;
22592
- writeFileSync13(tmp, JSON.stringify({ bySender }, null, 2), "utf8");
22593
- renameSync9(tmp, path3);
23223
+ writeFileSync14(tmp, JSON.stringify({ bySender }, null, 2), "utf8");
23224
+ renameSync10(tmp, path3);
22594
23225
  }
22595
23226
  function clearChannelOverrideForSession(accountDir, sessionId) {
22596
23227
  const raw = readRaw2(accountDir);
@@ -22605,8 +23236,8 @@ function clearChannelOverrideForSession(accountDir, sessionId) {
22605
23236
  if (cleared.length === 0) return [];
22606
23237
  const path3 = channelOverridePath(accountDir);
22607
23238
  const tmp = `${path3}.${process.pid}.tmp`;
22608
- writeFileSync13(tmp, JSON.stringify({ bySender: kept }, null, 2), "utf8");
22609
- renameSync9(tmp, path3);
23239
+ writeFileSync14(tmp, JSON.stringify({ bySender: kept }, null, 2), "utf8");
23240
+ renameSync10(tmp, path3);
22610
23241
  return cleared;
22611
23242
  }
22612
23243
 
@@ -22956,24 +23587,24 @@ var session_rc_spawn_default = app36;
22956
23587
  import { randomUUID as randomUUID12 } from "crypto";
22957
23588
 
22958
23589
  // server/wa-descriptor.ts
22959
- import { resolve as resolve30, join as join38 } from "path";
23590
+ import { resolve as resolve30, join as join39 } from "path";
22960
23591
  function waGatewayUrl() {
22961
23592
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
22962
23593
  }
22963
23594
  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");
23595
+ return process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve30(process.env.MAXY_PLATFORM_ROOT ?? join39(__dirname, ".."), "services/whatsapp-channel/dist/server.js");
22965
23596
  }
22966
23597
  function waChannelDescriptor(senderId) {
22967
23598
  return { senderId, gatewayUrl: waGatewayUrl(), serverPath: waServerPath() };
22968
23599
  }
22969
23600
 
22970
23601
  // server/telegram-descriptor.ts
22971
- import { resolve as resolve31, join as join39 } from "path";
23602
+ import { resolve as resolve31, join as join40 } from "path";
22972
23603
  function telegramGatewayUrl() {
22973
23604
  return `http://127.0.0.1:${process.env.MAXY_UI_INTERNAL_PORT ?? ""}`;
22974
23605
  }
22975
23606
  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");
23607
+ return process.env.MAXY_TELEGRAM_CHANNEL_SERVER_PATH ?? resolve31(process.env.MAXY_PLATFORM_ROOT ?? join40(__dirname, ".."), "services/telegram-channel/dist/server.js");
22977
23608
  }
22978
23609
  function telegramChannelDescriptor(senderId) {
22979
23610
  return { senderId, gatewayUrl: telegramGatewayUrl(), serverPath: telegramServerPath() };
@@ -23257,14 +23888,14 @@ app38.get("/", async (c) => {
23257
23888
  var system_stats_default = app38;
23258
23889
 
23259
23890
  // 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";
23891
+ import { existsSync as existsSync37, readFileSync as readFileSync38 } from "fs";
23892
+ import { resolve as resolve32, join as join41 } from "path";
23262
23893
  var PLATFORM_ROOT6 = process.env.MAXY_PLATFORM_ROOT ?? resolve32(process.cwd(), "..");
23263
23894
  var brandHostname = "maxy";
23264
- var brandJsonPath = join40(PLATFORM_ROOT6, "config", "brand.json");
23265
- if (existsSync36(brandJsonPath)) {
23895
+ var brandJsonPath = join41(PLATFORM_ROOT6, "config", "brand.json");
23896
+ if (existsSync37(brandJsonPath)) {
23266
23897
  try {
23267
- const brand = JSON.parse(readFileSync37(brandJsonPath, "utf-8"));
23898
+ const brand = JSON.parse(readFileSync38(brandJsonPath, "utf-8"));
23268
23899
  if (brand.hostname) brandHostname = brand.hostname;
23269
23900
  } catch {
23270
23901
  }
@@ -23273,8 +23904,8 @@ var VERSION_FILE = resolve32(PLATFORM_ROOT6, `config/.${brandHostname}-version`)
23273
23904
  var PROCESS_STARTED_AT = (/* @__PURE__ */ new Date()).toISOString();
23274
23905
  var PROBE_TIMEOUT_MS = 1e3;
23275
23906
  function readVersion() {
23276
- if (!existsSync36(VERSION_FILE)) return "unknown";
23277
- return readFileSync37(VERSION_FILE, "utf-8").trim() || "unknown";
23907
+ if (!existsSync37(VERSION_FILE)) return "unknown";
23908
+ return readFileSync38(VERSION_FILE, "utf-8").trim() || "unknown";
23278
23909
  }
23279
23910
  async function probeConversationDb() {
23280
23911
  let session;
@@ -24050,8 +24681,8 @@ app46.post("/launch", requireAdminSession, async (c) => {
24050
24681
  var browser_default = app46;
24051
24682
 
24052
24683
  // server/routes/admin/calendar.ts
24053
- import { existsSync as existsSync37 } from "fs";
24054
- import { join as join42 } from "path";
24684
+ import { existsSync as existsSync38 } from "fs";
24685
+ import { join as join43 } from "path";
24055
24686
 
24056
24687
  // server/lib/calendar-ics.ts
24057
24688
  var CRLF = "\r\n";
@@ -24150,8 +24781,8 @@ function countVEvents(ics) {
24150
24781
  }
24151
24782
 
24152
24783
  // server/lib/calendar-availability.ts
24153
- import { readFileSync as readFileSync38 } from "fs";
24154
- import { join as join41 } from "path";
24784
+ import { readFileSync as readFileSync39 } from "fs";
24785
+ import { join as join42 } from "path";
24155
24786
  var AVAILABILITY_FILENAME = "calendar-availability.json";
24156
24787
  var REQUIRED_KEYS = [
24157
24788
  "timezone",
@@ -24160,10 +24791,10 @@ var REQUIRED_KEYS = [
24160
24791
  "weekly"
24161
24792
  ];
24162
24793
  function readAvailabilityConfig(accountDir) {
24163
- const path3 = join41(accountDir, AVAILABILITY_FILENAME);
24794
+ const path3 = join42(accountDir, AVAILABILITY_FILENAME);
24164
24795
  let raw;
24165
24796
  try {
24166
- raw = readFileSync38(path3, "utf-8");
24797
+ raw = readFileSync39(path3, "utf-8");
24167
24798
  } catch {
24168
24799
  throw new Error(`availability not configured: ${path3} not found`);
24169
24800
  }
@@ -24522,7 +25153,7 @@ app47.get("/booking-link", requireAdminSession, (c) => {
24522
25153
  console.error('[calendar] op=booking-link-fail err="no account configured"');
24523
25154
  return c.json({ bookingDomain: null });
24524
25155
  }
24525
- if (!existsSync37(join42(account.accountDir, AVAILABILITY_FILENAME))) {
25156
+ if (!existsSync38(join43(account.accountDir, AVAILABILITY_FILENAME))) {
24526
25157
  console.log("[calendar] op=booking-link bookingDomain=none source=availability-config");
24527
25158
  return c.json({ bookingDomain: null });
24528
25159
  }
@@ -24724,7 +25355,7 @@ app48.delete("/:eventId", requireAdminSession, async (c) => {
24724
25355
  var routines_default = app48;
24725
25356
 
24726
25357
  // server/routes/admin/skills.ts
24727
- import { existsSync as existsSync38, readdirSync as readdirSync24, readFileSync as readFileSync39, rmSync as rmSync3 } from "fs";
25358
+ import { existsSync as existsSync39, readdirSync as readdirSync25, readFileSync as readFileSync40, rmSync as rmSync3 } from "fs";
24728
25359
  import { resolve as resolve33 } from "path";
24729
25360
  var app49 = new Hono();
24730
25361
  var NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
@@ -24748,9 +25379,9 @@ function stripQuotes(s) {
24748
25379
  return s;
24749
25380
  }
24750
25381
  function subdirs2(dir) {
24751
- if (!existsSync38(dir)) return [];
25382
+ if (!existsSync39(dir)) return [];
24752
25383
  try {
24753
- return readdirSync24(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
25384
+ return readdirSync25(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name);
24754
25385
  } catch {
24755
25386
  return [];
24756
25387
  }
@@ -24771,11 +25402,11 @@ app49.get("/", requireAdminSession, async (c) => {
24771
25402
  const skillsDir = resolve33(pluginsDir, plugin, "skills");
24772
25403
  for (const skill of subdirs2(skillsDir)) {
24773
25404
  const skillMd = resolve33(skillsDir, skill, "SKILL.md");
24774
- if (!existsSync38(skillMd)) continue;
25405
+ if (!existsSync39(skillMd)) continue;
24775
25406
  try {
24776
- const { frontmatter } = splitSkillMd(readFileSync39(skillMd, "utf-8"));
25407
+ const { frontmatter } = splitSkillMd(readFileSync40(skillMd, "utf-8"));
24777
25408
  const refsDir = resolve33(skillsDir, skill, "references");
24778
- const refCount = existsSync38(refsDir) ? readdirSync24(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).length : 0;
25409
+ const refCount = existsSync39(refsDir) ? readdirSync25(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).length : 0;
24779
25410
  skills.push({ plugin, skill, description: frontmatter.description, refCount });
24780
25411
  } catch (err) {
24781
25412
  console.error(`[admin:skills] op=list-skip plugin=${plugin} skill=${skill} reason="${err instanceof Error ? err.message : String(err)}"`);
@@ -24799,13 +25430,13 @@ app49.get("/:plugin/:skill", requireAdminSession, async (c) => {
24799
25430
  }
24800
25431
  const skillDir = resolve33(acct.accountDir, "plugins", plugin, "skills", skill);
24801
25432
  const skillMd = resolve33(skillDir, "SKILL.md");
24802
- const found = existsSync38(skillMd);
25433
+ const found = existsSync39(skillMd);
24803
25434
  console.log(`[admin:skills] op=get plugin=${plugin} skill=${skill} found=${found}`);
24804
25435
  if (!found) return c.json({ error: "Skill not found" }, 404);
24805
25436
  try {
24806
- const { frontmatter, body } = splitSkillMd(readFileSync39(skillMd, "utf-8"));
25437
+ const { frontmatter, body } = splitSkillMd(readFileSync40(skillMd, "utf-8"));
24807
25438
  const refsDir = resolve33(skillDir, "references");
24808
- const references = existsSync38(refsDir) ? readdirSync24(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).sort() : [];
25439
+ const references = existsSync39(refsDir) ? readdirSync25(refsDir, { withFileTypes: true }).filter((e) => e.isFile()).map((e) => e.name).sort() : [];
24809
25440
  return c.json({ skill: { plugin, skill, frontmatter, body, references } });
24810
25441
  } catch (err) {
24811
25442
  const message = err instanceof Error ? err.message : String(err);
@@ -24825,7 +25456,7 @@ app49.delete("/:plugin/:skill", requireAdminSession, async (c) => {
24825
25456
  const pluginDir = resolve33(acct.accountDir, "plugins", plugin);
24826
25457
  const skillsDir = resolve33(pluginDir, "skills");
24827
25458
  const skillDir = resolve33(skillsDir, skill);
24828
- if (!existsSync38(resolve33(skillDir, "SKILL.md"))) {
25459
+ if (!existsSync39(resolve33(skillDir, "SKILL.md"))) {
24829
25460
  console.error(`[admin:skills] op=delete outcome=rejected reason=not-found plugin=${plugin} skill=${skill}`);
24830
25461
  return c.json({ error: "Skill not found" }, 404);
24831
25462
  }
@@ -24833,7 +25464,7 @@ app49.delete("/:plugin/:skill", requireAdminSession, async (c) => {
24833
25464
  rmSync3(skillDir, { recursive: true, force: true });
24834
25465
  const pluginDirRemoved = subdirs2(skillsDir).length === 0;
24835
25466
  if (pluginDirRemoved) rmSync3(pluginDir, { recursive: true, force: true });
24836
- const skillDirGone = !existsSync38(skillDir);
25467
+ const skillDirGone = !existsSync39(skillDir);
24837
25468
  if (!skillDirGone) {
24838
25469
  console.error(`[admin:skills] op=delete plugin=${plugin} skill=${skill} outcome=rejected reason=rm-incomplete skillDirGone=false`);
24839
25470
  return c.json({ error: "Delete did not remove the skill directory" }, 503);
@@ -25243,20 +25874,20 @@ app54.post("/", requireAdminSession, async (c) => {
25243
25874
  var task_time_adjust_default = app54;
25244
25875
 
25245
25876
  // app/lib/admin-roster.ts
25246
- import { existsSync as existsSync39, readdirSync as readdirSync25, readFileSync as readFileSync40 } from "fs";
25877
+ import { existsSync as existsSync40, readdirSync as readdirSync26, readFileSync as readFileSync41 } from "fs";
25247
25878
  import { resolve as resolve34 } from "path";
25248
25879
  function readHouseAdminUserIds(accountsDir = ACCOUNTS_DIR) {
25249
25880
  let entries2;
25250
25881
  try {
25251
- entries2 = readdirSync25(accountsDir);
25882
+ entries2 = readdirSync26(accountsDir);
25252
25883
  } catch {
25253
25884
  return [];
25254
25885
  }
25255
25886
  for (const entry of entries2) {
25256
25887
  const cfgPath = resolve34(accountsDir, entry, "account.json");
25257
- if (!existsSync39(cfgPath)) continue;
25888
+ if (!existsSync40(cfgPath)) continue;
25258
25889
  try {
25259
- const cfg = JSON.parse(readFileSync40(cfgPath, "utf-8"));
25890
+ const cfg = JSON.parse(readFileSync41(cfgPath, "utf-8"));
25260
25891
  if (cfg.role !== "house") continue;
25261
25892
  if (!Array.isArray(cfg.admins)) return [];
25262
25893
  return cfg.admins.map(
@@ -25435,7 +26066,7 @@ app56.get("/", requireAdminSession, async (c) => {
25435
26066
  var admin_users_list_default = app56;
25436
26067
 
25437
26068
  // server/routes/admin/activity.ts
25438
- import { readdirSync as readdirSync26 } from "fs";
26069
+ import { readdirSync as readdirSync27 } from "fs";
25439
26070
  var app57 = new Hono();
25440
26071
  var TAG47 = "[activity]";
25441
26072
  function resolveHouseAccountId(accounts) {
@@ -25451,7 +26082,7 @@ function requestToken() {
25451
26082
  var short = (id) => id ? id.slice(0, 8) : "unset";
25452
26083
  function countAccountDirsOnDisk() {
25453
26084
  try {
25454
- return readdirSync26(ACCOUNTS_DIR, { withFileTypes: true }).filter(
26085
+ return readdirSync27(ACCOUNTS_DIR, { withFileTypes: true }).filter(
25455
26086
  (e) => e.isDirectory() && !e.name.startsWith(".")
25456
26087
  ).length;
25457
26088
  } catch {
@@ -25855,7 +26486,7 @@ app61.route("/request-magic-link", request_magic_link_default);
25855
26486
  var access_default = app61;
25856
26487
 
25857
26488
  // server/routes/sites.ts
25858
- import { existsSync as existsSync40, readFileSync as readFileSync41, realpathSync as realpathSync8, statSync as statSync17 } from "fs";
26489
+ import { existsSync as existsSync41, readFileSync as readFileSync42, realpathSync as realpathSync8, statSync as statSync18 } from "fs";
25859
26490
  import { resolve as resolve36 } from "path";
25860
26491
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
25861
26492
  var MIME = {
@@ -25921,7 +26552,7 @@ app62.get("/:rel{.*}", (c) => {
25921
26552
  }
25922
26553
  let stat11;
25923
26554
  try {
25924
- stat11 = existsSync40(filePath) ? statSync17(filePath) : null;
26555
+ stat11 = existsSync41(filePath) ? statSync18(filePath) : null;
25925
26556
  } catch {
25926
26557
  stat11 = null;
25927
26558
  }
@@ -25940,7 +26571,7 @@ app62.get("/:rel{.*}", (c) => {
25940
26571
  console.error(`[sites] path-traversal-rejected path=${reqPath} reason=escape status=403`);
25941
26572
  return c.text("Forbidden", 403);
25942
26573
  }
25943
- if (!existsSync40(filePath)) {
26574
+ if (!existsSync41(filePath)) {
25944
26575
  console.error(`[sites] not-found path=${reqPath} status=404`);
25945
26576
  return c.text("Not found", 404);
25946
26577
  }
@@ -25959,7 +26590,7 @@ app62.get("/:rel{.*}", (c) => {
25959
26590
  }
25960
26591
  let body;
25961
26592
  try {
25962
- body = readFileSync41(realPath);
26593
+ body = readFileSync42(realPath);
25963
26594
  } catch (err) {
25964
26595
  const code = err?.code;
25965
26596
  if (code === "EISDIR") {
@@ -25995,7 +26626,7 @@ var sites_default = app62;
25995
26626
 
25996
26627
  // app/lib/visitor-token.ts
25997
26628
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
25998
- import { mkdirSync as mkdirSync8, readFileSync as readFileSync42, writeFileSync as writeFileSync14 } from "fs";
26629
+ import { mkdirSync as mkdirSync9, readFileSync as readFileSync43, writeFileSync as writeFileSync15 } from "fs";
25999
26630
  import { dirname as dirname14 } from "path";
26000
26631
  var TOKEN_PREFIX = "v1.";
26001
26632
  var SECRET_BYTES = 32;
@@ -26004,7 +26635,7 @@ var cachedSecret = null;
26004
26635
  function getSecret() {
26005
26636
  if (cachedSecret) return cachedSecret;
26006
26637
  try {
26007
- const hex2 = readFileSync42(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
26638
+ const hex2 = readFileSync43(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
26008
26639
  if (hex2.length === SECRET_BYTES * 2) {
26009
26640
  cachedSecret = Buffer.from(hex2, "hex");
26010
26641
  return cachedSecret;
@@ -26013,12 +26644,12 @@ function getSecret() {
26013
26644
  }
26014
26645
  const fresh = randomBytes(SECRET_BYTES).toString("hex");
26015
26646
  try {
26016
- mkdirSync8(dirname14(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
26017
- writeFileSync14(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
26647
+ mkdirSync9(dirname14(VISITOR_TOKEN_SECRET_FILE), { recursive: true, mode: 448 });
26648
+ writeFileSync15(VISITOR_TOKEN_SECRET_FILE, fresh, { mode: 384, flag: "wx" });
26018
26649
  console.log(`[visitor-token] secret minted path=${VISITOR_TOKEN_SECRET_FILE}`);
26019
26650
  } catch {
26020
26651
  }
26021
- const hex = readFileSync42(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
26652
+ const hex = readFileSync43(VISITOR_TOKEN_SECRET_FILE, "utf-8").trim();
26022
26653
  cachedSecret = Buffer.from(hex, "hex");
26023
26654
  return cachedSecret;
26024
26655
  }
@@ -26071,8 +26702,8 @@ var VISITOR_COOKIE_NAME = "mxy_v";
26071
26702
  var VISITOR_COOKIE_MAX_AGE_SECONDS = Math.floor(DEFAULT_TTL_MS / 1e3);
26072
26703
 
26073
26704
  // app/lib/brand-config.ts
26074
- import { existsSync as existsSync41, readFileSync as readFileSync43 } from "fs";
26075
- import { join as join43 } from "path";
26705
+ import { existsSync as existsSync42, readFileSync as readFileSync44 } from "fs";
26706
+ import { join as join44 } from "path";
26076
26707
  var cached2 = null;
26077
26708
  var cachedAttempted = false;
26078
26709
  function readBrandConfig() {
@@ -26080,10 +26711,10 @@ function readBrandConfig() {
26080
26711
  cachedAttempted = true;
26081
26712
  const platformRoot5 = process.env.MAXY_PLATFORM_ROOT;
26082
26713
  if (!platformRoot5) return null;
26083
- const brandPath = join43(platformRoot5, "config", "brand.json");
26084
- if (!existsSync41(brandPath)) return null;
26714
+ const brandPath = join44(platformRoot5, "config", "brand.json");
26715
+ if (!existsSync42(brandPath)) return null;
26085
26716
  try {
26086
- cached2 = JSON.parse(readFileSync43(brandPath, "utf-8"));
26717
+ cached2 = JSON.parse(readFileSync44(brandPath, "utf-8"));
26087
26718
  return cached2;
26088
26719
  } catch {
26089
26720
  return null;
@@ -26581,13 +27212,13 @@ var visitor_event_default = app65;
26581
27212
 
26582
27213
  // server/routes/session.ts
26583
27214
  import { resolve as resolve37 } from "path";
26584
- import { existsSync as existsSync42, writeFileSync as writeFileSync15, mkdirSync as mkdirSync9 } from "fs";
27215
+ import { existsSync as existsSync43, writeFileSync as writeFileSync16, mkdirSync as mkdirSync10 } from "fs";
26585
27216
  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
27217
  function writeBrandingCache(accountId, agentSlug, branding) {
26587
27218
  try {
26588
27219
  const cacheDir = resolve37(MAXY_DIR, "branding-cache", accountId);
26589
- mkdirSync9(cacheDir, { recursive: true });
26590
- writeFileSync15(resolve37(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
27220
+ mkdirSync10(cacheDir, { recursive: true });
27221
+ writeFileSync16(resolve37(cacheDir, `${agentSlug}.json`), JSON.stringify(branding), "utf-8");
26591
27222
  } catch (err) {
26592
27223
  console.error(`[branding] cache write failed: ${err instanceof Error ? err.message : String(err)}`);
26593
27224
  }
@@ -26665,7 +27296,7 @@ app66.post("/", async (c) => {
26665
27296
  let agentConfig = null;
26666
27297
  if (account) {
26667
27298
  const agentDir = resolve37(account.accountDir, "agents", agentSlug);
26668
- if (!existsSync42(agentDir) || !existsSync42(resolve37(agentDir, "config.json"))) {
27299
+ if (!existsSync43(agentDir) || !existsSync43(resolve37(agentDir, "config.json"))) {
26669
27300
  return c.json({ error: "Agent not found" }, 404);
26670
27301
  }
26671
27302
  agentConfig = resolveAgentConfig(account.accountDir, agentSlug);
@@ -26925,7 +27556,7 @@ var calendar_public_default = app67;
26925
27556
  // server/routes/portal-fetch.ts
26926
27557
  import { createReadStream as createReadStream3 } from "fs";
26927
27558
  import { stat as stat8, readFile as readFile9, realpath } from "fs/promises";
26928
- import { join as join44, resolve as resolve38, sep as sep10 } from "path";
27559
+ import { join as join45, resolve as resolve38, sep as sep10 } from "path";
26929
27560
  import { Readable as Readable3 } from "stream";
26930
27561
  var app68 = new Hono();
26931
27562
  var TAG50 = "[portal-fetch]";
@@ -26998,7 +27629,7 @@ function isValidAccountId2(value) {
26998
27629
  }
26999
27630
  async function readExposeFolders2(accountDir) {
27000
27631
  try {
27001
- const cfg = JSON.parse(await readFile9(join44(accountDir, "data-portal.json"), "utf8"));
27632
+ const cfg = JSON.parse(await readFile9(join45(accountDir, "data-portal.json"), "utf8"));
27002
27633
  return Array.isArray(cfg?.exposeFolders) ? cfg.exposeFolders.filter((f) => typeof f === "string") : [];
27003
27634
  } catch {
27004
27635
  return [];
@@ -27007,7 +27638,7 @@ async function readExposeFolders2(accountDir) {
27007
27638
  async function resolveFetchTarget(accountDir, relPath, ownerId) {
27008
27639
  let schemaText = null;
27009
27640
  try {
27010
- schemaText = await readFile9(join44(accountDir, "SCHEMA.md"), "utf8");
27641
+ schemaText = await readFile9(join45(accountDir, "SCHEMA.md"), "utf8");
27011
27642
  } catch {
27012
27643
  schemaText = null;
27013
27644
  }
@@ -27177,8 +27808,8 @@ function startTimeEntryCensus(openSession, opts = {}) {
27177
27808
  }
27178
27809
 
27179
27810
  // 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";
27811
+ import { readdirSync as readdirSync28, readFileSync as readFileSync45, statSync as statSync19 } from "fs";
27812
+ import { join as join46 } from "path";
27182
27813
 
27183
27814
  // ../lib/ledger-core/dist/reconcile.js
27184
27815
  var LEDGER_INDEX_NAMES = [
@@ -27226,16 +27857,16 @@ var DAY_MS = 864e5;
27226
27857
  function countWriteRejects24h(logDir, now) {
27227
27858
  let entries2;
27228
27859
  try {
27229
- entries2 = readdirSync27(logDir).filter((f) => f.startsWith("mcp-ledger-") && f.endsWith(".log"));
27860
+ entries2 = readdirSync28(logDir).filter((f) => f.startsWith("mcp-ledger-") && f.endsWith(".log"));
27230
27861
  } catch {
27231
27862
  return 0;
27232
27863
  }
27233
27864
  let total = 0;
27234
27865
  for (const name of entries2) {
27235
- const path3 = join45(logDir, name);
27866
+ const path3 = join46(logDir, name);
27236
27867
  try {
27237
- if (now - statSync18(path3).mtimeMs > DAY_MS) continue;
27238
- for (const line of readFileSync44(path3, "utf8").split("\n")) {
27868
+ if (now - statSync19(path3).mtimeMs > DAY_MS) continue;
27869
+ for (const line of readFileSync45(path3, "utf8").split("\n")) {
27239
27870
  if (line.includes("[graph-write] reject")) total += 1;
27240
27871
  }
27241
27872
  } catch {
@@ -27730,8 +28361,8 @@ async function migrateUploads(opts = {}) {
27730
28361
 
27731
28362
  // app/lib/migrate-admin-webchat-sidecars.ts
27732
28363
  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";
28364
+ import { existsSync as existsSync44 } from "fs";
28365
+ import { join as join47 } from "path";
27735
28366
  var ADMIN_ROLE2 = "admin";
27736
28367
  var WEBCHAT_CHANNEL2 = "webchat";
27737
28368
  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 +28391,7 @@ async function writeRaw(path3, obj) {
27760
28391
  await rename4(tmp, path3);
27761
28392
  } catch (err) {
27762
28393
  try {
27763
- if (existsSync43(tmp)) await unlink4(tmp);
28394
+ if (existsSync44(tmp)) await unlink4(tmp);
27764
28395
  } catch {
27765
28396
  }
27766
28397
  throw err;
@@ -27776,7 +28407,7 @@ async function collectLiveSidecars(projectsRoot) {
27776
28407
  }
27777
28408
  for (const slug of slugs) {
27778
28409
  if (!slug.isDirectory()) continue;
27779
- const slugDir = join46(projectsRoot, slug.name);
28410
+ const slugDir = join47(projectsRoot, slug.name);
27780
28411
  let entries2;
27781
28412
  try {
27782
28413
  entries2 = await readdir7(slugDir, { withFileTypes: true });
@@ -27785,9 +28416,9 @@ async function collectLiveSidecars(projectsRoot) {
27785
28416
  }
27786
28417
  for (const entry of entries2) {
27787
28418
  if (entry.isFile() && SESSION_META_RE.test(entry.name)) {
27788
- out.push(join46(slugDir, entry.name));
28419
+ out.push(join47(slugDir, entry.name));
27789
28420
  } else if (entry.isDirectory() && entry.name === "subagents") {
27790
- const subDir = join46(slugDir, entry.name);
28421
+ const subDir = join47(slugDir, entry.name);
27791
28422
  let subs;
27792
28423
  try {
27793
28424
  subs = await readdir7(subDir, { withFileTypes: true });
@@ -27795,7 +28426,7 @@ async function collectLiveSidecars(projectsRoot) {
27795
28426
  continue;
27796
28427
  }
27797
28428
  for (const s of subs) {
27798
- if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join46(subDir, s.name));
28429
+ if (s.isFile() && SESSION_META_RE.test(s.name)) out.push(join47(subDir, s.name));
27799
28430
  }
27800
28431
  }
27801
28432
  }
@@ -27807,7 +28438,7 @@ function shortId(path3) {
27807
28438
  return base.slice(0, 8);
27808
28439
  }
27809
28440
  async function migrateAdminWebchatSidecars(opts = {}) {
27810
- const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join46(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
28441
+ const projectsRoot = opts.projectsRoot ?? (process.env.CLAUDE_CONFIG_DIR ? join47(process.env.CLAUDE_CONFIG_DIR, "projects") : null) ?? "";
27811
28442
  const usersFile = opts.usersFile ?? USERS_FILE;
27812
28443
  const accountId = opts.accountId ?? resolveAccount()?.accountId ?? null;
27813
28444
  const resolveName = opts.resolveName ?? defaultResolveName;
@@ -30510,14 +31141,14 @@ function warnOnChannelAdminBindingDrift() {
30510
31141
  }
30511
31142
 
30512
31143
  // server/lib/booking-site-accounts.ts
30513
- import { existsSync as existsSync44, readFileSync as readFileSync45 } from "fs";
31144
+ import { existsSync as existsSync45, readFileSync as readFileSync46 } from "fs";
30514
31145
  import { resolve as resolve43 } from "path";
30515
31146
  function listBookingSiteAccounts(accounts) {
30516
31147
  return accounts.filter((a) => {
30517
31148
  const availPath = resolve43(a.accountDir, "calendar-availability.json");
30518
- if (!existsSync44(availPath)) return false;
31149
+ if (!existsSync45(availPath)) return false;
30519
31150
  try {
30520
- const cfg = JSON.parse(readFileSync45(availPath, "utf-8"));
31151
+ const cfg = JSON.parse(readFileSync46(availPath, "utf-8"));
30521
31152
  return typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
30522
31153
  } catch {
30523
31154
  return false;
@@ -30554,8 +31185,8 @@ function broadcastAdminShutdown(reason) {
30554
31185
  }
30555
31186
 
30556
31187
  // ../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";
31188
+ import { createPublicKey, createHash as createHash7, verify as cryptoVerify } from "crypto";
31189
+ import { existsSync as existsSync46, readFileSync as readFileSync47, statSync as statSync20 } from "fs";
30559
31190
  import { resolve as resolve44 } from "path";
30560
31191
 
30561
31192
  // ../lib/entitlement/src/canonicalize.ts
@@ -30604,10 +31235,10 @@ function resolveEntitlement(brand, account) {
30604
31235
  return logResolved(implicitTrust(account), null);
30605
31236
  }
30606
31237
  const entitlementPath = resolve44(brand.configDir, "entitlement.json");
30607
- if (!existsSync45(entitlementPath)) {
31238
+ if (!existsSync46(entitlementPath)) {
30608
31239
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
30609
31240
  }
30610
- const stat11 = statSync19(entitlementPath);
31241
+ const stat11 = statSync20(entitlementPath);
30611
31242
  const key = memoKey(stat11.mtimeMs, account);
30612
31243
  if (memo && memo.key === key) {
30613
31244
  return memo.result;
@@ -30619,13 +31250,13 @@ function resolveEntitlement(brand, account) {
30619
31250
  function verifyAndResolve(brand, entitlementPath, account) {
30620
31251
  let pubkeyPem;
30621
31252
  try {
30622
- pubkeyPem = readFileSync46(pubkeyPath(brand), "utf-8");
31253
+ pubkeyPem = readFileSync47(pubkeyPath(brand), "utf-8");
30623
31254
  } catch (err) {
30624
31255
  return logResolved(anonymousFallback("pubkey-missing"), {
30625
31256
  reason: "pubkey-missing"
30626
31257
  });
30627
31258
  }
30628
- const pubkeyHash = createHash6("sha256").update(pubkeyPem).digest("hex");
31259
+ const pubkeyHash = createHash7("sha256").update(pubkeyPem).digest("hex");
30629
31260
  if (pubkeyHash !== PUBKEY_SHA256) {
30630
31261
  return logResolved(anonymousFallback("pubkey-tamper"), {
30631
31262
  reason: "pubkey-tamper"
@@ -30633,7 +31264,7 @@ function verifyAndResolve(brand, entitlementPath, account) {
30633
31264
  }
30634
31265
  let envelope;
30635
31266
  try {
30636
- envelope = JSON.parse(readFileSync46(entitlementPath, "utf-8"));
31267
+ envelope = JSON.parse(readFileSync47(entitlementPath, "utf-8"));
30637
31268
  } catch {
30638
31269
  return logResolved(anonymousFallback("malformed"), { reason: "malformed" });
30639
31270
  }
@@ -30795,14 +31426,14 @@ function clientFrom(c) {
30795
31426
  }
30796
31427
  installMediaDownloadGuard();
30797
31428
  var PLATFORM_ROOT8 = process.env.MAXY_PLATFORM_ROOT || "";
30798
- var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join47(PLATFORM_ROOT8, "config", "brand.json") : "";
31429
+ var BRAND_JSON_PATH = PLATFORM_ROOT8 ? join48(PLATFORM_ROOT8, "config", "brand.json") : "";
30799
31430
  var BRAND = { productName: "Maxy", hostname: "maxy", configDir: ".maxy", marketingUrl: "https://getmaxy.com" };
30800
- if (BRAND_JSON_PATH && !existsSync46(BRAND_JSON_PATH)) {
31431
+ if (BRAND_JSON_PATH && !existsSync47(BRAND_JSON_PATH)) {
30801
31432
  console.error(`[brand] WARNING: brand.json not found at ${BRAND_JSON_PATH} \u2014 using Maxy defaults`);
30802
31433
  }
30803
- if (BRAND_JSON_PATH && existsSync46(BRAND_JSON_PATH)) {
31434
+ if (BRAND_JSON_PATH && existsSync47(BRAND_JSON_PATH)) {
30804
31435
  try {
30805
- const parsed = JSON.parse(readFileSync47(BRAND_JSON_PATH, "utf-8"));
31436
+ const parsed = JSON.parse(readFileSync48(BRAND_JSON_PATH, "utf-8"));
30806
31437
  BRAND = { ...BRAND, ...parsed };
30807
31438
  } catch (err) {
30808
31439
  console.error(`[brand] Failed to parse brand.json: ${err.message}`);
@@ -30834,11 +31465,11 @@ var brandLoginOpts = {
30834
31465
  appleTouchIconPath: brandAppIcon512Path,
30835
31466
  themeColor: BRAND.defaultColors?.primary
30836
31467
  };
30837
- var ALIAS_DOMAINS_PATH = join47(homedir4(), BRAND.configDir, "alias-domains.json");
31468
+ var ALIAS_DOMAINS_PATH = join48(homedir4(), BRAND.configDir, "alias-domains.json");
30838
31469
  function loadAliasDomains() {
30839
31470
  try {
30840
- if (!existsSync46(ALIAS_DOMAINS_PATH)) return null;
30841
- const parsed = JSON.parse(readFileSync47(ALIAS_DOMAINS_PATH, "utf-8"));
31471
+ if (!existsSync47(ALIAS_DOMAINS_PATH)) return null;
31472
+ const parsed = JSON.parse(readFileSync48(ALIAS_DOMAINS_PATH, "utf-8"));
30842
31473
  if (!Array.isArray(parsed)) {
30843
31474
  console.error("[alias-domains] malformed alias-domains.json \u2014 expected array");
30844
31475
  return null;
@@ -30913,7 +31544,7 @@ var waGateway = new WaGateway({
30913
31544
  fetchStandingRules: fetchAccountStandingRules,
30914
31545
  resolveSessionOverride: (accountId, senderId) => resolveChannelOverride(accountId, "whatsapp", senderId),
30915
31546
  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"),
31547
+ serverPath: process.env.MAXY_WA_CHANNEL_SERVER_PATH ?? resolve45(process.env.MAXY_PLATFORM_ROOT ?? join48(__dirname, ".."), "services/whatsapp-channel/dist/server.js"),
30917
31548
  // Task 751 / 1390 — file delivery on the native channel. `maxyAccountId` (the
30918
31549
  // path-validation scope) is the sender's effective SESSION account, resolved
30919
31550
  // once at the inbound gate and threaded here via the gateway's per-sender doc
@@ -30928,13 +31559,13 @@ var waGateway = new WaGateway({
30928
31559
  caption,
30929
31560
  accountId,
30930
31561
  maxyAccountId,
30931
- platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, ".."))
31562
+ platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join48(__dirname, ".."))
30932
31563
  });
30933
31564
  return result.ok ? { ok: true, messageId: result.messageId } : { ok: false, error: result.error };
30934
31565
  },
30935
31566
  ensureChannelSession: async ({ accountId, effectiveAccountId, senderId, role, personId, gatewayUrl, serverPath, passive, text, msgId, ownerSelfPhone, replyContext }) => {
30936
31567
  if (passive) {
30937
- const phoneHash = createHash7("sha256").update(senderId).digest("hex").slice(0, 12);
31568
+ const phoneHash = createHash8("sha256").update(senderId).digest("hex").slice(0, 12);
30938
31569
  const prompt = (text ?? "").trim();
30939
31570
  if (prompt.length === 0) {
30940
31571
  console.error(`[wa-passive] op=dropped account=${effectiveAccountId} phoneHash=${phoneHash} msgId=${msgId ?? "none"} reason=empty-text`);
@@ -31046,7 +31677,7 @@ function runDuplicateSenderAudit() {
31046
31677
  try {
31047
31678
  const configDir2 = process.env.CLAUDE_CONFIG_DIR;
31048
31679
  if (!configDir2) return;
31049
- const projectsRoot = join47(configDir2, "projects");
31680
+ const projectsRoot = join48(configDir2, "projects");
31050
31681
  const records = [];
31051
31682
  for (const { path: jsonlPath, isSubagent, archived } of enumerateJsonls(projectsRoot)) {
31052
31683
  if (isSubagent || archived) continue;
@@ -31621,14 +32252,14 @@ app69.get("/agent-assets/:slug/:filename", (c) => {
31621
32252
  console.error(`[agent-assets] path-traversal-rejected slug=${slug} file=${filename}`);
31622
32253
  return c.text("Forbidden", 403);
31623
32254
  }
31624
- if (!existsSync46(filePath)) {
32255
+ if (!existsSync47(filePath)) {
31625
32256
  console.error(`[agent-assets] serve slug=${slug} file=${filename} status=404`);
31626
32257
  return c.text("Not found", 404);
31627
32258
  }
31628
32259
  const ext = "." + filename.split(".").pop()?.toLowerCase();
31629
32260
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
31630
32261
  console.log(`[agent-assets] serve slug=${slug} file=${filename} status=200`);
31631
- const body = readFileSync47(filePath);
32262
+ const body = readFileSync48(filePath);
31632
32263
  return c.body(body, 200, {
31633
32264
  "Content-Type": contentType,
31634
32265
  "Cache-Control": "public, max-age=3600"
@@ -31651,14 +32282,14 @@ app69.get("/generated/:filename", (c) => {
31651
32282
  console.error(`[generated] serve file=${filename} status=403`);
31652
32283
  return c.text("Forbidden", 403);
31653
32284
  }
31654
- if (!existsSync46(filePath)) {
32285
+ if (!existsSync47(filePath)) {
31655
32286
  console.error(`[generated] serve file=${filename} status=404`);
31656
32287
  return c.text("Not found", 404);
31657
32288
  }
31658
32289
  const ext = "." + filename.split(".").pop()?.toLowerCase();
31659
32290
  const contentType = IMAGE_MIME[ext] || "application/octet-stream";
31660
32291
  console.log(`[generated] serve file=${filename} status=200`);
31661
- const body = readFileSync47(filePath);
32292
+ const body = readFileSync48(filePath);
31662
32293
  return c.body(body, 200, {
31663
32294
  "Content-Type": contentType,
31664
32295
  "Cache-Control": "public, max-age=86400"
@@ -31671,9 +32302,9 @@ app69.route("/v", visitor_consent_default);
31671
32302
  var htmlCache = /* @__PURE__ */ new Map();
31672
32303
  var brandLogoPath = "/brand/maxy-monochrome.png";
31673
32304
  var brandIconPath = "/brand/maxy-monochrome.png";
31674
- if (BRAND_JSON_PATH && existsSync46(BRAND_JSON_PATH)) {
32305
+ if (BRAND_JSON_PATH && existsSync47(BRAND_JSON_PATH)) {
31675
32306
  try {
31676
- const fullBrand = JSON.parse(readFileSync47(BRAND_JSON_PATH, "utf-8"));
32307
+ const fullBrand = JSON.parse(readFileSync48(BRAND_JSON_PATH, "utf-8"));
31677
32308
  if (fullBrand.assets?.logo) brandLogoPath = `/brand/${fullBrand.assets.logo}`;
31678
32309
  brandIconPath = fullBrand.assets?.icon ? `/brand/${fullBrand.assets.icon}` : brandLogoPath;
31679
32310
  } catch {
@@ -31700,11 +32331,11 @@ var brandScript = `<script>window.__BRAND__=${JSON.stringify({
31700
32331
  var brandThemeColor = BRAND.defaultColors?.primary ?? "#000000";
31701
32332
  var brandBackgroundColor = BRAND.defaultColors?.background ?? "#ffffff";
31702
32333
  var brandAppIconsExist = [brandAppIcon192Path, brandAppIcon512Path, brandMaskableIconPath].every(
31703
- (p) => existsSync46(resolve45(process.cwd(), "public", p.replace(/^\//, "")))
32334
+ (p) => existsSync47(resolve45(process.cwd(), "public", p.replace(/^\//, "")))
31704
32335
  );
31705
32336
  var SW_SOURCE = (() => {
31706
32337
  try {
31707
- return readFileSync47(resolve45(process.cwd(), "public", "sw.js"), "utf-8");
32338
+ return readFileSync48(resolve45(process.cwd(), "public", "sw.js"), "utf-8");
31708
32339
  } catch {
31709
32340
  return null;
31710
32341
  }
@@ -31712,9 +32343,9 @@ var SW_SOURCE = (() => {
31712
32343
  function readInstalledVersion() {
31713
32344
  try {
31714
32345
  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();
32346
+ const versionFile = join48(PLATFORM_ROOT8, "config", `.${BRAND.hostname}-version`);
32347
+ if (!existsSync47(versionFile)) return "unknown";
32348
+ const content = readFileSync48(versionFile, "utf-8").trim();
31718
32349
  return content || "unknown";
31719
32350
  } catch {
31720
32351
  return "unknown";
@@ -31755,7 +32386,7 @@ var clientErrorReporterScript = `<script>
31755
32386
  function cachedHtml(file) {
31756
32387
  let html = htmlCache.get(file);
31757
32388
  if (!html) {
31758
- html = readFileSync47(resolve45(process.cwd(), "public", file), "utf-8");
32389
+ html = readFileSync48(resolve45(process.cwd(), "public", file), "utf-8");
31759
32390
  const productNameEsc = escapeHtml(BRAND.productName);
31760
32391
  html = html.replace(/<title>([^<]*)<\/title>/, (_match, inner) => `<title>${escapeHtml(inner).replace(/Maxy/g, productNameEsc)}</title>`);
31761
32392
  html = html.replace('href="/favicon.ico"', `href="${escapeHtml(brandFaviconPath)}"`);
@@ -31772,13 +32403,13 @@ ${clientErrorReporterScript}
31772
32403
  return html;
31773
32404
  }
31774
32405
  function loadBrandingCache(agentSlug) {
31775
- const configDir2 = join47(homedir4(), BRAND.configDir);
32406
+ const configDir2 = join48(homedir4(), BRAND.configDir);
31776
32407
  try {
31777
32408
  const accountId = getDefaultAccountId();
31778
32409
  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"));
32410
+ const cachePath = join48(configDir2, "branding-cache", accountId, `${agentSlug}.json`);
32411
+ if (!existsSync47(cachePath)) return null;
32412
+ return JSON.parse(readFileSync48(cachePath, "utf-8"));
31782
32413
  } catch {
31783
32414
  return null;
31784
32415
  }
@@ -31873,7 +32504,7 @@ app69.use("/vnc-popout.html", logViewerFetch);
31873
32504
  app69.get("/vnc-popout.html", (c) => {
31874
32505
  let html = htmlCache.get("vnc-popout.html");
31875
32506
  if (!html) {
31876
- html = readFileSync47(resolve45(process.cwd(), "public", "vnc-popout.html"), "utf-8");
32507
+ html = readFileSync48(resolve45(process.cwd(), "public", "vnc-popout.html"), "utf-8");
31877
32508
  const name = escapeHtml(BRAND.productName);
31878
32509
  html = html.replace("<title>Browser \u2014 Maxy</title>", `<title>${name}</title>`);
31879
32510
  html = html.replace("</head>", ` ${brandScript}
@@ -32025,10 +32656,10 @@ var hostname = process.env.HOSTNAME ?? "127.0.0.1";
32025
32656
  var httpServer = serve({ fetch: app69.fetch, port, hostname });
32026
32657
  console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32027
32658
  {
32028
- const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32659
+ const reconcilePlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join48(__dirname, "..");
32029
32660
  const reconcileScript = resolve45(reconcilePlatformRoot, "plugins/scheduling/mcp/dist/scripts/reconcile-bookings.js");
32030
32661
  const runReconcile = (ctx) => {
32031
- if (!existsSync46(reconcileScript)) return;
32662
+ if (!existsSync47(reconcileScript)) return;
32032
32663
  try {
32033
32664
  const child = spawn3(process.execPath, [reconcileScript], {
32034
32665
  env: { ...process.env, PLATFORM_ROOT: reconcilePlatformRoot },
@@ -32048,7 +32679,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32048
32679
  detached: true,
32049
32680
  run: runReconcile
32050
32681
  });
32051
- const reconcileStatePath = join47(MAXY_DIR, "booking-reconcile-state.json");
32682
+ const reconcileStatePath = join48(MAXY_DIR, "booking-reconcile-state.json");
32052
32683
  registerLoop({
32053
32684
  name: "calendar-reconcile-liveness",
32054
32685
  intervalMs: 6e5,
@@ -32066,7 +32697,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32066
32697
  }
32067
32698
  {
32068
32699
  const DREAM_CYCLE_SWEEP_INTERVAL_MS = 36e5;
32069
- const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32700
+ const dreamPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join48(__dirname, "..");
32070
32701
  const dreamSweepScript = resolve45(dreamPlatformRoot, "plugins/memory/mcp/dist/scripts/dream-cycle-sweep.js");
32071
32702
  registerLoop({
32072
32703
  name: "dream-cycle-sweep",
@@ -32074,7 +32705,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32074
32705
  firstRunDelayMs: 3e4,
32075
32706
  detached: true,
32076
32707
  run: (ctx) => {
32077
- if (!existsSync46(dreamSweepScript)) return;
32708
+ if (!existsSync47(dreamSweepScript)) return;
32078
32709
  try {
32079
32710
  const child = spawn3(process.execPath, [dreamSweepScript], {
32080
32711
  env: { ...process.env, PLATFORM_ROOT: dreamPlatformRoot },
@@ -32090,11 +32721,11 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32090
32721
  });
32091
32722
  }
32092
32723
  {
32093
- const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32724
+ const outlookPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join48(__dirname, "..");
32094
32725
  const outlookScript = resolve45(outlookPlatformRoot, "plugins/outlook/mcp/dist/scripts/complete-registration.js");
32095
32726
  const OUTLOOK_COMPLETE_INTERVAL_MS = 3e4;
32096
32727
  const runOutlookComplete = (ctx) => {
32097
- if (!existsSync46(outlookScript)) return;
32728
+ if (!existsSync47(outlookScript)) return;
32098
32729
  try {
32099
32730
  const child = spawn3(process.execPath, [outlookScript], {
32100
32731
  env: { ...process.env, PLATFORM_ROOT: outlookPlatformRoot },
@@ -32116,20 +32747,20 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32116
32747
  });
32117
32748
  }
32118
32749
  {
32119
- const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32750
+ const auditRoot = process.env.MAXY_PLATFORM_ROOT ?? join48(__dirname, "..");
32120
32751
  const strandedAccountsDir = resolve45(auditRoot, "..", "data/accounts");
32121
32752
  const STRANDED_AUDIT_INTERVAL_MS = 3e5;
32122
32753
  const STRANDED_AGE_MS = 16 * 6e4;
32123
32754
  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
32755
  const runStrandedAudit = () => {
32125
32756
  try {
32126
- if (!existsSync46(strandedAccountsDir)) return;
32757
+ if (!existsSync47(strandedAccountsDir)) return;
32127
32758
  const now = Date.now();
32128
- for (const name of readdirSync28(strandedAccountsDir)) {
32759
+ for (const name of readdirSync29(strandedAccountsDir)) {
32129
32760
  if (!STRANDED_UUID_RE.test(name)) continue;
32130
32761
  const pendingPath2 = resolve45(strandedAccountsDir, name, "secrets/outlook/pending-devicecode.enc");
32131
- if (!existsSync46(pendingPath2)) continue;
32132
- const ageMs2 = now - statSync20(pendingPath2).mtimeMs;
32762
+ if (!existsSync47(pendingPath2)) continue;
32763
+ const ageMs2 = now - statSync21(pendingPath2).mtimeMs;
32133
32764
  if (ageMs2 > STRANDED_AGE_MS) {
32134
32765
  console.error(`[outlook-mcp] devicecode-stranded account=${name} ageSec=${Math.floor(ageMs2 / 1e3)}`);
32135
32766
  }
@@ -32146,7 +32777,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32146
32777
  });
32147
32778
  }
32148
32779
  {
32149
- const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32780
+ const googleRoot = process.env.MAXY_PLATFORM_ROOT ?? join48(__dirname, "..");
32150
32781
  const googleAccountsDir = resolve45(googleRoot, "..", "data/accounts");
32151
32782
  const GOOGLE_PENDING_AUDIT_INTERVAL_MS = 3e5;
32152
32783
  const runGooglePendingAuditSafe = () => {
@@ -32165,7 +32796,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32165
32796
  const googleAuditScript = resolve45(googleRoot, "plugins/google/mcp/dist/scripts/account-audit.js");
32166
32797
  const GOOGLE_ACCOUNT_AUDIT_INTERVAL_MS = 36e5;
32167
32798
  const runGoogleAccountAudit = (ctx) => {
32168
- if (!existsSync46(googleAuditScript)) return;
32799
+ if (!existsSync47(googleAuditScript)) return;
32169
32800
  try {
32170
32801
  const child = spawn3(process.execPath, [googleAuditScript], {
32171
32802
  env: { ...process.env, PLATFORM_ROOT: googleRoot },
@@ -32190,7 +32821,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32190
32821
  });
32191
32822
  }
32192
32823
  {
32193
- const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32824
+ const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join48(__dirname, "..");
32194
32825
  const STORAGE_AUDIT_INTERVAL_MS = 3e5;
32195
32826
  const runStorageAuditSafe = () => runStorageAudit(auditPlatformRoot).catch((err) => {
32196
32827
  console.error(`[storage-audit] error="${err.message}"`);
@@ -32236,7 +32867,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32236
32867
  });
32237
32868
  }
32238
32869
  {
32239
- const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32870
+ const publishPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join48(__dirname, "..");
32240
32871
  const publishScript = resolve45(publishPlatformRoot, "plugins/scheduling/mcp/dist/scripts/publish-availability.js");
32241
32872
  const PUBLISH_INTERVAL_MS = 3e5;
32242
32873
  const bookingAccounts = () => {
@@ -32248,7 +32879,7 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32248
32879
  }
32249
32880
  };
32250
32881
  const spawnPublish = (account, ctx) => {
32251
- if (!existsSync46(publishScript)) return;
32882
+ if (!existsSync47(publishScript)) return;
32252
32883
  try {
32253
32884
  const child = spawn3(process.execPath, [publishScript], {
32254
32885
  env: {
@@ -32270,8 +32901,8 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32270
32901
  const availPath = resolve45(account.accountDir, "calendar-availability.json");
32271
32902
  let hasBookingSite = false;
32272
32903
  try {
32273
- if (existsSync46(availPath)) {
32274
- const cfg = JSON.parse(readFileSync47(availPath, "utf-8"));
32904
+ if (existsSync47(availPath)) {
32905
+ const cfg = JSON.parse(readFileSync48(availPath, "utf-8"));
32275
32906
  hasBookingSite = typeof cfg.bookingDbName === "string" && cfg.bookingDbName.length > 0;
32276
32907
  }
32277
32908
  } catch {
@@ -32279,9 +32910,9 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32279
32910
  if (!hasBookingSite) return;
32280
32911
  const statePath = resolve45(account.accountDir, "state", "booking-availability", "last-publish.json");
32281
32912
  let lastSuccessAt = null;
32282
- if (existsSync46(statePath)) {
32913
+ if (existsSync47(statePath)) {
32283
32914
  try {
32284
- const rec = JSON.parse(readFileSync47(statePath, "utf-8"));
32915
+ const rec = JSON.parse(readFileSync48(statePath, "utf-8"));
32285
32916
  lastSuccessAt = rec.lastSuccessAt ?? null;
32286
32917
  } catch {
32287
32918
  console.error(`[calendar-availability] op=audit accountId=${account.accountId} snapshotAgeMs=na reason=bad-state-file`);
@@ -32313,12 +32944,12 @@ console.log(`${BRAND.productName} listening on http://${hostname}:${port}`);
32313
32944
  startTimeEntryCensus(() => getSession());
32314
32945
  startLedgerCensus(() => getSession());
32315
32946
  {
32316
- const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..");
32947
+ const auditPlatformRoot = process.env.MAXY_PLATFORM_ROOT ?? join48(__dirname, "..");
32317
32948
  const auditScript = resolve45(auditPlatformRoot, "plugins/connector/mcp/dist/scripts/audit-connectors.js");
32318
32949
  const auditLogDir = process.env.LOG_DIR ?? LOG_DIR;
32319
32950
  const CONNECTOR_AUDIT_INTERVAL_MS = 3e5;
32320
32951
  const runConnectorAudit = (ctx) => {
32321
- if (!existsSync46(auditScript)) return;
32952
+ if (!existsSync47(auditScript)) return;
32322
32953
  try {
32323
32954
  const child = spawn3(process.execPath, [auditScript], {
32324
32955
  env: { ...process.env, PLATFORM_ROOT: auditPlatformRoot, LOG_DIR: auditLogDir },
@@ -32438,11 +33069,11 @@ try {
32438
33069
  var ADMINUSER_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
32439
33070
  async function runAdminUserReconcileTick() {
32440
33071
  try {
32441
- if (!existsSync46(USERS_FILE)) {
33072
+ if (!existsSync47(USERS_FILE)) {
32442
33073
  console.error("[adminuser-self-heal] skip reason=no-users-file");
32443
33074
  return;
32444
33075
  }
32445
- const usersRaw = readFileSync47(USERS_FILE, "utf-8").trim();
33076
+ const usersRaw = readFileSync48(USERS_FILE, "utf-8").trim();
32446
33077
  if (!usersRaw) {
32447
33078
  console.error("[adminuser-self-heal] skip reason=empty-users-file");
32448
33079
  return;
@@ -32489,8 +33120,8 @@ registerLoop({
32489
33120
  });
32490
33121
  var USERS_RECONCILE_INTERVAL_MS = 60 * 60 * 1e3;
32491
33122
  function countUsersRows() {
32492
- if (!existsSync46(USERS_FILE)) return 0;
32493
- const raw = readFileSync47(USERS_FILE, "utf-8").trim();
33123
+ if (!existsSync47(USERS_FILE)) return 0;
33124
+ const raw = readFileSync48(USERS_FILE, "utf-8").trim();
32494
33125
  if (!raw) return 0;
32495
33126
  const users = JSON.parse(raw);
32496
33127
  return users.filter((u) => typeof u.userId === "string").length;
@@ -32623,7 +33254,7 @@ if (bootAccountConfig?.whatsapp) {
32623
33254
  }
32624
33255
  init({
32625
33256
  configDir: configDirForWhatsApp,
32626
- platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join47(__dirname, "..")),
33257
+ platformRoot: resolve45(process.env.MAXY_PLATFORM_ROOT ?? join48(__dirname, "..")),
32627
33258
  accountConfig: bootAccountConfig,
32628
33259
  onMessage: async (msg) => {
32629
33260
  if (isObserveAccount(msg.accountId)) {