@rubytech/create-maxy-code 0.1.320 → 0.1.322

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 (71) hide show
  1. package/dist/index.js +82 -1
  2. package/package.json +1 -1
  3. package/payload/platform/lib/embed-client/dist/index.d.ts +2 -0
  4. package/payload/platform/lib/embed-client/dist/index.d.ts.map +1 -1
  5. package/payload/platform/lib/embed-client/dist/index.js +50 -10
  6. package/payload/platform/lib/embed-client/dist/index.js.map +1 -1
  7. package/payload/platform/lib/embed-client/src/index.ts +57 -9
  8. package/payload/platform/lib/models/dist/index.d.ts +6 -0
  9. package/payload/platform/lib/models/dist/index.d.ts.map +1 -1
  10. package/payload/platform/lib/models/dist/index.js +9 -0
  11. package/payload/platform/lib/models/dist/index.js.map +1 -1
  12. package/payload/platform/lib/models/src/index.ts +9 -0
  13. package/payload/platform/plugins/admin/skills/platform-architecture/SKILL.md +11 -7
  14. package/payload/platform/plugins/docs/references/admin-ui.md +5 -4
  15. package/payload/platform/plugins/docs/references/deployment.md +1 -0
  16. package/payload/platform/plugins/docs/references/internals.md +2 -0
  17. package/payload/platform/plugins/docs/references/platform.md +1 -1
  18. package/payload/platform/plugins/docs/references/troubleshooting.md +1 -1
  19. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-body-server-sliced.test.js +41 -2
  20. package/payload/platform/plugins/memory/mcp/dist/tools/__tests__/memory-ingest-body-server-sliced.test.js.map +1 -1
  21. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.d.ts.map +1 -1
  22. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js +34 -4
  23. package/payload/platform/plugins/memory/mcp/dist/tools/memory-ingest.js.map +1 -1
  24. package/payload/platform/services/claude-session-manager/dist/http-server.d.ts.map +1 -1
  25. package/payload/platform/services/claude-session-manager/dist/http-server.js +99 -8
  26. package/payload/platform/services/claude-session-manager/dist/http-server.js.map +1 -1
  27. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts +6 -0
  28. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.d.ts.map +1 -1
  29. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js +17 -3
  30. package/payload/platform/services/claude-session-manager/dist/jsonl-enumerator.js.map +1 -1
  31. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts +13 -0
  32. package/payload/platform/services/claude-session-manager/dist/pty-spawner.d.ts.map +1 -1
  33. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js +24 -2
  34. package/payload/platform/services/claude-session-manager/dist/pty-spawner.js.map +1 -1
  35. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts +1 -25
  36. package/payload/platform/services/claude-session-manager/dist/rc-daemon.d.ts.map +1 -1
  37. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js +23 -95
  38. package/payload/platform/services/claude-session-manager/dist/rc-daemon.js.map +1 -1
  39. package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.d.ts +9 -0
  40. package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.d.ts.map +1 -1
  41. package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.js +29 -0
  42. package/payload/platform/services/claude-session-manager/dist/settings-permission-mode.js.map +1 -1
  43. package/payload/server/public/assets/{AdminLoginScreens-D_e5PYXv.js → AdminLoginScreens-D1X4M9wX.js} +1 -1
  44. package/payload/server/public/assets/AdminShell-BGZ3d3gY.js +1 -0
  45. package/payload/server/public/assets/{Checkbox-BHxSr_cA.js → Checkbox-DjANdKoK.js} +1 -1
  46. package/payload/server/public/assets/OperatorConversations-BkitSIiT.js +9 -0
  47. package/payload/server/public/assets/{OperatorConversations-pu50BU11.css → OperatorConversations-C-eFXT7w.css} +1 -1
  48. package/payload/server/public/assets/admin--FlkQOMu.js +1 -0
  49. package/payload/server/public/assets/{browser-C1Dp1UxB.js → browser-vowQc0TJ.js} +1 -1
  50. package/payload/server/public/assets/chat-Cw6rUWiC.js +1 -0
  51. package/payload/server/public/assets/data-9ArhwX1q.js +1 -0
  52. package/payload/server/public/assets/{graph-ticN9QbK.js → graph-B-64Cq-y.js} +3 -3
  53. package/payload/server/public/assets/{graph-labels-C2r7zl8O.js → graph-labels-Dtd2ckXH.js} +1 -1
  54. package/payload/server/public/assets/operator-Cqn1Ne60.js +1 -0
  55. package/payload/server/public/assets/page-DQ5D6Dg9.js +30 -0
  56. package/payload/server/public/assets/{public-CjT_WNkz.js → public-CrFepd06.js} +1 -1
  57. package/payload/server/public/browser.html +4 -4
  58. package/payload/server/public/chat.html +5 -5
  59. package/payload/server/public/data.html +4 -4
  60. package/payload/server/public/graph.html +6 -6
  61. package/payload/server/public/index.html +6 -6
  62. package/payload/server/public/operator.html +7 -7
  63. package/payload/server/public/public.html +5 -5
  64. package/payload/server/server.js +209 -14
  65. package/payload/server/public/assets/AdminShell-Dc23yALw.js +0 -1
  66. package/payload/server/public/assets/OperatorConversations-BqNOXEu8.js +0 -9
  67. package/payload/server/public/assets/admin-DE55chV9.js +0 -1
  68. package/payload/server/public/assets/chat-BLQDFyDL.js +0 -1
  69. package/payload/server/public/assets/data-D_L6g-L_.js +0 -1
  70. package/payload/server/public/assets/operator-COIYJFG7.js +0 -1
  71. package/payload/server/public/assets/page-CsOGSSSb.js +0 -30
@@ -5,14 +5,14 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Chat — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/chat-BLQDFyDL.js"></script>
8
+ <script type="module" crossorigin src="/assets/chat-Cw6rUWiC.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-Pqm5yXtL.js">
10
- <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BqNOXEu8.js">
11
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-Dc23yALw.js">
10
+ <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BkitSIiT.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-BGZ3d3gY.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/admin-types-CJrGd46U.js">
13
13
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-Bf_JiD2A.js">
14
- <link rel="modulepreload" crossorigin href="/assets/page-CsOGSSSb.js">
15
- <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-pu50BU11.css">
14
+ <link rel="modulepreload" crossorigin href="/assets/page-DQ5D6Dg9.js">
15
+ <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-C-eFXT7w.css">
16
16
  </head>
17
17
  <body>
18
18
  <div id="root"></div>
@@ -5,11 +5,11 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Data — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/data-D_L6g-L_.js"></script>
8
+ <script type="module" crossorigin src="/assets/data-9ArhwX1q.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-Pqm5yXtL.js">
10
- <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BqNOXEu8.js">
11
- <link rel="modulepreload" crossorigin href="/assets/graph-labels-C2r7zl8O.js">
12
- <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-pu50BU11.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BkitSIiT.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/graph-labels-Dtd2ckXH.js">
12
+ <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-C-eFXT7w.css">
13
13
  </head>
14
14
  <body>
15
15
  <div id="root"></div>
@@ -5,13 +5,13 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Graph — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/graph-ticN9QbK.js"></script>
8
+ <script type="module" crossorigin src="/assets/graph-B-64Cq-y.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-Pqm5yXtL.js">
10
- <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BqNOXEu8.js">
11
- <link rel="modulepreload" crossorigin href="/assets/graph-labels-C2r7zl8O.js">
12
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-Dc23yALw.js">
13
- <link rel="modulepreload" crossorigin href="/assets/Checkbox-BHxSr_cA.js">
14
- <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-pu50BU11.css">
10
+ <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BkitSIiT.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/graph-labels-Dtd2ckXH.js">
12
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-BGZ3d3gY.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/Checkbox-DjANdKoK.js">
14
+ <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-C-eFXT7w.css">
15
15
  </head>
16
16
  <body>
17
17
  <div id="root"></div>
@@ -5,14 +5,14 @@
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/admin-DE55chV9.js"></script>
8
+ <script type="module" crossorigin src="/assets/admin--FlkQOMu.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-Pqm5yXtL.js">
10
- <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BqNOXEu8.js">
11
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-Dc23yALw.js">
10
+ <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BkitSIiT.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-BGZ3d3gY.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/admin-types-CJrGd46U.js">
13
- <link rel="modulepreload" crossorigin href="/assets/Checkbox-BHxSr_cA.js">
14
- <link rel="modulepreload" crossorigin href="/assets/AdminLoginScreens-D_e5PYXv.js">
15
- <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-pu50BU11.css">
13
+ <link rel="modulepreload" crossorigin href="/assets/Checkbox-DjANdKoK.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/AdminLoginScreens-D1X4M9wX.js">
15
+ <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-C-eFXT7w.css">
16
16
  <link rel="stylesheet" crossorigin href="/assets/AdminLoginScreens-CWMpccrR.css">
17
17
  <link rel="stylesheet" href="/brand-defaults.css">
18
18
  </head>
@@ -5,16 +5,16 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <title>Operator — Maxy</title>
7
7
  <link rel="icon" href="/favicon.ico">
8
- <script type="module" crossorigin src="/assets/operator-COIYJFG7.js"></script>
8
+ <script type="module" crossorigin src="/assets/operator-Cqn1Ne60.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-Pqm5yXtL.js">
10
- <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BqNOXEu8.js">
11
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-Dc23yALw.js">
10
+ <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BkitSIiT.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-BGZ3d3gY.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/admin-types-CJrGd46U.js">
13
- <link rel="modulepreload" crossorigin href="/assets/Checkbox-BHxSr_cA.js">
14
- <link rel="modulepreload" crossorigin href="/assets/AdminLoginScreens-D_e5PYXv.js">
13
+ <link rel="modulepreload" crossorigin href="/assets/Checkbox-DjANdKoK.js">
14
+ <link rel="modulepreload" crossorigin href="/assets/AdminLoginScreens-D1X4M9wX.js">
15
15
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-Bf_JiD2A.js">
16
- <link rel="modulepreload" crossorigin href="/assets/page-CsOGSSSb.js">
17
- <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-pu50BU11.css">
16
+ <link rel="modulepreload" crossorigin href="/assets/page-DQ5D6Dg9.js">
17
+ <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-C-eFXT7w.css">
18
18
  <link rel="stylesheet" crossorigin href="/assets/AdminLoginScreens-CWMpccrR.css">
