@rubytech/create-maxy-code 0.1.310 → 0.1.311

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 (51) hide show
  1. package/package.json +1 -1
  2. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +2 -2
  3. package/payload/platform/plugins/docs/references/admin-ui.md +1 -1
  4. package/payload/platform/scripts/check-no-esm-require.mjs +4 -0
  5. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  6. package/payload/platform/services/claude-session-manager/dist/http-server.js +29 -0
  7. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  8. package/payload/platform/services/claude-session-manager/dist/index.js +16 -2
  9. package/payload/platform/services/claude-session-manager/dist/index.js.map +1 -1
  10. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +10 -0
  11. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  12. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +22 -2
  13. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  14. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts +39 -0
  15. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.d.ts.map +1 -0
  16. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js +139 -0
  17. package/payload/platform/services/claude-session-manager/dist/reseat-ledger.js.map +1 -0
  18. package/payload/server/public/assets/{AccessGate-BOqUU-za.js → AccessGate-ChFLk-rp.js} +1 -1
  19. package/payload/server/public/assets/{AdminLoginScreens-WvRuaNIg.js → AdminLoginScreens-DU6zgbk5.js} +1 -1
  20. package/payload/server/public/assets/AdminShell-BJCYb1v5.js +1 -0
  21. package/payload/server/public/assets/{Checkbox-DjM6aYP_.js → Checkbox-CQGLKMXu.js} +1 -1
  22. package/payload/server/public/assets/{OperatorConversations-CDY0jUMb.js → OperatorConversations-CHEQTz20.js} +1 -1
  23. package/payload/server/public/assets/{admin-XbVTsU2q.js → admin-COHPIWdb.js} +1 -1
  24. package/payload/server/public/assets/{audio-attachment-mime-CVxjPN8V.js → audio-attachment-mime-DL06xo72.js} +1 -1
  25. package/payload/server/public/assets/brand-CN7uSSKl.css +1 -0
  26. package/payload/server/public/assets/{browser-Ct5Kwlmk.js → browser-L7N4tAOl.js} +1 -1
  27. package/payload/server/public/assets/chat-B_jYIH9a.js +1 -0
  28. package/payload/server/public/assets/data-BmSTKHR1.js +1 -0
  29. package/payload/server/public/assets/{graph-DWT1rhy9.js → graph-Cro3-mgY.js} +1 -1
  30. package/payload/server/public/assets/{graph-labels-OBadNo54.js → graph-labels-WQQn6JIJ.js} +1 -1
  31. package/payload/server/public/assets/operator-B4I25isQ.js +1 -0
  32. package/payload/server/public/assets/page-B-6ZQ4JG.js +1 -0
  33. package/payload/server/public/assets/{public-owWW-MIA.js → public-CX148JKi.js} +1 -1
  34. package/payload/server/public/assets/{public-next-ClQwtyeC.js → public-next-BCItsUbZ.js} +1 -1
  35. package/payload/server/public/assets/{useSelectionMode-BZsJuUm-.js → useSelectionMode-BHAAhkDg.js} +1 -1
  36. package/payload/server/public/browser.html +6 -6
  37. package/payload/server/public/chat.html +8 -8
  38. package/payload/server/public/data.html +5 -5
  39. package/payload/server/public/graph.html +8 -8
  40. package/payload/server/public/index.html +8 -8
  41. package/payload/server/public/operator.html +10 -10
  42. package/payload/server/public/public-next.html +9 -9
  43. package/payload/server/public/public.html +7 -7
  44. package/payload/server/server.js +196 -35
  45. package/payload/server/public/assets/AdminShell-DHv6_SZ4.js +0 -1
  46. package/payload/server/public/assets/brand-N-Hi3IPA.css +0 -1
  47. package/payload/server/public/assets/chat-CEde1CLX.js +0 -1
  48. package/payload/server/public/assets/data-TZOmA1Qg.js +0 -1
  49. package/payload/server/public/assets/operator-BpzQ9Ezb.js +0 -1
  50. package/payload/server/public/assets/page-Dts8u8MD.js +0 -1
  51. /package/payload/server/public/assets/{brand-zL3tAdql.js → brand-MKGM8WZp.js} +0 -0
@@ -5,15 +5,15 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/public-owWW-MIA.js"></script>
8
+ <script type="module" crossorigin src="/assets/public-CX148JKi.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-CAM3fms7.js">
10
- <link rel="modulepreload" crossorigin href="/assets/brand-zL3tAdql.js">
11
- <link rel="modulepreload" crossorigin href="/assets/useSelectionMode-BZsJuUm-.js">
12
- <link rel="modulepreload" crossorigin href="/assets/Checkbox-DjM6aYP_.js">
10
+ <link rel="modulepreload" crossorigin href="/assets/brand-MKGM8WZp.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/useSelectionMode-BHAAhkDg.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/Checkbox-CQGLKMXu.js">
13
13
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-C5gCWwwF.js">
14
- <link rel="modulepreload" crossorigin href="/assets/audio-attachment-mime-CVxjPN8V.js">
15
- <link rel="modulepreload" crossorigin href="/assets/AccessGate-BOqUU-za.js">
16
- <link rel="stylesheet" crossorigin href="/assets/brand-N-Hi3IPA.css">
14
+ <link rel="modulepreload" crossorigin href="/assets/audio-attachment-mime-DL06xo72.js">
15
+ <link rel="modulepreload" crossorigin href="/assets/AccessGate-ChFLk-rp.js">
16
+ <link rel="stylesheet" crossorigin href="/assets/brand-CN7uSSKl.css">
17
17
  <link rel="stylesheet" crossorigin href="/assets/public-vnj7OhQj.css">
18
18
  <link rel="stylesheet" href="/brand-defaults.css">
19
19
  </head>
@@ -4871,6 +4871,10 @@ function crossesForeignAccountPartition(relPath, accountId) {
4871
4871
  if (!ACCOUNT_UUID_RE.test(owner)) return false;
4872
4872
  return owner !== accountId;
4873
4873
  }
