@ottocode/web-sdk 0.1.267 → 0.1.268

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.
package/dist/index.js CHANGED
@@ -333,9 +333,14 @@ function ToastItem({ toast: toast2 }) {
333
333
  }),
334
334
  toast2.action && /* @__PURE__ */ jsxs2("button", {
335
335
  type: "button",
336
- onClick: (e) => {
336
+ onClick: async (e) => {
337
337
  e.stopPropagation();
338
- openUrl(toast2.action?.href);
338
+ if (toast2.action?.onClick) {
339
+ await toast2.action.onClick();
340
+ } else if (toast2.action?.href) {
341
+ openUrl(toast2.action.href);
342
+ }
343
+ handleDismiss();
339
344
  },
340
345
  className: "ml-auto flex items-center gap-1 text-xs text-primary hover:underline",
341
346
  children: [
@@ -6665,7 +6670,7 @@ var NewSessionLanding = memo6(forwardRef9(function NewSessionLanding2({ onSessio
6665
6670
  });
6666
6671
  }));
6667
6672
  // src/components/messages/MessageThread.tsx
6668
- import { useEffect as useEffect22, useRef as useRef14, useState as useState30, useMemo as useMemo15, memo as memo14, useCallback as useCallback17 } from "react";
6673
+ import { useEffect as useEffect23, useRef as useRef14, useState as useState30, useMemo as useMemo15, memo as memo14, useCallback as useCallback17 } from "react";
6669
6674
  import { ArrowDown } from "lucide-react";
6670
6675
  import { useQueryClient as useQueryClient9 } from "@tanstack/react-query";
6671
6676
 
@@ -7559,6 +7564,7 @@ function WriteRenderer({
7559
7564
  }
7560
7565
 
7561
7566
  // src/components/messages/renderers/BashRenderer.tsx
7567
+ import { useEffect as useEffect15 } from "react";
7562
7568
  import { Terminal as Terminal3 } from "lucide-react";
7563
7569
  import { Prism as SyntaxHighlighter4 } from "react-syntax-highlighter";
7564
7570
  import {
@@ -7566,6 +7572,56 @@ import {
7566
7572
  vscDarkPlus as vscDarkPlus4
7567
7573
  } from "react-syntax-highlighter/dist/esm/styles/prism";
7568
7574
 
7575
+ // src/lib/nerd-font.ts
7576
+ var NERD_FONT_FAMILY = '"JetBrainsMono NFM", monospace';
7577
+ var fontsLoaded = false;
7578
+ var loadPromise = null;
7579
+ function loadNerdFont() {
7580
+ if (fontsLoaded)
7581
+ return Promise.resolve();
7582
+ if (loadPromise)
7583
+ return loadPromise;
7584
+ loadPromise = doLoad().then(() => {
7585
+ fontsLoaded = true;
7586
+ });
7587
+ return loadPromise;
7588
+ }
7589
+ async function doLoad() {
7590
+ if (typeof document === "undefined" || !("FontFace" in window))
7591
+ return;
7592
+ const variants = [
7593
+ {
7594
+ file: "JetBrainsMonoNerdFontMono-Regular.woff2",
7595
+ weight: "400",
7596
+ style: "normal"
7597
+ },
7598
+ {
7599
+ file: "JetBrainsMonoNerdFontMono-Bold.woff2",
7600
+ weight: "700",
7601
+ style: "normal"
7602
+ },
7603
+ {
7604
+ file: "JetBrainsMonoNerdFontMono-Italic.woff2",
7605
+ weight: "400",
7606
+ style: "italic"
7607
+ },
7608
+ {
7609
+ file: "JetBrainsMonoNerdFontMono-BoldItalic.woff2",
7610
+ weight: "700",
7611
+ style: "italic"
7612
+ }
7613
+ ];
7614
+ const loads = variants.map(async (v) => {
7615
+ try {
7616
+ const url = new URL(`../assets/fonts/${v.file}`, import.meta.url).href;
7617
+ const face = new FontFace("JetBrainsMono NFM", `url("${url}") format("woff2")`, { weight: v.weight, style: v.style });
7618
+ const loaded = await face.load();
7619
+ document.fonts.add(loaded);
7620
+ } catch {}
7621
+ });
7622
+ await Promise.allSettled(loads);
7623
+ }
7624
+
7569
7625
  // src/components/messages/renderers/shared/CopyButton.tsx
7570
7626
  import { useState as useState17 } from "react";
7571
7627
  import { Copy, Check as Check5 } from "lucide-react";
@@ -7832,6 +7888,9 @@ function BashRenderer({
7832
7888
  onToggle,
7833
7889
  compact
7834
7890
  }) {
7891
+ useEffect15(() => {
7892
+ loadNerdFont();
7893
+ }, []);
7835
7894
  const result = contentJson.result || {};
7836
7895
  const args = contentJson.args || {};
7837
7896
  const hasToolError = typeof result === "object" && "ok" in result && result.ok === false;
@@ -7849,6 +7908,20 @@ function BashRenderer({
7849
7908
  const hasStderr = stderr.length > 0;
7850
7909
  const combinedOutput = stdout + (stdout && stderr ? `
7851
7910
  ` : "") + stderr;
7911
+ const outputStyle = {
7912
+ margin: 0,
7913
+ padding: "0.75rem",
7914
+ fontFamily: NERD_FONT_FAMILY,
7915
+ fontSize: "0.75rem",
7916
+ lineHeight: "1.5",
7917
+ background: "transparent",
7918
+ maxWidth: "100%"
7919
+ };
7920
+ const outputCodeProps = {
7921
+ style: {
7922
+ fontFamily: NERD_FONT_FAMILY
7923
+ }
7924
+ };
7852
7925
  return /* @__PURE__ */ jsxs26("div", {
7853
7926
  className: "text-xs",
7854
7927
  children: [
@@ -7926,14 +7999,8 @@ function BashRenderer({
7926
7999
  children: /* @__PURE__ */ jsx33(SyntaxHighlighter4, {
7927
8000
  language: "bash",
7928
8001
  style: syntaxTheme,
7929
- customStyle: {
7930
- margin: 0,
7931
- padding: "0.75rem",
7932
- fontSize: "0.75rem",
7933
- lineHeight: "1.5",
7934
- background: "transparent",
7935
- maxWidth: "100%"
7936
- },
8002
+ customStyle: outputStyle,
8003
+ codeTagProps: outputCodeProps,
7937
8004
  wrapLines: true,
7938
8005
  wrapLongLines: true,
7939
8006
  children: combinedOutput
@@ -7947,14 +8014,8 @@ function BashRenderer({
7947
8014
  children: /* @__PURE__ */ jsx33(SyntaxHighlighter4, {
7948
8015
  language: "bash",
7949
8016
  style: syntaxTheme,
7950
- customStyle: {
7951
- margin: 0,
7952
- padding: "0.75rem",
7953
- fontSize: "0.75rem",
7954
- lineHeight: "1.5",
7955
- background: "transparent",
7956
- maxWidth: "100%"
7957
- },
8017
+ customStyle: outputStyle,
8018
+ codeTagProps: outputCodeProps,
7958
8019
  wrapLines: true,
7959
8020
  wrapLongLines: true,
7960
8021
  children: stdout
@@ -7968,14 +8029,8 @@ function BashRenderer({
7968
8029
  children: /* @__PURE__ */ jsx33(SyntaxHighlighter4, {
7969
8030
  language: "bash",
7970
8031
  style: syntaxTheme,
7971
- customStyle: {
7972
- margin: 0,
7973
- padding: "0.75rem",
7974
- fontSize: "0.75rem",
7975
- lineHeight: "1.5",
7976
- background: "transparent",
7977
- maxWidth: "100%"
7978
- },
8032
+ customStyle: outputStyle,
8033
+ codeTagProps: outputCodeProps,
7979
8034
  wrapLines: true,
7980
8035
  wrapLongLines: true,
7981
8036
  children: stderr
@@ -10342,60 +10397,8 @@ function DatabaseToolRenderer({
10342
10397
  }
10343
10398
 
10344
10399
  // src/components/messages/renderers/TerminalRenderer.tsx
10345
- import { useEffect as useEffect15, useState as useState20 } from "react";
10400
+ import { useEffect as useEffect16, useState as useState20 } from "react";
10346
10401
  import { Terminal as Terminal4 } from "lucide-react";
10347
-
10348
- // src/lib/nerd-font.ts
10349
- var NERD_FONT_FAMILY = '"JetBrainsMono NFM", monospace';
10350
- var fontsLoaded = false;
10351
- var loadPromise = null;
10352
- function loadNerdFont() {
10353
- if (fontsLoaded)
10354
- return Promise.resolve();
10355
- if (loadPromise)
10356
- return loadPromise;
10357
- loadPromise = doLoad().then(() => {
10358
- fontsLoaded = true;
10359
- });
10360
- return loadPromise;
10361
- }
10362
- async function doLoad() {
10363
- if (typeof document === "undefined" || !("FontFace" in window))
10364
- return;
10365
- const variants = [
10366
- {
10367
- file: "JetBrainsMonoNerdFontMono-Regular.woff2",
10368
- weight: "400",
10369
- style: "normal"
10370
- },
10371
- {
10372
- file: "JetBrainsMonoNerdFontMono-Bold.woff2",
10373
- weight: "700",
10374
- style: "normal"
10375
- },
10376
- {
10377
- file: "JetBrainsMonoNerdFontMono-Italic.woff2",
10378
- weight: "400",
10379
- style: "italic"
10380
- },
10381
- {
10382
- file: "JetBrainsMonoNerdFontMono-BoldItalic.woff2",
10383
- weight: "700",
10384
- style: "italic"
10385
- }
10386
- ];
10387
- const loads = variants.map(async (v) => {
10388
- try {
10389
- const url = new URL(`../assets/fonts/${v.file}`, import.meta.url).href;
10390
- const face = new FontFace("JetBrainsMono NFM", `url("${url}") format("woff2")`, { weight: v.weight, style: v.style });
10391
- const loaded = await face.load();
10392
- document.fonts.add(loaded);
10393
- } catch {}
10394
- });
10395
- await Promise.allSettled(loads);
10396
- }
10397
-
10398
- // src/components/messages/renderers/TerminalRenderer.tsx
10399
10402
  import { jsx as jsx49, jsxs as jsxs42, Fragment as Fragment18 } from "react/jsx-runtime";
10400
10403
  var ANSI_RE = /[\x1B\x9B][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nq-uy=><~]/g;
10401
10404
  var CONTROL_RE = /[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g;
@@ -10413,7 +10416,7 @@ function TerminalRenderer({
10413
10416
  compact
10414
10417
  }) {
10415
10418
  const [, setFontReady] = useState20(false);
10416
- useEffect15(() => {
10419
+ useEffect16(() => {
10417
10420
  loadNerdFont().then(() => setFontReady(true));
10418
10421
  }, []);
10419
10422
  const result = contentJson.result || {};
@@ -11057,7 +11060,7 @@ function formatFileSize(bytes) {
11057
11060
  return `${(kb / 1024).toFixed(1)}MB`;
11058
11061
  }
11059
11062
  // src/components/messages/renderers/ReasoningRenderer.tsx
11060
- import { useState as useState21, useRef as useRef9, useEffect as useEffect16 } from "react";
11063
+ import { useState as useState21, useRef as useRef9, useEffect as useEffect17 } from "react";
11061
11064
  import { ChevronDown as ChevronDown5, ChevronRight as ChevronRight9 } from "lucide-react";
11062
11065
  import { jsx as jsx53, jsxs as jsxs46 } from "react/jsx-runtime";
11063
11066
  function ReasoningRenderer({ part }) {
@@ -11071,7 +11074,7 @@ function ReasoningRenderer({ part }) {
11071
11074
  } else if (typeof data === "string") {
11072
11075
  content = data;
11073
11076
  }
11074
- useEffect16(() => {
11077
+ useEffect17(() => {
11075
11078
  if (scrollRef.current && isExpanded && !part.completedAt && !isHoveredRef.current) {
11076
11079
  scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
11077
11080
  }
@@ -11831,7 +11834,7 @@ var MessagePartItem = memo8(function MessagePartItem2({
11831
11834
  });
11832
11835
 
11833
11836
  // src/components/messages/CompactActivityGroup.tsx
11834
- import { useEffect as useEffect17, useLayoutEffect as useLayoutEffect2, useMemo as useMemo10, useRef as useRef10, useState as useState23 } from "react";
11837
+ import { useEffect as useEffect18, useLayoutEffect as useLayoutEffect2, useMemo as useMemo10, useRef as useRef10, useState as useState23 } from "react";
11835
11838
  import { Brain as Brain4, Search as Search6 } from "lucide-react";
11836
11839
 
11837
11840
  // src/components/messages/compactActivity.ts
@@ -12150,7 +12153,7 @@ function CompactActivityGroup({
12150
12153
  const summaryText = [summaryTitle, ...summary.details].join(" · ");
12151
12154
  const hasReasoning = entries.some((e) => e.toolName === "reasoning");
12152
12155
  const lastEntry = entries.length > 0 ? entries[entries.length - 1] : null;
12153
- useEffect17(() => {
12156
+ useEffect18(() => {
12154
12157
  if (!collapsed && !latched) {
12155
12158
  setShowSummary(false);
12156
12159
  return;
@@ -12180,14 +12183,14 @@ function CompactActivityGroup({
12180
12183
  observer.observe(el);
12181
12184
  return () => observer.disconnect();
12182
12185
  }, [showSummary]);
12183
- useEffect17(() => {
12186
+ useEffect18(() => {
12184
12187
  return () => {
12185
12188
  if (scrollAnimationRef.current !== null) {
12186
12189
  window.cancelAnimationFrame(scrollAnimationRef.current);
12187
12190
  }
12188
12191
  };
12189
12192
  }, []);
12190
- useEffect17(() => {
12193
+ useEffect18(() => {
12191
12194
  if (showSummary || hoveredRef.current)
12192
12195
  return;
12193
12196
  const el = scrollRef.current;
@@ -12224,7 +12227,7 @@ function CompactActivityGroup({
12224
12227
  };
12225
12228
  scrollAnimationRef.current = window.requestAnimationFrame(tick);
12226
12229
  }, [entries.length, lastEntry?.fullText, showSummary, contentHeight]);
12227
- useEffect17(() => {
12230
+ useEffect18(() => {
12228
12231
  prevCountRef.current = entries.length;
12229
12232
  }, [entries.length]);
12230
12233
  const isLive = !showSummary;
@@ -12347,7 +12350,7 @@ function CompactActivityGroup({
12347
12350
  }
12348
12351
 
12349
12352
  // src/components/messages/ActionToolBox.tsx
12350
- import { useEffect as useEffect18, useLayoutEffect as useLayoutEffect3, useRef as useRef11, useState as useState24 } from "react";
12353
+ import { useEffect as useEffect19, useLayoutEffect as useLayoutEffect3, useRef as useRef11, useState as useState24 } from "react";
12351
12354
  import {
12352
12355
  Terminal as Terminal6,
12353
12356
  FileEdit as FileEdit3,
@@ -12507,7 +12510,7 @@ function ActionToolBox({ part, showLine }) {
12507
12510
  const streamedContent = getContentFromStream(toolName, streamedInput);
12508
12511
  const displayContent = isShellTool3(toolName) ? streamedOutput || streamedContent || (args ? getContentFromArgs(toolName, args) : "") : args ? getContentFromArgs(toolName, args) : streamedContent;
12509
12512
  const hasDisplayContent = displayContent.trim().length > 0;
12510
- useEffect18(() => {
12513
+ useEffect19(() => {
12511
12514
  if (!isComplete && !latched) {
12512
12515
  setShowSummary(false);
12513
12516
  return;
@@ -12533,14 +12536,14 @@ function ActionToolBox({ part, showLine }) {
12533
12536
  const nextHeight = Math.min(el.scrollHeight, MAX_SCROLL_H2 - 12);
12534
12537
  setContentHeight((prev) => prev === nextHeight ? prev : nextHeight);
12535
12538
  }, [displayContent, hasDisplayContent]);
12536
- useEffect18(() => {
12539
+ useEffect19(() => {
12537
12540
  return () => {
12538
12541
  if (scrollAnimationRef.current !== null) {
12539
12542
  window.cancelAnimationFrame(scrollAnimationRef.current);
12540
12543
  }
12541
12544
  };
12542
12545
  }, []);
12543
- useEffect18(() => {
12546
+ useEffect19(() => {
12544
12547
  const el = scrollRef.current;
12545
12548
  if (!el || hoveredRef.current)
12546
12549
  return;
@@ -13823,7 +13826,7 @@ import {
13823
13826
  } from "lucide-react";
13824
13827
 
13825
13828
  // src/components/sessions/EditableTitle.tsx
13826
- import { useState as useState28, useRef as useRef12, useEffect as useEffect19, useCallback as useCallback14 } from "react";
13829
+ import { useState as useState28, useRef as useRef12, useEffect as useEffect20, useCallback as useCallback14 } from "react";
13827
13830
  import { Pencil as Pencil2 } from "lucide-react";
13828
13831
  import { jsx as jsx61, jsxs as jsxs53 } from "react/jsx-runtime";
13829
13832
  function EditableTitle({
@@ -13835,13 +13838,13 @@ function EditableTitle({
13835
13838
  const [draft, setDraft] = useState28(title || "");
13836
13839
  const inputRef = useRef12(null);
13837
13840
  const { mutate: updateSession } = useUpdateSession(sessionId);
13838
- useEffect19(() => {
13841
+ useEffect20(() => {
13839
13842
  if (isEditing && inputRef.current) {
13840
13843
  inputRef.current.focus();
13841
13844
  inputRef.current.select();
13842
13845
  }
13843
13846
  }, [isEditing]);
13844
- useEffect19(() => {
13847
+ useEffect20(() => {
13845
13848
  setDraft(title || "");
13846
13849
  }, [title]);
13847
13850
  const save = useCallback14(() => {
@@ -14394,7 +14397,7 @@ var UsageModal = memo12(function UsageModal2() {
14394
14397
  });
14395
14398
 
14396
14399
  // src/hooks/useProviderUsage.ts
14397
- import { useEffect as useEffect20, useCallback as useCallback15, useRef as useRef13 } from "react";
14400
+ import { useEffect as useEffect21, useCallback as useCallback15, useRef as useRef13 } from "react";
14398
14401
  var POLL_INTERVAL = 60000;
14399
14402
  var STALE_THRESHOLD = 30000;
14400
14403
  var inflight = new Set;
@@ -14425,7 +14428,7 @@ function useProviderUsage(provider, authType) {
14425
14428
  }, [provider, isOAuthProvider, setUsage, setLoading, setLastFetched]);
14426
14429
  const fetchRef = useRef13(fetchUsage);
14427
14430
  fetchRef.current = fetchUsage;
14428
- useEffect20(() => {
14431
+ useEffect21(() => {
14429
14432
  if (!provider || !isOAuthProvider)
14430
14433
  return;
14431
14434
  fetchRef.current();
@@ -14440,7 +14443,7 @@ function useProviderUsage(provider, authType) {
14440
14443
  }
14441
14444
 
14442
14445
  // src/hooks/useOttoRouterBalance.ts
14443
- import { useEffect as useEffect21, useCallback as useCallback16 } from "react";
14446
+ import { useEffect as useEffect22, useCallback as useCallback16 } from "react";
14444
14447
  function useOttoRouterBalance(providerName) {
14445
14448
  const setBalance = useOttoRouterStore((s) => s.setBalance);
14446
14449
  const setUsdcBalance = useOttoRouterStore((s) => s.setUsdcBalance);
@@ -14517,7 +14520,7 @@ function useOttoRouterBalance(providerName) {
14517
14520
  setUsage
14518
14521
  ]);
14519
14522
  const needsUsageWindows = subscription?.active && !subscription.usageWindows;
14520
- useEffect21(() => {
14523
+ useEffect22(() => {
14521
14524
  if (providerName === "ottorouter" && (balance === null || usdcBalance === null || needsUsageWindows)) {
14522
14525
  fetchBalance();
14523
14526
  }
@@ -14957,7 +14960,7 @@ var MessageThread = memo14(function MessageThread2({
14957
14960
  setShowLeanHeader(headerRect.bottom < containerRect.top);
14958
14961
  }
14959
14962
  }, []);
14960
- useEffect22(() => {
14963
+ useEffect23(() => {
14961
14964
  if (disableAutoScroll)
14962
14965
  return;
14963
14966
  const sessionChanged = session?.id !== lastSessionIdRef.current;
@@ -14973,7 +14976,7 @@ var MessageThread = memo14(function MessageThread2({
14973
14976
  }
14974
14977
  }
14975
14978
  }, [messages.length, session?.id, disableAutoScroll]);
14976
- useEffect22(() => {
14979
+ useEffect23(() => {
14977
14980
  if (disableAutoScroll)
14978
14981
  return;
14979
14982
  const justStartedGenerating = isGenerating && !prevIsGeneratingRef.current;
@@ -14997,7 +15000,7 @@ var MessageThread = memo14(function MessageThread2({
14997
15000
  setAutoScroll(true);
14998
15001
  }
14999
15002
  }, [messages.length, isGenerating, disableAutoScroll]);
15000
- useEffect22(() => {
15003
+ useEffect23(() => {
15001
15004
  if (disableAutoScroll)
15002
15005
  return;
15003
15006
  const container = scrollContainerRef.current;
@@ -15027,7 +15030,7 @@ var MessageThread = memo14(function MessageThread2({
15027
15030
  }
15028
15031
  animationFrameRef.current = requestAnimationFrame(animate);
15029
15032
  }, [messages, autoScroll]);
15030
- useEffect22(() => {
15033
+ useEffect23(() => {
15031
15034
  return () => {
15032
15035
  if (userScrollTimeoutRef.current) {
15033
15036
  clearTimeout(userScrollTimeoutRef.current);
@@ -15191,7 +15194,7 @@ var MessageThread = memo14(function MessageThread2({
15191
15194
  import { memo as memo17, useMemo as useMemo16 } from "react";
15192
15195
 
15193
15196
  // src/hooks/useSessionStream.ts
15194
- import { useEffect as useEffect23, useRef as useRef15 } from "react";
15197
+ import { useEffect as useEffect24, useRef as useRef15 } from "react";
15195
15198
  import { useQueryClient as useQueryClient10 } from "@tanstack/react-query";
15196
15199
 
15197
15200
  // src/lib/sse-client.ts
@@ -15317,7 +15320,7 @@ function useSessionStream(sessionId, enabled = true) {
15317
15320
  updatePendingApproval,
15318
15321
  setPendingApprovals
15319
15322
  } = useToolApprovalStore();
15320
- useEffect23(() => {
15323
+ useEffect24(() => {
15321
15324
  if (!sessionId || !enabled) {
15322
15325
  return;
15323
15326
  }
@@ -16044,7 +16047,7 @@ function useSessionStream(sessionId, enabled = true) {
16044
16047
  }
16045
16048
 
16046
16049
  // src/hooks/useToolApprovalShortcuts.ts
16047
- import { useEffect as useEffect24, useCallback as useCallback18 } from "react";
16050
+ import { useEffect as useEffect25, useCallback as useCallback18 } from "react";
16048
16051
  function useToolApprovalShortcuts(sessionId) {
16049
16052
  const { pendingApprovals, removePendingApproval } = useToolApprovalStore();
16050
16053
  const sessionPendingApprovals = pendingApprovals;
@@ -16080,7 +16083,7 @@ function useToolApprovalShortcuts(sessionId) {
16080
16083
  console.error("Failed to approve all tool calls:", error);
16081
16084
  }
16082
16085
  }, [sessionId, sessionPendingApprovals, removePendingApproval]);
16083
- useEffect24(() => {
16086
+ useEffect25(() => {
16084
16087
  if (!sessionId || sessionPendingApprovals.length === 0)
16085
16088
  return;
16086
16089
  const handleKeyDown = (e) => {
@@ -16111,7 +16114,7 @@ function useToolApprovalShortcuts(sessionId) {
16111
16114
  }
16112
16115
 
16113
16116
  // src/components/settings/OttoRouterTopupModal.tsx
16114
- import { memo as memo16, useState as useState31, useEffect as useEffect25, useCallback as useCallback19, useRef as useRef16 } from "react";
16117
+ import { memo as memo16, useState as useState31, useEffect as useEffect26, useCallback as useCallback19, useRef as useRef16 } from "react";
16115
16118
  import {
16116
16119
  CreditCard as CreditCard4,
16117
16120
  Wallet as Wallet2,
@@ -16356,7 +16359,7 @@ var OttoRouterTopupModal = memo16(function OttoRouterTopupModal2() {
16356
16359
  setIsLoadingEstimate(false);
16357
16360
  }
16358
16361
  }, [gateway, minAmount]);
16359
- useEffect25(() => {
16362
+ useEffect26(() => {
16360
16363
  if (isOpen && effectiveAmount >= minAmount && view === "amount") {
16361
16364
  const timeout = setTimeout(() => fetchEstimate(effectiveAmount), 300);
16362
16365
  return () => clearTimeout(timeout);
@@ -16369,7 +16372,7 @@ var OttoRouterTopupModal = memo16(function OttoRouterTopupModal2() {
16369
16372
  }
16370
16373
  setIsPolling(false);
16371
16374
  }, []);
16372
- useEffect25(() => {
16375
+ useEffect26(() => {
16373
16376
  if (!isOpen) {
16374
16377
  stopPolling();
16375
16378
  setView("amount");
@@ -16378,7 +16381,7 @@ var OttoRouterTopupModal = memo16(function OttoRouterTopupModal2() {
16378
16381
  setPollCount(0);
16379
16382
  }
16380
16383
  }, [isOpen, stopPolling]);
16381
- useEffect25(() => {
16384
+ useEffect26(() => {
16382
16385
  return () => stopPolling();
16383
16386
  }, [stopPolling]);
16384
16387
  const startPolling = useCallback19((checkoutId) => {
@@ -17080,7 +17083,7 @@ var SessionItem = memo18(function SessionItem2({
17080
17083
  });
17081
17084
  });
17082
17085
  // src/components/sessions/SessionListContainer.tsx
17083
- import { memo as memo19, useMemo as useMemo17, useCallback as useCallback20, useEffect as useEffect26, useRef as useRef17 } from "react";
17086
+ import { memo as memo19, useMemo as useMemo17, useCallback as useCallback20, useEffect as useEffect27, useRef as useRef17 } from "react";
17084
17087
 
17085
17088
  // src/stores/focusStore.ts
17086
17089
  import { create as create18 } from "zustand";
@@ -17142,7 +17145,7 @@ var SessionListContainer = memo19(function SessionListContainer2({
17142
17145
  sessions: groupedSessions
17143
17146
  }));
17144
17147
  }, [sessionSnapshot]);
17145
- useEffect26(() => {
17148
+ useEffect27(() => {
17146
17149
  if (currentFocus === "sessions") {
17147
17150
  const session = sessionSnapshot[sessionIndex];
17148
17151
  if (session) {
@@ -17151,7 +17154,7 @@ var SessionListContainer = memo19(function SessionListContainer2({
17151
17154
  }
17152
17155
  }
17153
17156
  }, [currentFocus, sessionIndex, sessionSnapshot]);
17154
- useEffect26(() => {
17157
+ useEffect27(() => {
17155
17158
  if (!activeSessionId || lastScrolledSessionId.current === activeSessionId || sessions.length === 0)
17156
17159
  return;
17157
17160
  const activeIndex = sessions.findIndex((s) => s.id === activeSessionId);
@@ -17167,7 +17170,7 @@ var SessionListContainer = memo19(function SessionListContainer2({
17167
17170
  });
17168
17171
  }
17169
17172
  }, [activeSessionId, sessions, hasNextPage, fetchNextPage]);
17170
- useEffect26(() => {
17173
+ useEffect27(() => {
17171
17174
  const container = scrollContainerRef.current;
17172
17175
  if (!container)
17173
17176
  return;
@@ -17889,7 +17892,7 @@ ${file.absPath}`,
17889
17892
  }
17890
17893
 
17891
17894
  // src/components/git/GitFileList.tsx
17892
- import { useEffect as useEffect27, useRef as useRef18, useMemo as useMemo18 } from "react";
17895
+ import { useEffect as useEffect28, useRef as useRef18, useMemo as useMemo18 } from "react";
17893
17896
  import { jsx as jsx75, jsxs as jsxs67 } from "react/jsx-runtime";
17894
17897
  function GitFileList({ status }) {
17895
17898
  const { openCommitModal, openDiff } = useGitStore();
@@ -17924,7 +17927,7 @@ function GitFileList({ status }) {
17924
17927
  }
17925
17928
  };
17926
17929
  const conflictedLength = status.conflicted?.length ?? 0;
17927
- useEffect27(() => {
17930
+ useEffect28(() => {
17928
17931
  if (currentFocus === "git" && gitFileIndex >= 0) {
17929
17932
  const element = itemRefs.current.get(gitFileIndex);
17930
17933
  element?.scrollIntoView({ block: "nearest", behavior: "smooth" });
@@ -18128,7 +18131,7 @@ function GitFileList({ status }) {
18128
18131
  });
18129
18132
  }
18130
18133
  // src/components/git/GitSidebar.tsx
18131
- import { memo as memo20, useCallback as useCallback21, useEffect as useEffect28, useState as useState33 } from "react";
18134
+ import { memo as memo20, useCallback as useCallback21, useEffect as useEffect29, useState as useState33 } from "react";
18132
18135
  import {
18133
18136
  FolderGit2,
18134
18137
  ChevronRight as ChevronRight10,
@@ -18169,7 +18172,7 @@ var GitSidebar = memo20(function GitSidebar2({
18169
18172
  const [remoteName, setRemoteName] = useState33("origin");
18170
18173
  const [remoteUrl, setRemoteUrl] = useState33("");
18171
18174
  const [confirmRemoveRemote, setConfirmRemoveRemote] = useState33(null);
18172
- useEffect28(() => {
18175
+ useEffect29(() => {
18173
18176
  if (isExpanded) {
18174
18177
  queryClient.invalidateQueries({ queryKey: ["git", "status"] });
18175
18178
  }
@@ -18618,7 +18621,7 @@ var GitSidebarToggle = memo21(function GitSidebarToggle2() {
18618
18621
  });
18619
18622
  });
18620
18623
  // src/components/git/GitDiffPanel.tsx
18621
- import { useEffect as useEffect29, useRef as useRef19, memo as memo22, useState as useState34 } from "react";
18624
+ import { useEffect as useEffect30, useRef as useRef19, memo as memo22, useState as useState34 } from "react";
18622
18625
  import { X as X12, Maximize2, Minimize2 as Minimize22 } from "lucide-react";
18623
18626
 
18624
18627
  // src/stores/sidebarStore.ts
@@ -18677,7 +18680,7 @@ var GitDiffPanel = memo22(function GitDiffPanel2() {
18677
18680
  const { data: fullFileDiff, isLoading: fullFileLoading } = useGitDiffFullFile(selectedFile, selectedFileStaged, showFullFile);
18678
18681
  const activeDiff = showFullFile && fullFileDiff ? fullFileDiff : diff;
18679
18682
  const activeLoading = showFullFile ? fullFileLoading : isLoading;
18680
- useEffect29(() => {
18683
+ useEffect30(() => {
18681
18684
  if (!isDiffOpen)
18682
18685
  setShowFullFile(false);
18683
18686
  if (isDiffOpen && !prevDiffOpenRef.current) {
@@ -18692,7 +18695,7 @@ var GitDiffPanel = memo22(function GitDiffPanel2() {
18692
18695
  }
18693
18696
  prevDiffOpenRef.current = isDiffOpen;
18694
18697
  }, [isDiffOpen, setCollapsed]);
18695
- useEffect29(() => {
18698
+ useEffect30(() => {
18696
18699
  const handleEscape = (e) => {
18697
18700
  const target = e.target;
18698
18701
  const isInInput = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable;
@@ -18771,7 +18774,7 @@ ${activeDiff?.absPath || ""}`,
18771
18774
  });
18772
18775
  });
18773
18776
  // src/components/git/GitCommitModal.tsx
18774
- import { useState as useState35, useId as useId2, useEffect as useEffect30, useCallback as useCallback22 } from "react";
18777
+ import { useState as useState35, useId as useId2, useEffect as useEffect31, useCallback as useCallback22 } from "react";
18775
18778
  import { GitCommit as GitCommit4, Sparkles as Sparkles5, Loader2 as Loader28 } from "lucide-react";
18776
18779
  import { jsx as jsx79, jsxs as jsxs71, Fragment as Fragment33 } from "react/jsx-runtime";
18777
18780
  function GitCommitModal() {
@@ -18804,7 +18807,7 @@ function GitCommitModal() {
18804
18807
  console.error("Failed to generate commit message:", error);
18805
18808
  }
18806
18809
  }, [generateMessage]);
18807
- useEffect30(() => {
18810
+ useEffect31(() => {
18808
18811
  if (!isCommitModalOpen)
18809
18812
  return;
18810
18813
  const handleKeyDown = (e) => {
@@ -18942,7 +18945,7 @@ function GitCommitModal() {
18942
18945
  });
18943
18946
  }
18944
18947
  // src/components/terminals/TerminalsPanel.tsx
18945
- import { memo as memo24, useCallback as useCallback24, useRef as useRef21, useEffect as useEffect32 } from "react";
18948
+ import { memo as memo24, useCallback as useCallback24, useRef as useRef21, useEffect as useEffect33 } from "react";
18946
18949
  import {
18947
18950
  Terminal as TerminalIcon,
18948
18951
  Maximize2 as Maximize22,
@@ -19112,7 +19115,7 @@ var TerminalTabBar = memo23(function TerminalTabBar2({
19112
19115
  });
19113
19116
 
19114
19117
  // src/components/terminals/TerminalViewer.tsx
19115
- import { useEffect as useEffect31, useRef as useRef20, useState as useState36, useCallback as useCallback23 } from "react";
19118
+ import { useEffect as useEffect32, useRef as useRef20, useState as useState36, useCallback as useCallback23 } from "react";
19116
19119
  import { init, Terminal as Terminal7, FitAddon } from "ghostty-web";
19117
19120
  import { client as client3 } from "@ottocode/api";
19118
19121
  import { jsx as jsx81, jsxs as jsxs73 } from "react/jsx-runtime";
@@ -19277,7 +19280,7 @@ function TerminalViewer({
19277
19280
  }
19278
19281
  };
19279
19282
  }, [terminalId]);
19280
- useEffect31(() => {
19283
+ useEffect32(() => {
19281
19284
  if (!containerRef.current || !terminalId)
19282
19285
  return;
19283
19286
  let disposed = false;
@@ -19447,7 +19450,7 @@ function TerminalViewer({
19447
19450
  fitAddonRef.current = null;
19448
19451
  };
19449
19452
  }, [terminalId, connectWebSocket]);
19450
- useEffect31(() => {
19453
+ useEffect32(() => {
19451
19454
  const term = termRef.current;
19452
19455
  if (!term)
19453
19456
  return;
@@ -19465,7 +19468,7 @@ function TerminalViewer({
19465
19468
  }
19466
19469
  }
19467
19470
  }, [isActive, fitTerminal]);
19468
- useEffect31(() => {
19471
+ useEffect32(() => {
19469
19472
  fitTerminal();
19470
19473
  }, [fitTerminal]);
19471
19474
  return /* @__PURE__ */ jsx81("div", {
@@ -19540,12 +19543,12 @@ var TerminalsPanel = memo24(function TerminalsPanel2() {
19540
19543
  const autoCreatingRef = useRef21(false);
19541
19544
  const terminalsListRef = useRef21(terminalsList);
19542
19545
  terminalsListRef.current = terminalsList;
19543
- useEffect32(() => {
19546
+ useEffect33(() => {
19544
19547
  if (isOpen && terminalsListRef.current.length > 0 && (!activeTabId || !terminalsListRef.current.find((t) => t.id === activeTabId))) {
19545
19548
  selectTab(terminalsListRef.current[0].id);
19546
19549
  }
19547
19550
  }, [isOpen, terminalsList.length, activeTabId, selectTab]);
19548
- useEffect32(() => {
19551
+ useEffect33(() => {
19549
19552
  if (isOpen && terminals && terminalsList.length === 0 && !autoCreatingRef.current && !createTerminal.isPending) {
19550
19553
  autoCreatingRef.current = true;
19551
19554
  createTerminal.mutateAsync({
@@ -19581,7 +19584,7 @@ var TerminalsPanel = memo24(function TerminalsPanel2() {
19581
19584
  }
19582
19585
  } catch {}
19583
19586
  }, [killTerminal, activeTabId, selectTab, closePanel]);
19584
- useEffect32(() => {
19587
+ useEffect33(() => {
19585
19588
  const handleKeyDown = (e) => {
19586
19589
  if (e.key === "`" && e.ctrlKey) {
19587
19590
  e.preventDefault();
@@ -20007,7 +20010,7 @@ var SessionFilesSidebarToggle = memo27(function SessionFilesSidebarToggle2({
20007
20010
  });
20008
20011
  });
20009
20012
  // src/components/session-files/SessionFilesDiffPanel.tsx
20010
- import { useEffect as useEffect33, useMemo as useMemo20, memo as memo28, useRef as useRef22 } from "react";
20013
+ import { useEffect as useEffect34, useMemo as useMemo20, memo as memo28, useRef as useRef22 } from "react";
20011
20014
  import { X as X14, ChevronLeft, ChevronRight as ChevronRight11 } from "lucide-react";
20012
20015
  import { Prism as SyntaxHighlighter10 } from "react-syntax-highlighter";
20013
20016
  import {
@@ -20339,7 +20342,7 @@ ${contentLines.map((line) => `+${line}`).join(`
20339
20342
  }
20340
20343
  return rawPatch;
20341
20344
  }, [selectedOperation, selectedFile]);
20342
- useEffect33(() => {
20345
+ useEffect34(() => {
20343
20346
  if (isDiffOpen && !prevDiffOpenRef.current) {
20344
20347
  const { isCollapsed } = useSidebarStore.getState();
20345
20348
  wasCollapsedRef.current = isCollapsed;
@@ -20352,7 +20355,7 @@ ${contentLines.map((line) => `+${line}`).join(`
20352
20355
  }
20353
20356
  prevDiffOpenRef.current = isDiffOpen;
20354
20357
  }, [isDiffOpen, setCollapsed]);
20355
- useEffect33(() => {
20358
+ useEffect34(() => {
20356
20359
  const handleKeyDown = (e) => {
20357
20360
  const target = e.target;
20358
20361
  const isInInput = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable;
@@ -20504,7 +20507,7 @@ ${contentLines.map((line) => `+${line}`).join(`
20504
20507
  });
20505
20508
  });
20506
20509
  // src/components/research/ResearchSidebar.tsx
20507
- import { memo as memo29, useState as useState37, useEffect as useEffect34, useCallback as useCallback25, useRef as useRef23, useMemo as useMemo21 } from "react";
20510
+ import { memo as memo29, useState as useState37, useEffect as useEffect35, useCallback as useCallback25, useRef as useRef23, useMemo as useMemo21 } from "react";
20508
20511
  import {
20509
20512
  FlaskConical as FlaskConical3,
20510
20513
  Plus as Plus5,
@@ -20680,12 +20683,12 @@ var ResearchSidebar = memo29(function ResearchSidebar2({
20680
20683
  queryClient.invalidateQueries({ queryKey: ["messages", sessionId] });
20681
20684
  }
20682
20685
  });
20683
- useEffect34(() => {
20686
+ useEffect35(() => {
20684
20687
  if (parentSessionId) {
20685
20688
  useResearchStore.getState().setParentSessionId(parentSessionId);
20686
20689
  }
20687
20690
  }, [parentSessionId]);
20688
- useEffect34(() => {
20691
+ useEffect35(() => {
20689
20692
  if (researchData?.sessions?.length) {
20690
20693
  const currentIsValid = researchData.sessions.some((s) => s.id === activeResearchSessionId);
20691
20694
  if (!currentIsValid) {
@@ -20695,7 +20698,7 @@ var ResearchSidebar = memo29(function ResearchSidebar2({
20695
20698
  selectResearchSession(null);
20696
20699
  }
20697
20700
  }, [researchData, activeResearchSessionId, selectResearchSession]);
20698
- useEffect34(() => {
20701
+ useEffect35(() => {
20699
20702
  messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });
20700
20703
  }, []);
20701
20704
  const adjustTextareaHeight = useCallback25(() => {
@@ -20705,7 +20708,7 @@ var ResearchSidebar = memo29(function ResearchSidebar2({
20705
20708
  textarea.style.height = "auto";
20706
20709
  textarea.style.height = `${Math.min(textarea.scrollHeight, 120)}px`;
20707
20710
  }, []);
20708
- useEffect34(() => {
20711
+ useEffect35(() => {
20709
20712
  adjustTextareaHeight();
20710
20713
  }, [adjustTextareaHeight]);
20711
20714
  const handleCreateNew = useCallback25(async () => {
@@ -21197,7 +21200,7 @@ var ResearchSidebarToggle = memo30(function ResearchSidebarToggle2({
21197
21200
  });
21198
21201
  });
21199
21202
  // src/components/settings/SettingsSidebar.tsx
21200
- import { memo as memo31, useState as useState39, useMemo as useMemo22, useCallback as useCallback27, useEffect as useEffect37, useRef as useRef26 } from "react";
21203
+ import { memo as memo31, useState as useState39, useMemo as useMemo22, useCallback as useCallback27, useEffect as useEffect38, useRef as useRef26 } from "react";
21201
21204
  import { createPortal } from "react-dom";
21202
21205
  import {
21203
21206
  Settings as Settings2,
@@ -21259,7 +21262,7 @@ var useOnboardingStore = create21((set, get) => ({
21259
21262
  }));
21260
21263
 
21261
21264
  // src/hooks/useAuthStatus.ts
21262
- import { useEffect as useEffect35, useCallback as useCallback26, useState as useState38, useRef as useRef24 } from "react";
21265
+ import { useEffect as useEffect36, useCallback as useCallback26, useState as useState38, useRef as useRef24 } from "react";
21263
21266
  import { useQueryClient as useQueryClient15 } from "@tanstack/react-query";
21264
21267
  var isInIframe = typeof window !== "undefined" && window.self !== window.top;
21265
21268
  function useAuthStatus() {
@@ -21453,7 +21456,7 @@ function useAuthStatus() {
21453
21456
  setLoading(false);
21454
21457
  }
21455
21458
  }, [fetchAuthStatus, setLoading, setError]);
21456
- useEffect35(() => {
21459
+ useEffect36(() => {
21457
21460
  if (!oauthPolling || !isInIframe)
21458
21461
  return;
21459
21462
  oauthPollingRef.current = setInterval(() => {
@@ -21467,7 +21470,7 @@ function useAuthStatus() {
21467
21470
  clearTimeout(timeout);
21468
21471
  };
21469
21472
  }, [oauthPolling, fetchAuthStatus]);
21470
- useEffect35(() => {
21473
+ useEffect36(() => {
21471
21474
  if (!oauthPolling || !authStatus)
21472
21475
  return;
21473
21476
  const currentConfigured = Object.entries(authStatus.providers).filter(([, p]) => p.configured);
@@ -21476,7 +21479,7 @@ function useAuthStatus() {
21476
21479
  setOauthPolling(false);
21477
21480
  }
21478
21481
  }, [authStatus, oauthPolling]);
21479
- useEffect35(() => {
21482
+ useEffect36(() => {
21480
21483
  const handleOAuthMessage = (event) => {
21481
21484
  if (event.data?.type === "oauth-success") {
21482
21485
  fetchAuthStatus();
@@ -21547,14 +21550,14 @@ function useAuthStatus() {
21547
21550
  }
21548
21551
 
21549
21552
  // src/hooks/useTopupCallback.ts
21550
- import { useEffect as useEffect36, useRef as useRef25 } from "react";
21553
+ import { useEffect as useEffect37, useRef as useRef25 } from "react";
21551
21554
  var STORAGE_KEY2 = "pendingPolarCheckout";
21552
21555
  function useTopupCallback() {
21553
21556
  const hasHandled = useRef25(false);
21554
21557
  const loadingToastId = useRef25(null);
21555
21558
  const setBalance = useOttoRouterStore((s) => s.setBalance);
21556
21559
  const removeToast = useToastStore((s) => s.removeToast);
21557
- useEffect36(() => {
21560
+ useEffect37(() => {
21558
21561
  if (hasHandled.current)
21559
21562
  return;
21560
21563
  const params = new URLSearchParams(window.location.search);
@@ -21745,7 +21748,7 @@ var SelectRow = memo31(function SelectRow2({
21745
21748
  const [menuStyle, setMenuStyle] = useState39(null);
21746
21749
  const buttonRef = useRef26(null);
21747
21750
  const selectedOption = options.find((o) => o.id === value);
21748
- useEffect37(() => {
21751
+ useEffect38(() => {
21749
21752
  if (!isOpen || !buttonRef.current)
21750
21753
  return;
21751
21754
  const update = () => {
@@ -21962,7 +21965,7 @@ var NumberInputRow = memo31(function NumberInputRow2({
21962
21965
  disabled
21963
21966
  }) {
21964
21967
  const [draft, setDraft] = useState39(value !== null && value !== undefined ? String(value) : "");
21965
- useEffect37(() => {
21968
+ useEffect38(() => {
21966
21969
  setDraft(value !== null && value !== undefined ? String(value) : "");
21967
21970
  }, [value]);
21968
21971
  const persistedValue = value !== null && value !== undefined ? String(value) : "";
@@ -22686,7 +22689,7 @@ import { QRCodeSVG as QRCodeSVG2 } from "qrcode.react";
22686
22689
 
22687
22690
  // src/hooks/useTunnel.ts
22688
22691
  import { useQuery as useQuery12, useMutation as useMutation9, useQueryClient as useQueryClient16 } from "@tanstack/react-query";
22689
- import { useEffect as useEffect38, useCallback as useCallback28, useRef as useRef27 } from "react";
22692
+ import { useEffect as useEffect39, useCallback as useCallback28, useRef as useRef27 } from "react";
22690
22693
  import {
22691
22694
  client as client4,
22692
22695
  getTunnelQr,
@@ -22729,7 +22732,7 @@ function useTunnelStatus() {
22729
22732
  queryFn: fetchTunnelStatus,
22730
22733
  refetchInterval: 3000
22731
22734
  });
22732
- useEffect38(() => {
22735
+ useEffect39(() => {
22733
22736
  if (query.data) {
22734
22737
  setStatus(query.data.status);
22735
22738
  setUrl(query.data.url);
@@ -22789,7 +22792,7 @@ function useTunnelQr() {
22789
22792
  queryFn: fetchTunnelQr,
22790
22793
  enabled: !!url
22791
22794
  });
22792
- useEffect38(() => {
22795
+ useEffect39(() => {
22793
22796
  if (query.data?.ok && query.data.qrCode) {
22794
22797
  setQrCode(query.data.qrCode);
22795
22798
  }
@@ -22829,7 +22832,7 @@ function useTunnelStream() {
22829
22832
  eventSourceRef.current = null;
22830
22833
  };
22831
22834
  }, [setStatus, setUrl, setError, setProgress]);
22832
- useEffect38(() => {
22835
+ useEffect39(() => {
22833
22836
  if (isExpanded) {
22834
22837
  const cleanup = connect();
22835
22838
  return cleanup;
@@ -23083,7 +23086,7 @@ var TunnelSidebarToggle = memo34(function TunnelSidebarToggle2() {
23083
23086
  });
23084
23087
  });
23085
23088
  // src/components/mcp/MCPSidebar.tsx
23086
- import { memo as memo37, useState as useState42, useCallback as useCallback31, useMemo as useMemo23, useEffect as useEffect41, useRef as useRef30 } from "react";
23089
+ import { memo as memo37, useState as useState42, useCallback as useCallback31, useMemo as useMemo23, useEffect as useEffect42, useRef as useRef30 } from "react";
23087
23090
  import {
23088
23091
  ChevronDown as ChevronDown10,
23089
23092
  ChevronRight as ChevronRight13,
@@ -23103,7 +23106,7 @@ import { useQueryClient as useQueryClient18 } from "@tanstack/react-query";
23103
23106
 
23104
23107
  // src/hooks/useMCP.ts
23105
23108
  import { useQuery as useQuery13, useMutation as useMutation10, useQueryClient as useQueryClient17 } from "@tanstack/react-query";
23106
- import { useEffect as useEffect39, useRef as useRef28, useCallback as useCallback29 } from "react";
23109
+ import { useEffect as useEffect40, useRef as useRef28, useCallback as useCallback29 } from "react";
23107
23110
  import {
23108
23111
  listMcpServers,
23109
23112
  startMcpServer,
@@ -23125,7 +23128,7 @@ function useMCPServers() {
23125
23128
  },
23126
23129
  refetchInterval: 1e4
23127
23130
  });
23128
- useEffect39(() => {
23131
+ useEffect40(() => {
23129
23132
  if (query.data?.servers) {
23130
23133
  setServers(query.data.servers);
23131
23134
  }
@@ -23276,7 +23279,7 @@ function useCopilotDevicePoller() {
23276
23279
  timerRef.current = null;
23277
23280
  }
23278
23281
  }, []);
23279
- useEffect39(() => {
23282
+ useEffect40(() => {
23280
23283
  if (!copilotDevice) {
23281
23284
  stopPolling();
23282
23285
  return;
@@ -23312,7 +23315,7 @@ function useCopilotDevicePoller() {
23312
23315
  }
23313
23316
 
23314
23317
  // src/components/mcp/AddMCPServerModal.tsx
23315
- import { memo as memo35, useState as useState41, useCallback as useCallback30, useRef as useRef29, useEffect as useEffect40 } from "react";
23318
+ import { memo as memo35, useState as useState41, useCallback as useCallback30, useRef as useRef29, useEffect as useEffect41 } from "react";
23316
23319
  import { Globe as Globe5, Laptop, Loader2 as Loader212, FolderDot, Terminal as Terminal9 } from "lucide-react";
23317
23320
  import { jsx as jsx93, jsxs as jsxs84, Fragment as Fragment39 } from "react/jsx-runtime";
23318
23321
  function parseCommandString(input) {
@@ -23435,7 +23438,7 @@ var AddMCPServerModal = memo35(function AddMCPServerModal2({
23435
23438
  ]);
23436
23439
  const contentRef = useRef29(null);
23437
23440
  const [contentHeight, setContentHeight] = useState41(undefined);
23438
- useEffect40(() => {
23441
+ useEffect41(() => {
23439
23442
  const el = contentRef.current;
23440
23443
  if (!el)
23441
23444
  return;
@@ -23972,7 +23975,7 @@ var MCPServerCard = memo37(function MCPServerCard2({
23972
23975
  function useAuthPoller(name, onAuthenticated) {
23973
23976
  const { data } = useMCPAuthStatus(name);
23974
23977
  const prevAuth = useRef30(false);
23975
- useEffect41(() => {
23978
+ useEffect42(() => {
23976
23979
  if (data?.authenticated && !prevAuth.current) {
23977
23980
  onAuthenticated();
23978
23981
  }
@@ -24006,7 +24009,7 @@ var MCPSidebar = memo37(function MCPSidebar2() {
24006
24009
  }
24007
24010
  }, [pollingServer, setAuthUrl, queryClient]);
24008
24011
  useAuthPoller(pollingServer, handleAuthCompleted);
24009
- useEffect41(() => {
24012
+ useEffect42(() => {
24010
24013
  for (const name of loading) {
24011
24014
  const server = servers.find((s) => s.name === name);
24012
24015
  if (server?.connected) {
@@ -24260,7 +24263,7 @@ import {
24260
24263
 
24261
24264
  // src/hooks/useSkills.ts
24262
24265
  import { useMutation as useMutation11, useQuery as useQuery14, useQueryClient as useQueryClient19 } from "@tanstack/react-query";
24263
- import { useEffect as useEffect42 } from "react";
24266
+ import { useEffect as useEffect43 } from "react";
24264
24267
  function useSkills() {
24265
24268
  const setSkillsConfig = useSkillsStore((s) => s.setSkillsConfig);
24266
24269
  const query = useQuery14({
@@ -24270,7 +24273,7 @@ function useSkills() {
24270
24273
  },
24271
24274
  refetchInterval: 30000
24272
24275
  });
24273
- useEffect42(() => {
24276
+ useEffect43(() => {
24274
24277
  if (query.data?.items) {
24275
24278
  setSkillsConfig({
24276
24279
  skills: query.data.items,
@@ -24664,7 +24667,7 @@ var SkillsSidebarToggle = memo40(function SkillsSidebarToggle2() {
24664
24667
  });
24665
24668
  });
24666
24669
  // src/components/skills/SkillViewerPanel.tsx
24667
- import { memo as memo41, useEffect as useEffect43 } from "react";
24670
+ import { memo as memo41, useEffect as useEffect44 } from "react";
24668
24671
  import { X as X16 } from "lucide-react";
24669
24672
  import { Prism as SyntaxHighlighter11 } from "react-syntax-highlighter";
24670
24673
  import {
@@ -24719,7 +24722,7 @@ var SkillViewerPanel = memo41(function SkillViewerPanel2() {
24719
24722
  const isLoading = isMainFile ? !skillDetail : fileLoading;
24720
24723
  const displayPath = isMainFile ? "SKILL.md" : viewingFile ?? "";
24721
24724
  const language = inferLanguage(displayPath);
24722
- useEffect43(() => {
24725
+ useEffect44(() => {
24723
24726
  const handleEscape = (e) => {
24724
24727
  const target = e.target;
24725
24728
  const isInInput = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable;
@@ -25005,7 +25008,7 @@ var FileBrowserSidebarToggle = memo43(function FileBrowserSidebarToggle2() {
25005
25008
  });
25006
25009
  });
25007
25010
  // src/components/file-browser/FileViewerPanel.tsx
25008
- import { memo as memo44, useEffect as useEffect44 } from "react";
25011
+ import { memo as memo44, useEffect as useEffect45 } from "react";
25009
25012
  import { X as X17 } from "lucide-react";
25010
25013
  import ReactMarkdown3 from "react-markdown";
25011
25014
  import { Prism as SyntaxHighlighter12 } from "react-syntax-highlighter";
@@ -25066,7 +25069,7 @@ var FileViewerPanel = memo44(function FileViewerPanel2() {
25066
25069
  const selectedFile = useFileBrowserStore((s) => s.selectedFile);
25067
25070
  const closeViewer = useFileBrowserStore((s) => s.closeViewer);
25068
25071
  const { data, isLoading } = useFileContent(selectedFile);
25069
- useEffect44(() => {
25072
+ useEffect45(() => {
25070
25073
  const handleEscape = (e) => {
25071
25074
  const target = e.target;
25072
25075
  const isInInput = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable;
@@ -25196,7 +25199,7 @@ var FileViewerPanel = memo44(function FileViewerPanel2() {
25196
25199
  });
25197
25200
  });
25198
25201
  // src/components/file-browser/QuickFilePicker.tsx
25199
- import { memo as memo45, useState as useState43, useEffect as useEffect45, useRef as useRef31, useCallback as useCallback33, useMemo as useMemo25 } from "react";
25202
+ import { memo as memo45, useState as useState43, useEffect as useEffect46, useRef as useRef31, useCallback as useCallback33, useMemo as useMemo25 } from "react";
25200
25203
  import { FileCode as FileCode4, Search as Search7 } from "lucide-react";
25201
25204
 
25202
25205
  // src/stores/filePickerStore.ts
@@ -25252,14 +25255,14 @@ var QuickFilePicker = memo45(function QuickFilePicker2() {
25252
25255
  const results = filesData.files.map((file) => ({ file, ...fuzzyMatch(query, file) })).filter((r) => r.match).sort((a, b) => b.score - a.score).slice(0, 50);
25253
25256
  return results.map((r) => r.file);
25254
25257
  }, [filesData?.files, query]);
25255
- useEffect45(() => {
25258
+ useEffect46(() => {
25256
25259
  if (isOpen) {
25257
25260
  setQuery("");
25258
25261
  setSelectedIndex(0);
25259
25262
  setTimeout(() => inputRef.current?.focus(), 0);
25260
25263
  }
25261
25264
  }, [isOpen]);
25262
- useEffect45(() => {
25265
+ useEffect46(() => {
25263
25266
  const item = listRef.current?.children[selectedIndex];
25264
25267
  item?.scrollIntoView({ block: "nearest" });
25265
25268
  }, [selectedIndex]);
@@ -25421,7 +25424,7 @@ function HighlightedPath({ path, query }) {
25421
25424
  import { memo as memo48 } from "react";
25422
25425
 
25423
25426
  // src/components/onboarding/steps/ProviderSetupStep.tsx
25424
- import { memo as memo46, useEffect as useEffect46, useState as useState44, useRef as useRef32 } from "react";
25427
+ import { memo as memo46, useEffect as useEffect47, useState as useState44, useRef as useRef32 } from "react";
25425
25428
  import {
25426
25429
  Copy as Copy5,
25427
25430
  Check as Check13,
@@ -25529,34 +25532,34 @@ var ProviderSetupStep = memo46(function ProviderSetupStep2({
25529
25532
  const { fetchBalance } = useOttoRouterBalance("ottorouter");
25530
25533
  const effectivePayg = payg?.effectiveSpendableUsd ?? balance ?? 0;
25531
25534
  const setuStatusLabel = subscription?.active ? `GO ${(subscription.creditsRemaining ?? 0).toFixed(1)} credits` : `$${effectivePayg.toFixed(2)}`;
25532
- useEffect46(() => {
25535
+ useEffect47(() => {
25533
25536
  if (prevTopupModalOpen.current && !isTopupModalOpen) {
25534
25537
  fetchBalance();
25535
25538
  }
25536
25539
  prevTopupModalOpen.current = isTopupModalOpen;
25537
25540
  }, [isTopupModalOpen, fetchBalance]);
25538
- useEffect46(() => {
25541
+ useEffect47(() => {
25539
25542
  if (!authStatus.ottorouter.configured && !isSettingUp) {
25540
25543
  setIsSettingUp(true);
25541
25544
  onSetupWallet().finally(() => setIsSettingUp(false));
25542
25545
  }
25543
25546
  }, [authStatus.ottorouter.configured, onSetupWallet, isSettingUp]);
25544
- useEffect46(() => {
25547
+ useEffect47(() => {
25545
25548
  if (addingProvider && apiKeyInputRef.current) {
25546
25549
  apiKeyInputRef.current.focus();
25547
25550
  }
25548
25551
  }, [addingProvider]);
25549
- useEffect46(() => {
25552
+ useEffect47(() => {
25550
25553
  if (oauthSession && oauthCodeInputRef.current) {
25551
25554
  oauthCodeInputRef.current.focus();
25552
25555
  }
25553
25556
  }, [oauthSession]);
25554
- useEffect46(() => {
25557
+ useEffect47(() => {
25555
25558
  if (isImportModalOpen && importPrivateKeyRef.current) {
25556
25559
  importPrivateKeyRef.current.focus();
25557
25560
  }
25558
25561
  }, [isImportModalOpen]);
25559
- useEffect46(() => {
25562
+ useEffect47(() => {
25560
25563
  if (!copilotPolling || !copilotDevice || !copilotPollFnRef.current)
25561
25564
  return;
25562
25565
  copilotCancelledRef.current = false;
@@ -26941,7 +26944,7 @@ var ProviderSetupStep = memo46(function ProviderSetupStep2({
26941
26944
  });
26942
26945
 
26943
26946
  // src/components/onboarding/steps/DefaultsStep.tsx
26944
- import { memo as memo47, useState as useState45, useEffect as useEffect47, useId as useId3, useRef as useRef33 } from "react";
26947
+ import { memo as memo47, useState as useState45, useEffect as useEffect48, useId as useId3, useRef as useRef33 } from "react";
26945
26948
  import { Loader2 as Loader217, ArrowLeft, Sparkles as Sparkles9, ChevronDown as ChevronDown12 } from "lucide-react";
26946
26949
  import { jsx as jsx105, jsxs as jsxs93, Fragment as Fragment43 } from "react/jsx-runtime";
26947
26950
  var DefaultsStep = memo47(function DefaultsStep2({
@@ -26964,7 +26967,7 @@ var DefaultsStep = memo47(function DefaultsStep2({
26964
26967
  const modelId = useId3();
26965
26968
  const agentId = useId3();
26966
26969
  const approvalId = useId3();
26967
- useEffect47(() => {
26970
+ useEffect48(() => {
26968
26971
  const loadConfig = async () => {
26969
26972
  try {
26970
26973
  const [configData, modelsData] = await Promise.all([
@@ -26995,7 +26998,7 @@ var DefaultsStep = memo47(function DefaultsStep2({
26995
26998
  };
26996
26999
  loadConfig();
26997
27000
  }, []);
26998
- useEffect47(() => {
27001
+ useEffect48(() => {
26999
27002
  if (config2?.agents?.length) {
27000
27003
  const agents = config2.agents;
27001
27004
  if (!selectedAgent || !agents.includes(selectedAgent)) {
@@ -27003,7 +27006,7 @@ var DefaultsStep = memo47(function DefaultsStep2({
27003
27006
  }
27004
27007
  }
27005
27008
  }, [config2, selectedAgent]);
27006
- useEffect47(() => {
27009
+ useEffect48(() => {
27007
27010
  if (allModels?.[selectedProvider] && hasUserChangedProvider.current) {
27008
27011
  const providerModels = allModels[selectedProvider];
27009
27012
  if (!providerModels.models.some((m) => m.id === selectedModel)) {
@@ -27365,8 +27368,179 @@ var OnboardingModal = memo48(function OnboardingModal2({
27365
27368
  ]
27366
27369
  });
27367
27370
  });
27371
+ // src/hooks/useClientEvents.ts
27372
+ import { useEffect as useEffect49, useRef as useRef34 } from "react";
27373
+ import { useQueryClient as useQueryClient20 } from "@tanstack/react-query";
27374
+ import {
27375
+ buildClientEventsStreamUrl,
27376
+ createClientEventsStream
27377
+ } from "@ottocode/api";
27378
+ function toastTypeForLevel(level) {
27379
+ if (level === "success")
27380
+ return "success";
27381
+ if (level === "error")
27382
+ return "error";
27383
+ return "default";
27384
+ }
27385
+ function showInAppNotification(notification) {
27386
+ const message = notification.body ? `${notification.title}: ${notification.body}` : notification.title;
27387
+ if (notification.action) {
27388
+ const id = toast(message, toastTypeForLevel(notification.level), 6000);
27389
+ useToastStore.getState().updateToast(id, { action: notification.action });
27390
+ return;
27391
+ }
27392
+ toast(message, toastTypeForLevel(notification.level), 5000);
27393
+ }
27394
+ function sendBrowserNotification(notification) {
27395
+ if (typeof window === "undefined")
27396
+ return;
27397
+ if (window.parent && window.parent !== window) {
27398
+ const message = {
27399
+ type: "otto-notification",
27400
+ notification
27401
+ };
27402
+ window.parent.postMessage(message, "*");
27403
+ return;
27404
+ }
27405
+ if (!("Notification" in window) || Notification.permission !== "granted")
27406
+ return;
27407
+ const browserNotification = new Notification(notification.title, {
27408
+ body: notification.body,
27409
+ tag: notification.id
27410
+ });
27411
+ browserNotification.onclick = () => {
27412
+ window.focus();
27413
+ if (notification.sessionId) {
27414
+ window.location.href = `/sessions/${notification.sessionId}`;
27415
+ }
27416
+ browserNotification.close();
27417
+ };
27418
+ }
27419
+ function updateSessionStatusInCache(queryClient, status) {
27420
+ queryClient.setQueryData(sessionsQueryKey, (old) => {
27421
+ if (!old)
27422
+ return old;
27423
+ return {
27424
+ ...old,
27425
+ pages: old.pages.map((page) => ({
27426
+ ...page,
27427
+ items: page.items.map((session) => session.id === status.sessionId ? {
27428
+ ...session,
27429
+ isRunning: status.status === "running"
27430
+ } : session)
27431
+ }))
27432
+ };
27433
+ });
27434
+ }
27435
+ function isLocalApiUrl(baseUrl) {
27436
+ try {
27437
+ const { hostname } = new URL(baseUrl);
27438
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname.startsWith("192.168.") || hostname.startsWith("10.") || /^172\.(1[6-9]|2\d|3[01])\./.test(hostname);
27439
+ } catch {
27440
+ return false;
27441
+ }
27442
+ }
27443
+ async function requestLocalhostAccess(baseUrl) {
27444
+ const response = await fetch(new URL("/openapi.json", baseUrl), {
27445
+ cache: "no-store",
27446
+ credentials: "include"
27447
+ });
27448
+ if (!response.ok) {
27449
+ throw new Error(`Local API returned ${response.status}`);
27450
+ }
27451
+ }
27452
+ function useClientEvents(activeSessionId) {
27453
+ const queryClient = useQueryClient20();
27454
+ const activeSessionIdRef = useRef34(activeSessionId);
27455
+ useEffect49(() => {
27456
+ activeSessionIdRef.current = activeSessionId;
27457
+ }, [activeSessionId]);
27458
+ useEffect49(() => {
27459
+ if (typeof window === "undefined" || window.parent !== window)
27460
+ return;
27461
+ if (!("Notification" in window))
27462
+ return;
27463
+ if (Notification.permission !== "default")
27464
+ return;
27465
+ if (window.localStorage.getItem("otto-notification-permission-prompted")) {
27466
+ return;
27467
+ }
27468
+ window.localStorage.setItem("otto-notification-permission-prompted", "1");
27469
+ const id = toast("Enable browser notifications for background session updates.", "default", 0);
27470
+ useToastStore.getState().updateToast(id, {
27471
+ action: {
27472
+ label: "Enable",
27473
+ onClick: async () => {
27474
+ const permission = await Notification.requestPermission();
27475
+ if (permission === "granted") {
27476
+ toast.success("Browser notifications enabled.");
27477
+ } else {
27478
+ toast.info("Browser notifications were not enabled.");
27479
+ }
27480
+ }
27481
+ }
27482
+ });
27483
+ }, []);
27484
+ useEffect49(() => {
27485
+ const controller = new AbortController;
27486
+ let hasShownLocalAccessToast = false;
27487
+ const baseUrl = getBaseUrl();
27488
+ createClientEventsStream({
27489
+ baseUrl,
27490
+ onEvent: (event) => {
27491
+ if (event.event === "heartbeat")
27492
+ return;
27493
+ let payload;
27494
+ try {
27495
+ payload = JSON.parse(event.data);
27496
+ } catch (error) {
27497
+ console.error("[client-events] Failed to parse event:", error);
27498
+ return;
27499
+ }
27500
+ if (event.event === "session.status") {
27501
+ const status = payload;
27502
+ updateSessionStatusInCache(queryClient, status);
27503
+ if (status.status !== "running") {
27504
+ queryClient.invalidateQueries({
27505
+ queryKey: sessionsQueryKey
27506
+ });
27507
+ }
27508
+ return;
27509
+ }
27510
+ if (event.event === "notification") {
27511
+ const notification = payload;
27512
+ showInAppNotification(notification);
27513
+ const isActiveVisibleSession = notification.sessionId === activeSessionIdRef.current && document.visibilityState === "visible";
27514
+ if (!isActiveVisibleSession) {
27515
+ sendBrowserNotification(notification);
27516
+ }
27517
+ }
27518
+ },
27519
+ onError: (error) => {
27520
+ if (!controller.signal.aborted) {
27521
+ console.error("[client-events] Stream error:", error);
27522
+ if (!hasShownLocalAccessToast && isLocalApiUrl(baseUrl)) {
27523
+ hasShownLocalAccessToast = true;
27524
+ const id = toast("Safari may need permission to access the local otto server.", "default", 0);
27525
+ useToastStore.getState().updateToast(id, {
27526
+ action: {
27527
+ label: "Allow access",
27528
+ onClick: async () => {
27529
+ await requestLocalhostAccess(baseUrl);
27530
+ toast.success("Local otto server access confirmed.");
27531
+ }
27532
+ }
27533
+ });
27534
+ }
27535
+ }
27536
+ }
27537
+ }, controller.signal);
27538
+ return () => controller.abort();
27539
+ }, [queryClient]);
27540
+ return buildClientEventsStreamUrl({ baseUrl: getBaseUrl() });
27541
+ }
27368
27542
  // src/hooks/useTheme.ts
27369
- import { useEffect as useEffect48, useState as useState46, useCallback as useCallback34, useMemo as useMemo26 } from "react";
27543
+ import { useEffect as useEffect50, useState as useState46, useCallback as useCallback34, useMemo as useMemo26 } from "react";
27370
27544
  var STORAGE_KEY3 = "otto-theme";
27371
27545
  function resolveInitialTheme() {
27372
27546
  if (typeof window === "undefined") {
@@ -27383,7 +27557,7 @@ function resolveInitialTheme() {
27383
27557
  }
27384
27558
  function useTheme() {
27385
27559
  const [theme, setTheme] = useState46(() => resolveInitialTheme());
27386
- useEffect48(() => {
27560
+ useEffect50(() => {
27387
27561
  if (typeof document === "undefined")
27388
27562
  return;
27389
27563
  const root = document.documentElement;
@@ -27401,7 +27575,7 @@ function useTheme() {
27401
27575
  window.parent.postMessage({ type: "otto-set-theme", theme }, "*");
27402
27576
  }
27403
27577
  }, [theme]);
27404
- useEffect48(() => {
27578
+ useEffect50(() => {
27405
27579
  if (typeof window === "undefined")
27406
27580
  return;
27407
27581
  const handler = (e) => {
@@ -27418,11 +27592,11 @@ function useTheme() {
27418
27592
  return useMemo26(() => ({ theme, setTheme, toggleTheme }), [theme, toggleTheme]);
27419
27593
  }
27420
27594
  // src/hooks/useWorkingDirectory.ts
27421
- import { useEffect as useEffect49, useState as useState47 } from "react";
27595
+ import { useEffect as useEffect51, useState as useState47 } from "react";
27422
27596
  import { getCwd } from "@ottocode/api";
27423
27597
  function useWorkingDirectory() {
27424
27598
  const [dirName, setDirName] = useState47(null);
27425
- useEffect49(() => {
27599
+ useEffect51(() => {
27426
27600
  const fetchWorkingDirectory = async () => {
27427
27601
  try {
27428
27602
  const response = await getCwd({ baseURL: getBaseUrl() });
@@ -27446,7 +27620,7 @@ function useWorkingDirectory() {
27446
27620
  return dirName;
27447
27621
  }
27448
27622
  // src/hooks/useKeyboardShortcuts.ts
27449
- import { useEffect as useEffect50, useCallback as useCallback35 } from "react";
27623
+ import { useEffect as useEffect52, useCallback as useCallback35 } from "react";
27450
27624
  function useKeyboardShortcuts({
27451
27625
  sessionIds,
27452
27626
  activeSessionId,
@@ -27678,7 +27852,7 @@ function useKeyboardShortcuts({
27678
27852
  onReturnToInput,
27679
27853
  closeDiff
27680
27854
  ]);
27681
- useEffect50(() => {
27855
+ useEffect52(() => {
27682
27856
  window.addEventListener("keydown", handleKeyDown);
27683
27857
  return () => window.removeEventListener("keydown", handleKeyDown);
27684
27858
  }, [handleKeyDown]);
@@ -27692,7 +27866,7 @@ function useKeyboardShortcuts({
27692
27866
  import {
27693
27867
  useState as useState48,
27694
27868
  useCallback as useCallback36,
27695
- useEffect as useEffect51
27869
+ useEffect as useEffect53
27696
27870
  } from "react";
27697
27871
  var SUPPORTED_TYPES2 = ["image/png", "image/jpeg", "image/gif", "image/webp"];
27698
27872
  function generateId2() {
@@ -27828,7 +28002,7 @@ function useImageUpload(options = {}) {
27828
28002
  addImages(imageFiles);
27829
28003
  }
27830
28004
  }, [addImages]);
27831
- useEffect51(() => {
28005
+ useEffect53(() => {
27832
28006
  if (!pageWide)
27833
28007
  return;
27834
28008
  let dragCounter = 0;
@@ -27889,17 +28063,17 @@ function useImageUpload(options = {}) {
27889
28063
  };
27890
28064
  }
27891
28065
  // src/hooks/useSetuPayments.ts
27892
- import { useEffect as useEffect52, useRef as useRef34 } from "react";
28066
+ import { useEffect as useEffect54, useRef as useRef35 } from "react";
27893
28067
  function useSetuPayments(sessionId) {
27894
- const clientRef = useRef34(null);
27895
- const loadingToastIdRef = useRef34(null);
28068
+ const clientRef = useRef35(null);
28069
+ const loadingToastIdRef = useRef35(null);
27896
28070
  const setBalance = useOttoRouterStore((s) => s.setBalance);
27897
28071
  const setPaymentPending = useOttoRouterStore((s) => s.setPaymentPending);
27898
28072
  const removeToast = useToastStore((s) => s.removeToast);
27899
28073
  const updateToast = useToastStore((s) => s.updateToast);
27900
28074
  const setPendingTopup = useTopupApprovalStore((s) => s.setPendingTopup);
27901
28075
  const clearPendingTopup = useTopupApprovalStore((s) => s.clearPendingTopup);
27902
- useEffect52(() => {
28076
+ useEffect54(() => {
27903
28077
  if (!sessionId)
27904
28078
  return;
27905
28079
  const client5 = new SSEClient;
@@ -28119,6 +28293,7 @@ export {
28119
28293
  useConfirmationStore,
28120
28294
  useConfig,
28121
28295
  useCommitChanges,
28296
+ useClientEvents,
28122
28297
  useBranches,
28123
28298
  useAuthenticateMCPServer,
28124
28299
  useAuthStatus,
@@ -28204,4 +28379,4 @@ export {
28204
28379
  API_BASE_URL
28205
28380
  };
28206
28381
 
28207
- //# debugId=A0D9DB2AD6889D8964756E2164756E21
28382
+ //# debugId=DF50BEED8600D28B64756E2164756E21