19
19
  </head>
20
20
  <body>
@@ -5,14 +5,14 @@
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-CjT_WNkz.js"></script>
8
+ <script type="module" crossorigin src="/assets/public-CrFepd06.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/assets/chunk-Pqm5yXtL.js">
10
- <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BqNOXEu8.js">
11
- <link rel="modulepreload" crossorigin href="/assets/AdminShell-Dc23yALw.js">
10
+ <link rel="modulepreload" crossorigin href="/assets/OperatorConversations-BkitSIiT.js">
11
+ <link rel="modulepreload" crossorigin href="/assets/AdminShell-BGZ3d3gY.js">
12
12
  <link rel="modulepreload" crossorigin href="/assets/admin-types-CJrGd46U.js">
13
13
  <link rel="modulepreload" crossorigin href="/assets/preload-helper-Bf_JiD2A.js">
14
- <link rel="modulepreload" crossorigin href="/assets/page-CsOGSSSb.js">
15
- <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-pu50BU11.css">
14
+ <link rel="modulepreload" crossorigin href="/assets/page-DQ5D6Dg9.js">
15
+ <link rel="stylesheet" crossorigin href="/assets/OperatorConversations-C-eFXT7w.css">
16
16
  <link rel="stylesheet" href="/brand-defaults.css">
17
17
  </head>
18
18
  <body class="public-surface">
@@ -8028,6 +8028,9 @@ var MODEL_CONTEXT_WINDOW = {
8028
8028
  [SONNET_MODEL]: 2e5,
8029
8029
  [HAIKU_MODEL]: 2e5
8030
8030
  };
8031
+ function contextWindow(model) {
8032
+ return MODEL_CONTEXT_WINDOW[model] ?? 2e5;
8033
+ }
8031
8034
  var MODEL_DISPLAY_NAMES = {
8032
8035
  [OPUS_MODEL]: "Opus 4.8 (1M context)",
8033
8036
  [SONNET_MODEL]: "Sonnet 4.6",
@@ -8037,6 +8040,12 @@ var SELECTABLE_MODELS = [OPUS_MODEL, SONNET_MODEL, HAIKU_MODEL];
8037
8040
  function isSelectableModel(id) {
8038
8041
  return SELECTABLE_MODELS.includes(id);
8039
8042
  }
8043
+ function baseModelId(id) {
8044
+ return id.replace(/\[1m\]$/, "");
8045
+ }
8046
+ function canonicalModelId(id) {
8047
+ return SELECTABLE_MODELS.find((m) => baseModelId(m) === baseModelId(id)) ?? id;
8048
+ }
8040
8049
  var PERMISSION_MODES = ["default", "acceptEdits", "plan", "auto", "bypassPermissions"];
8041
8050
  function isPermissionMode(value) {
8042
8051
  return PERMISSION_MODES.includes(value);
@@ -8238,7 +8247,9 @@ var NO_INDICATORS = {
8238
8247
  activity: null,
8239
8248
  permissionMode: null,
8240
8249
  effectivePermissionMode: null,
8241
- model: null
8250
+ model: null,
8251
+ effort: null,
8252
+ contextUsage: null
8242
8253
  };
8243
8254
  var indicatorsErrorLogged = false;
8244
8255
  var INDICATORS_TIMEOUT_MS = 1500;
@@ -8255,11 +8266,21 @@ async function fetchComposerIndicators(sessionId) {
8255
8266
  });
8256
8267
  if (!res.ok) return NO_INDICATORS;
8257
8268
  const body = await res.json();
8269
+ const model = typeof body.model === "string" ? body.model : null;
8270
+ const effort = typeof body.effortLevel === "string" ? body.effortLevel : null;
8271
+ const turnCount = typeof body.turnCount === "number" ? body.turnCount : 0;
8272
+ const usedTokens = typeof body.usedTokens === "number" ? body.usedTokens : null;
8273
+ const window = contextWindow(canonicalModelId(model ?? ""));
8274
+ const pct = usedTokens != null ? Math.round(usedTokens / window * 100) : null;
8275
+ const contextUsage = usedTokens != null ? { usedTokens, window, pct } : null;
8276
+ console.log(`[webchat-session] op=context-usage key=${sessionId} turns=${turnCount} used=${usedTokens ?? "absent"} window=${window} pct=${pct ?? "absent"}`);
8258
8277
  return {
8259
8278
  activity: typeof body.activity === "string" ? body.activity : null,
8260
8279
  permissionMode: typeof body.permissionMode === "string" ? body.permissionMode : null,
8261
8280
  effectivePermissionMode: typeof body.effectivePermissionMode === "string" ? body.effectivePermissionMode : null,
8262
- model: typeof body.model === "string" ? body.model : null
8281
+ model,
8282
+ effort,
8283
+ contextUsage
8263
8284
  };
8264
8285
  } catch (err) {
8265
8286
  if (!indicatorsErrorLogged) {
@@ -8616,7 +8637,7 @@ ${note}` : note;
8616
8637
  }
8617
8638
  const known = resolvedProjectDir !== null || sessionSidecarExists(target);
8618
8639
  const indicators2 = await fetchComposerIndicators(target);
8619
- return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${target}`) ?? null, ...indicators2, ...readLevers() });
8640
+ return c.json({ sessionId: target, projectDir: resolvedProjectDir, transcriptSessionId, channelBinding: conflictingBinding(channel), known, sizeBytes: jsonlSizeBytes(projectDir2, target), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${target}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${target}`) ?? null, ...indicators2, ...readLevers() });
8620
8641
  }
8621
8642
  let account;
8622
8643
  try {
@@ -8649,7 +8670,7 @@ ${note}` : note;
8649
8670
  }
8650
8671
  }
8651
8672
  const indicators = await fetchComposerIndicators(sessionId);
8652
- return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
8673
+ return c.json({ sessionId, projectDir, sizeBytes: jsonlSizeBytes(projectDir, sessionId), pendingPermissionPrompt: deps.pendingPromptFor?.(`session:${sessionId}`) ?? null, deliveryFailure: deps.deliveryFailureFor?.(`session:${sessionId}`) ?? null, ...indicators, ...readLevers(account) });
8653
8674
  });