4874
+ function isWithinOwnAccountPartition(relPath, accountId) {
4875
+ const segs = relPath.split("/").filter(Boolean);
4876
+ return segs.length >= 2 && segs[0] === "accounts" && segs[1] === accountId;
4877
+ }
4874
4878
  function resolveUnderRoot(raw, rootAbs, rootLabel) {
4875
4879
  const cleaned = normalize("/" + (raw ?? "").replace(/\\/g, "/")).replace(/^\/+/, "");
4876
4880
  const absolute = resolve5(rootAbs, cleaned);
@@ -6615,10 +6619,8 @@ function selectReaderChannelSessions(rows) {
6615
6619
  // server/routes/admin/sidebar-sessions.ts
6616
6620
  var SESSION_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
6617
6621
  var CLI_MARKER_PREFIXES = ["<local-command-", "<command-name>", "<command-message>"];
6618
- var PUBLIC_ROLE = "public";
6619
6622
  var ADMIN_ROLE = "admin";
6620
6623
  var WEBCHAT_CHANNEL = "webchat";
6621
- var WHATSAPP_CHANNEL = "whatsapp";
6622
6624
  var app3 = new Hono();
6623
6625
  function claudeConfigDir() {
6624
6626
  return process.env.CLAUDE_CONFIG_DIR ?? null;
@@ -6836,7 +6838,6 @@ app3.get("/", requireAdminSession, async (c) => {
6836
6838
  const seenIds = /* @__PURE__ */ new Set();
6837
6839
  let liveCount = 0;
6838
6840
  let subagentCount = 0;
6839
- let nonResumableCount = 0;
6840
6841
  let archivedCount = 0;
6841
6842
  let excludedChannelCount = 0;
6842
6843
  const titleSourceCounts = { user: 0, ai: 0, "first-message": 0, prefix: 0 };
@@ -6870,7 +6871,6 @@ app3.get("/", requireAdminSession, async (c) => {
6870
6871
  excludedChannelCount += 1;
6871
6872
  continue;
6872
6873
  }
6873
- const resumable = !(role === PUBLIC_ROLE && (sidecarChannel === WEBCHAT_CHANNEL || sidecarChannel === WHATSAPP_CHANNEL));
6874
6874
  if (personId) personIdBySession.set(sessionId, personId);
6875
6875
  if (adminUserId && role === ADMIN_ROLE && sidecarChannel === WEBCHAT_CHANNEL) {
6876
6876
  adminUserIdBySession.set(sessionId, adminUserId);
@@ -6885,14 +6885,12 @@ app3.get("/", requireAdminSession, async (c) => {
6885
6885
  pid,
6886
6886
  projectDir,
6887
6887
  bridgeIds,
6888
- resumable,
6889
6888
  archived,
6890
6889
  channel: resolved.channel,
6891
6890
  personName: null
6892
6891
  });
6893
6892
  if (live) liveCount += 1;
6894
6893
  if (isSubagent) subagentCount += 1;
6895
- if (!resumable) nonResumableCount += 1;
6896
6894
  if (archived) archivedCount += 1;
6897
6895
  }
6898
6896
  let personNameCount = 0;
@@ -6923,7 +6921,7 @@ app3.get("/", requireAdminSession, async (c) => {
6923
6921
  }
6924
6922
  rows.sort((a, b) => a.startedAt < b.startedAt ? 1 : -1);
6925
6923
  console.log(
6926
- `[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} nonResumable=${nonResumableCount} excludedChannel=${excludedChannelCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
6924
+ `[admin-sessions-list] rows=${rows.length} live=${liveCount} subagents=${subagentCount} archived=${archivedCount} excludedChannel=${excludedChannelCount} titles user=${titleSourceCounts.user} ai=${titleSourceCounts.ai} first=${titleSourceCounts["first-message"]} prefix=${titleSourceCounts.prefix} personNames=${personNameCount} adminNames=${adminNameCount} accountId=${accountId ? accountId.slice(0, 8) : "unset"}`
6927
6925
  );
6928
6926
  return c.json({ sessions: rows, accountId });
6929
6927
  });
@@ -7653,7 +7651,7 @@ var public_reader_default = app5;
7653
7651
  // server/routes/webchat.ts
7654
7652
  import { basename as basename4, dirname as dirname3 } from "path";
7655
7653
  import { join as join13 } from "path";
7656
- import { existsSync as existsSync8, readdirSync as readdirSync7, readFileSync as readFileSync13, renameSync as renameSync2, writeFileSync as writeFileSync6 } from "fs";
7654
+ import { existsSync as existsSync8, readdirSync as readdirSync7, readFileSync as readFileSync13, renameSync as renameSync2, statSync as statSync6, writeFileSync as writeFileSync6 } from "fs";
7657
7655
 
7658
7656
  // server/canonical-webchat-override.ts
7659
7657
  import { readFileSync as readFileSync12, writeFileSync as writeFileSync5, renameSync } from "fs";
@@ -7726,6 +7724,14 @@ function locateSidecar(sessionId) {
7726
7724
  function sessionSidecarExists(sessionId) {
7727
7725
  return locateSidecar(sessionId) !== null;
7728
7726
  }
7727
+ function jsonlSizeBytes(projectDir, sessionId) {
7728
+ if (projectDir === null) return null;
7729
+ try {
7730
+ return statSync6(join13(projectDir, `${sessionId}.jsonl`)).size;
7731
+ } catch {
7732
+ return null;
7733
+ }
7734
+ }
7729
7735
  function conflictingBinding(channel) {
7730
7736
  return channel !== null && channel !== "webchat" ? channel : null;
7731
7737
  }
@@ -7813,6 +7819,8 @@ async function reapplyLeversViaManager() {
7813
7819
  return false;
7814
7820
  }
7815
7821
  }
7822
+ var WEBCHAT_SEND_TURN_WINDOW_MS = Number(process.env.WEBCHAT_SEND_TURN_WINDOW_MS ?? String(15e3));
7823
+ var sendSeq = 0;
7816
7824
  function createWebchatRoutes(deps) {
7817
7825
  const app51 = new Hono();
7818
7826
  app51.post("/send", requireAdminSession, async (c) => {
@@ -7944,6 +7952,30 @@ ${note}` : note;
7944
7952
  } else {
7945
7953
  await deps.handleInbound({ role: "admin", accountId, key: deliveryKey, text });
7946
7954
  }
7955
+ const sendId = ++sendSeq;
7956
+ let turnSessionId = deliverySessionId;
7957
+ if (turnSessionId === void 0) {
7958
+ let canonAccount;
7959
+ try {
7960
+ canonAccount = resolveAccount();
7961
+ } catch {
7962
+ canonAccount = null;
7963
+ }
7964
+ turnSessionId = resolveCanonicalSessionId(accountId, canonAccount?.accountDir ?? null);
7965
+ }
7966
+ const keyDisplay2 = deliveryKey.startsWith("session:") ? deliveryKey.slice(0, "session:".length + 8) : WEBCHAT_ADMIN_KEY;
7967
+ const baseline = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
7968
+ console.error(`[webchat:inbound] op=send-accepted key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"}`);
7969
+ const turnTimer = setTimeout(() => {
7970
+ const now = jsonlSizeBytes(locateSession(turnSessionId).projectDir, turnSessionId);
7971
+ const grew = now !== null && (baseline === null || now > baseline);
7972
+ if (grew) {
7973
+ console.error(`[webchat:inbound] op=send-turned key=${keyDisplay2} sendId=${sendId} bytes=${now}`);
7974
+ } else {
7975
+ console.error(`[webchat:inbound] op=send-no-turn key=${keyDisplay2} sendId=${sendId} baselineBytes=${baseline ?? "absent"}`);
7976
+ }
7977
+ }, WEBCHAT_SEND_TURN_WINDOW_MS);
7978
+ if (turnTimer.unref) turnTimer.unref();
7947
7979
  return c.json({ ok: true });
7948
7980
  });
7949
7981
  app51.post("/settings", requireAdminSession, async (c) => {
@@ -8003,7 +8035,7 @@ ${note}` : note;
8003
8035
  const { projectDir: projectDir2, channel } = locateSession(target);
8004
8036
  const known = projectDir2 !== null || sessionSidecarExists(target);
8005
8037
  const indicators2 = await fetchComposerIndicators(target);
8006
- return c.json({ sessionId: target, projectDir: projectDir2, channelBinding: conflictingBinding(channel), known, ...indicators2, ...readLevers() });
8038
+ return c.json({ sessionId: target, projectDir: projectDir2, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), ...indicators2, ...readLevers() });
8007
8039
  }
8008
8040
  let account;
8009
8041
  try {
@@ -8023,7 +8055,7 @@ ${note}` : note;
8023
8055
  }
8024
8056
  }
8025
8057
  const indicators = await fetchComposerIndicators(sessionId);
8026
- return c.json({ sessionId, projectDir, ...indicators, ...readLevers(account) });
8058
+ return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), ...indicators, ...readLevers(account) });
8027
8059
  });
8028
8060
  return app51;
8029
8061
  }
@@ -9164,7 +9196,7 @@ import { openSync as openSync3, closeSync as closeSync3, writeFileSync as writeF
9164
9196
  import { createHash as createHash3, randomUUID as randomUUID8 } from "crypto";
9165
9197
 
9166
9198
  // ../lib/admins-write/src/index.ts
9167
- import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync7, renameSync as renameSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync9, statSync as statSync6 } from "fs";
9199
+ import { existsSync as existsSync11, readFileSync as readFileSync16, writeFileSync as writeFileSync7, renameSync as renameSync3, mkdirSync as mkdirSync2, readdirSync as readdirSync9, statSync as statSync7 } from "fs";
9168
9200
  import { dirname as dirname4, join as join16 } from "path";
