@ottocode/web-sdk 0.1.290 → 0.1.292

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.
@@ -1 +1 @@
1
- {"version":3,"file":"useTheme.d.ts","sourceRoot":"","sources":["../../src/hooks/useTheme.ts"],"names":[],"mappings":"AAGA,KAAK,KAAK,GAAG,OAAO,GAAG,MAAM,CAAC;AAM9B,wBAAgB,QAAQ;;0BAqBV,KAAK;;EAclB;AAED,YAAY,EAAE,KAAK,EAAE,CAAC"}
1
+ {"version":3,"file":"useTheme.d.ts","sourceRoot":"","sources":["../../src/hooks/useTheme.ts"],"names":[],"mappings":"AAGA,KAAK,KAAK,GAAG,OAAO,GAAG,MAAM,CAAC;AAM9B,wBAAgB,QAAQ;;0BA6BV,KAAK;;EAwBlB;AAED,YAAY,EAAE,KAAK,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -1372,6 +1372,8 @@ function normalizeApiBaseUrl(value) {
1372
1372
  function getStoredApiBaseUrl() {
1373
1373
  if (typeof window === "undefined")
1374
1374
  return;
1375
+ if (isPlatformDesktop())
1376
+ return;
1375
1377
  try {
1376
1378
  return window.localStorage.getItem(RUNTIME_API_BASE_URL_STORAGE_KEY) ?? undefined;
1377
1379
  } catch {
@@ -1403,9 +1405,11 @@ function setRuntimeApiBaseUrl(value) {
1403
1405
  if (typeof window !== "undefined") {
1404
1406
  const win = window;
1405
1407
  win.OTTO_SERVER_URL = baseUrl;
1406
- try {
1407
- window.localStorage.setItem(RUNTIME_API_BASE_URL_STORAGE_KEY, baseUrl);
1408
- } catch {}
1408
+ if (!isPlatformDesktop()) {
1409
+ try {
1410
+ window.localStorage.setItem(RUNTIME_API_BASE_URL_STORAGE_KEY, baseUrl);
1411
+ } catch {}
1412
+ }
1409
1413
  }
1410
1414
  return baseUrl;
1411
1415
  }
@@ -3138,12 +3142,12 @@ var SHORTCUTS = [
3138
3142
  category: "Chat"
3139
3143
  },
3140
3144
  {
3141
- keys: ["Fn", "hold"],
3145
+ keys: ["Globe", "hold"],
3142
3146
  description: "Record voice while held",
3143
3147
  category: "Chat"
3144
3148
  },
3145
3149
  {
3146
- keys: ["Fn", "Fn"],
3150
+ keys: ["Globe", "Globe"],
3147
3151
  description: "Toggle hands-free voice recording",
3148
3152
  category: "Chat"
3149
3153
  },
@@ -6722,8 +6726,8 @@ var DictationInstallPrompt = memo6(function DictationInstallPrompt2({
6722
6726
  // src/components/chat/ChatInput.tsx
6723
6727
  import { jsx as jsx22, jsxs as jsxs15, Fragment as Fragment4 } from "react/jsx-runtime";
6724
6728
  var VOICE_SHORTCUT_DOUBLE_PRESS_WINDOW_MS = 280;
6725
- function isFunctionKeyEvent(event) {
6726
- return event.key === "Fn" || event.key === "Function" || event.code === "Fn" || event.code === "Function";
6729
+ function isGlobeKeyEvent(event) {
6730
+ return event.key === "Globe" || event.key === "Fn" || event.key === "Function" || event.code === "Globe" || event.code === "Fn" || event.code === "Function" || event.keyCode === 63 || event.which === 63;
6727
6731
  }
6728
6732
  function isWebVoiceShortcutDown(event) {
6729
6733
  return event.code === "Space" && (event.ctrlKey || event.altKey);
@@ -6883,6 +6887,7 @@ var ChatInput = memo7(forwardRef5(function ChatInput2({
6883
6887
  ]);
6884
6888
  const { status: dictationStatus } = useDictationModels();
6885
6889
  const voiceBaseTextRef = useRef7("");
6890
+ const shouldFocusAfterDictationRef = useRef7(false);
6886
6891
  const {
6887
6892
  isListening,
6888
6893
  isTranscribing,
@@ -6902,9 +6907,18 @@ var ChatInput = memo7(forwardRef5(function ChatInput2({
6902
6907
  return;
6903
6908
  }
6904
6909
  setMessage(nextMessage);
6910
+ if (isFinal) {
6911
+ shouldFocusAfterDictationRef.current = true;
6912
+ }
6905
6913
  }
6906
6914
  });
6907
6915
  const isVoiceActive = isListening || isTranscribing;
6916
+ useEffect14(() => {
6917
+ if (isVoiceActive || !shouldFocusAfterDictationRef.current)
6918
+ return;
6919
+ shouldFocusAfterDictationRef.current = false;
6920
+ textareaRef.current?.focus({ preventScroll: true });
6921
+ }, [isVoiceActive]);
6908
6922
  const defaultDictationModel = dictationStatus?.models.find((model) => model.id === dictationStatus.defaultModel);
6909
6923
  const handleStartVoice = useCallback13(() => {
6910
6924
  setVoiceShortcutMode(null);
@@ -7037,19 +7051,19 @@ var ChatInput = memo7(forwardRef5(function ChatInput2({
7037
7051
  fnStopRequestedRef.current = true;
7038
7052
  };
7039
7053
  const handleKeyDown2 = (event) => {
7040
- const isFnShortcut = isFunctionKeyEvent(event);
7054
+ const isGlobeShortcut = isGlobeKeyEvent(event);
7041
7055
  const isWebShortcut = isWebVoiceShortcutDown(event);
7042
- if (!isFnShortcut && !isWebShortcut)
7056
+ if (!isGlobeShortcut && !isWebShortcut)
7043
7057
  return;
7044
7058
  event.preventDefault();
7045
7059
  event.stopPropagation();
7046
7060
  if (event.repeat)
7047
7061
  return;
7048
- startShortcutPress(isFnShortcut ? "fn" : "web");
7062
+ startShortcutPress(isGlobeShortcut ? "fn" : "web");
7049
7063
  };
7050
7064
  const handleKeyUp = (event) => {
7051
7065
  const shortcutKind = voiceShortcutKindRef.current;
7052
- const isCurrentShortcut = shortcutKind === "fn" && isFunctionKeyEvent(event) || shortcutKind === "web" && isWebVoiceShortcutUp(event);
7066
+ const isCurrentShortcut = shortcutKind === "fn" && isGlobeKeyEvent(event) || shortcutKind === "web" && isWebVoiceShortcutUp(event);
7053
7067
  if (!isCurrentShortcut)
7054
7068
  return;
7055
7069
  event.preventDefault();
@@ -12980,9 +12994,10 @@ function DebugRenderer({
12980
12994
  import { jsx as jsx55, jsxs as jsxs46 } from "react/jsx-runtime";
12981
12995
  function ProgressUpdateRenderer({ contentJson }) {
12982
12996
  const result = contentJson.result || {};
12983
- const message = String(result.message || "Processing...");
12984
- const stage = result.stage ? String(result.stage) : undefined;
12985
- const pct = result.pct ? Number(result.pct) : undefined;
12997
+ const args = contentJson.args || {};
12998
+ const message = String(result.message || args.message || "Processing...");
12999
+ const stage = result.stage ? String(result.stage) : args.stage ? String(args.stage) : undefined;
13000
+ const pct = result.pct ? Number(result.pct) : args.pct ? Number(args.pct) : undefined;
12986
13001
  return /* @__PURE__ */ jsxs46("div", {
12987
13002
  className: "flex min-h-5 items-start gap-2 text-sm leading-5 text-violet-700 dark:text-violet-300 animate-pulse",
12988
13003
  children: [
@@ -19320,28 +19335,55 @@ function parseToolResultContent(part) {
19320
19335
  function isTodoStatus(status) {
19321
19336
  return status === "pending" || status === "in_progress" || status === "completed" || status === "cancelled";
19322
19337
  }
19323
- function getTodoToolName(part, content) {
19324
- const name = part.toolName ?? content?.name;
19325
- return typeof name === "string" ? name : null;
19338
+ function asRecord(value) {
19339
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
19326
19340
  }
19327
- function parseTodoSnapshot(content) {
19328
- const rawResult = content.result;
19329
- const result = rawResult && typeof rawResult === "object" && !Array.isArray(rawResult) ? rawResult : content;
19330
- const rawItems = result.items;
19341
+ function normalizeTodoItems(rawItems) {
19331
19342
  if (!Array.isArray(rawItems))
19332
19343
  return null;
19333
19344
  const items = rawItems.flatMap((item) => {
19334
- if (!item || typeof item !== "object" || Array.isArray(item)) {
19335
- return [];
19345
+ if (typeof item === "string") {
19346
+ const step2 = item.trim();
19347
+ return step2 ? [{ step: step2, status: "pending" }] : [];
19336
19348
  }
19337
- const record = item;
19338
- if (typeof record.step !== "string" || !isTodoStatus(record.status)) {
19349
+ const record = asRecord(item);
19350
+ if (!record)
19339
19351
  return [];
19340
- }
19341
- return [{ step: record.step, status: record.status }];
19352
+ const rawStep = typeof record.step === "string" ? record.step : typeof record.description === "string" ? record.description : "";
19353
+ const step = rawStep.trim();
19354
+ if (!step)
19355
+ return [];
19356
+ return [
19357
+ {
19358
+ step,
19359
+ status: isTodoStatus(record.status) ? record.status : "pending"
19360
+ }
19361
+ ];
19342
19362
  });
19343
- const note = typeof result.note === "string" ? result.note : undefined;
19344
- return { items, note };
19363
+ return items.length > 0 ? items : null;
19364
+ }
19365
+ function getTodoToolName(part, content) {
19366
+ const name = part.toolName ?? content?.name;
19367
+ return typeof name === "string" ? name : null;
19368
+ }
19369
+ function parseTodoSnapshot(content) {
19370
+ const result = asRecord(content.result) ?? content;
19371
+ const args = asRecord(content.args);
19372
+ const sources = [
19373
+ { rawItems: result.items, note: result.note },
19374
+ { rawItems: content.items, note: content.note },
19375
+ { rawItems: args?.todos, note: args?.note }
19376
+ ];
19377
+ for (const source of sources) {
19378
+ const items = normalizeTodoItems(source.rawItems);
19379
+ if (items) {
19380
+ return {
19381
+ items,
19382
+ note: typeof source.note === "string" ? source.note : undefined
19383
+ };
19384
+ }
19385
+ }
19386
+ return null;
19345
19387
  }
19346
19388
  function isTodoSnapshotDone(snapshot) {
19347
19389
  return snapshot.items.length > 0 && snapshot.items.every((item) => item.status === "completed" || item.status === "cancelled");
@@ -30293,18 +30335,22 @@ var ToggleSwitch = memo41(function ToggleSwitch2({
30293
30335
  role: "switch",
30294
30336
  "aria-checked": checked,
30295
30337
  disabled: disabled || loading,
30338
+ onPointerDown: (event) => event.stopPropagation(),
30296
30339
  onClick: (event) => {
30297
30340
  event.stopPropagation();
30298
30341
  onChange();
30299
30342
  },
30300
- className: `relative inline-flex h-5 w-9 flex-shrink-0 items-center rounded-full transition-colors duration-200 focus-visible:outline-none disabled:opacity-50 disabled:cursor-not-allowed ${checked ? "bg-green-500" : "bg-muted-foreground/30"}`,
30343
+ className: "relative -m-2 inline-flex h-9 w-[52px] flex-shrink-0 items-center justify-center rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
30301
30344
  children: /* @__PURE__ */ jsx114("span", {
30302
- className: `inline-block h-3.5 w-3.5 rounded-full transition-transform duration-200 ${checked ? "translate-x-[18px]" : "translate-x-[3px]"} ${loading ? "bg-transparent" : "bg-white"}`,
30303
- children: loading ? /* @__PURE__ */ jsx114(StableSpinner, {
30304
- size: "sm",
30305
- className: "text-white",
30306
- title: "Updating"
30307
- }) : null
30345
+ className: `relative inline-flex h-5 w-9 items-center rounded-full transition-colors duration-200 ${checked ? "bg-green-500" : "bg-muted-foreground/30"}`,
30346
+ children: /* @__PURE__ */ jsx114("span", {
30347
+ className: `inline-block h-3.5 w-3.5 rounded-full transition-transform duration-200 ${checked ? "translate-x-[18px]" : "translate-x-[3px]"} ${loading ? "bg-transparent" : "bg-white"}`,
30348
+ children: loading ? /* @__PURE__ */ jsx114(StableSpinner, {
30349
+ size: "sm",
30350
+ className: "text-white",
30351
+ title: "Updating"
30352
+ }) : null
30353
+ })
30308
30354
  })
30309
30355
  });
30310
30356
  });
@@ -31164,26 +31210,31 @@ var SkillsSidebar = memo44(function SkillsSidebar2() {
31164
31210
  SCOPE_LABELS[scope] ?? scope
31165
31211
  ]
31166
31212
  }),
31167
- scopeSkills.map((skill) => /* @__PURE__ */ jsx117("button", {
31168
- type: "button",
31169
- onClick: () => selectSkill(skill.name),
31170
- className: `w-full text-left px-3 py-2 hover:bg-accent transition-colors ${selectedSkill === skill.name ? "bg-accent" : ""}`,
31213
+ scopeSkills.map((skill) => /* @__PURE__ */ jsx117("div", {
31214
+ className: `w-full px-3 py-2 hover:bg-accent transition-colors ${selectedSkill === skill.name ? "bg-accent" : ""}`,
31171
31215
  children: /* @__PURE__ */ jsxs102("div", {
31172
31216
  className: "flex items-start gap-2",
31173
31217
  children: [
31174
- /* @__PURE__ */ jsx117(FileText7, {
31175
- className: "w-3.5 h-3.5 flex-shrink-0 text-muted-foreground"
31176
- }),
31177
- /* @__PURE__ */ jsxs102("div", {
31178
- className: "min-w-0 flex-1",
31218
+ /* @__PURE__ */ jsxs102("button", {
31219
+ type: "button",
31220
+ onClick: () => selectSkill(skill.name),
31221
+ className: "flex min-w-0 flex-1 cursor-pointer items-start gap-2 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
31179
31222
  children: [
31180
- /* @__PURE__ */ jsx117("div", {
31181
- className: "text-sm font-medium truncate",
31182
- children: skill.name
31223
+ /* @__PURE__ */ jsx117(FileText7, {
31224
+ className: "w-3.5 h-3.5 flex-shrink-0 text-muted-foreground"
31183
31225
  }),
31184
- /* @__PURE__ */ jsx117("div", {
31185
- className: "text-xs text-muted-foreground truncate",
31186
- children: skill.description
31226
+ /* @__PURE__ */ jsxs102("div", {
31227
+ className: "min-w-0 flex-1",
31228
+ children: [
31229
+ /* @__PURE__ */ jsx117("div", {
31230
+ className: "text-sm font-medium truncate",
31231
+ children: skill.name
31232
+ }),
31233
+ /* @__PURE__ */ jsx117("div", {
31234
+ className: "text-xs text-muted-foreground truncate",
31235
+ children: skill.description
31236
+ })
31237
+ ]
31187
31238
  })
31188
31239
  ]
31189
31240
  }),
@@ -33995,6 +34046,19 @@ var ViewerTabs = memo52(function ViewerTabs2() {
33995
34046
  ]
33996
34047
  })
33997
34048
  }),
34049
+ /* @__PURE__ */ jsx128("div", {
34050
+ className: "h-12 w-12 shrink-0 border-r border-b border-sidebar-border bg-background flex items-stretch",
34051
+ children: /* @__PURE__ */ jsx128("button", {
34052
+ type: "button",
34053
+ onClick: closeAllTabs,
34054
+ title: "Close all tabs and collapse viewer",
34055
+ "aria-label": "Close all tabs and collapse viewer",
34056
+ className: "h-full w-full inline-flex items-center justify-center rounded-none text-muted-foreground/70 transition-colors hover:bg-destructive/10 hover:text-destructive active:translate-y-0 active:scale-100",
34057
+ children: /* @__PURE__ */ jsx128(X24, {
34058
+ className: "h-3.5 w-3.5"
34059
+ })
34060
+ })
34061
+ }),
33998
34062
  /* @__PURE__ */ jsxs111("div", {
33999
34063
  className: "h-12 min-w-0 flex-1 flex overflow-x-auto overflow-y-hidden overscroll-x-contain scrollbar-hide",
34000
34064
  children: [
@@ -34036,19 +34100,6 @@ ${tabKindLabel(tab)}`,
34036
34100
  }),
34037
34101
  /* @__PURE__ */ jsx128("div", {
34038
34102
  className: "min-w-8 flex-1 border-b border-sidebar-border bg-background"
34039
- }),
34040
- /* @__PURE__ */ jsx128("div", {
34041
- className: "h-12 shrink-0 border-b border-l border-sidebar-border bg-background flex items-center px-1.5",
34042
- children: /* @__PURE__ */ jsx128("button", {
34043
- type: "button",
34044
- onClick: closeAllTabs,
34045
- title: "Close all tabs and collapse viewer",
34046
- "aria-label": "Close all tabs and collapse viewer",
34047
- className: "h-8 w-8 inline-flex items-center justify-center rounded-md text-muted-foreground/70 transition-colors hover:bg-destructive/10 hover:text-destructive",
34048
- children: /* @__PURE__ */ jsx128(X24, {
34049
- className: "h-3.5 w-3.5"
34050
- })
34051
- })
34052
34103
  })
34053
34104
  ]
34054
34105
  })
@@ -37696,14 +37747,21 @@ function useClientEvents(activeSessionId) {
37696
37747
  return buildClientEventsStreamUrl({ baseUrl: getBaseUrl() });
37697
37748
  }
37698
37749
  // src/hooks/useTheme.ts
37699
- import { useCallback as useCallback43, useEffect as useEffect68, useMemo as useMemo36 } from "react";
37750
+ import { useCallback as useCallback43, useEffect as useEffect68, useMemo as useMemo36, useState as useState59 } from "react";
37700
37751
  function normalizeTheme(theme) {
37701
37752
  return theme === "light" ? "light" : "dark";
37702
37753
  }
37703
37754
  function useTheme() {
37704
37755
  const { data: config2 } = useConfig();
37705
37756
  const updateDefaults = useUpdateDefaults();
37706
- const theme = normalizeTheme(config2?.defaults?.theme);
37757
+ const configTheme = normalizeTheme(config2?.defaults?.theme);
37758
+ const [optimisticTheme, setOptimisticTheme] = useState59(null);
37759
+ const theme = optimisticTheme ?? configTheme;
37760
+ useEffect68(() => {
37761
+ if (optimisticTheme === configTheme) {
37762
+ setOptimisticTheme(null);
37763
+ }
37764
+ }, [configTheme, optimisticTheme]);
37707
37765
  useEffect68(() => {
37708
37766
  if (typeof document === "undefined")
37709
37767
  return;
@@ -37718,7 +37776,12 @@ function useTheme() {
37718
37776
  }
37719
37777
  }, [theme]);
37720
37778
  const setTheme = useCallback43((nextTheme) => {
37721
- updateDefaults.mutate({ theme: nextTheme, scope: "global" });
37779
+ setOptimisticTheme(nextTheme);
37780
+ updateDefaults.mutate({ theme: nextTheme, scope: "global" }, {
37781
+ onError: () => {
37782
+ setOptimisticTheme((currentTheme) => currentTheme === nextTheme ? null : currentTheme);
37783
+ }
37784
+ });
37722
37785
  }, [updateDefaults]);
37723
37786
  const toggleTheme = useCallback43(() => {
37724
37787
  setTheme(theme === "dark" ? "light" : "dark");
@@ -37726,10 +37789,10 @@ function useTheme() {
37726
37789
  return useMemo36(() => ({ theme, setTheme, toggleTheme }), [theme, setTheme, toggleTheme]);
37727
37790
  }
37728
37791
  // src/hooks/useWorkingDirectory.ts
37729
- import { useEffect as useEffect69, useState as useState59 } from "react";
37792
+ import { useEffect as useEffect69, useState as useState60 } from "react";
37730
37793
  import { getCwd } from "@ottocode/api";
37731
37794
  function useWorkingDirectory() {
37732
- const [dirName, setDirName] = useState59(null);
37795
+ const [dirName, setDirName] = useState60(null);
37733
37796
  useEffect69(() => {
37734
37797
  const fetchWorkingDirectory = async () => {
37735
37798
  try {
@@ -38072,7 +38135,7 @@ function useKeyboardShortcuts({
38072
38135
  }
38073
38136
  // src/hooks/useImageUpload.ts
38074
38137
  import {
38075
- useState as useState60,
38138
+ useState as useState61,
38076
38139
  useCallback as useCallback45,
38077
38140
  useEffect as useEffect71
38078
38141
  } from "react";
@@ -38102,9 +38165,9 @@ async function fileToPreview2(file) {
38102
38165
  }
38103
38166
  function useImageUpload(options = {}) {
38104
38167
  const { maxImages = 5, maxSizeMB = 5, pageWide = true } = options;
38105
- const [images, setImages] = useState60([]);
38106
- const [isDragging, setIsDragging] = useState60(false);
38107
- const [error, setError] = useState60(null);
38168
+ const [images, setImages] = useState61([]);
38169
+ const [isDragging, setIsDragging] = useState61(false);
38170
+ const [error, setError] = useState61(null);
38108
38171
  const maxSizeBytes = maxSizeMB * 1024 * 1024;
38109
38172
  const validateFile = useCallback45((file) => {
38110
38173
  if (!SUPPORTED_TYPES.includes(file.type)) {
@@ -38641,4 +38704,4 @@ export {
38641
38704
  API_BASE_URL
38642
38705
  };
38643
38706
 
38644
- //# debugId=E39841C869472F6964756E2164756E21
38707
+ //# debugId=EF889705B19F428E64756E2164756E21