8654
8675
  app53.post("/permission-verdict", requireAdminSession, async (c) => {
8655
8676
  const body = await c.req.json().catch(() => null);
@@ -8893,6 +8914,33 @@ async function managerRcSpawn(opts) {
8893
8914
  const out = await r.json();
8894
8915
  return { sessionId: out.sessionId ?? opts.sessionId, pid: out.spawnedPid ?? null };
8895
8916
  }
8917
+ async function managerRcRecover(opts) {
8918
+ const auth = await ensureAuth();
8919
+ if (auth.status === "dead" || auth.status === "missing") {
8920
+ console.log(`[channel-pty-bridge] rc-recover-refused reason=auth-${auth.status} ${opts.logContext}`);
8921
+ return { error: "claude-auth-dead", status: 503 };
8922
+ }
8923
+ const res = await fetch(`${managerBase2()}/rc-spawn`, {
8924
+ method: "POST",
8925
+ headers: { "content-type": "application/json" },
8926
+ body: JSON.stringify({
8927
+ sessionId: opts.sessionId,
8928
+ recover: true,
8929
+ role: "admin",
8930
+ channel: "webchat",
8931
+ senderId: opts.webchatChannel.key,
8932
+ adminUserId: opts.adminUserId,
8933
+ webchatChannel: opts.webchatChannel
8934
+ })
8935
+ }).catch((err) => ({ __throw: err instanceof Error ? err.message : String(err) }));
8936
+ if ("__throw" in res) {
8937
+ return { error: res.__throw, status: 0 };
8938
+ }
8939
+ const r = res;
8940
+ if (!r.ok) return { error: `manager-status-${r.status}`, status: r.status };
8941
+ const out = await r.json();
8942
+ return { live: out.live === true, classification: out.classification, recovered: out.recovered === true };
8943
+ }
8896
8944
  async function managerWriteInput(sessionId, text) {
8897
8945
  const res = await fetch(`${managerBase2()}/${sessionId}/input`, {
8898
8946
  method: "POST",
@@ -19418,12 +19466,12 @@ var InboundHub2 = class {
19418
19466
  * that never reached the agent:
19419
19467
  * - a still-queued message older than queuedThresholdMs WHILE a subscriber
19420
19468
  * is attached -> inbound-undelivered (the readiness handoff broke);
19421
- * - a still-queued message older than queuedThresholdMs with NO subscriber
19422
- * attached -> spawn-undelivered (the channel server never attached: spawn
19423
- * failed, or the session ended and never resumed);
19424
19469
  * - a drained message unacked past ackThresholdMs -> drain-undelivered (the
19425
19470
  * channel server never confirmed receipt — the silent cold-start drop).
19426
- * Each message is emitted at most once (removed when emitted). */
19471
+ * A still-queued message with NO subscriber is NOT handled here: the gateway
19472
+ * owns that policy via staleQueued/dropQueued (Task-962) — a live session is
19473
+ * given a recovery window + respawn before any drop; a not-live one keeps the
19474
+ * cold-start drop. Each message is emitted at most once (removed when emitted). */
19427
19475
  sweep(now, t) {
19428
19476
  const events = [];
19429
19477
  for (const [key, s] of this.keys) {
@@ -19432,10 +19480,6 @@ var InboundHub2 = class {
19432
19480
  events.push({ kind: "inbound-undelivered", key, messageId: e.payload.messageId, ageMs: now - e.enqueuedAt });
19433
19481
  return false;
19434
19482
  }
19435
- if (e.state === "queued" && !s.subscriber && now - e.enqueuedAt > t.queuedThresholdMs) {
19436
- events.push({ kind: "spawn-undelivered", key, messageId: e.payload.messageId, ageMs: now - e.enqueuedAt });
19437
- return false;
19438
- }
19439
19483
  if (e.state === "drained" && e.drainedAt != null && now - e.drainedAt > t.ackThresholdMs) {
19440
19484
  events.push({ kind: "drain-undelivered", key, messageId: e.payload.messageId, ageMs: now - e.drainedAt });
19441
19485
  return false;
@@ -19445,6 +19489,32 @@ var InboundHub2 = class {
19445
19489
  }
19446
19490
  return events;
19447
19491
  }
19492
+ /** Task-962 — queued messages with NO subscriber attached, older than
19493
+ * thresholdMs. Read-only: it does NOT remove anything. The gateway drives
19494
+ * recovery/drop for these (a live session gets a redelivery window + a wedged
19495
+ * respawn; a not-live one keeps the immediate cold-start drop). */
19496
+ staleQueued(now, thresholdMs) {
19497
+ const out = [];
19498
+ for (const [key, s] of this.keys) {
19499
+ if (s.subscriber) continue;
19500
+ for (const e of s.inFlight) {
19501
+ if (e.state === "queued" && now - e.enqueuedAt > thresholdMs) {
19502
+ out.push({ key, messageId: e.payload.messageId, ageMs: now - e.enqueuedAt });
19503
+ }
19504
+ }
19505
+ }
19506
+ return out;
19507
+ }
19508
+ /** Task-962 — terminal-drop one still-queued in-flight message by id. Returns
19509
+ * whether a matching queued entry was found and removed. */
19510
+ dropQueued(key, messageId) {
19511
+ const s = this.keys.get(key);
19512
+ if (!s) return false;
19513
+ const i = s.inFlight.findIndex((e) => e.payload.messageId === messageId && e.state === "queued");
19514
+ if (i < 0) return false;
19515
+ s.inFlight.splice(i, 1);
19516
+ return true;
19517
+ }
19448
19518
  /** Whether a key currently has a live channel server attached. The gateway
19449
19519
  * uses this to decide whether an inbound needs a cold-start spawn/resume. */
19450
19520
  hasSubscriber(key) {
@@ -19529,6 +19599,8 @@ function createWebchatChannelRoutes(deps) {
19529
19599
  var QUEUED_THRESHOLD_MS2 = 3e4;
19530
19600
  var ACK_THRESHOLD_MS2 = 3e4;
19531
19601
  var SWEEP_INTERVAL_MS2 = 15e3;
19602
+ var RECOVER_TRIGGER_MS = Number(process.env.WEBCHAT_RECOVER_TRIGGER_MS ?? String(3e4));
19603
+ var DELIVER_FINAL_MS = Number(process.env.WEBCHAT_DELIVER_FINAL_MS ?? String(9e4));
19532
19604
  function channelIdleMs() {
19533
19605
  return Number(process.env.CHANNEL_PTY_IDLE_MS ?? String(5 * 6e4));
19534
19606
  }
@@ -19560,6 +19632,18 @@ var WebchatGateway = class _WebchatGateway {
19560
19632
  /** Task 756 — live public sessions, for the idle reaper + session-end review.
19561
19633
  * Admin sessions are never recorded here (they never reap). */
19562
19634
  publicSessions = /* @__PURE__ */ new Map();
19635
+ /** Task-962 — per-key recover context, set on each admin inbound so the
19636
+ * recovery pass can ask the manager to respawn a wedged live child. */
19637
+ recoverable = /* @__PURE__ */ new Map();
19638
+ /** Task-962 — per-session delivery-failure markers (set when redelivery is
19639
+ * exhausted; cleared on the next successful drain/ack). Surfaced on the
19640
+ * /session pointer the operator /chat polls. */
19641
+ deliveryFailures = /* @__PURE__ */ new Map();
19642
+ /** Task-962 — `${key}::${messageId}` for messages a recovery call has already
19643
+ * been issued for, so recovery is attempted at most once per message. */
19644
+ recoveryAttempted = /* @__PURE__ */ new Set();
19645
+ /** Task-962 — guards against overlapping async recovery passes. */
19646
+ recovering = false;
19563
19647
  seq = 0;
19564
19648
  /** Register a one-shot awaiter for the next reply on `key`. Resolves with the
19565
19649
  * reply text, or `{ timeout: true }` if no reply arrives within `timeoutMs`.
@@ -19681,6 +19765,7 @@ var WebchatGateway = class _WebchatGateway {
19681
19765
  if (count > 0) {
19682
19766
  console.error(`[webchat:inbound] op=drained key=${key} count=${count}`);
19683
19767
  this.lastDeliveredAt.set(key, now);
19768
+ this.deliveryFailures.delete(key);
19684
19769
  }
19685
19770
  },
19686
19771
  onReceived: (key, messageId) => {
@@ -19688,6 +19773,10 @@ var WebchatGateway = class _WebchatGateway {
19688
19773
  console.error(
19689
19774
  `[webchat:inbound] op=channel-received key=${key} messageId=${messageId}${found ? "" : " note=unknown"}`
19690
19775
  );
19776
+ if (found) {
19777
+ this.recoveryAttempted.delete(`${key}::${messageId}`);
19778
+ this.deliveryFailures.delete(key);
19779
+ }
19691
19780
  },
19692
19781
  onReply: (key, text) => this.handleReply(key, text),
19693
19782
  awaitPermissionVerdict: (p) => this.awaitPermissionVerdict(p, permissionVerdictTtlMs())
@@ -19706,9 +19795,85 @@ var WebchatGateway = class _WebchatGateway {
19706
19795
  }
19707
19796
  return events;
19708
19797
  }
19709
- /** Start the periodic reconciliation sweep in the long-lived UI process. */
19798
+ /** Start the periodic reconciliation sweep in the long-lived UI process. Each
19799
+ * tick runs the sync sweep (drain-/inbound-undelivered) AND the async
19800
+ * recovery pass for queued-no-subscriber messages (Task-962). */
19710
19801
  startSweeper(intervalMs = SWEEP_INTERVAL_MS2) {
19711
- return setInterval(() => this.reconcile(Date.now()), intervalMs);
19802
+ return setInterval(() => {
19803
+ const now = Date.now();
19804
+ this.reconcile(now);
19805
+ void this.recoverStalled(now);
19806
+ }, intervalMs);
19807
+ }
19808
+ /** Task-962 — the per-session delivery-failure marker for the /session pointer.
19809
+ * Non-null only when redelivery was exhausted for `key`; cleared on the next
19810
+ * successful drain/ack. */
19811
+ deliveryFailureFor(key) {
19812
+ return this.deliveryFailures.get(key) ?? null;
19813
+ }
19814
+ /** Task-962 — clear a key's delivery-failure marker (a later message drained,
19815
+ * or the operator dismissed/retried). */
19816
+ clearDeliveryFailure(key) {
19817
+ this.deliveryFailures.delete(key);
19818
+ }
19819
+ /** Task-962 — recovery-aware pass over queued-no-subscriber messages.
19820
+ * - age in [RECOVER_TRIGGER_MS, DELIVER_FINAL_MS): ask the manager to recover
19821
+ * the live session ONCE. busy → leave queued for the channel server's
19822
+ * auto-reconnect to drain; wedged → the manager respawns and the resumed
19823
+ * child re-binds the channel + drains. A not-live target (or no recover
19824
+ * dep/descriptor) is dropped now — the cold-start class, out of scope.
19825
+ * - age ≥ DELIVER_FINAL_MS: terminal-drop and record a delivery-failure
19826
+ * marker (redelivery exhausted).
19827
+ * Single-flight; safe to call every sweep tick. */
19828
+ async recoverStalled(now) {
19829
+ if (this.recovering) return;
19830
+ this.recovering = true;
19831
+ try {
19832
+ for (const c of this.hub.staleQueued(now, RECOVER_TRIGGER_MS)) {
19833
+ const attemptKey = `${c.key}::${c.messageId}`;
19834
+ if (c.ageMs >= DELIVER_FINAL_MS) {
19835
+ this.hub.dropQueued(c.key, c.messageId);
19836
+ this.recoveryAttempted.delete(attemptKey);
19837
+ this.deliveryFailures.set(c.key, { messageId: c.messageId, at: now });
19838
+ console.error(
19839
+ `[webchat:inbound] op=delivery-failed key=${keyDisplay(c.key)} messageId=${c.messageId} ageMs=${c.ageMs}`
19840
+ );
19841
+ continue;
19842
+ }
19843
+ if (this.recoveryAttempted.has(attemptKey)) continue;
19844
+ const d = this.recoverable.get(c.key);
19845
+ if (!d || !this.deps.recoverLiveSession) {
19846
+ this.hub.dropQueued(c.key, c.messageId);
19847
+ console.error(
19848
+ `[webchat:inbound] op=spawn-undelivered key=${keyDisplay(c.key)} messageId=${c.messageId} ageMs=${c.ageMs} reason=no-descriptor`
19849
+ );
19850
+ continue;
19851
+ }
19852
+ this.recoveryAttempted.add(attemptKey);
19853
+ let r;
19854
+ try {
19855
+ r = await this.deps.recoverLiveSession(d);
19856
+ } catch (err) {
19857
+ console.error(
19858
+ `[webchat:inbound] op=recover-error key=${keyDisplay(c.key)} messageId=${c.messageId} err=${err instanceof Error ? err.message : String(err)}`
19859
+ );
19860
+ continue;
19861
+ }
19862
+ if (!r.live) {
19863
+ this.hub.dropQueued(c.key, c.messageId);
19864
+ this.recoveryAttempted.delete(attemptKey);
19865
+ console.error(
19866
+ `[webchat:inbound] op=spawn-undelivered key=${keyDisplay(c.key)} messageId=${c.messageId} ageMs=${c.ageMs} reason=not-live`
19867
+ );
19868
+ } else {
19869
+ console.error(
19870
+ `[webchat:inbound] op=recover key=${keyDisplay(c.key)} messageId=${c.messageId} classification=${r.classification ?? "unknown"} respawned=${r.recovered === true}`
19871
+ );
19872
+ }
19873
+ }
19874
+ } finally {
19875
+ this.recovering = false;
19876
+ }
19712
19877
  }
19713
19878
  /** Handle one inbound webchat message (browser POST → here). */
19714
19879
  async handleInbound(input) {
@@ -19723,6 +19888,15 @@ var WebchatGateway = class _WebchatGateway {
19723
19888
  console.error(
19724
19889
  `[webchat:inbound] op=received key=${keyDisplay(input.key)} role=${input.role} bytes=${bytes} delivery=${willDeliverNow ? "immediate" : "queued"}`
19725
19890
  );
19891
+ if (input.role === "admin") {
19892
+ this.recoverable.set(input.key, {
19893
+ accountId: input.accountId,
19894
+ key: input.key,
19895
+ role: input.role,
19896
+ ...input.sessionId !== void 0 ? { sessionId: input.sessionId } : {},
19897
+ ...input.adminUserId !== void 0 ? { adminUserId: input.adminUserId } : {}
19898
+ });
19899
+ }
19726
19900
  const existing = this.publicSessions.get(input.key);
19727
19901
  if (existing) existing.lastActivityAt = Date.now();
19728
19902
  if (!hadSubscriber && !this.spawning.has(input.key)) {
@@ -19770,6 +19944,7 @@ function buildPublicWebchatSpawnRequest(input) {
19770
19944
  channel: "webchat",
19771
19945
  accountId: input.accountId,
19772
19946
  agentSlug,
19947
+ model: SONNET_MODEL,
19773
19948
  // sliceToken/personId are present only for a gated visitor; open-mode
19774
19949
  // public agents carry neither (mirrors the bridge's open-mode key).
19775
19950
  ...sliceToken ? { sliceToken } : {},
@@ -20291,6 +20466,25 @@ var webchatGateway = new WebchatGateway({
20291
20466
  }
20292
20467
  return { sessionId: result.sessionId };
20293
20468
  },
20469
+ // Task-962 — the recovery pass asks the manager to respawn a wedged already-
20470
+ // live admin session (rc-spawn recover:true). Resolve the session id the same
20471
+ // way ensureChannelSession does. Public sessions recover via the idle reaper,
20472
+ // so a non-admin descriptor is reported not-live (no respawn).
20473
+ recoverLiveSession: async ({ accountId, key, role, sessionId, adminUserId }) => {
20474
+ if (role !== "admin") return { live: false };
20475
+ const id = sessionId ?? adminSessionIdFor(accountId, key, adminUserId);
20476
+ const r = await managerRcRecover({
20477
+ sessionId: id,
20478
+ webchatChannel: { key, gatewayUrl: webchatGatewayUrl(), serverPath: webchatServerPath() },
20479
+ ...adminUserId !== void 0 ? { adminUserId } : {},
20480
+ logContext: `channel=webchat key=${key} recover`
20481
+ });
20482
+ if ("error" in r) {
20483
+ console.error(`[webchat:inbound] op=recover-failed key=${key} error=${r.error} status=${r.status}`);
20484
+ return { live: false };
20485
+ }
20486
+ return r;
20487
+ },
20294
20488
  // Task 756 — the public idle reaper deletes the manager PTY and dispatches the
20295
20489
  // session-end review (gated visitors), since the native path has no bridge
20296
20490
  // entry to drive them. Admin sessions are never recorded, so never reaped.
@@ -20619,6 +20813,7 @@ app52.route("/api/webchat", createWebchatRoutes({
20619
20813
  handleInbound: (input) => webchatGateway.handleInbound(input),
20620
20814
  // Task 940 — the permission relay's pointer read + verdict write.
20621
20815
  pendingPromptFor: (key) => webchatGateway.pendingPromptFor(key),
20816
+ deliveryFailureFor: (key) => webchatGateway.deliveryFailureFor(key),
20622
20817
  resolvePermissionVerdict: (key, requestId, behavior) => webchatGateway.resolvePermissionVerdict(key, requestId, behavior)
20623
20818
  }));
20624
20819
  app52.route("/api/webchat/greeting", webchat_greeting_default);
@@ -1 +0,0 @@
1
- import{o as e}from"./chunk-Pqm5yXtL.js";import{A as t,C as n,E as r,L as i,N as a,R as o,T as s,f as c,g as l,h as u,k as d,m as f,p,t as m,v as h,x as g,y as ee}from"./OperatorConversations-BqNOXEu8.js";async function te(){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 ne=a(`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`}]]),_=a(`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`}]]),v=a(`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`}]]),re=a(`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`}]]),y=a(`ellipsis`,[[`circle`,{cx:`12`,cy:`12`,r:`1`,key:`41hilf`}],[`circle`,{cx:`19`,cy:`12`,r:`1`,key:`1wjl8i`}],[`circle`,{cx:`5`,cy:`12`,r:`1`,key:`1pcz8c`}]]),b=a(`file-text`,[[`path`,{d:`M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z`,key:`1oefj6`}],[`path`,{d:`M14 2v5a1 1 0 0 0 1 1h5`,key:`wfsgrz`}],[`path`,{d:`M10 9H8`,key:`b1mrlr`}],[`path`,{d:`M16 13H8`,key:`t4e002`}],[`path`,{d:`M16 17H8`,key:`z1uh3a`}]]),ie=a(`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=a(`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`}]]),ae=a(`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`}]]),oe=a(`plus`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`M12 5v14`,key:`s699le`}]]),se=a(`sliders-horizontal`,[[`path`,{d:`M10 5H3`,key:`1qgfaw`}],[`path`,{d:`M12 19H3`,key:`yhmn1j`}],[`path`,{d:`M14 3v4`,key:`1sua03`}],[`path`,{d:`M16 17v4`,key:`1q0r14`}],[`path`,{d:`M21 12h-9`,key:`1o4lsq`}],[`path`,{d:`M21 19h-5`,key:`1rlt1p`}],[`path`,{d:`M21 5h-7`,key:`1oszz2`}],[`path`,{d:`M8 10v4`,key:`tgpxqk`}],[`path`,{d:`M8 12H3`,key:`a7s4jb`}]]),ce=a(`square`,[[`rect`,{width:`18`,height:`18`,x:`3`,y:`3`,rx:`2`,key:`afitv7`}]]),S=a(`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`}]]),C=e(o(),1),w=g(),le={sm:14,md:16,lg:18},T={sm:30,md:38,lg:46};function E({variant:e=`primary`,size:t=`md`,icon:n,iconPosition:r=`leading`,loading:i=!1,fullWidth:a=!1,disabled:o=!1,type:s=`button`,onClick:c,"aria-label":l,style:u,className:d,children:f}){let p=[`btn`,`btn--${e}`,t===`md`?``:`btn--${t}`,a?`btn--full`:``,d].filter(Boolean).join(` `),m=le[t],h={...e===`send`?{width:T[t],height:T[t]}:{},...u},g=Object.keys(h).length>0;return(0,w.jsxs)(`button`,{type:s,className:p,disabled:i||o,onClick:c,"aria-label":l,style:g?h:void 0,children:[(0,w.jsxs)(`span`,{className:`btn__content`,style:{visibility:i?`hidden`:`visible`},children:[n&&r===`leading`&&(0,w.jsx)(n,{size:m}),f,n&&r===`trailing`&&(0,w.jsx)(n,{size:m})]}),i&&(0,w.jsx)(`span`,{className:`btn__spinner`,children:`✱`})]})}var 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 ue({targetSelector:e=`.platform`}){let t=(0,C.useRef)(null),[n,r]=(0,C.useState)(()=>A()),i=(0,C.useRef)(n);(0,C.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,C.useCallback)(()=>{r(e=>{let t=k(e);return t===e?e:t})},[]);(0,C.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,w.jsx)(`div`,{ref:t,className:`side-resize-handle`,role:`separator`,"aria-orientation":`vertical`,"aria-label":`Resize sidebar`,onPointerDown:o,onDoubleClick:s})}var de=i();function j({anchorRef:e,onClose:t,className:n,role:r,ariaLabel:i,children:a}){let o=(0,C.useRef)(null),[s,c]=(0,C.useState)({position:`fixed`,visibility:`hidden`}),l=(0,C.useCallback)(()=>{let t=e.current,n=o.current;if(!t||!n)return;let r=t.getBoundingClientRect(),i=n.getBoundingClientRect(),a=r.right-i.width;a<4&&(a=4);let s=window.innerHeight-r.bottom<i.height+8&&r.top>i.height+8?r.top-i.height:r.bottom;c({position:`fixed`,left:a,top:s,visibility:`visible`})},[e]);return(0,C.useLayoutEffect)(()=>{if(l(),typeof ResizeObserver>`u`)return;let e=new ResizeObserver(()=>l());return o.current&&e.observe(o.current),()=>e.disconnect()},[l]),(0,C.useEffect)(()=>{let n=e=>{e.key===`Escape`&&t()},r=n=>{let r=n.target;e.current?.contains(r)||o.current?.contains(r)||t()},i=n=>{let r=e.current;r&&n.target instanceof Node&&n.target.contains(r)&&t()},a=()=>t();return document.addEventListener(`keydown`,n),document.addEventListener(`pointerdown`,r),window.addEventListener(`scroll`,i,!0),window.addEventListener(`resize`,a),()=>{document.removeEventListener(`keydown`,n),document.removeEventListener(`pointerdown`,r),window.removeEventListener(`scroll`,i,!0),window.removeEventListener(`resize`,a)}},[e,t]),(0,de.createPortal)((0,w.jsx)(`div`,{ref:o,className:n,role:r,"aria-label":i,style:s,children:a}),document.body)}function fe({action:e,disabled:t,open:n,onToggle:r,onClose:i}){let a=(0,C.useRef)(null);return(0,w.jsxs)(w.Fragment,{children:[(0,w.jsx)(`button`,{ref:a,type:`button`,className:`conv-action`,onClick:r,disabled:t,"aria-haspopup":`dialog`,"aria-expanded":n,"aria-label":e.label,title:e.title,children:e.icon}),n&&(0,w.jsx)(j,{anchorRef:a,onClose:i,className:e.panelClassName,role:`dialog`,ariaLabel:e.label,children:e.panel()})]})}function pe({actions:e,disabled:t,collapsed:n}){let[r,i]=(0,C.useState)(null),[a,o]=(0,C.useState)(!1),[s,c]=(0,C.useState)(null),l=(0,C.useRef)(null);(0,C.useEffect)(()=>{i(null),o(!1),c(null)},[n]);let u=(0,C.useCallback)(()=>{o(!1),c(null)},[]);return n?(0,w.jsxs)(`div`,{className:`conv-actions`,children:[(0,w.jsx)(`button`,{ref:l,type:`button`,className:`conv-action conv-actions-overflow`,onClick:()=>o(e=>!e),disabled:t,"aria-haspopup":`menu`,"aria-expanded":a,"aria-label":`Session actions`,title:`Session actions`,children:(0,w.jsx)(y,{size:12})}),a&&(0,w.jsx)(j,{anchorRef:l,onClose:u,className:`conv-actions-menu`,role:`menu`,children:e.map(e=>e.panel?(0,w.jsxs)(`div`,{className:`conv-actions-menu-disclosure`,children:[(0,w.jsxs)(`button`,{type:`button`,role:`menuitem`,"aria-haspopup":`dialog`,"aria-expanded":s===e.key,disabled:t,onClick:()=>c(t=>t===e.key?null:e.key),children:[e.icon,(0,w.jsx)(`span`,{children:e.menuLabel})]}),s===e.key&&(0,w.jsx)(`div`,{className:`conv-actions-menu-panel`,children:e.panel()})]},e.key):(0,w.jsxs)(`button`,{type:`button`,role:`menuitem`,className:e.danger?`conv-action-danger`:void 0,"aria-busy":e.busy,disabled:t,onClick:t=>{e.onClick?.(t),u()},children:[e.icon,(0,w.jsx)(`span`,{children:e.menuLabel})]},e.key))})]}):(0,w.jsx)(`div`,{className:`conv-actions`,children:e.map(e=>e.panel?(0,w.jsx)(fe,{action:e,disabled:t,open:r===e.key,onToggle:()=>i(t=>t===e.key?null:e.key),onClose:()=>i(null)},e.key):(0,w.jsx)(`button`,{type:`button`,className:e.danger?`conv-action conv-action-danger`:`conv-action`,onClick:e.onClick,disabled:t,"aria-busy":e.busy,"aria-label":e.label,title:e.title,children:e.icon},e.key))})}var M=`claude-opus-4-8[1m]`,N=`claude-sonnet-4-6`,P=`claude-haiku-4-5`,me={[M]:`Opus 4.8 (1M context)`,[N]:`Sonnet 4.6`,[P]:`Haiku 4.5`};function F(e){return me[e]??e}function I(e){return e.replace(/\[1m\]$/,``)}var L=[`default`,`acceptEdits`,`plan`,`auto`,`bypassPermissions`];function he(e){return L.includes(e)}var R=[`low`,`medium`,`high`,`xhigh`];[...L],[...R];var z=[M,N,P],B={default:`Ask permissions`,acceptEdits:`Accept edits`,plan:`Plan mode`,auto:`Auto mode`,bypassPermissions:`Bypass permissions`},ge=L.map(e=>({value:e,label:B[e]??e})),V={low:`Low`,medium:`Medium`,high:`High`,xhigh:`Highest`},H=R.map(e=>({value:e,label:V[e]??e}));function _e(e){if(e){let t=z.find(t=>I(t)===I(e));if(t)return t}return M}function ve({row:e,adminFetch:t,onError:n}){let[r,i]=(0,C.useState)(()=>_e(e.model)),[a,o]=(0,C.useState)(``),[s,c]=(0,C.useState)(``),[l,u]=(0,C.useState)(!1),d=(0,C.useRef)(!1);(0,C.useEffect)(()=>{i(_e(e.model))},[e.model]);let f=async()=>{if(!d.current){d.current=!0,u(!0);try{let i=await t(`/api/admin/session-reseat`,{method:`POST`,headers:{"content-type":`application/json`},body:JSON.stringify({fromSessionId:e.sessionId,model:r,...a?{permissionMode:a}:{},...s?{effort:s}:{}})});if(!i.ok){n(`Could not re-seat ${e.title} (status ${i.status})`),console.error(`[admin-ui] dashboard-reseat-failed sessionId=${e.sessionId} status=${i.status}`),d.current=!1,u(!1);return}let o=await i.json().catch(()=>({}));o.target?window.location.assign(o.target):(n(`Re-seat of ${e.title} returned no target`),d.current=!1,u(!1))}catch(t){n(`Could not re-seat ${e.title} (network error)`),console.error(`[admin-ui] dashboard-reseat-failed sessionId=${e.sessionId} error=${t instanceof Error?t.message:String(t)}`),d.current=!1,u(!1)}}};return(0,w.jsxs)(w.Fragment,{children:[(0,w.jsxs)(`label`,{className:`reseat-field`,children:[(0,w.jsx)(`span`,{children:`Model`}),(0,w.jsx)(`select`,{"data-kind":`model`,value:r,disabled:l,onChange:e=>i(e.target.value),children:z.map(e=>(0,w.jsx)(`option`,{value:e,children:F(e)},e))})]}),(0,w.jsxs)(`label`,{className:`reseat-field`,children:[(0,w.jsx)(`span`,{children:`Mode`}),(0,w.jsxs)(`select`,{"data-kind":`mode`,value:a,disabled:l,onChange:e=>o(e.target.value),children:[(0,w.jsx)(`option`,{value:``,children:`Keep current`}),ge.map(e=>(0,w.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,w.jsxs)(`label`,{className:`reseat-field`,children:[(0,w.jsx)(`span`,{children:`Effort`}),(0,w.jsxs)(`select`,{"data-kind":`effort`,value:s,disabled:l,onChange:e=>c(e.target.value),children:[(0,w.jsx)(`option`,{value:``,children:`Keep current`}),H.map(e=>(0,w.jsx)(`option`,{value:e.value,children:e.label},e.value))]})]}),(0,w.jsx)(`button`,{type:`button`,className:`reseat-apply`,disabled:l,"aria-busy":l,onClick:()=>void f(),children:`Re-seat`})]})}var ye=[`whatsapp`,`telegram`];function U(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 W(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}async function be(e){if(navigator.clipboard)try{return await navigator.clipboard.writeText(e),!0}catch{}try{let t=document.createElement(`textarea`);t.value=e,t.style.position=`fixed`,t.style.opacity=`0`,document.body.appendChild(t),t.select();let n=document.execCommand(`copy`);return document.body.removeChild(t),n}catch{return!1}}function xe({target:e,onConfirm:t,onCancel:n}){return e?(0,w.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,w.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Confirm delete session`,children:[(0,w.jsxs)(`div`,{className:`claude-info-header`,children:[(0,w.jsx)(`span`,{children:`Delete this conversation?`}),(0,w.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[`This permanently removes the transcript. It is not moved to Archive and cannot be recovered.`,e.live&&(0,w.jsx)(`div`,{style:{marginTop:`8px`},children:`This session is running; deleting stops it first.`})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,style:{display:`flex`,gap:`8px`,padding:`10px 14px`},children:[(0,w.jsx)(E,{variant:`danger`,size:`sm`,style:{flex:1},onClick:t,children:`Delete`}),(0,w.jsx)(E,{variant:`secondary`,size:`sm`,style:{flex:1},onClick:n,children:`Cancel`})]})]})}):null}var G=`auth-refresh-failed`;function Se({error:e,onClose:t}){if(!e)return null;let n=e.reason===G,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,w.jsx)(`div`,{className:`claude-info-overlay`,onClick:t,children:(0,w.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),role:`alertdialog`,"aria-label":`Session could not be opened`,children:[(0,w.jsxs)(`div`,{className:`claude-info-header`,children:[(0,w.jsx)(`span`,{children:r}),(0,w.jsx)(`button`,{className:`claude-info-close`,onClick:t,"aria-label":`Close`,children:`✕`})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,style:{padding:`12px 14px`,fontSize:`11px`,color:`var(--text-secondary)`},children:[i,(0,w.jsxs)(`div`,{className:`claude-info-row`,style:{marginTop:`8px`},children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Reason`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:e.reason})]}),e.sessionId&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,w.jsxs)(`span`,{className:`claude-info-value`,children:[e.sessionId.slice(0,8),`…`]})]})]})]})})}function Ce(e){let{show:t,onClose:n,claudeInfo:r,messages:i,sessionElapsed:a,sessionId:o,cacheKey:s}=e,[c,l]=(0,C.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,ee=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,w.jsx)(`div`,{className:`claude-info-overlay`,onClick:n,children:(0,w.jsxs)(`div`,{className:`claude-info-modal`,onClick:e=>e.stopPropagation(),children:[(0,w.jsxs)(`div`,{className:`claude-info-header`,children:[(0,w.jsx)(`img`,{src:`/brand/claude.png`,alt:`Claude`,className:`claude-info-icon`}),(0,w.jsx)(`span`,{children:`Claude Code`}),(0,w.jsx)(`button`,{className:`claude-info-close`,onClick:n,"aria-label":`Close`,children:`✕`})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,children:[(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Version`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:r?r.version:`…`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Email`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:r?.account?.email??`…`})]})]}),(g||m||h>0)&&(0,w.jsxs)(`div`,{className:`claude-info-section`,children:[g&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Plan`}),(0,w.jsx)(`span`,{className:`claude-info-value`,style:{textTransform:`capitalize`},children:g})]}),m&&(0,w.jsxs)(w.Fragment,{children:[(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Usage`}),(0,w.jsxs)(`span`,{className:`claude-info-value`,children:[Math.round(m.utilization*100),`%`]})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Resets in`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:ee(m.resetsAt)})]}),m.isUsingOverage&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Overage`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:`Active`})]})]}),h>0&&(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session cost`}),(0,w.jsxs)(`span`,{className:`claude-info-value`,children:[`$`,h<.01?h.toFixed(4):h.toFixed(2)]})]})]}),(0,w.jsxs)(`div`,{className:`claude-info-section`,children:[(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Model`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:r?.model??`…`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Context used`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:f>0?`${f}%`:`—`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Tokens`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:p>0?W(p):`—`})]}),(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,w.jsx)(`span`,{className:`claude-info-value`,children:U(a)})]}),(o||s)&&(()=>{let e=o??s??``;return(0,w.jsxs)(`div`,{className:`claude-info-row`,children:[(0,w.jsx)(`span`,{className:`claude-info-label`,children:`Session`}),(0,w.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 be(e)?`copied`:`failed`),setTimeout(()=>l(null),1200)},children:c===`copied`?`copied ✓`:c===`failed`?`copy failed ✕`:`${e.slice(0,8)}…`})]})})()]})]})})}var K=`https://claude.ai/code`,we=200,Te=[500,1e3,1500,2e3,2500,3e3,3e3];function Ee(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:`${K}/${r}`};let i=n.reason||n.error||`status ${t}`;return{kind:`error`,sessionId:n.sessionId??null,reason:i}}function De(e){if(!e)return``;let t=Date.parse(e);return Number.isFinite(t)?new Date(t).toLocaleString(void 0,{dateStyle:`medium`,timeStyle:`short`}):``}function Oe(e){let{businessName:i,cacheKey:a,role:o,userName:l,userAvatar:m,onSelectProjects:g,onSelectPeople:te,onSelectTasks:y,onSelectAgents:le,onCloseMobileDrawer:T,collapsed:E,selectedWhatsappId:D,onSelectWhatsappConversation:O,initialWhatsappSurface:k=!1}=e,A=h(a),ue=(0,C.useCallback)(e=>({key:`reseat`,label:`Re-seat session ${e.title} (model, mode, effort)`,menuLabel:`Re-seat`,title:`Re-seat — move this session onto a chosen model, mode, and effort`,icon:(0,w.jsx)(se,{size:12}),panelClassName:`reseat-panel`,panel:()=>(0,w.jsx)(ve,{row:e,adminFetch:A,onError:e=>H({message:e,failed:!0})})}),[A]),de=ee.productName,j=typeof l==`string`?l:l===null?`name unavailable`:i||de,fe=(j.trim().charAt(0)||`?`).toUpperCase(),[M,N]=(0,C.useState)(k?`whatsapp`:`sessions`),[P,me]=(0,C.useState)([]),[F,I]=(0,C.useState)(!1),[L,he]=(0,C.useState)(null),[R,z]=(0,C.useState)(!1),[B,ge]=(0,C.useState)(`file`),[V,H]=(0,C.useState)(null),[_e,U]=(0,C.useState)(null),[W,be]=(0,C.useState)([]),[G,Ce]=(0,C.useState)(!1),[K,Oe]=(0,C.useState)(null),[ke,q]=(0,C.useState)(!1),[J,Ne]=(0,C.useState)(!1),[Y,Pe]=(0,C.useState)(!1),[Fe,Ie]=(0,C.useState)(null),[Le,Re]=(0,C.useState)(new Set),[ze,Be]=(0,C.useState)(null),[Ve,He]=(0,C.useState)(new Set),[Ue,We]=(0,C.useState)(new Set),[Ge,Ke]=(0,C.useState)(new Set),[qe,Je]=(0,C.useState)(null),[Ye,X]=(0,C.useState)(``),[Xe,Ze]=(0,C.useState)(!1),[Z,Qe]=(0,C.useState)(!1),$e=(0,C.useRef)(null),et=(0,C.useRef)(0),[tt,nt]=(0,C.useState)(0);(0,C.useEffect)(()=>{let e=$e.current;if(!e||typeof ResizeObserver>`u`)return;let t=new ResizeObserver(e=>{let t=e[0]?.contentRect.width??0;nt(e=>Math.abs(e-t)<1?e:t)});return t.observe(e),()=>t.disconnect()},[M]);let rt=tt>0&&tt<400,[it,at]=(0,C.useState)([]),[ot,st]=(0,C.useState)(!1),[ct,lt]=(0,C.useState)(null),[ut,dt]=(0,C.useState)(`whatsapp`),ft=(0,C.useCallback)(e=>{if(T(),!a){console.error(`[admin-ui] artefact-download-blocked id=${e.id} reason=no-cache-key`),H({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`),H({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}`),c(a,e.downloadPath,e.downloadRoot??`data`),H({message:`Downloading ${e.name}`,failed:!1})},[a,T]);(0,C.useEffect)(()=>{if(!V)return;let e=setTimeout(()=>H(null),2500);return()=>clearTimeout(e)},[V]);let pt=(0,C.useCallback)(async()=>{if(a){z(!0),he(null);try{let e=await A(`/api/admin/sidebar-artefacts`);if(!e.ok)throw Error(`status ${e.status}`);me((await e.json()).artefacts??[]),I(!0)}catch(e){let t=e instanceof Error?e.message:String(e);he(`Failed to load artefacts: ${t}`),console.error(`[admin-ui] sidebar-artefacts fetch failed: ${t}`)}finally{z(!1)}}},[a,A]),Q=(0,C.useCallback)(async()=>{if(!a)return null;let e=++et.current;q(!0),Oe(null);try{let t=await A(`/api/admin/sidebar-sessions`);if(!t.ok)throw Error(`status ${t.status}`);let n=await t.json(),r=n.sessions??[];return e===et.current?(be(r),Ie(n.accountId??null),Ce(!0),r):(console.info(`[admin-ui] sidebar-sessions-stale-response-dropped token=${e}`),r)}catch(t){let n=t instanceof Error?t.message:String(t);return e===et.current&&Oe(`Failed to load sessions: ${n}`),console.error(`[admin-ui] sidebar-sessions fetch failed: ${n}`),null}finally{e===et.current&&q(!1)}},[a,A]),mt=(0,C.useCallback)(async()=>{if(a){lt(null);try{let e=await A(`/api/whatsapp-reader/conversations`);if(!e.ok)throw Error(`status ${e.status}`);at((await e.json()).conversations??[]),st(!0)}catch(e){let t=e instanceof Error?e.message:String(e);lt(`Couldn't load conversations.`),console.error(`[admin-ui] channel-convos fetch failed: ${t}`)}}},[a,A]);(0,C.useEffect)(()=>{!a||G||Q()},[a,G,Q]),(0,C.useEffect)(()=>{if(!a)return;let e=null;return mt(),e=setInterval(()=>{mt()},Ae),()=>{e!==null&&clearInterval(e)}},[a,mt]),(0,C.useEffect)(()=>{if(!a)return;let e=null;function t(){console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=poll`),Q()}function n(){e===null&&(e=setInterval(t,je))}function r(){e!==null&&(clearInterval(e),e=null)}function i(){document.hidden?r():(t(),n())}return document.hidden||n(),document.addEventListener(`visibilitychange`,i),()=>{r(),document.removeEventListener(`visibilitychange`,i)}},[a,Q]);let ht=(0,C.useMemo)(()=>{let e=new Map;for(let t of ye)e.set(t,[]);for(let t of it)e.get(t.channel)?.push(t);for(let t of ye)console.info(`[admin-ui] sidebar-nav surface=${t} count=${e.get(t).length}`);return e},[it]),gt={whatsapp:`WhatsApp`,telegram:`Telegram`,webchat:`Webchat`},_t=()=>{O(null),N(`artefacts`),console.info(`[admin-ui] sidebar-nav surface=artefacts count=${F?P.length:0} collapsed=${E}`),pt()},$=1.5,vt=()=>{console.info(`[admin-ui] sidebar-refresh surface=artefacts`),pt()},yt=()=>{O(null),N(`sessions`),console.info(`[admin-ui] sidebar-nav surface=sessions count=${G?W.length:0} collapsed=${E}`),G||Q()},bt=()=>{console.info(`[admin-ui] sidebar-refresh surface=sessions trigger=manual`),Q()},xt=e=>{N(`whatsapp`),dt(e),console.info(`[admin-ui] sidebar-nav surface=${e} count=${ht.get(e)?.length??0} collapsed=${E}`)},St=(0,C.useCallback)(async e=>{if(Ve.has(e.sessionId))return;He(t=>{let n=new Set(t);return n.add(e.sessionId),n});let t=window.open(``,`_blank`);try{let n=await A(`/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=Ee(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`?(T(),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}`),U(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}`),U({sessionId:e.sessionId,reason:r})}finally{He(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}},[A,T,Ve]),Ct=(0,C.useCallback)(async e=>{let t=e.slice(0,8);for(let n=1;n<=Te.length;n++){await new Promise(e=>setTimeout(e,Te[n-1]));let r=await Q();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}`)},[Q]),wt=(0,C.useCallback)(async()=>{if(Z)return;Qe(!0);let e=window.open(``,`_blank`);try{let t=await A(`/api/admin/session-rc-spawn`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({})}),n=await t.json().catch(()=>({})),r=Ee(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?Ct(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}`),U(r))}catch(t){e?.close();let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-new-session-failed error=${n}`),U({sessionId:null,reason:n})}finally{Qe(!1)}},[A,Z,Ct]),Tt=(0,C.useCallback)((e,t)=>{e.stopPropagation(),Be(t)},[]),Et=(0,C.useCallback)(async e=>{if(!Le.has(e.sessionId)){Re(t=>{let n=new Set(t);return n.add(e.sessionId),n});try{let t=await A(`/api/admin/session-delete`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId})});if(!t.ok){let n=await t.json().catch(()=>({}));console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} status=${t.status} error=${n.error??`unknown`}`),H({message:`Delete failed: ${n.error??`status ${t.status}`}`,failed:!0});return}let n=await t.json();console.info(`[admin-ui] sidebar-session-delete sessionId=${e.sessionId} live=${e.live} confirmed=true pidKilled=${n.pidKilled??`?`} deleted=${n.deleted??`?`}`),be(t=>t.filter(t=>t.sessionId!==e.sessionId)),Q()}catch(t){let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-session-delete-failed sessionId=${e.sessionId} error=${n}`),H({message:`Delete failed: ${n}`,failed:!0})}finally{Re(t=>{let n=new Set(t);return n.delete(e.sessionId),n})}}},[A,Le,Q]),Dt=(0,C.useCallback)(async(e,t)=>{if(e.stopPropagation(),!Ue.has(t.sessionId)){We(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await A(`/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`}`),H({message:`Stop failed: ${n.error??`status ${e.status}`}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-stop sessionId=${t.sessionId}`),Q()}catch(e){let n=e instanceof Error?e.message:String(e);console.error(`[admin-ui] sidebar-session-stop-failed sessionId=${t.sessionId} error=${n}`),H({message:`Stop failed: ${n}`,failed:!0})}finally{We(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[A,Ue,Q]),Ot=(0,C.useCallback)(async(e,t,n)=>{if(e.stopPropagation(),!Ge.has(t.sessionId)){Ke(e=>{let n=new Set(e);return n.add(t.sessionId),n});try{let e=await A(`/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`}`),H({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${i}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-archive sessionId=${t.sessionId} mode=${n}`),Q()}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}`),H({message:`${n===`archive`?`Archive`:`Unarchive`} failed: ${r}`,failed:!0})}finally{Ke(e=>{let n=new Set(e);return n.delete(t.sessionId),n})}}},[A,Ge,Q]),kt=(0,C.useCallback)(async e=>{let t=Ye.trim();if(!t){H({message:`Title can’t be empty`,failed:!0});return}if(t.length>we){H({message:`Title too long (max ${we})`,failed:!0});return}Ze(!0);try{let n=await A(`/api/admin/session-rename`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({sessionId:e.sessionId,title:t})});if(!n.ok){let t=await n.json().catch(()=>({})),r=t.reason??t.error??`status ${n.status}`;console.error(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=rejected reason=${r}`),H({message:`Rename failed: ${r}`,failed:!0});return}console.info(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=ok`),Je(null),X(``),Q()}catch(t){let n=t instanceof Error?t.message:String(t);console.error(`[admin-ui] sidebar-session-rename sessionId=${e.sessionId.slice(0,8)} outcome=rejected reason=${n}`),H({message:`Rename failed: ${n}`,failed:!0})}finally{Ze(!1)}},[A,Ye,Q]);return(0,w.jsxs)(`aside`,{className:`side`,children:[(0,w.jsx)(`div`,{className:`side-new-session-row`,children:(0,w.jsxs)(`button`,{type:`button`,className:`side-new-session`,onClick:wt,disabled:Z,"aria-busy":Z,children:[(0,w.jsx)(oe,{size:14}),(0,w.jsx)(`span`,{children:Z?`Spawning…`:`New session`})]})}),(0,w.jsxs)(`nav`,{className:`side-nav`,children:[(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=people`),te(),T()},children:[(0,w.jsx)(S,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`People`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=agents`),le(),T()},children:[(0,w.jsx)(v,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Agents`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=projects`),g(),T()},children:[(0,w.jsx)(re,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Projects`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row`,onClick:()=>{console.info(`[admin-ui] sidebar-nav surface=tasks`),y(),T()},children:[(0,w.jsx)(x,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Tasks`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row${M===`artefacts`?` active`:``}`,onClick:_t,children:[(0,w.jsx)(b,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Artefacts`}),(0,w.jsx)(`span`,{className:`kbd`})]}),(0,w.jsxs)(`button`,{type:`button`,className:`nav-row${M===`sessions`?` active`:``}`,onClick:yt,children:[(0,w.jsx)(ie,{size:20,strokeWidth:$}),(0,w.jsx)(`span`,{className:`label`,children:`Sessions`}),(0,w.jsx)(`span`,{className:`kbd`})]}),ot&&ye.filter(e=>ht.get(e).length>0).map(e=>(0,w.jsxs)(`button`,{type:`button`,className:`nav-row${M===`whatsapp`&&ut===e?` active`:``}`,onClick:()=>xt(e),children:[(0,w.jsx)(f,{channel:e,size:16}),(0,w.jsx)(`span`,{className:`label`,children:gt[e]}),(0,w.jsx)(`span`,{className:`kbd`})]},e)),ct&&(0,w.jsx)(`div`,{className:`nav-row`,style:{color:`var(--text-tertiary)`,cursor:`default`},"aria-disabled":`true`,children:(0,w.jsx)(`span`,{className:`label`,children:ct})})]}),M===`artefacts`&&(0,w.jsxs)(`div`,{className:`side-list`,children:[(0,w.jsxs)(`div`,{className:`group-head`,children:[(0,w.jsx)(`span`,{children:`Artefacts`}),(0,w.jsxs)(`span`,{className:`group-head-meta`,children:[(0,w.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh artefacts`,"aria-label":`Refresh artefacts`,onClick:vt,disabled:R,children:(0,w.jsx)(s,{size:12,className:R?`spinning`:void 0})}),(0,w.jsx)(`span`,{children:R?`…`:String(P.length)})]})]}),L&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:L}),F&&!L&&P.length>0&&(()=>{let e=P.filter(e=>e.kind===`agent-template`).length,t=P.length-e;return(0,w.jsx)(`div`,{className:`artefact-filter-chips`,children:[{key:`all`,label:`All`,count:P.length},{key:`agent`,label:`Agents`,count:e},{key:`file`,label:`Files`,count:t}].map(e=>(0,w.jsxs)(`button`,{type:`button`,className:`artefact-filter-chip${B===e.key?` active`:``}`,onClick:()=>ge(e.key),disabled:e.count===0&&e.key!==`all`,children:[e.label,(0,w.jsx)(`span`,{className:`artefact-filter-chip-count`,children:e.count})]},e.key))})})(),F&&!L&&P.length===0&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No artefacts yet`}),P.filter(e=>B===`all`?!0:B===`agent`?e.kind===`agent-template`:e.kind!==`agent-template`).map(e=>{let n=e.kind===`agent-template`,r=n?v:b,i=De(e.updatedAt),a=e.downloadPath!==null;return(0,w.jsxs)(`button`,{type:`button`,className:`conv`,onClick:()=>ft(e),disabled:!a,style:a?void 0:{cursor:`default`},title:a?`Download ${e.name}`:`${e.name} can’t be downloaded`,children:[(0,w.jsx)(r,{size:14,className:`conv-icon`,"data-kind":n?`agent`:`file`,"aria-label":n?`agent template`:`file`}),(0,w.jsxs)(`span`,{className:`conv-stack`,children:[(0,w.jsx)(`span`,{className:`conv-name-line`,children:(0,w.jsx)(`span`,{className:`conv-name`,children:e.name})}),i&&(0,w.jsx)(`span`,{className:`conv-timestamp`,children:i})]}),a&&(0,w.jsx)(t,{size:12,className:`conv-rc-icon`,"aria-hidden":`true`})]},e.id)})]}),M===`sessions`&&(()=>{let e=W.filter(e=>J?!0:!e.isSubagent).filter(e=>Y?!0:!e.archived),t=W.some(e=>e.isSubagent),i=W.some(e=>e.archived);return(0,w.jsxs)(`div`,{className:`side-list`,ref:$e,children:[(0,w.jsxs)(`div`,{className:`group-head`,children:[(0,w.jsx)(`span`,{children:`Sessions`}),(0,w.jsxs)(`span`,{className:`group-head-meta`,children:[(0,w.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh sessions`,"aria-label":`Refresh sessions`,onClick:bt,disabled:ke,children:(0,w.jsx)(s,{size:12,className:ke?`spinning`:void 0})}),(0,w.jsx)(`span`,{children:ke?`…`:String(e.length)})]})]}),Fe&&(0,w.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,w.jsx)(`code`,{children:Fe})}),(t||i)&&(0,w.jsxs)(`div`,{className:`artefact-filter-chips`,children:[t&&(0,w.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${J?` active`:``}`,"aria-pressed":J,onClick:()=>Ne(e=>!e),title:J?`Hide subagent sessions`:`Show subagent sessions`,children:`Subagents`}),i&&(0,w.jsx)(`button`,{type:`button`,className:`artefact-filter-chip${Y?` active`:``}`,"aria-pressed":Y,onClick:()=>Pe(e=>!e),title:Y?`Hide archived sessions`:`Show archived sessions`,children:`Archived`})]}),K&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:K}),G&&!K&&e.length===0&&(0,w.jsx)(`div`,{className:`conv`,style:{color:`var(--text-tertiary)`,cursor:`default`},children:`No sessions yet`}),e.map(e=>{let t=De(e.startedAt),i=Ve.has(e.sessionId),a=Le.has(e.sessionId),o=Ue.has(e.sessionId),s=Ge.has(e.sessionId),c=i||a||o||s,l=[{key:`open`,label:`Resume session ${e.title} in claude.ai/code`,menuLabel:`Resume in claude.ai/code`,title:`Resume in a fresh local Remote Control PTY`,icon:(0,w.jsx)(d,{size:12}),busy:i,onClick:()=>{St(e)}},{key:`message`,label:`Open session ${e.title} in admin webchat`,menuLabel:`Open in webchat`,title:`Open in admin webchat (/chat) — sending resumes this session`,icon:(0,w.jsx)(ae,{size:12}),onClick:()=>{window.location.assign(`/chat?session=${e.sessionId}`)}},...e.live?[{key:`stop`,label:`Stop session ${e.title}`,menuLabel:`Stop`,title:`Stop session process (keeps the conversation, can resume later)`,icon:(0,w.jsx)(ce,{size:12}),busy:o,onClick:t=>{Dt(t,e)}}]:[],e.archived?{key:`unarchive`,label:`Unarchive session ${e.title}`,menuLabel:`Unarchive`,title:`Unarchive (move back to the active list)`,icon:(0,w.jsx)(ne,{size:12}),busy:s,onClick:t=>{Ot(t,e,`unarchive`)}}:{key:`archive`,label:`Archive session ${e.title}`,menuLabel:`Archive`,title:`Archive (hide from the list, keeps the conversation resumable)`,icon:(0,w.jsx)(_,{size:12}),busy:s,onClick:t=>{Ot(t,e,`archive`)}},{key:`rename`,label:`Rename session ${e.title}`,menuLabel:`Rename`,title:`Rename this session`,icon:(0,w.jsx)(r,{size:12}),busy:Xe&&qe===e.sessionId,onClick:t=>{t.stopPropagation(),Je(e.sessionId),X(e.personName??e.title)}},{key:`delete`,label:`Delete session ${e.title}`,menuLabel:`Delete`,title:`Delete session (stops the process, removes the conversation)`,icon:(0,w.jsx)(n,{size:12}),danger:!0,busy:a,onClick:t=>{Tt(t,e)}},ue({sessionId:e.sessionId,model:e.model??null,title:e.personName??e.title})];return(0,w.jsxs)(`div`,{className:`conv conv-with-actions`,children:[(0,w.jsxs)(`div`,{className:`conv-main-static`,children:[(0,w.jsx)(`span`,{className:`conv-live-dot`,"data-live":e.live?`1`:`0`,"aria-label":e.live?`live session`:`ended session`}),(0,w.jsxs)(`span`,{className:`conv-stack`,children:[(0,w.jsxs)(`span`,{className:`conv-name-line`,children:[e.channel&&(0,w.jsx)(u,{channel:e.channel,size:13}),qe===e.sessionId?(0,w.jsx)(`input`,{className:`conv-name conv-name-edit`,autoFocus:!0,value:Ye,disabled:Xe,"aria-label":`New title for session ${e.title}`,onChange:e=>X(e.target.value),onClick:e=>e.stopPropagation(),onKeyDown:t=>{t.key===`Enter`?(t.preventDefault(),kt(e)):t.key===`Escape`&&(t.preventDefault(),Je(null),X(``))},onBlur:()=>{qe===e.sessionId&&!Xe&&(Je(null),X(``))}}):(0,w.jsx)(`span`,{className:`conv-name`,title:e.personName??e.title,children:e.personName??e.title})]}),(0,w.jsxs)(`span`,{className:`conv-timestamp`,children:[(0,w.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,w.jsxs)(`span`,{children:[` · `,t]})]})]})]}),(0,w.jsx)(pe,{actions:l,disabled:c,collapsed:rt})]},e.sessionId)})]})})(),M===`whatsapp`&&(0,w.jsxs)(`div`,{className:`side-list`,children:[(0,w.jsxs)(`div`,{className:`group-head`,children:[(0,w.jsx)(`span`,{children:gt[ut]}),(0,w.jsxs)(`span`,{className:`group-head-meta`,children:[(0,w.jsx)(`button`,{type:`button`,className:`group-head-refresh`,title:`Refresh conversations`,"aria-label":`Refresh conversations`,onClick:()=>{mt()},children:(0,w.jsx)(s,{size:12})}),(0,w.jsx)(`span`,{children:String(ht.get(ut).length)})]})]}),ht.get(ut).map(e=>{let t=De(e.lastMessageAt);return(0,w.jsxs)(`div`,{className:`conv conv-with-actions${D===e.sessionId?` active`:``}`,children:[(0,w.jsxs)(`button`,{type:`button`,className:`conv-main-static conv-main-btn`,onClick:()=>{O(e),T()},title:e.title,children:[(0,w.jsx)(f,{channel:e.channel,size:14}),(0,w.jsxs)(`span`,{className:`conv-stack`,children:[(0,w.jsxs)(`span`,{className:`conv-name-line`,children:[(0,w.jsx)(`span`,{className:`conv-name`,children:p(e)}),e.role===`public`&&(0,w.jsx)(`span`,{className:`conv-tag conv-tag-public`,children:`Public`})]}),t&&(0,w.jsx)(`span`,{className:`conv-timestamp`,children:t})]})]}),(0,w.jsx)(pe,{actions:[ue({sessionId:e.sessionId,model:e.model,title:e.title})],disabled:!1,collapsed:rt})]},e.sessionId)})]}),(0,w.jsx)(Me,{}),(0,w.jsxs)(`div`,{className:`side-foot`,children:[(0,w.jsx)(`div`,{className:`avatar`,children:m?(0,w.jsx)(`img`,{src:m,alt:j}):fe}),(0,w.jsxs)(`div`,{className:`who`,children:[(0,w.jsx)(`span`,{className:`name`,children:j}),(0,w.jsx)(`span`,{className:`role`,children:o??`operator`})]})]}),V&&(0,w.jsx)(`div`,{className:`copy-toast${V.failed?` copy-toast-failed`:``}`,role:`status`,children:V.message}),(0,w.jsx)(Se,{error:_e,onClose:()=>U(null)}),(0,w.jsx)(xe,{target:ze,onCancel:()=>Be(null),onConfirm:()=>{let e=ze;Be(null),e&&Et(e)}})]})}var ke=5e3,Ae=3e4,je=3e4;function Me(){let[e,t]=(0,C.useState)(null);if((0,C.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()},ke))}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,w.jsxs)(`div`,{className:f.join(` `),role:`status`,"aria-label":`host CPU and RAM`,children:[(0,w.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,w.jsxs)(`span`,{className:i?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`CPU `,u(n)]}),(0,w.jsx)(`div`,{className:`system-stats__bar`,children:(0,w.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(n)})})]}),(0,w.jsxs)(`div`,{className:`system-stats__metric`,children:[(0,w.jsxs)(`span`,{className:o?`system-stats__fig system-stats__fig--warn`:`system-stats__fig`,children:[`RAM `,u(r)]}),(0,w.jsx)(`div`,{className:`system-stats__bar`,children:(0,w.jsx)(`div`,{className:`system-stats__bar-fill`,style:d(r)})})]})]})}var q=`admin-sidebar-collapsed`,J=`admin-sidebar-drawer-open`;function Ne(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(q)===`1`}catch{return!1}}function Y(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(q,`1`):window.sessionStorage.removeItem(q)}catch{}}function Pe(){if(typeof window>`u`)return!1;try{return window.sessionStorage.getItem(J)===`1`}catch{return!1}}function Fe(e){if(!(typeof window>`u`))try{e?window.sessionStorage.setItem(J,`1`):window.sessionStorage.removeItem(J)}catch{}}var Ie=720;function Le(e,t){return e===`/`?{via:`in-place`}:{via:`navigate`,href:`/?wa=${encodeURIComponent(t.sessionId)}&projectDir=${encodeURIComponent(t.projectDir)}`}}function Re(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 ze(e,t){return t===`operator`&&e===`chat`||e===`dashboard`?`/`:e===`data`?`/data`:e===`graph`?`/graph`:e===`chat`?`/chat`:`/browser`}function Be(e){let{cacheKey:t,businessName:n,variant:r=`admin`,onLogout:i,onDisconnect:a,disconnecting:o,userName:s,userAvatar:c,role:u,children:d,footer:f}=e,[p,h]=(0,C.useState)(()=>Ne()),[g,ee]=(0,C.useState)(()=>Pe()),[te,ne]=(0,C.useState)(()=>typeof window<`u`&&window.matchMedia(`(max-width: ${Ie}px)`).matches),[_,v]=(0,C.useState)(()=>typeof window>`u`?null:Re(window.location.pathname,window.location.search)),[re]=(0,C.useState)(()=>_!==null);(0,C.useEffect)(()=>{if(typeof window>`u`)return;let e=window.matchMedia(`(max-width: ${Ie}px)`),t=e=>ne(e.matches);return e.addEventListener(`change`,t),()=>e.removeEventListener(`change`,t)},[]);let y=(0,C.useCallback)(e=>{Y(e),h(e)},[]),b=(0,C.useCallback)(e=>{Fe(e),ee(e)},[]);(0,C.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=${p} drawer=${g}`)},[]),(0,C.useEffect)(()=>{typeof window>`u`||!_||(console.info(`[admin-ui] wa-hydrate route=/ sessionId=${_.sessionId.slice(0,8)}`),window.history.replaceState(null,``,`/`))},[]);let ie=(0,C.useCallback)(e=>{if(e===null){v(null);return}let t=typeof window<`u`?window.location.pathname:`/`,n=Le(t,e);console.info(`[admin-ui] wa-open route=${t} via=${n.via} sessionId=${e.sessionId.slice(0,8)}`),n.via===`in-place`?v(e):window.location.href=n.href},[]),x=te?g:!p,ae=(0,C.useCallback)(()=>{if(!(typeof window>`u`))if(window.matchMedia(`(max-width: ${Ie}px)`).matches){let e=g;console.info(`[admin-ui] header-sidebar-toggle from=${e?`open`:`closed`} mode=drawer`),b(!e)}else{let e=p;console.info(`[admin-ui] header-sidebar-toggle from=${e?`closed`:`open`} mode=collapse`),y(!e)}},[p,g,y,b]),oe=(0,C.useCallback)(e=>{let t=ze(e,r);console.info(`[admin-ui] header-menu-nav target=${e} dest=${t}`),window.location.href=t},[r]),[se,ce]=(0,C.useState)(`chat`),[S,le]=(0,C.useState)([]);(0,C.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||le(t.conversations??[])}).catch(()=>{}),()=>{e=!0}},[r,t]);let T=(0,C.useMemo)(()=>[...new Set(S.map(e=>e.channel))],[S]),E={collapsed:p,mobileDrawerOpen:g,sidebarOpen:x,onToggleSidebar:ae,setMobileDrawerOpen:b,selectedWhatsapp:_,onClearWhatsapp:()=>v(null)};return r===`operator`?(0,w.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,w.jsx)(l,{businessName:n,variant:r,onNavigate:oe,conversationsCount:S.length,conversationsChannels:T,onOpenConversations:()=>ce(`conversations`),onToggleSidebar:ae,sidebarOpen:x,onLogout:i,onDisconnect:a,disconnecting:o}),(0,w.jsx)(`div`,{className:`platform platform-operator`,children:se===`conversations`?(0,w.jsx)(m,{conversations:S,sessionKey:t??``,onBack:()=>ce(`chat`)}):typeof d==`function`?d(E):d}),f]}):(0,w.jsxs)(`div`,{className:`admin-shell admin-page admin-shell-root`,children:[(0,w.jsx)(l,{businessName:n,variant:r,onNavigate:oe,onToggleSidebar:ae,sidebarOpen:x,onLogout:i,onDisconnect:a,disconnecting:o}),(0,w.jsxs)(`div`,{className:`platform${g?` menu-open`:``}${p?` sidebar-collapsed`:``}`,"data-artefact":`closed`,children:[(0,w.jsx)(Oe,{businessName:n,cacheKey:t,role:u??null,userName:s,userAvatar:c??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:()=>b(!1),collapsed:p,mobileDrawerOpen:g,selectedWhatsappId:_?.sessionId??null,onSelectWhatsappConversation:ie,initialWhatsappSurface:re}),!te&&(0,w.jsx)(ue,{}),typeof d==`function`?d(E):d]}),g&&(0,w.jsx)(`div`,{className:`sidebar-backdrop menu-open`,"aria-hidden":`true`,onClick:()=>b(!1)}),f]})}export{v as _,M as a,I as c,E as d,S as f,b as g,x as h,P as i,he as l,oe as m,Ce as n,L as o,se as p,R as r,N as s,Be as t,F as u,te as v};