9169
9201
  function logLine(input, result) {
9170
9202
  const userIdShort = input.userId.slice(0, 8);
@@ -9264,7 +9296,7 @@ function checkAdminAuthInvariant(input) {
9264
9296
  if (entry.startsWith(".")) continue;
9265
9297
  const accountDir = join16(input.accountsDir, entry);
9266
9298
  try {
9267
- if (!statSync6(accountDir).isDirectory()) continue;
9299
+ if (!statSync7(accountDir).isDirectory()) continue;
9268
9300
  } catch {
9269
9301
  continue;
9270
9302
  }
@@ -9556,7 +9588,7 @@ app8.delete("/set-pin", async (c) => {
9556
9588
  var onboarding_default = app8;
9557
9589
 
9558
9590
  // server/routes/client-error.ts
9559
- import { appendFileSync, existsSync as existsSync13, renameSync as renameSync4, statSync as statSync7 } from "fs";
9591
+ import { appendFileSync, existsSync as existsSync13, renameSync as renameSync4, statSync as statSync8 } from "fs";
9560
9592
  import { join as join17 } from "path";
9561
9593
  var CLIENT_ERRORS_LOG = join17(LOG_DIR, "client-errors.log");
9562
9594
  var MAX_LOG_SIZE = 10 * 1024 * 1024;
@@ -9602,7 +9634,7 @@ function stackHead(stack) {
9602
9634
  function rotateIfNeeded() {
9603
9635
  try {
9604
9636
  if (!existsSync13(CLIENT_ERRORS_LOG)) return;
9605
- const stats = statSync7(CLIENT_ERRORS_LOG);
9637
+ const stats = statSync8(CLIENT_ERRORS_LOG);
9606
9638
  if (stats.size < MAX_LOG_SIZE) return;
9607
9639
  renameSync4(CLIENT_ERRORS_LOG, CLIENT_ERRORS_LOG + ".1");
9608
9640
  } catch (err) {
@@ -9883,7 +9915,7 @@ app10.post("/", async (c) => {
9883
9915
  var session_default = app10;
9884
9916
 
9885
9917
  // server/routes/admin/logs.ts
9886
- import { existsSync as existsSync15, readdirSync as readdirSync10, readFileSync as readFileSync18, statSync as statSync8 } from "fs";
9918
+ import { existsSync as existsSync15, readdirSync as readdirSync10, readFileSync as readFileSync18, statSync as statSync9 } from "fs";
9887
9919
  import { resolve as resolve16, basename as basename5 } from "path";
9888
9920
 
9889
9921
  // app/lib/logs-read-resolve.ts
@@ -9923,7 +9955,7 @@ app11.get("/", async (c) => {
9923
9955
  searched.push(filePath);
9924
9956
  try {
9925
9957
  const buffer = readFileSync18(filePath);
9926
- const onDiskBytes = statSync8(filePath).size;
9958
+ const onDiskBytes = statSync9(filePath).size;
9927
9959
  const headers = {
9928
9960
  "Content-Type": "text/plain; charset=utf-8",
9929
9961
  "Content-Length": String(buffer.byteLength)
@@ -9988,7 +10020,7 @@ app11.get("/", async (c) => {
9988
10020
  try {
9989
10021
  const filename = basename5(hit.path);
9990
10022
  const buffer = readFileSync18(hit.path);
9991
- const onDiskBytes = statSync8(hit.path).size;
10023
+ const onDiskBytes = statSync9(hit.path).size;
9992
10024
  const headers = {
9993
10025
  "Content-Type": "text/plain; charset=utf-8",
9994
10026
  "Content-Length": String(buffer.byteLength)
@@ -10031,7 +10063,7 @@ app11.get("/", async (c) => {
10031
10063
  console.warn(`[admin/logs] readdir-fail dir=${dir} reason=${reason}`);
10032
10064
  continue;
10033
10065
  }
10034
- files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync8(resolve16(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
10066
+ files.filter((f) => !seen.has(f)).map((f) => ({ name: f, mtime: statSync9(resolve16(dir, f)).mtimeMs })).sort((a, b) => b.mtime - a.mtime).forEach(({ name }) => {
10035
10067
  seen.add(name);
10036
10068
  try {
10037
10069
  const content = readFileSync18(resolve16(dir, name));
@@ -10894,7 +10926,7 @@ app15.put("/:id/label", requireAdminSession, async (c) => {
10894
10926
  var sessions_default = app15;
10895
10927
 
10896
10928
  // app/lib/claude-agent/spawn-context.ts
10897
- import { existsSync as existsSync19, readFileSync as readFileSync20, readdirSync as readdirSync12, statSync as statSync9 } from "fs";
10929
+ import { existsSync as existsSync19, readFileSync as readFileSync20, readdirSync as readdirSync12, statSync as statSync10 } from "fs";
10898
10930
  import { dirname as dirname5, resolve as resolve19, join as join19 } from "path";
10899
10931
  async function resolveOwnerProfileBlock(accountId, userId) {
10900
10932
  if (!userId) return { ok: false, reason: "missing-user-id" };
@@ -10997,7 +11029,7 @@ function listPluginDirs() {
10997
11029
  for (const name of readdirSync12(platformPlugins)) {
10998
11030
  const dir = join19(platformPlugins, name);
10999
11031
  try {
11000
- if (statSync9(dir).isDirectory()) out.set(name, dir);
11032
+ if (statSync10(dir).isDirectory()) out.set(name, dir);
11001
11033
  } catch {
11002
11034
  }
11003
11035
  }
@@ -11011,7 +11043,7 @@ function listPluginDirs() {
11011
11043
  for (const name of readdirSync12(bundlePlugins)) {
11012
11044
  const dir = join19(bundlePlugins, name);
11013
11045
  try {
11014
- if (statSync9(dir).isDirectory()) out.set(name, dir);
11046
+ if (statSync10(dir).isDirectory()) out.set(name, dir);
11015
11047
  } catch {
11016
11048
  }
11017
11049
  }
@@ -11448,7 +11480,7 @@ var events_default = app18;
11448
11480
 
11449
11481
  // server/routes/admin/files.ts
11450
11482
  import { createReadStream as createReadStream2 } from "fs";
11451
- import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2 } from "fs/promises";
11483
+ import { readdir as readdir3, readFile as readFile4, stat as stat4, mkdir as mkdir3, writeFile as writeFile4, unlink as unlink2, rename } from "fs/promises";
11452
11484
  import { realpathSync as realpathSync4 } from "fs";
11453
11485
  import { basename as basename7, dirname as dirname6, join as join21, resolve as resolve22, sep as sep6 } from "path";
11454
11486
  import { Readable as Readable2 } from "stream";
@@ -12311,6 +12343,44 @@ function isProtectedFromDeletion(relPath) {
12311
12343
  }
12312
12344
  return { protected: false };
12313
12345
  }
12346
+ function isProtectedFromRename(relPath) {
12347
+ if (isProtectedFromDeletion(relPath).protected) return true;
12348
+ const segments = relPath.split("/").filter(Boolean);
12349
+ const base = segments[segments.length - 1] ?? "";
12350
+ if (segments.length === 2 && segments[0] === "accounts") return true;
12351
+ if (segments.length === 3 && segments[0] === "accounts" && segments[2] === "uploads") {
12352
+ return true;
12353
+ }
12354
+ if (segments.length === 4 && segments[0] === "accounts" && segments[2] === "uploads" && UUID_RE3.test(segments[3])) {
12355
+ return true;
12356
+ }
12357
+ if (parseAttachmentPath(relPath) !== null) return true;
12358
+ if (UUID_RE3.test(base.replace(/\.meta\.json$/, "")) && base.endsWith(".meta.json")) {
12359
+ return true;
12360
+ }
12361
+ return false;
12362
+ }
12363
+ function isValidEntryName(name) {
12364
+ if (typeof name !== "string" || name.length === 0) return false;
12365
+ if (name === "." || name === "..") return false;
12366
+ return !/[\\/\0]/.test(name);
12367
+ }
12368
+ function resolveOwnAccountWrite(rawPath, accountId, endpoint) {
12369
+ const res = resolveDataPath(rawPath);
12370
+ if (!res.ok) {
12371
+ if (res.status === 403) console.error(`[data] path-traversal-blocked requested="${rawPath}" resolved="${res.resolved ?? "n/a"}"`);
12372
+ return { ok: false, status: res.status, error: res.error };
12373
+ }
12374
+ if (crossesForeignAccountPartition(res.relative, accountId)) {
12375
+ console.error(`[data] account-scope-blocked endpoint="${endpoint}" path="${res.relative}" account=${accountId.slice(0, 8)}\u2026`);
12376
+ return { ok: false, status: 404, error: "Not found" };
12377
+ }
12378
+ if (!isWithinOwnAccountPartition(res.relative, accountId)) {
12379
+ console.error(`[data] write-scope-blocked endpoint="${endpoint}" path="${res.relative}" account=${accountId.slice(0, 8)}\u2026`);
12380
+ return { ok: false, status: 403, error: "Path is outside your account folder" };
12381
+ }
12382
+ return { ok: true, absolute: res.absolute, relative: res.relative };
12383
+ }
12314
12384
  async function knowledgeDocOwnedByAccount(accountId, attachmentId) {
12315
12385
  if (!attachmentId) return false;
12316
12386
  const session = getSession();
@@ -12494,14 +12564,18 @@ app19.post("/upload", requireAdminSession, async (c) => {
12494
12564
  }
12495
12565
  const safeName = basename7(file.name).replace(/[\0/\\]/g, "_");
12496
12566
  const finalName = `${Date.now()}-${safeName}`;
12497
- const destDir = resolve22(DATA_ROOT, "accounts", accountId, "uploads");
12567
+ const rawDir = formData.get("path");
12568
+ const dest = resolveOwnAccountWrite(typeof rawDir === "string" ? rawDir : "", accountId, "POST /api/admin/files/upload");
12569
+ if (!dest.ok) return c.json({ error: dest.error }, dest.status);
12570
+ const destDir = dest.absolute;
12498
12571
  const destPath = resolve22(destDir, finalName);
12499
12572
  try {
12500
- await mkdir3(destDir, { recursive: true });
12573
+ const info = await stat4(destDir);
12574
+ if (!info.isDirectory()) return c.json({ error: "Upload destination is not a directory" }, 400);
12501
12575
  const dataRootReal = realpathSync4(DATA_ROOT);
12502
12576
  const destDirReal = realpathSync4(destDir);
12503
12577
  if (destDirReal !== dataRootReal && !destDirReal.startsWith(dataRootReal + sep6)) {
12504
- console.error(`[data] path-traversal-blocked requested="accounts/${accountId}/uploads" resolved="${destDirReal}"`);
12578
+ console.error(`[data] path-traversal-blocked requested="${dest.relative}" resolved="${destDirReal}"`);
12505
12579
  return c.json({ error: "Upload destination escapes DATA_ROOT" }, 403);
12506
12580
  }
12507
12581
  const buffer = Buffer.from(await file.arrayBuffer());
@@ -12511,7 +12585,7 @@ app19.post("/upload", requireAdminSession, async (c) => {
12511
12585
  console.error(`[data] file-upload error filename="${safeName}" err="${message}"`);
12512
12586
  return c.json({ error: message }, 500);
12513
12587
  }
12514
- const relativeDest = `accounts/${accountId}/uploads/${finalName}`;
12588
+ const relativeDest = `${dest.relative}/${finalName}`;
12515
12589
  console.error(`[data] file-upload filename="${safeName}" size=${file.size} dest="${relativeDest}"`);
12516
12590
  void indexFile(accountId, relativeDest).catch((err) => {
12517
12591
  console.error(`[data] file-upload index-failed dest="${relativeDest}" err="${err instanceof Error ? err.message : String(err)}"`);
@@ -12599,6 +12673,91 @@ app19.delete("/", requireAdminSession, async (c) => {
12599
12673
  return c.json({ error: message }, 500);
12600
12674
  }
12601
12675
  });
12676
+ app19.post("/folder", requireAdminSession, async (c) => {
12677
+ const cacheKey = c.var.cacheKey;
12678
+ const accountId = getAccountIdForSession(cacheKey);
12679
+ if (!accountId) {
12680
+ console.error(`[data] auth-rejected endpoint="POST /api/admin/files/folder" reason="no account for session"`);
12681
+ return c.json({ error: "Account not found for session" }, 401);
12682
+ }
12683
+ let body;
12684
+ try {
12685
+ body = await c.req.json();
12686
+ } catch {
12687
+ return c.json({ error: "Invalid JSON body" }, 400);
12688
+ }
12689
+ const rawPath = typeof body.path === "string" ? body.path : "";
12690
+ const name = typeof body.name === "string" ? body.name : "";
12691
+ if (!isValidEntryName(name)) return c.json({ error: "Invalid folder name" }, 400);
12692
+ const parent = resolveOwnAccountWrite(rawPath, accountId, "POST /api/admin/files/folder");
12693
+ if (!parent.ok) return c.json({ error: parent.error }, parent.status);
12694
+ const newAbs = resolve22(parent.absolute, name);
12695
+ const newRel = `${parent.relative}/${name}`;
12696
+ try {
12697
+ const info = await stat4(parent.absolute);
12698
+ if (!info.isDirectory()) return c.json({ error: "Parent is not a directory" }, 400);
12699
+ await mkdir3(newAbs, { recursive: false });
12700
+ } catch (err) {
12701
+ const code = err.code;
12702
+ if (code === "EEXIST") return c.json({ error: "A file or folder with that name already exists" }, 409);
12703
+ if (code === "ENOENT") return c.json({ error: "Not found" }, 404);
12704
+ const message = err instanceof Error ? err.message : String(err);
12705
+ console.error(`[data] folder-create error path="${newRel}" err="${message}"`);
12706
+ return c.json({ error: message }, 500);
12707
+ }
12708
+ console.error(`[data] folder-create path="${newRel}"`);
12709
+ return c.json({ path: newRel });
12710
+ });
12711
+ app19.post("/rename", requireAdminSession, async (c) => {
12712
+ const cacheKey = c.var.cacheKey;
12713
+ const accountId = getAccountIdForSession(cacheKey);
12714
+ if (!accountId) {
12715
+ console.error(`[data] auth-rejected endpoint="POST /api/admin/files/rename" reason="no account for session"`);
12716
+ return c.json({ error: "Account not found for session" }, 401);
12717
+ }
12718
+ let body;
12719
+ try {
12720
+ body = await c.req.json();
12721
+ } catch {
12722
+ return c.json({ error: "Invalid JSON body" }, 400);
12723
+ }
12724
+ const rawPath = typeof body.path === "string" ? body.path : "";
12725
+ const newName = typeof body.newName === "string" ? body.newName : "";
12726
+ if (!isValidEntryName(newName)) return c.json({ error: "Invalid name" }, 400);
12727
+ const src = resolveOwnAccountWrite(rawPath, accountId, "POST /api/admin/files/rename");
12728
+ if (!src.ok) return c.json({ error: src.error }, src.status);
12729
+ if (isProtectedFromRename(src.relative)) {
12730
+ console.error(`[data] file-rename blocked path="${src.relative}" reason="protected"`);
12731
+ return c.json({ error: "Protected entry \u2014 refusing to rename" }, 403);
12732
+ }
12733
+ const destAbs = resolve22(dirname6(src.absolute), newName);
12734
+ const newRel = `${dirname6(src.relative)}/${newName}`.replace(/^\.\//, "");
12735
+ if (isProtectedFromRename(newRel)) {
12736
+ console.error(`[data] file-rename blocked path="${newRel}" reason="protected-target"`);
12737
+ return c.json({ error: "That name is reserved" }, 403);
12738
+ }
12739
+ try {
12740
+ let collision = true;
12741
+ try {
12742
+ await stat4(destAbs);
12743
+ } catch (e) {
12744
+ if (e.code === "ENOENT") collision = false;
12745
+ }
12746
+ if (collision) return c.json({ error: "A file or folder with that name already exists" }, 409);
12747
+ await rename(src.absolute, destAbs);
12748
+ } catch (err) {
12749
+ const code = err.code;
12750
+ if (code === "ENOENT") return c.json({ error: "Not found" }, 404);
12751
+ const message = err instanceof Error ? err.message : String(err);
12752
+ console.error(`[data] file-rename error from="${src.relative}" to="${newRel}" err="${message}"`);
12753
+ return c.json({ error: message }, 500);
12754
+ }
12755
+ console.error(`[data] file-rename from="${src.relative}" to="${newRel}"`);
12756
+ void reconcileFileIndex(accountId).catch((err) => {
12757
+ console.error(`[data] file-rename reconcile-failed account=${accountId.slice(0, 8)}\u2026 err="${err instanceof Error ? err.message : String(err)}"`);
12758
+ });
12759
+ return c.json({ path: newRel });
12760
+ });
12602
12761
  var files_default = app19;
12603
12762
 
12604
12763
  // ../lib/graph-search/src/index.ts
@@ -14938,7 +15097,9 @@ function resolveSpawnPlan(host, operatorDomains, body, mintId = randomUUID10, ad
14938
15097
  }
14939
15098
  function shapeWebchatResponse(sessionId, manager) {
14940
15099
  const outcome = typeof manager?.outcome === "string" ? manager.outcome : "bound";
14941
- return { sessionId, outcome, target: `/chat?session=${sessionId}` };
15100
+ const redirected = manager?.redirected === true && typeof manager?.sessionId === "string";
15101
+ const landed = redirected ? manager.sessionId : sessionId;
15102
+ return { sessionId: landed, outcome, target: `/chat?session=${landed}` };
14942
15103
  }
14943
15104
  var app30 = new Hono();
14944
15105
  app30.post("/", requireAdminSession, async (c) => {
@@ -16101,7 +16262,7 @@ app44.route("/request-magic-link", request_magic_link_default);
16101
16262
  var access_default = app44;
16102
16263
 
16103
16264
  // server/routes/sites.ts
16104
- import { existsSync as existsSync23, readFileSync as readFileSync23, realpathSync as realpathSync5, statSync as statSync10 } from "fs";
16265
+ import { existsSync as existsSync23, readFileSync as readFileSync23, realpathSync as realpathSync5, statSync as statSync11 } from "fs";
16105
16266
  import { resolve as resolve26 } from "path";
16106
16267
  var SAFE_SEG_RE = /^[a-z0-9_][a-z0-9_.-]{0,99}$/i;
16107
16268
  var MIME = {
@@ -16167,7 +16328,7 @@ app45.get("/:rel{.*}", (c) => {
16167
16328
  }
16168
16329
  let stat7;
16169
16330
  try {
16170
- stat7 = existsSync23(filePath) ? statSync10(filePath) : null;
16331
+ stat7 = existsSync23(filePath) ? statSync11(filePath) : null;
16171
16332
  } catch {
16172
16333
  stat7 = null;
16173
16334
  }
@@ -17295,7 +17456,7 @@ async function startFileWatcher(opts = {}) {
17295
17456
  }
17296
17457
 
17297
17458
  // app/lib/migrate-uploads.ts
17298
- import { mkdir as mkdir5, readdir as readdir5, rename, rm as rm3 } from "fs/promises";
17459
+ import { mkdir as mkdir5, readdir as readdir5, rename as rename2, rm as rm3 } from "fs/promises";
17299
17460
  import { dirname as dirname8, relative as relative4, resolve as resolve29 } from "path";
17300
17461
  var ACCOUNT_UUID_RE3 = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
17301
17462
  async function walkFiles(dir) {
@@ -17329,7 +17490,7 @@ async function relocateTree(srcDir, destDir, dataRoot, accountId, session) {
17329
17490
  const suffix = relative4(srcDir, oldAbs);
17330
17491
  const newAbs = resolve29(destDir, suffix);
17331
17492
  await mkdir5(dirname8(newAbs), { recursive: true });
17332
- await rename(oldAbs, newAbs);
17493
+ await rename2(oldAbs, newAbs);
17333
17494
  moved++;
17334
17495
  const oldRel = relative4(dataRoot, oldAbs);
17335
17496
  const newRel = relative4(dataRoot, newAbs);
@@ -17418,7 +17579,7 @@ async function migrateUploads(opts = {}) {
17418
17579
  }
17419
17580
 
17420
17581
  // app/lib/migrate-admin-webchat-sidecars.ts
17421
- import { readdir as readdir6, readFile as readFile6, rename as rename2, writeFile as writeFile5, unlink as unlink3 } from "fs/promises";
17582
+ import { readdir as readdir6, readFile as readFile6, rename as rename3, writeFile as writeFile5, unlink as unlink3 } from "fs/promises";
17422
17583
  import { existsSync as existsSync26 } from "fs";
17423
17584
  import { join as join24 } from "path";
17424
17585
  var ADMIN_ROLE2 = "admin";
@@ -17446,7 +17607,7 @@ async function writeRaw(path2, obj) {
17446
17607
  const tmp = `${path2}.tmp.${process.pid}.${Date.now()}`;
17447
17608
  try {
17448
17609
  await writeFile5(tmp, JSON.stringify(obj, null, 2), "utf8");
17449
- await rename2(tmp, path2);
17610
+ await rename3(tmp, path2);
17450
17611
  } catch (err) {
17451
17612
  try {
17452
17613
  if (existsSync26(tmp)) await unlink3(tmp);
@@ -18581,7 +18742,7 @@ function broadcastAdminShutdown(reason) {
18581
18742
 
18582
18743
  // ../lib/entitlement/src/index.ts
18583
18744
  import { createPublicKey, createHash as createHash5, verify as cryptoVerify } from "crypto";
18584
- import { existsSync as existsSync27, readFileSync as readFileSync26, statSync as statSync11 } from "fs";
18745
+ import { existsSync as existsSync27, readFileSync as readFileSync26, statSync as statSync12 } from "fs";
18585
18746
  import { resolve as resolve30 } from "path";
18586
18747
 
18587
18748
  // ../lib/entitlement/src/canonicalize.ts
@@ -18633,7 +18794,7 @@ function resolveEntitlement(brand, account) {
18633
18794
  if (!existsSync27(entitlementPath)) {
18634
18795
  return logResolved(anonymousFallback("missing"), { reason: "missing" });
18635
18796
  }
18636
- const stat7 = statSync11(entitlementPath);
18797
+ const stat7 = statSync12(entitlementPath);
18637
18798
  const key = memoKey(stat7.mtimeMs, account);
18638
18799
  if (memo && memo.key === key) {
18639
18800
  return memo.result;
@@ -1 +0,0 @@
1
- import{o as e}from"./chunk-CAM3fms7.js";import{c as t,o as n,s as r,t as i,u as a}from"./brand-zL3tAdql.js";import{b as o,c as s,d as c,g as l,l as u,p as d,s as f,t as p,u as m,y as h}from"./OperatorConversations-CDY0jUMb.js";import{i as g,t as ee}from"./useSelectionMode-BZsJuUm-.js";async function _(){try{let e=await fetch(`/api/onboarding/claude-auth`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({action:`logout`})});return e.ok?(await e.json().catch(()=>({})))?.logged_out===!0:(console.error(`[admin-ui] claude-logout http-status=${e.status}`),!1)}catch(e){return console.error(`[admin-ui] claude-logout fetch failed: ${e instanceof Error?e.message:String(e)}`),!1}}var te=t(`archive-restore`,[[`rect`,{width:`20`,height:`5`,x:`2`,y:`3`,rx:`1`,key:`1wp1u1`}],[`path`,{d:`M4 8v11a2 2 0 0 0 2 2h2`,key:`tvwodi`}],[`path`,{d:`M20 8v11a2 2 0 0 1-2 2h-2`,key:`1gkqxj`}],[`path`,{d:`m9 15 3-3 3 3`,key:`1pd0qc`}],[`path`,{d:`M12 12v9`,key:`192myk`}]]),v=t(`archive`,[[`rect`,{width:`20`,height:`5`,x:`2`,y:`3`,rx:`1`,key:`1wp1u1`}],[`path`,{d:`M4 8v11a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8`,key:`1s80jp`}],[`path`,{d:`M10 12h4`,key:`a56b0p`}]]),y=t(`bot`,[[`path`,{d:`M12 8V4H8`,key:`hb8ula`}],[`rect`,{width:`16`,height:`12`,x:`4`,y:`8`,rx:`2`,key:`enze0r`}],[`path`,{d:`M2 14h2`,key:`vft8re`}],[`path`,{d:`M20 14h2`,key:`4cs60a`}],[`path`,{d:`M15 13v2`,key:`1xurst`}],[`path`,{d:`M9 13v2`,key:`rq6x2g`}]]),ne=t(`box`,[[`path`,{d:`M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z`,key:`hh9hay`}],[`path`,{d:`m3.3 7 8.7 5 8.7-5`,key:`g66t2b`}],[`path`,{d:`M12 22V12`,key:`d0xqtd`}]]),b=t(`history`,[[`path`,{d:`M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8`,key:`1357e3`}],[`path`,{d:`M3 3v5h5`,key:`1xhq8a`}],[`path`,{d:`M12 7v5l4 2`,key:`1fdv2h`}]]),x=t(`list-todo`,[[`path`,{d:`M13 5h8`,key:`a7qcls`}],[`path`,{d:`M13 12h8`,key:`h98zly`}],[`path`,{d:`M13 19h8`,key:`c3s6r1`}],[`path`,{d:`m3 17 2 2 4-4`,key:`1jhpwq`}],[`rect`,{x:`3`,y:`4`,width:`6`,height:`6`,rx:`1`,key:`cif1o7`}]]),re=t(`message-square`,[[`path`,{d:`M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z`,key:`18887p`}]]),S=t(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),C=t(`square`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}]]),w=t(`users`,[[`path`,{d:`M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2`,key:`1yyitq`}],[`path`,{d:`M16 3.128a4 4 0 0 1 0 7.744`,key:`16gr8j`}],[`path`,{d:`M22 21v-2a4 4 0 0 0-3-3.87`,key:`kshegd`}],[`circle`,{cx:`9`,cy:`7`,r:`4`,key:`nufk8`}]]),T=e(a(),1),E=n(),D=`maxy-shell-side-px`;function O(){if(typeof window>`u`)return 0;let e=document.querySelector(`.platform > .artefact`)?.getBoundingClientRect();return e&&e.width>0?Math.round(e.width):0}function k(e){if(typeof window>`u`)return e;let t=window.innerWidth,n=Math.max(248,t-480-O());return Math.min(Math.max(e,248),n)}function A(){if(typeof window>`u`)return 264;try{let e=window.localStorage.getItem(D);if(!e)return 264;let t=parseInt(e,10);if(!Number.isFinite(t))return console.warn(`[admin-ui] sidebar-width-parse-failed stored=${JSON.stringify(e)} fallback=264`),264;if(t>=248)return k(t)}catch{}return 264}function ie({targetSelector:e=`.platform`}){let t=(0,T.useRef)(null),[n,r]=(0,T.useState)(()=>A()),i=(0,T.useRef)(n);(0,T.useLayoutEffect)(()=>{let t=document.querySelector(e);!t||!(t instanceof HTMLElement)||(t.style.setProperty(`--side-px`,`${n}px`),i.current=n)},[n,e]);let a=(0,T.useCallback)(()=>{r(e=>{let t=k(e);return t===e?e:t})},[]);(0,T.useEffect)(()=>{a(),window.addEventListener(`resize`,a);let t=document.querySelector(e),n=null;return t instanceof HTMLElement&&(n=new MutationObserver(a),n.observe(t,{attributes:!0,attributeFilter:[`data-artefact`,`class`]})),()=>{window.removeEventListener(`resize`,a),n?.disconnect()}},[a,e]);let o=e=>{e.preventDefault();let n=t.current;if(!n)return;n.setPointerCapture(e.pointerId),n.classList.add(`dragging`);let a=!1,o=e=>{a=!0,r(k(Math.round(e.clientX)))},s=()=>{if(n.releasePointerCapture(e.pointerId),n.classList.remove(`dragging`),window.removeEventListener(`pointermove`,o),window.removeEventListener(`pointerup`,s),!a)return;let t=i.current;try{window.localStorage.setItem(D,String(t))}catch{}console.info(`[admin-ui] sidebar-resize px=${t}`)};window.addEventListener(`pointermove`,o),window.addEventListener(`pointerup`,s)},s=()=>{let e=k(264);r(e);try{window.localStorage.removeItem(D)}catch{}console.info(`[admin-ui] sidebar-resize px=${e}`)};return(0,E.jsx)(`div`,{ref:t,className:`side-resize-handle`,role:`separator`,"aria-orientation":`vertical`,"aria-label":`Resize sidebar`,onPointerDown:o,onDoubleClick:s})}var j=[`whatsapp`,`telegram`];function M(e){if(e<60)return`${e}s`;let t=Math.floor(e/60),n=e%60;return n>0?`${t}m ${n}s`:`${t}m`}function ae(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}var N=`auth-refresh-failed`;function oe({error:e,onClose:t}){if(!e)return null;let n=e.reason===N,r=n?`Claude sign-in expired`:`Session didn’t open`,i=n?`Your claude.ai login has expired. Re-authenticate to resume sessions.`:`The session did not bind within 60 seconds, so there is no live conversation to open.`;return(0,E.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,E.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Session could not be opened`,children:[(0,E.jsxs)(`div`,{className:`claude-info-header`,children:[(0,E.jsx)(`span`,{children:r}),(0,E.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:`✕`})]}),(0,E.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[i,(0,E.jsxs)(`div`,{className:`claude-info-row`,style:{marginTop:`8px`},children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Reason`}),(0,E.jsx)(`span`,{className:`claude-info-value`,children:e.reason})]}),e.sessionId&&(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,E.jsxs)(`span`,{className:`claude-info-value`,children:[e.sessionId.slice(0,8),`…`]})]})]})]})})}function se(e){let{show:t,onClose:n,claudeInfo:r,messages:i,sessionElapsed:a,sessionId:o,cacheKey:s}=e,[c,l]=(0,T.useState)(null);if(!t)return null;let u=i.flatMap(e=>e.events?.filter(e=>e.type===`usage`)??[]),d=u.at(-1),f=d?.peak_request_pct==null?d?.context_window?Math.round((d.input_tokens+d.cache_creation_tokens+d.cache_read_tokens)/d.context_window*100):0:Math.round(d.peak_request_pct*100),p=u.reduce((e,t)=>e+t.input_tokens+t.cache_creation_tokens+t.cache_read_tokens+t.output_tokens,0),m=i.flatMap(e=>e.events?.filter(e=>e.type===`rate_limit`)??[]).at(-1),h=u.reduce((e,t)=>e+(t.total_cost_usd??0),0),g=r?.account?.subscriptionType,_=e=>{let t=e*1e3-Date.now();if(t<=0)return`now`;let n=Math.floor(t/36e5),r=Math.floor(t%36e5/6e4);return n>0?`${n}h ${r}m`:`${r}m`};return(0,E.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,E.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),children:[(0,E.jsxs)(`div`,{className:`claude-info-header`,children:[(0,E.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`claude-info-icon`}),(0,E.jsx)(`span`,{children:`Claude Code`}),(0,E.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,E.jsxs)(`div`,{className:`claude-info-section`,children:[(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Version`}),(0,E.jsx)(`span`,{className:`claude-info-value`,children:r?r.version:`…`})]}),(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Email`}),(0,E.jsx)(`span`,{className:`claude-info-value`,children:r?.account?.email??`…`})]})]}),(g||m||h>0)&&(0,E.jsxs)(`div`,{className:`claude-info-section`,children:[g&&(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Plan`}),(0,E.jsx)(`span`,{className:`claude-info-value`,style:{textTransform:`capitalize`},children:g})]}),m&&(0,E.jsxs)(E.Fragment,{children:[(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Usage`}),(0,E.jsxs)(`span`,{className:`claude-info-value`,children:[Math.round(m.utilization*100),`%`]})]}),(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Resets in`}),(0,E.jsx)(`span`,{className:`claude-info-value`,children:_(m.resetsAt)})]}),m.isUsingOverage&&(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Overage`}),(0,E.jsx)(`span`,{className:`claude-info-value`,children:`Active`})]})]}),h>0&&(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Session cost`}),(0,E.jsxs)(`span`,{className:`claude-info-value`,children:[`$`,h<.01?h.toFixed(4):h.toFixed(2)]})]})]}),(0,E.jsxs)(`div`,{className:`claude-info-section`,children:[(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Model`}),(0,E.jsx)(`span`,{className:`claude-info-value`,children:r?.model??`…`})]}),(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Context used`}),(0,E.jsx)(`span`,{className:`claude-info-value`,children:f>0?`${f}%`:`—`})]}),(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Tokens`}),(0,E.jsx)(`span`,{className:`claude-info-value`,children:p>0?ae(p):`—`})]}),(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,E.jsx)(`span`,{className:`claude-info-value`,children:M(a)})]}),(o||s)&&(()=>{let e=o??s??``;return(0,E.jsxs)(`div`,{className:`claude-info-row`,children:[(0,E.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,E.jsx)(`button`,{type:`button`,className:`claude-info-value claude-info-id-copy`,title:`${e} (${o?`flushed`:`pre-flush`}) — click to copy`,onClick:async()=>{l(await ee(e)?`copied`:`failed`),setTimeout(()=>l(null),1200)},children:c===`copied`?`copied ✓`:c===`failed`?`copy failed ✕`:`${e.slice(0,8)}…`})]})})()]})]})})}var P=`https://claude.ai/code`,ce=[500,1e3,1500,2e3,2500,3e3,3e3];function le(e,t,n){if(e&&n.target)return{kind:`navigate`,url:n.target};let r=n.slug??n.bridgeSessionId??null;if(e&&r)return{kind:`navigate`,url:`${P}/${r}`};let i=n.reason||n.error||`status ${t}`;return{kind:`error`,sessionId:n.sessionId??null,reason:i}}function ue(e){if(!e)return``;let t=Date.parse(e);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:`medium`,timeStyle:`short`}):``}function de(e){let{businessName:t,cacheKey:n,role:a,userName:c,userAvatar:p,onSelectProjects:ee,onSelectPeople:_,onSelectTasks:D,onSelectAgents:O,onCloseMobileDrawer:k,collapsed:A,selectedWhatsappId:ie,onSelectWhatsappConversation:M,initialWhatsappSurface:ae=!1}=e,N=d(n),se=i.productName,P=typeof c==`string`?c:c===null?`name unavailable`:t||se,de=(P.trim().charAt(0)||`?`).toUpperCase(),[F,I]=(0,T.useState)(ae?`whatsapp`:`sessions`),[L,me]=(0,T.useState)([]),[R,he]=(0,T.useState)(!1),[z,B]=(0,T.useState)(null),[V,ge]=(0,T.useState)(!1),[H,_e]=(0,T.useState)(`file`),[U,W]=(0,T.useState)(null),[ve,G]=(0,T.useState)(null),[K,ye]=(0,T.useState)([]),[q,be]=(0,T.useState)(!1),[xe,Se]=(0,T.useState)(null),[Ce,we]=(0,T.useState)(!1),[Te,Ee]=(0,T.useState)(!1),[De,Oe]=(0,T.useState)(!1),[ke,Ae]=(0,T.useState)(null),[je,Me]=(0,T.useState)(new Set),[Ne,Pe]=(0,T.useState)(new Set),[Fe,Ie]=(0,T.useState)(new Set),[Le,Re]=(0,T.useState)(new Set),[J,ze]=(0,T.useState)(!1),[Be,Ve]=(0,T.useState)([]),[He,Ue]=(0,T.useState)(!1),[We,Ge]=(0,T.useState)(null),[Y,Ke]=(0,T.useState)(`whatsapp`),qe=(0,T.useCallback)(e=>{if(k(),!n){console.error(`[admin-ui] artefact-download-blocked id=${e.id} reason=no-cache-key`),W({message:`Session not ready — try again`,failed:!0});return}if(!e.downloadPath){console.error(`[admin-ui] artefact-download-blocked id=${e.id} reason=not-downloadable`),W({message:`${e.name} can’t be downloaded`,failed:!0});return}console.info(`[admin-ui] artefact-download id=${e.id} root=${e.downloadRoot??`data`} path=${e.downloadPath}`),f(n,e.downloadPath,e.downloadRoot??`data`),W({message:`Downloading ${e.name}`,failed:!1})},[n,k]);(0,T.useEffect)(()=>{if(!U)return;let e=setTimeout(()=>W(null),2500);return()=>clearTimeout(e)},[U]);let Je=(0,T.useCallback)(async()=>{if(n){ge(!0),B(null);try{let e=await N(`/api/admin/sidebar-artefacts`);if(!e.ok)throw Error(`status ${e.status}`);me((await e.json()).artefacts??[]),he(!0)}catch(e){let t=e instanceof Error?e.message:String(e);B(`Failed to load artefacts: ${t}`),console.error(`[admin-ui] sidebar-artefacts fetch failed: ${t}`)}finally{ge(!1)}}},[n,N]),X=(0,T.useCallback)(async()=>{if(!n)return null;we(!0),Se(null);try{let e=await N(`/api/admin/sidebar-sessions`);if(!e.ok)throw Error(`status ${e.status}`);let t=await e.json(),n=t.sessions??[];return ye(n),Ae(t.accountId??null),be(!0),n}catch(e){let t=e instanceof Error?e.message:String(e);return Se(`Failed to load sessions: ${t}`),console.error(`[admin-ui] sidebar-sessions fetch failed: ${t}`),null}finally{we(!1)}},[n,N]),Z=(0,T.useCallback)(async()=>{if(n){Ge(null);try{let e=await N(`/api/whatsapp-reader/conversations`);if(!e.ok)throw Error(`status ${e.status}`);Ve((await e.json()).conversations??[]),Ue(!0)}catch(e){let t=e instanceof Error?e.message:String(e);Ge(`Couldn't load conversations.`),console.error(`[admin-ui] channel-convos fetch failed: ${t}`)}}},[n,N]);(0,T.useEffect)(()=>{!n||q||X()},[n,q,X]),(0,T.useEffect)(()=>{if(!n)return;let e=null;return Z(),e=setInterval(()=>{Z()},fe),()=>{e!==null&&clearInterval(e)}},[n,Z]);let Q=(0,T.useMemo)(()=>{let e=new Map;for(let t of j)e.set(t,[]);for(let t of Be)e.get(t.channel)?.push(t);for(let t of j)console.info(`[admin-ui] sidebar-nav surface=${t} count=${e.get(t).length}`);return e},[Be]),Ye={whatsapp:`WhatsApp`,telegram:`Telegram`,webchat:`Webchat`},Xe=()=>{M(null),I(`artefacts`),console.info(`[admin-ui] sidebar-nav surface=artefacts count=${R?L.length:0} collapsed=${A}`),Je()},$=1.5,Ze=()=>{console.info(`[admin-ui] sidebar-refresh surface=artefacts`),Je()},Qe=()=>{M(null),I(`sessions`),console.info(`[admin-ui] sidebar-nav surface=sessions count=${q?K.length:0} collapsed=${A}`),q||X()},$e=()=>{console.info(`[admin-ui] sidebar-refresh surface=sessions`),X()},et=e=>{I(`whatsapp`),Ke(e),console.info(`[admin-ui] sidebar-nav surface=${e} count=${Q.get(e)?.length??0} collapsed=${A}`)},tt=(0,T.useCallback)(async e=>{if(e.resumable===!1||Ne.has(e.sessionId))return;Pe(t=>{let n=new Set(t);return n.add(e.sessionId),n});let t=window.open(``,`_blank`);try{let n=await N(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId,name:e.title||e.sessionId})}),r=await n.json().catch(()=>({})),i=le(n.ok,n.status,{...r,sessionId:r.sessionId??e.sessionId});console.info(`[admin-ui] sidebar-session-resume sessionId=${e.sessionId} status=${n.status} outcome=${i.kind} slug=${r.slug??r.bridgeSessionId??`none`}`),i.kind===`navigate`?(k(),t?t.location.href=i.url:window.open(i.url,`_blank`)):(t?.close(),console.error(`[admin-ui] sidebar-session-resume-failed sessionId=${e.sessionId} status=${n.status} reason=${i.reason}`),G(i))}catch(n){t?.close();let r=n instanceof Error?n.message:String(n);console.error(`[admin-ui] sidebar-session-resume-failed sessionId=${e.sessionId} error=${r}`),G({sessionId:e.sessionId,reason:r})}finally{Pe(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}},[N,k,Ne]),nt=(0,T.useCallback)(async e=>{let t=e.slice(0,8);for(let n=1;n<=ce.length;n++){await new Promise(e=>setTimeout(e,ce[n-1]));let r=await X();if(r&&r.some(t=>t.sessionId===e)){console.info(`[admin-ui] sidebar-new-session-converged sessionId=${t} via=retry attempts=${n}`);return}}console.error(`[admin-ui] sidebar-new-session-converge-timeout sessionId=${t}`)},[X]),rt=(0,T.useCallback)(async()=>{if(J)return;ze(!0);let e=window.open(``,`_blank`);try{let t=await N(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({})}),n=await t.json().catch(()=>({})),r=le(t.ok,t.status,n);console.info(`[admin-ui] sidebar-new-session-spawned status=${t.status} outcome=${r.kind} slug=${n.slug??n.bridgeSessionId??`none`}`),r.kind===`navigate`?(e?e.location.href=r.url:window.open(r.url,`_blank`),n.sessionId?nt(n.sessionId):console.error(`[admin-ui] sidebar-new-session-converge-skipped reason=no-session-id`)):(e?.close(),console.error(`[admin-ui] sidebar-new-session-failed status=${t.status} reason=${r.reason}`),G(r))}catch(t){e?.close();let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-new-session-failed error=${n}`),G({sessionId:null,reason:n})}finally{ze(!1)}},[N,J,nt]),it=(0,T.useCallback)(async(e,t)=>{if(e.stopPropagation(),!je.has(t.sessionId)){Me(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await N(`/api/admin/session-delete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:t.sessionId})});if(!e.ok){let n=await e.json().catch(()=>({}));console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${t.sessionId} status=${e.status} error=${n.error??`unknown`}`),W({message:`Delete failed: ${n.error??`status ${e.status}`}`,failed:!0});return}let n=await e.json();console.info(`[admin-ui] sidebar-session-delete sessionId=${t.sessionId} pidKilled=${n.pidKilled??`?`} deleted=${n.deleted??`?`}`),ye(e=>e.filter(e=>e.sessionId!==t.sessionId)),X()}catch(e){let n=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${t.sessionId} error=${n}`),W({message:`Delete failed: ${n}`,failed:!0})}finally{Me(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[N,je,X]),at=(0,T.useCallback)(async(e,t)=>{if(e.stopPropagation(),!Fe.has(t.sessionId)){Ie(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await N(`/api/admin/session-stop`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:t.sessionId})});if(!e.ok){let n=await e.json().catch(()=>({}));console.error(`[admin-ui] sidebar-session-stop-failed sessionId=${t.sessionId} status=${e.status} error=${n.error??`unknown`}`),W({message:`Stop failed: ${n.error??`status ${e.status}`}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-stop sessionId=${t.sessionId}`),X()}catch(e){let n=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-session-stop-failed sessionId=${t.sessionId} error=${n}`),W({message:`Stop failed: ${n}`,failed:!0})}finally{Ie(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[N,Fe,X]),ot=(0,T.useCallback)(async(e,t,n)=>{if(e.stopPropagation(),!Le.has(t.sessionId)){Re(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await N(`/api/admin/session-archive`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:t.sessionId,mode:n})});if(!e.ok){let r=await e.json().catch(()=>({})),i=r.detail??r.error??`status ${e.status}`;console.error(`[admin-ui] sidebar-session-archive-failed sessionId=${t.sessionId} mode=${n} status=${e.status} error=${r.error??`unknown`}`),W({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${i}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-archive sessionId=${t.sessionId} mode=${n}`),X()}catch(e){let r=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-session-archive-failed sessionId=${t.sessionId} mode=${n} error=${r}`),W({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${r}`,failed:!0})}finally{Re(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[N,Le,X]);return(0,E.jsxs)(`aside`,{className:`side`,children:[(0,E.jsx)(`div`,{className:`side-new-session-row`,children:(0,E.jsxs)(`button`,{type:`button`,className:`side-new-session`,onClick:rt,disabled:J,"aria-busy":J,children:[(0,E.jsx)(S,{size:14}),(0,E.jsx)(`span`,{children:J?`Spawning…`:`New session`})]})}),(0,E.jsxs)(`nav`,{className:`side-nav`,children:[(0,E.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=people`),_(),k()},children:[(0,E.jsx)(w,{size:20,strokeWidth:$}),(0,E.jsx)(`span`,{className:`label`,children:`People`}),(0,E.jsx)(`span`,{className:`kbd`})]}),(0,E.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=agents`),O(),k()},children:[(0,E.jsx)(y,{size:20,strokeWidth:$}),(0,E.jsx)(`span`,{className:`label`,children:`Agents`}),(0,E.jsx)(`span`,{className:`kbd`})]}),(0,E.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=projects`),ee(),k()},children:[(0,E.jsx)(ne,{size:20,strokeWidth:$}),(0,E.jsx)(`span`,{className:`label`,children:`Projects`}),(0,E.jsx)(`span`,{className:`kbd`})]}),(0,E.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=tasks`),D(),k()},children:[(0,E.jsx)(x,{size:20,strokeWidth:$}),(0,E.jsx)(`span`,{className:`label`,children:`Tasks`}),(0,E.jsx)(`span`,{className:`kbd`})]}),(0,E.jsxs)(`button`,{type:`button`,className:`nav-row${F===`artefacts`?` active`:``}`,onClick:Xe,children:[(0,E.jsx)(g,{size:20,strokeWidth:$}),(0,E.jsx)(`span`,{className:`label`,children:`Artefacts`}),(0,E.jsx)(`span`,{className:`kbd`})]}),(0,E.jsxs)(`button`,{type:`button`,className:`nav-row${F===`sessions`?` active`:``}`,onClick:Qe,children:[(0,E.jsx)(b,{size:20,strokeWidth:$}),(0,E.jsx)(`span`,{className:`label`,children:`Sessions`}),(0,E.jsx)(`span`,{className:`kbd`})]}),He&&j.filter(e=>Q.get(e).length>0).map(e=>(0,E.jsxs)(`button`,{type:`button`,className:`nav-row${F===`whatsapp`&&Y===e?` active`:``}`,onClick:()=>et(e),children:[(0,E.jsx)(u,{channel:e,size:16}),(0,E.jsx)(`span`,{className:`label`,children:Ye[e]}),(0,E.jsx)(`span`,{className:`kbd`})]},e)),We&&(0,E.jsx)(`div`,{className:`nav-row`,style:{color:`var(--text-tertiary)`,cursor:`default`},"aria-disabled":`true`,children:(0,E.jsx)(`span`,{className:`label`,children:We})})]}),F===`artefacts`&&(0,E.jsxs)(`div`,{className:`side-list`,children:[(0,E.jsxs)(`div`,{className:`group-head`,children:[(0,E.jsx)(`span`,{children:`Artefacts`}),(0,E.jsxs)(`span`,{className:`group-head-meta`,children:[(0,E.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh artefacts`,"aria-label":`Refresh artefacts`,onClick:Ze,disabled:V,children:(0,E.jsx)(l,{size:12,className:V?`spinning`:void 0})}),(0,E.jsx)(`span`,{children:V?`…`:String(L.length)})]})]}),z&&(0,E.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:z}),R&&!z&&L.length>0&&(()=>{let e=L.filter(e=>e.kind===`agent-template`).length,t=L.length-e;return(0,E.jsx)(`div`,{className:`artefact-filter-chips`,children:[{key:`all`,label:`All`,count:L.length},{key:`agent`,label:`Agents`,count:e},{key:`file`,label:`Files`,count:t}].map(e=>(0,E.jsxs)(`button`,{type:`button`,className:`artefact-filter-chip${H===e.key?` active`:``}`,onClick:()=>_e(e.key),disabled:e.count===0&&e.key!==`all`,children:[e.label,(0,E.jsx)(`span`,{className:`artefact-filter-chip-count`,children:e.count})]},e.key))})})(),R&&!z&&L.length===0&&(0,E.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No artefacts yet`}),L.filter(e=>H===`all`?!0:H===`agent`?e.kind===`agent-template`:e.kind!==`agent-template`).map(e=>{let t=e.kind===`agent-template`,n=t?y:g,r=ue(e.updatedAt),i=e.downloadPath!==null;return(0,E.jsxs)(`button`,{type:`button`,className:`conv`,onClick:()=>qe(e),disabled:!i,style:i?void 0:{cursor:`default`},title:i?`Download ${e.name}`:`${e.name} can’t be downloaded`,children:[(0,E.jsx)(n,{size:14,className:`conv-icon`,"data-kind":t?`agent`:`file`,"aria-label":t?`agent template`:`file`}),(0,E.jsxs)(`span`,{className:`conv-stack`,children:[(0,E.jsx)(`span`,{className:`conv-name-line`,children:(0,E.jsx)(`span`,{className:`conv-name`,children:e.name})}),r&&(0,E.jsx)(`span`,{className:`conv-timestamp`,children:r})]}),i&&(0,E.jsx)(o,{size:12,className:`conv-rc-icon`,"aria-hidden":`true`})]},e.id)})]}),F===`sessions`&&(()=>{let e=K.filter(e=>Te?!0:!e.isSubagent).filter(e=>De?!0:!e.archived),t=K.some(e=>e.isSubagent),n=K.some(e=>e.archived);return(0,E.jsxs)(`div`,{className:`side-list`,children:[(0,E.jsxs)(`div`,{className:`group-head`,children:[(0,E.jsx)(`span`,{children:`Sessions`}),(0,E.jsxs)(`span`,{className:`group-head-meta`,children:[(0,E.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh sessions`,"aria-label":`Refresh sessions`,onClick:$e,disabled:Ce,children:(0,E.jsx)(l,{size:12,className:Ce?`spinning`:void 0})}),(0,E.jsx)(`span`,{children:Ce?`…`:String(e.length)})]})]}),ke&&(0,E.jsx)(`div`,{className:`side-account-id`,title:`This install's accountId. The first 8 characters match the truncated UUID label on the live Remote Control daemon entry in claude.ai/code.`,children:(0,E.jsx)(`code`,{children:ke})}),(t||n)&&(0,E.jsxs)(`div`,{className:`artefact-filter-chips`,children:[t&&(0,E.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${Te?` active`:``}`,onClick:()=>Ee(e=>!e),title:Te?`Hide subagent sessions`:`Show subagent sessions`,children:`Subagents`}),n&&(0,E.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${De?` active`:``}`,onClick:()=>Oe(e=>!e),title:De?`Hide archived sessions`:`Show archived sessions`,children:`Archived`})]}),xe&&(0,E.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:xe}),q&&!xe&&e.length===0&&(0,E.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No sessions yet`}),e.map(e=>{let t=ue(e.startedAt),n=Ne.has(e.sessionId),i=je.has(e.sessionId),a=Fe.has(e.sessionId),o=Le.has(e.sessionId);return(0,E.jsxs)(`div`,{className:`conv conv-with-actions`,children:[(0,E.jsxs)(`div`,{className:`conv-main-static`,children:[(0,E.jsx)(`span`,{className:`conv-live-dot`,"data-live":e.live?`1`:`0`,"aria-label":e.live?`live session`:`ended session`}),(0,E.jsxs)(`span`,{className:`conv-stack`,children:[(0,E.jsxs)(`span`,{className:`conv-name-line`,children:[e.channel&&(0,E.jsx)(m,{channel:e.channel,size:13}),(0,E.jsx)(`span`,{className:`conv-name`,title:e.personName??e.title,children:e.personName??e.title})]}),(0,E.jsxs)(`span`,{className:`conv-timestamp`,children:[(0,E.jsx)(`code`,{className:`conv-session-id`,title:`First 8 characters of this session's id — distinguishes rows with identical auto-titles. The resume/delete buttons act on the full id.`,children:e.sessionId.slice(0,8)}),t&&(0,E.jsxs)(`span`,{children:[` · `,t]})]})]})]}),(0,E.jsxs)(`div`,{className:`conv-actions`,children:[e.resumable===!1?(0,E.jsx)(`span`,{className:`conv-ephemeral`,title:`Public webchat session — ephemeral, not resumable`,"aria-label":`Ephemeral public session (not resumable)`,children:(0,E.jsx)(b,{size:12})}):(0,E.jsxs)(E.Fragment,{children:[(0,E.jsx)(`button`,{type:`button`,className:`conv-action`,onClick:()=>{tt(e)},disabled:n||i||a||o,"aria-busy":n,"aria-label":`Resume session ${e.title} in claude.ai/code`,title:`Resume in a fresh local Remote Control PTY`,children:(0,E.jsx)(h,{size:12})}),(0,E.jsx)(`button`,{type:`button`,className:`conv-action`,onClick:()=>{window.location.assign(`/chat?session=${e.sessionId}`)},disabled:n||i||a||o,"aria-label":`Open session ${e.title} in admin webchat`,title:`Open in admin webchat (/chat) — sending resumes this session`,children:(0,E.jsx)(re,{size:12})})]}),e.live?(0,E.jsx)(`button`,{type:`button`,className:`conv-action`,onClick:t=>{at(t,e)},disabled:n||i||a||o,"aria-busy":a,"aria-label":`Stop session ${e.title}`,title:`Stop session process (keeps the conversation, can resume later)`,children:(0,E.jsx)(C,{size:12})}):null,e.archived?(0,E.jsx)(`button`,{type:`button`,className:`conv-action`,onClick:t=>{ot(t,e,`unarchive`)},disabled:n||i||a||o,"aria-busy":o,"aria-label":`Unarchive session ${e.title}`,title:`Unarchive (move back to the active list)`,children:(0,E.jsx)(te,{size:12})}):(0,E.jsx)(`button`,{type:`button`,className:`conv-action`,onClick:t=>{ot(t,e,`archive`)},disabled:n||i||a||o,"aria-busy":o,"aria-label":`Archive session ${e.title}`,title:`Archive (hide from the list, keeps the conversation resumable)`,children:(0,E.jsx)(v,{size:12})}),(0,E.jsx)(`button`,{type:`button`,className:`conv-action conv-action-danger`,onClick:t=>{it(t,e)},disabled:n||i||a||o,"aria-busy":i,"aria-label":`Delete session ${e.title}`,title:`Delete session (stops the process, removes the conversation)`,children:(0,E.jsx)(r,{size:12})})]})]},e.sessionId)})]})})(),F===`whatsapp`&&(0,E.jsxs)(`div`,{className:`side-list`,children:[(0,E.jsxs)(`div`,{className:`group-head`,children:[(0,E.jsx)(`span`,{children:Ye[Y]}),(0,E.jsxs)(`span`,{className:`group-head-meta`,children:[(0,E.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh conversations`,"aria-label":`Refresh conversations`,onClick:()=>{Z()},children:(0,E.jsx)(l,{size:12})}),(0,E.jsx)(`span`,{children:String(Q.get(Y).length)})]})]}),Q.get(Y).map(e=>{let t=ue(e.lastMessageAt);return(0,E.jsxs)(`button`,{type:`button`,className:`conv${ie===e.sessionId?` active`:``}`,onClick:()=>{M(e),k()},title:e.title,children:[(0,E.jsx)(u,{channel:e.channel,size:14}),(0,E.jsxs)(`span`,{className:`conv-stack`,children:[(0,E.jsxs)(`span`,{className:`conv-name-line`,children:[(0,E.jsx)(`span`,{className:`conv-name`,children:s(e)}),e.role===`public`&&(0,E.jsx)(`span`,{className:`conv-tag conv-tag-public`,children:`Public`})]}),t&&(0,E.jsx)(`span`,{className:`conv-timestamp`,children:t})]})]},e.sessionId)})]}),(0,E.jsx)(pe,{}),(0,E.jsxs)(`div`,{className:`side-foot`,children:[(0,E.jsx)(`div`,{className:`avatar`,children:p?(0,E.jsx)(`img`,{src:p,alt:P}):de}),(0,E.jsxs)(`div`,{className:`who`,children:[(0,E.jsx)(`span`,{className:`name`,children:P}),(0,E.jsx)(`span`,{className:`role`,children:a??`operator`})]})]}),U&&(0,E.jsx)(`div`,{className:`copy-toast${U.failed?` copy-toast-failed`:``}`,role:`status`,children:U.message}),(0,E.jsx)(oe,{error:ve,onClose:()=>G(null)})]})}var F=5e3,fe=3e4;function pe(){let[e,t]=(0,T.useState)(null);if((0,T.useEffect)(()=>{let e=!1,n=null;async function r(){try{let n=await fetch(`/api/admin/system-stats`);if(!n.ok){console.error(`[admin-ui] system-stats-fetch-failed status=${n.status}`);return}let r=await n.json();e||t(r)}catch(e){console.error(`[admin-ui] system-stats-fetch-failed reason=${e instanceof Error?e.message:String(e)}`)}}function i(){n===null&&(r(),n=setInterval(()=>{r()},F))}function a(){n!==null&&(clearInterval(n),n=null)}function o(){document.hidden?a():i()}return document.hidden||i(),document.addEventListener(`visibilitychange`,o),()=>{e=!0,a(),document.removeEventListener(`visibilitychange`,o)}},[]),!e||e.platform===`darwin`)return null;let n=e.cpuPct,r=e.memUsedPct,i=n!==null&&n>=.9,a=n!==null&&n>=.98,o=r!==null&&r>=.9,s=r!==null&&r>=.98,c=i||o,l=a||s,u=e=>e===null?`—`:`${Math.round(e*100)}%`,d=e=>{if(e===null)return{width:`0%`,background:`var(--text-tertiary)`};let t=Math.min(1,Math.max(0,e)),n=Math.round(140*(1-t));return{width:`${Math.round(t*100)}%`,background:`hsl(${n}, 65%, 45%)`}},f=[`system-stats`];return c&&f.push(`system-stats--warn`),l&&f.push(`system-stats--crit`),(0,E.jsxs)(`div`,{className:f.join(` `),role:`status`,"aria-label":`host CPU and RAM`,children:[(0,E.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,E.jsxs)(`span`,{className:i?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`CPU `,u(n)]}),(0,E.jsx)(`div`,{className:`system-stats__bar`,children:(0,E.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(n)})})]}),(0,E.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,E.jsxs)(`span`,{className:o?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`RAM `,u(r)]}),(0,E.jsx)(`div`,{className:`system-stats__bar`,children:(0,E.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(r)})})]})]})}var I=`admin-sidebar-collapsed`,L=`admin-sidebar-drawer-open`;function me(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(I)===`1`}catch{return!1}}function R(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(I,`1`):window.sessionStorage.removeItem(I)}catch{}}function he(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(L)===`1`}catch{return!1}}function z(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(L,`1`):window.sessionStorage.removeItem(L)}catch{}}var B=720;function V(e,t){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?wa=${encodeURIComponent(t.sessionId)}&projectDir=${encodeURIComponent(t.projectDir)}`}}function ge(e,t){if(e!==`/`)return null;let n=new URLSearchParams(t),r=n.get(`wa`),i=n.get(`projectDir`);return!r||!i?null:{sessionId:r,projectDir:i,title:``,senderId:null,startedAt:``,channel:`whatsapp`,role:`admin`,operatorName:null,whatsappName:null,lastMessageAt:null,modelGated:!1}}function H(e,t){return t===`operator`&&e===`chat`||e===`dashboard`?`/`:e===`data`?`/data`:e===`graph`?`/graph`:e===`chat`?`/chat`:`/browser`}function _e(e){let{cacheKey:t,businessName:n,variant:r=`admin`,onLogout:i,onDisconnect:a,disconnecting:o,userName:s,userAvatar:l,role:u,children:d,footer:f}=e,[m,h]=(0,T.useState)(()=>me()),[g,ee]=(0,T.useState)(()=>he()),[_,te]=(0,T.useState)(()=>typeof window<`u`&&window.matchMedia(`(max-width: ${B}px)`).matches),[v,y]=(0,T.useState)(()=>typeof window>`u`?null:ge(window.location.pathname,window.location.search)),[ne]=(0,T.useState)(()=>v!==null);(0,T.useEffect)(()=>{if(typeof window>`u`)return;let e=window.matchMedia(`(max-width: ${B}px)`),t=e=>te(e.matches);return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let b=(0,T.useCallback)(e=>{R(e),h(e)},[]),x=(0,T.useCallback)(e=>{z(e),ee(e)},[]);(0,T.useEffect)(()=>{if(typeof window>`u`)return;let e=window.location?.pathname??``;console.info(`[admin-ui] shell-mount route=${e} variant=${r} sidebar=${r===`operator`?`none`:`present`} collapsed=${m} drawer=${g}`)},[]),(0,T.useEffect)(()=>{typeof window>`u`||!v||(console.info(`[admin-ui] wa-hydrate route=/ sessionId=${v.sessionId.slice(0,8)}`),window.history.replaceState(null,``,`/`))},[]);let re=(0,T.useCallback)(e=>{if(e===null){y(null);return}let t=typeof window<`u`?window.location.pathname:`/`,n=V(t,e);console.info(`[admin-ui] wa-open route=${t} via=${n.via} sessionId=${e.sessionId.slice(0,8)}`),n.via===`in-place`?y(e):window.location.href=n.href},[]),S=_?g:!m,C=(0,T.useCallback)(()=>{if(!(typeof window>`u`))if(window.matchMedia(`(max-width: ${B}px)`).matches){let e=g;console.info(`[admin-ui] header-sidebar-toggle from=${e?`open`:`closed`} mode=drawer`),x(!e)}else{let e=m;console.info(`[admin-ui] header-sidebar-toggle from=${e?`closed`:`open`} mode=collapse`),b(!e)}},[m,g,b,x]),w=(0,T.useCallback)(e=>{let t=H(e,r);console.info(`[admin-ui] header-menu-nav target=${e} dest=${t}`),window.location.href=t},[r]),[D,O]=(0,T.useState)(`chat`),[k,A]=(0,T.useState)([]);(0,T.useEffect)(()=>{if(r!==`operator`||!t)return;let e=!1;return fetch(`/api/whatsapp-reader/conversations?session_key=${encodeURIComponent(t)}`).then(e=>e.ok?e.json():{conversations:[]}).then(t=>{e||A(t.conversations??[])}).catch(()=>{}),()=>{e=!0}},[r,t]);let j=(0,T.useMemo)(()=>[...new Set(k.map(e=>e.channel))],[k]),M={collapsed:m,mobileDrawerOpen:g,sidebarOpen:S,onToggleSidebar:C,setMobileDrawerOpen:x,selectedWhatsapp:v,onClearWhatsapp:()=>y(null)};return r===`operator`?(0,E.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,E.jsx)(c,{businessName:n,variant:r,onNavigate:w,conversationsCount:k.length,conversationsChannels:j,onOpenConversations:()=>O(`conversations`),onToggleSidebar:C,sidebarOpen:S,onLogout:i,onDisconnect:a,disconnecting:o}),(0,E.jsx)(`div`,{className:`platform platform-operator`,children:D===`conversations`?(0,E.jsx)(p,{conversations:k,sessionKey:t??``,onBack:()=>O(`chat`)}):typeof d==`function`?d(M):d}),f]}):(0,E.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,E.jsx)(c,{businessName:n,variant:r,onNavigate:w,onToggleSidebar:C,sidebarOpen:S,onLogout:i,onDisconnect:a,disconnecting:o}),(0,E.jsxs)(`div`,{className:`platform${g?` menu-open`:``}${m?` sidebar-collapsed`:``}`,"data-artefact":`closed`,children:[(0,E.jsx)(de,{businessName:n,cacheKey:t,role:u??null,userName:s,userAvatar:l??null,onSelectProjects:()=>{window.location.href=`/graph?label=Project`},onSelectPeople:()=>{window.location.href=`/graph?label=Person`},onSelectTasks:()=>{window.location.href=`/graph?label=Task`},onSelectAgents:()=>{window.location.href=`/graph?label=Agent`},onCloseMobileDrawer:()=>x(!1),collapsed:m,mobileDrawerOpen:g,selectedWhatsappId:v?.sessionId??null,onSelectWhatsappConversation:re,initialWhatsappSurface:ne}),!_&&(0,E.jsx)(ie,{}),typeof d==`function`?d(M):d]}),g&&(0,E.jsx)(`div`,{className:`sidebar-backdrop menu-open`,"aria-hidden":`true`,onClick:()=>x(!1)}),f]})}export{x as a,S as i,se as n,y as o,w as r,_ as s,_e as t};