@ottocode/web-sdk 0.1.294 → 0.1.296

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 (194) hide show
  1. package/dist/components/branch/BranchModal.d.ts +1 -1
  2. package/dist/components/branch/BranchModal.d.ts.map +1 -1
  3. package/dist/components/browser/BrowserViewerPanel.d.ts +1 -1
  4. package/dist/components/browser/BrowserViewerPanel.d.ts.map +1 -1
  5. package/dist/components/chat/ChatInput.d.ts.map +1 -1
  6. package/dist/components/chat/ChatInputContainer.d.ts.map +1 -1
  7. package/dist/components/chat/CommandSuggestionsPopup.d.ts +1 -1
  8. package/dist/components/chat/CommandSuggestionsPopup.d.ts.map +1 -1
  9. package/dist/components/chat/ConfigModal.d.ts +1 -1
  10. package/dist/components/chat/ConfigModal.d.ts.map +1 -1
  11. package/dist/components/chat/ConfigSelector.d.ts +1 -1
  12. package/dist/components/chat/ConfigSelector.d.ts.map +1 -1
  13. package/dist/components/chat/FileMentionPopup.d.ts +1 -1
  14. package/dist/components/chat/FileMentionPopup.d.ts.map +1 -1
  15. package/dist/components/chat/LiveWaveform.d.ts +1 -1
  16. package/dist/components/chat/LiveWaveform.d.ts.map +1 -1
  17. package/dist/components/chat/NewSessionLanding.d.ts.map +1 -1
  18. package/dist/components/chat/ReasoningTabs.d.ts +1 -1
  19. package/dist/components/chat/ReasoningTabs.d.ts.map +1 -1
  20. package/dist/components/chat/ShortcutsModal.d.ts +1 -1
  21. package/dist/components/chat/ShortcutsModal.d.ts.map +1 -1
  22. package/dist/components/chat/SkillMentionPopup.d.ts +1 -1
  23. package/dist/components/chat/SkillMentionPopup.d.ts.map +1 -1
  24. package/dist/components/chat/StopButton.d.ts +1 -1
  25. package/dist/components/chat/StopButton.d.ts.map +1 -1
  26. package/dist/components/common/FileTypeIcon.d.ts +1 -1
  27. package/dist/components/common/FileTypeIcon.d.ts.map +1 -1
  28. package/dist/components/dashboard/UsageDashboard.d.ts +1 -1
  29. package/dist/components/dashboard/UsageDashboard.d.ts.map +1 -1
  30. package/dist/components/file-browser/FileBrowserSidebar.d.ts.map +1 -1
  31. package/dist/components/file-browser/QuickFilePicker.d.ts.map +1 -1
  32. package/dist/components/git/GitBranchSwitcher.d.ts +1 -1
  33. package/dist/components/git/GitBranchSwitcher.d.ts.map +1 -1
  34. package/dist/components/git/GitCommitModal.d.ts +1 -1
  35. package/dist/components/git/GitCommitModal.d.ts.map +1 -1
  36. package/dist/components/git/GitCreateBranchModal.d.ts +1 -1
  37. package/dist/components/git/GitCreateBranchModal.d.ts.map +1 -1
  38. package/dist/components/git/GitDiffViewer.d.ts +1 -1
  39. package/dist/components/git/GitDiffViewer.d.ts.map +1 -1
  40. package/dist/components/git/GitFileItem.d.ts +1 -1
  41. package/dist/components/git/GitFileItem.d.ts.map +1 -1
  42. package/dist/components/git/GitFileList.d.ts +1 -1
  43. package/dist/components/git/GitFileList.d.ts.map +1 -1
  44. package/dist/components/git/GitFileTree.d.ts +1 -1
  45. package/dist/components/git/GitFileTree.d.ts.map +1 -1
  46. package/dist/components/git/GitSidebar.d.ts.map +1 -1
  47. package/dist/components/index.js +2662 -1864
  48. package/dist/components/index.js.map +40 -40
  49. package/dist/components/mcp/MCPSidebar.d.ts.map +1 -1
  50. package/dist/components/messages/ActionToolBox.d.ts +1 -1
  51. package/dist/components/messages/ActionToolBox.d.ts.map +1 -1
  52. package/dist/components/messages/AssistantMessageGroup.d.ts +1 -0
  53. package/dist/components/messages/AssistantMessageGroup.d.ts.map +1 -1
  54. package/dist/components/messages/CompactActivityGroup.d.ts +1 -1
  55. package/dist/components/messages/CompactActivityGroup.d.ts.map +1 -1
  56. package/dist/components/messages/MessageThread.d.ts.map +1 -1
  57. package/dist/components/messages/MessageThreadContainer.d.ts.map +1 -1
  58. package/dist/components/messages/renderers/ApplyPatchRenderer.d.ts +1 -1
  59. package/dist/components/messages/renderers/ApplyPatchRenderer.d.ts.map +1 -1
  60. package/dist/components/messages/renderers/BashRenderer.d.ts +1 -1
  61. package/dist/components/messages/renderers/BashRenderer.d.ts.map +1 -1
  62. package/dist/components/messages/renderers/CopyAttachmentRenderer.d.ts +1 -1
  63. package/dist/components/messages/renderers/CopyAttachmentRenderer.d.ts.map +1 -1
  64. package/dist/components/messages/renderers/CopyIntoRenderer.d.ts +1 -1
  65. package/dist/components/messages/renderers/CopyIntoRenderer.d.ts.map +1 -1
  66. package/dist/components/messages/renderers/DatabaseToolRenderer.d.ts +1 -1
  67. package/dist/components/messages/renderers/DatabaseToolRenderer.d.ts.map +1 -1
  68. package/dist/components/messages/renderers/DebugRenderer.d.ts +1 -1
  69. package/dist/components/messages/renderers/DebugRenderer.d.ts.map +1 -1
  70. package/dist/components/messages/renderers/DiffView.d.ts +1 -1
  71. package/dist/components/messages/renderers/DiffView.d.ts.map +1 -1
  72. package/dist/components/messages/renderers/ErrorRenderer.d.ts +2 -1
  73. package/dist/components/messages/renderers/ErrorRenderer.d.ts.map +1 -1
  74. package/dist/components/messages/renderers/FinishRenderer.d.ts +1 -1
  75. package/dist/components/messages/renderers/FinishRenderer.d.ts.map +1 -1
  76. package/dist/components/messages/renderers/GenericRenderer.d.ts +1 -1
  77. package/dist/components/messages/renderers/GenericRenderer.d.ts.map +1 -1
  78. package/dist/components/messages/renderers/GitCommitRenderer.d.ts +1 -1
  79. package/dist/components/messages/renderers/GitCommitRenderer.d.ts.map +1 -1
  80. package/dist/components/messages/renderers/GitDiffRenderer.d.ts +1 -1
  81. package/dist/components/messages/renderers/GitDiffRenderer.d.ts.map +1 -1
  82. package/dist/components/messages/renderers/GitStatusRenderer.d.ts +1 -1
  83. package/dist/components/messages/renderers/GitStatusRenderer.d.ts.map +1 -1
  84. package/dist/components/messages/renderers/ListRenderer.d.ts +1 -1
  85. package/dist/components/messages/renderers/ListRenderer.d.ts.map +1 -1
  86. package/dist/components/messages/renderers/LoadMcpToolsRenderer.d.ts +1 -1
  87. package/dist/components/messages/renderers/LoadMcpToolsRenderer.d.ts.map +1 -1
  88. package/dist/components/messages/renderers/LoadToolsRenderer.d.ts +1 -1
  89. package/dist/components/messages/renderers/LoadToolsRenderer.d.ts.map +1 -1
  90. package/dist/components/messages/renderers/McpToolRenderer.d.ts +1 -1
  91. package/dist/components/messages/renderers/McpToolRenderer.d.ts.map +1 -1
  92. package/dist/components/messages/renderers/ProgressUpdateRenderer.d.ts +1 -1
  93. package/dist/components/messages/renderers/ProgressUpdateRenderer.d.ts.map +1 -1
  94. package/dist/components/messages/renderers/ReadImageRenderer.d.ts +1 -1
  95. package/dist/components/messages/renderers/ReadImageRenderer.d.ts.map +1 -1
  96. package/dist/components/messages/renderers/ReadRenderer.d.ts +1 -1
  97. package/dist/components/messages/renderers/ReadRenderer.d.ts.map +1 -1
  98. package/dist/components/messages/renderers/ReasoningRenderer.d.ts +1 -1
  99. package/dist/components/messages/renderers/ReasoningRenderer.d.ts.map +1 -1
  100. package/dist/components/messages/renderers/SearchRenderer.d.ts +1 -1
  101. package/dist/components/messages/renderers/SearchRenderer.d.ts.map +1 -1
  102. package/dist/components/messages/renderers/SimulatorRenderer.d.ts +1 -1
  103. package/dist/components/messages/renderers/SimulatorRenderer.d.ts.map +1 -1
  104. package/dist/components/messages/renderers/SkillRenderer.d.ts +1 -1
  105. package/dist/components/messages/renderers/SkillRenderer.d.ts.map +1 -1
  106. package/dist/components/messages/renderers/TerminalRenderer.d.ts +1 -1
  107. package/dist/components/messages/renderers/TerminalRenderer.d.ts.map +1 -1
  108. package/dist/components/messages/renderers/TodosRenderer.d.ts +1 -1
  109. package/dist/components/messages/renderers/TodosRenderer.d.ts.map +1 -1
  110. package/dist/components/messages/renderers/ToolErrorDisplay.d.ts +1 -1
  111. package/dist/components/messages/renderers/ToolErrorDisplay.d.ts.map +1 -1
  112. package/dist/components/messages/renderers/TreeRenderer.d.ts +1 -1
  113. package/dist/components/messages/renderers/TreeRenderer.d.ts.map +1 -1
  114. package/dist/components/messages/renderers/WebSearchRenderer.d.ts +1 -1
  115. package/dist/components/messages/renderers/WebSearchRenderer.d.ts.map +1 -1
  116. package/dist/components/messages/renderers/WriteRenderer.d.ts +1 -1
  117. package/dist/components/messages/renderers/WriteRenderer.d.ts.map +1 -1
  118. package/dist/components/messages/renderers/index.d.ts +1 -1
  119. package/dist/components/messages/renderers/index.d.ts.map +1 -1
  120. package/dist/components/messages/renderers/shared/CopyButton.d.ts +1 -1
  121. package/dist/components/messages/renderers/shared/CopyButton.d.ts.map +1 -1
  122. package/dist/components/messages/renderers/shared/ImagePreview.d.ts +1 -1
  123. package/dist/components/messages/renderers/shared/ImagePreview.d.ts.map +1 -1
  124. package/dist/components/messages/renderers/shared/ToolContentBox.d.ts +1 -1
  125. package/dist/components/messages/renderers/shared/ToolContentBox.d.ts.map +1 -1
  126. package/dist/components/messages/renderers/shared/ToolHeader.d.ts +6 -6
  127. package/dist/components/messages/renderers/shared/ToolHeader.d.ts.map +1 -1
  128. package/dist/components/messages/threadDensity.d.ts +1 -1
  129. package/dist/components/messages/threadDensity.d.ts.map +1 -1
  130. package/dist/components/research/ResearchSidebar.d.ts.map +1 -1
  131. package/dist/components/session-files/SessionFilesSidebar.d.ts.map +1 -1
  132. package/dist/components/sessions/EditableTitle.d.ts +1 -1
  133. package/dist/components/sessions/EditableTitle.d.ts.map +1 -1
  134. package/dist/components/sessions/LeanHeader.d.ts +1 -1
  135. package/dist/components/sessions/LeanHeader.d.ts.map +1 -1
  136. package/dist/components/sessions/SessionHeader.d.ts +1 -1
  137. package/dist/components/sessions/SessionHeader.d.ts.map +1 -1
  138. package/dist/components/sessions/SessionItem.d.ts +1 -0
  139. package/dist/components/sessions/SessionItem.d.ts.map +1 -1
  140. package/dist/components/sessions/SessionListContainer.d.ts.map +1 -1
  141. package/dist/components/settings/OttoRouterTopupModal.d.ts.map +1 -1
  142. package/dist/components/settings/SettingsSidebar.d.ts.map +1 -1
  143. package/dist/components/skills/SkillsSidebar.d.ts.map +1 -1
  144. package/dist/components/terminals/TerminalTabBar.d.ts.map +1 -1
  145. package/dist/components/terminals/TerminalViewer.d.ts +1 -1
  146. package/dist/components/terminals/TerminalViewer.d.ts.map +1 -1
  147. package/dist/components/terminals/TerminalsPanel.d.ts.map +1 -1
  148. package/dist/components/tunnel/TunnelSidebar.d.ts.map +1 -1
  149. package/dist/components/ui/CodeMirrorViewer.d.ts +1 -1
  150. package/dist/components/ui/CodeMirrorViewer.d.ts.map +1 -1
  151. package/dist/components/ui/ConfirmationDialog.d.ts +1 -1
  152. package/dist/components/ui/ConfirmationDialog.d.ts.map +1 -1
  153. package/dist/components/ui/Modal.d.ts +1 -1
  154. package/dist/components/ui/Modal.d.ts.map +1 -1
  155. package/dist/components/ui/SidebarHeader.d.ts +1 -1
  156. package/dist/components/ui/SidebarHeader.d.ts.map +1 -1
  157. package/dist/components/ui/StableSpinner.d.ts +1 -1
  158. package/dist/components/ui/StableSpinner.d.ts.map +1 -1
  159. package/dist/components/ui/Toaster.d.ts +1 -1
  160. package/dist/components/ui/Toaster.d.ts.map +1 -1
  161. package/dist/components/ui/ToolApprovalDialog.d.ts +1 -1
  162. package/dist/components/ui/ToolApprovalDialog.d.ts.map +1 -1
  163. package/dist/components/workspace/ToolActivityToggle.d.ts +1 -1
  164. package/dist/components/workspace/ToolActivityToggle.d.ts.map +1 -1
  165. package/dist/components/workspace/ToolPreviewPanel.d.ts +1 -1
  166. package/dist/components/workspace/ToolPreviewPanel.d.ts.map +1 -1
  167. package/dist/components/workspace/ViewerStatusBar.d.ts +4 -4
  168. package/dist/components/workspace/ViewerStatusBar.d.ts.map +1 -1
  169. package/dist/hooks/index.js +111 -52
  170. package/dist/hooks/index.js.map +11 -11
  171. package/dist/hooks/useFileUpload.d.ts.map +1 -1
  172. package/dist/hooks/useKeyboardShortcuts.d.ts +3 -7
  173. package/dist/hooks/useKeyboardShortcuts.d.ts.map +1 -1
  174. package/dist/hooks/useSessions.d.ts +4 -0
  175. package/dist/hooks/useSessions.d.ts.map +1 -1
  176. package/dist/hooks/useSimulator.d.ts.map +1 -1
  177. package/dist/hooks/useSkills.d.ts +5 -1
  178. package/dist/hooks/useSkills.d.ts.map +1 -1
  179. package/dist/hooks/useVoiceInput.d.ts +2 -1
  180. package/dist/hooks/useVoiceInput.d.ts.map +1 -1
  181. package/dist/index.js +2707 -1905
  182. package/dist/index.js.map +41 -41
  183. package/dist/lib/api-client/index.d.ts.map +1 -1
  184. package/dist/lib/api-client/secure-input.d.ts.map +1 -1
  185. package/dist/lib/api-client/sessions.d.ts.map +1 -1
  186. package/dist/lib/api-client/usage.d.ts +9 -2
  187. package/dist/lib/api-client/usage.d.ts.map +1 -1
  188. package/dist/lib/api-client/utils.d.ts +12 -1
  189. package/dist/lib/api-client/utils.d.ts.map +1 -1
  190. package/dist/lib/index.js +40 -28
  191. package/dist/lib/index.js.map +6 -6
  192. package/dist/types/api.d.ts +2 -0
  193. package/dist/types/api.d.ts.map +1 -1
  194. package/package.json +5 -4
@@ -14,6 +14,8 @@ import {
14
14
  getSessionQueue as apiGetSessionQueue,
15
15
  removeFromQueue as apiRemoveFromQueue,
16
16
  retryMessage as apiRetryMessage,
17
+ createSessionHandoff as apiCreateSessionHandoff,
18
+ sendQueuedMessageNow as apiSendQueuedMessageNow,
17
19
  buildSessionStreamUrl
18
20
  } from "@ottocode/api";
19
21
 
@@ -222,7 +224,8 @@ function convertSession(apiSession) {
222
224
  title: apiSession.title ?? null,
223
225
  createdAt: typeof apiSession.createdAt === "string" ? new Date(apiSession.createdAt).getTime() : apiSession.createdAt,
224
226
  lastActiveAt: typeof apiSession.lastActiveAt === "string" ? new Date(apiSession.lastActiveAt).getTime() : apiSession.lastActiveAt,
225
- lastViewedAt: typeof apiSession.lastViewedAt === "string" ? new Date(apiSession.lastViewedAt).getTime() : apiSession.lastViewedAt
227
+ lastViewedAt: typeof apiSession.lastViewedAt === "string" ? new Date(apiSession.lastViewedAt).getTime() : apiSession.lastViewedAt,
228
+ pinnedAt: typeof apiSession.pinnedAt === "string" ? new Date(apiSession.pinnedAt).getTime() : apiSession.pinnedAt
226
229
  };
227
230
  }
228
231
  function convertMessage(apiMessage) {
@@ -285,10 +288,10 @@ var sessionsMixin = {
285
288
  return response.data;
286
289
  },
287
290
  async createHandoff(sessionId) {
288
- const response = await fetch(`${getBaseUrl()}/v1/sessions/${encodeURIComponent(sessionId)}/handoff`, { method: "POST" });
289
- const data = await response.json().catch(() => null);
290
- if (!response.ok)
291
- throw new Error(extractErrorMessage(data));
291
+ const response = await apiCreateSessionHandoff({ path: { sessionId } });
292
+ if (response.error)
293
+ throw new Error(extractErrorMessage(response.error));
294
+ const data = response.data;
292
295
  if (!data?.session || !data?.sessionId) {
293
296
  throw new Error("No data returned from handoff");
294
297
  }
@@ -300,14 +303,18 @@ var sessionsMixin = {
300
303
  };
301
304
  },
302
305
  async abortSession(sessionId) {
303
- const response = await apiAbortSession({ path: { sessionId } });
306
+ const response = await apiAbortSession({
307
+ path: { sessionId },
308
+ body: {}
309
+ });
304
310
  if (response.error)
305
311
  throw new Error(extractErrorMessage(response.error));
306
312
  return response.data;
307
313
  },
308
314
  async abortMessage(sessionId, _messageId) {
309
315
  const response = await apiAbortSession({
310
- path: { sessionId }
316
+ path: { sessionId },
317
+ body: {}
311
318
  });
312
319
  if (response.error)
313
320
  throw new Error("Failed to abort message");
@@ -328,11 +335,12 @@ var sessionsMixin = {
328
335
  return response.data;
329
336
  },
330
337
  async sendQueuedMessageNow(sessionId, messageId) {
331
- const response = await fetch(`${getBaseUrl()}/v1/sessions/${encodeURIComponent(sessionId)}/queue/${encodeURIComponent(messageId)}/send-now`, { method: "POST" });
332
- const data = await response.json().catch(() => null);
333
- if (!response.ok)
334
- throw new Error(extractErrorMessage(data));
335
- return data;
338
+ const response = await apiSendQueuedMessageNow({
339
+ path: { sessionId, messageId }
340
+ });
341
+ if (response.error)
342
+ throw new Error(extractErrorMessage(response.error));
343
+ return response.data;
336
344
  },
337
345
  async getMessages(sessionId) {
338
346
  const response = await apiListMessages({ path: { id: sessionId } });
@@ -1170,32 +1178,36 @@ var dictationMixin = {
1170
1178
  };
1171
1179
 
1172
1180
  // src/lib/api-client/secure-input.ts
1181
+ import {
1182
+ listPendingSecureInputs as apiListPendingSecureInputs,
1183
+ resolveSecureInput as apiResolveSecureInput
1184
+ } from "@ottocode/api";
1173
1185
  var secureInputMixin = {
1174
1186
  async submitSecureInput(sessionId, promptId, value) {
1175
- const response = await fetch(`${getBaseUrl()}/v1/sessions/${encodeURIComponent(sessionId)}/secure-input`, {
1176
- method: "POST",
1177
- headers: { "Content-Type": "application/json" },
1178
- body: JSON.stringify({ promptId, value })
1187
+ const response = await apiResolveSecureInput({
1188
+ path: { id: sessionId },
1189
+ body: { promptId, value }
1179
1190
  });
1180
- if (!response.ok)
1191
+ if (response.error)
1181
1192
  throw new Error("Failed to submit secure input");
1182
- return response.json();
1193
+ return response.data;
1183
1194
  },
1184
1195
  async cancelSecureInput(sessionId, promptId) {
1185
- const response = await fetch(`${getBaseUrl()}/v1/sessions/${encodeURIComponent(sessionId)}/secure-input`, {
1186
- method: "POST",
1187
- headers: { "Content-Type": "application/json" },
1188
- body: JSON.stringify({ promptId, cancelled: true })
1196
+ const response = await apiResolveSecureInput({
1197
+ path: { id: sessionId },
1198
+ body: { promptId, cancelled: true }
1189
1199
  });
1190
- if (!response.ok)
1200
+ if (response.error)
1191
1201
  throw new Error("Failed to cancel secure input");
1192
- return response.json();
1202
+ return response.data;
1193
1203
  },
1194
1204
  async getPendingSecureInputs(sessionId) {
1195
- const response = await fetch(`${getBaseUrl()}/v1/sessions/${encodeURIComponent(sessionId)}/secure-input/pending`);
1196
- if (!response.ok)
1205
+ const response = await apiListPendingSecureInputs({
1206
+ path: { id: sessionId }
1207
+ });
1208
+ if (response.error)
1197
1209
  throw new Error("Failed to get pending secure inputs");
1198
- return response.json();
1210
+ return response.data;
1199
1211
  }
1200
1212
  };
1201
1213
 
@@ -2656,6 +2668,32 @@ function useUpdateSession(sessionId) {
2656
2668
  }
2657
2669
  });
2658
2670
  }
2671
+ function useSetSessionPinned() {
2672
+ const queryClient = useQueryClient3();
2673
+ return useMutation3({
2674
+ mutationFn: ({
2675
+ sessionId,
2676
+ isPinned
2677
+ }) => apiClient.updateSession(sessionId, { isPinned }),
2678
+ onSuccess: async (updatedSession) => {
2679
+ queryClient.setQueryData(sessionsQueryKey, (old) => {
2680
+ if (!old)
2681
+ return old;
2682
+ return {
2683
+ ...old,
2684
+ pages: old.pages.map((page) => ({
2685
+ ...page,
2686
+ items: page.items.map((session) => session.id === updatedSession.id ? { ...session, ...updatedSession } : session)
2687
+ }))
2688
+ };
2689
+ });
2690
+ await queryClient.invalidateQueries({ queryKey: sessionsQueryKey });
2691
+ await queryClient.invalidateQueries({
2692
+ queryKey: ["session", updatedSession.id]
2693
+ });
2694
+ }
2695
+ });
2696
+ }
2659
2697
  function useMarkSessionViewed() {
2660
2698
  const queryClient = useQueryClient3();
2661
2699
  return useMutation3({
@@ -4728,7 +4766,8 @@ var useTerminalStore = create16((set) => ({
4728
4766
 
4729
4767
  // src/hooks/useKeyboardShortcuts.ts
4730
4768
  function useKeyboardShortcuts({
4731
- sessionIds,
4769
+ sessionIds = [],
4770
+ getSessionIds,
4732
4771
  activeSessionId,
4733
4772
  onSelectSession,
4734
4773
  onNewSession,
@@ -4766,12 +4805,13 @@ function useKeyboardShortcuts({
4766
4805
  const toggleSettings = useSettingsStore((state) => state.toggleSidebar);
4767
4806
  const toggleResearch = useResearchStore((state) => state.toggleSidebar);
4768
4807
  const toggleTerminalPanel = useTerminalStore((state) => state.togglePanel);
4769
- const currentSessionIndex = sessionIds.indexOf(activeSessionId || "");
4770
4808
  const handleKeyDown = useCallback3((e) => {
4771
4809
  const target = e.target;
4772
4810
  const isInInput = target.tagName === "INPUT" || target.tagName === "TEXTAREA" || target.isContentEditable;
4773
4811
  const isInTerminal = !!target.closest("[data-terminal-viewer]");
4774
4812
  const isShortcutModifierPressed = e.ctrlKey || e.metaKey;
4813
+ const latestSessionIds = getSessionIds?.() ?? sessionIds;
4814
+ const currentSessionIndex = latestSessionIds.indexOf(activeSessionId || "");
4775
4815
  if (isShortcutModifierPressed && !e.shiftKey && !e.altKey && e.key >= "1" && e.key <= "7") {
4776
4816
  e.preventDefault();
4777
4817
  switch (e.key) {
@@ -4900,21 +4940,21 @@ function useKeyboardShortcuts({
4900
4940
  return;
4901
4941
  }
4902
4942
  if (currentFocus === "sessions" && !isInInput) {
4903
- if (e.key === "j" && sessionIds.length > 0) {
4943
+ if (e.key === "j" && latestSessionIds.length > 0) {
4904
4944
  e.preventDefault();
4905
- const nextIndex = Math.min(sessionIndex + 1, sessionIds.length - 1);
4945
+ const nextIndex = Math.min(sessionIndex + 1, latestSessionIds.length - 1);
4906
4946
  setSessionIndex(nextIndex);
4907
4947
  return;
4908
4948
  }
4909
- if (e.key === "k" && sessionIds.length > 0) {
4949
+ if (e.key === "k" && latestSessionIds.length > 0) {
4910
4950
  e.preventDefault();
4911
4951
  const prevIndex = Math.max(sessionIndex - 1, 0);
4912
4952
  setSessionIndex(prevIndex);
4913
4953
  return;
4914
4954
  }
4915
- if (e.key === "Enter" && sessionIds[sessionIndex]) {
4955
+ if (e.key === "Enter" && latestSessionIds[sessionIndex]) {
4916
4956
  e.preventDefault();
4917
- onSelectSession(sessionIds[sessionIndex]);
4957
+ onSelectSession(latestSessionIds[sessionIndex]);
4918
4958
  setFocus("input");
4919
4959
  return;
4920
4960
  }
@@ -4988,8 +5028,9 @@ function useKeyboardShortcuts({
4988
5028
  sessionIndex,
4989
5029
  gitFileIndex,
4990
5030
  sessionIds,
5031
+ getSessionIds,
5032
+ activeSessionId,
4991
5033
  gitTreeRows,
4992
- currentSessionIndex,
4993
5034
  isGitExpanded,
4994
5035
  setFocus,
4995
5036
  setSessionIndex,
@@ -5235,6 +5276,7 @@ import {
5235
5276
  useCallback as useCallback5,
5236
5277
  useEffect as useEffect8
5237
5278
  } from "react";
5279
+ import { uploadAttachment } from "@ottocode/api";
5238
5280
  var IMAGE_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
5239
5281
  var PDF_TYPES = ["application/pdf"];
5240
5282
  var TEXT_TYPES = [
@@ -5339,19 +5381,16 @@ async function fileToPreview2(file) {
5339
5381
  });
5340
5382
  }
5341
5383
  async function uploadOriginalFile(file, sessionId) {
5342
- const form = new FormData;
5343
- form.set("file", file);
5344
- if (sessionId)
5345
- form.set("sessionId", sessionId);
5346
- const response = await fetch(`${getBaseUrl()}/v1/attachments`, {
5347
- method: "POST",
5348
- body: form
5384
+ const response = await uploadAttachment({
5385
+ body: {
5386
+ file,
5387
+ ...sessionId ? { sessionId } : {}
5388
+ }
5349
5389
  });
5350
- const data = await response.json().catch(() => null);
5351
- if (!response.ok) {
5352
- throw new Error(extractErrorMessage(data));
5390
+ if (response.error) {
5391
+ throw new Error(extractErrorMessage(response.error));
5353
5392
  }
5354
- return data;
5393
+ return response.data;
5355
5394
  }
5356
5395
  function useFileUpload(options = {}) {
5357
5396
  const {
@@ -7030,13 +7069,15 @@ function useCopilotDevicePoller() {
7030
7069
  // src/hooks/useSkills.ts
7031
7070
  import { useMutation as useMutation9, useQuery as useQuery13, useQueryClient as useQueryClient12 } from "@tanstack/react-query";
7032
7071
  import { useEffect as useEffect17 } from "react";
7033
- function useSkills() {
7072
+ function useSkills(options = {}) {
7073
+ const enabled = options.enabled ?? true;
7034
7074
  const setSkillsConfig = useSkillsStore((s) => s.setSkillsConfig);
7035
7075
  const query = useQuery13({
7036
7076
  queryKey: ["skills"],
7037
7077
  queryFn: async () => {
7038
7078
  return apiClient.getSkillsConfig();
7039
7079
  },
7080
+ enabled,
7040
7081
  refetchInterval: 30000
7041
7082
  });
7042
7083
  useEffect17(() => {
@@ -7171,6 +7212,7 @@ function appendBuffer(a, b) {
7171
7212
  function useVoiceInput({
7172
7213
  onTranscript,
7173
7214
  onError,
7215
+ onNeedsInstall,
7174
7216
  lang = "en-US"
7175
7217
  } = {}) {
7176
7218
  const [isListening, setIsListening] = useState7(false);
@@ -7187,15 +7229,24 @@ function useVoiceInput({
7187
7229
  const sessionIdRef = useRef9(null);
7188
7230
  const onTranscriptRef = useRef9(onTranscript);
7189
7231
  const onErrorRef = useRef9(onError);
7232
+ const onNeedsInstallRef = useRef9(onNeedsInstall);
7190
7233
  useEffect19(() => {
7191
7234
  onTranscriptRef.current = onTranscript;
7192
7235
  onErrorRef.current = onError;
7193
- }, [onTranscript, onError]);
7236
+ onNeedsInstallRef.current = onNeedsInstall;
7237
+ }, [onTranscript, onError, onNeedsInstall]);
7194
7238
  const isSupported = typeof window !== "undefined" && !!navigator.mediaDevices?.getUserMedia && !!getAudioContextConstructor() && typeof WebSocket !== "undefined";
7195
7239
  const emitError = useCallback12((message) => {
7196
7240
  setError(message);
7197
7241
  onErrorRef.current?.(message);
7198
7242
  }, []);
7243
+ const handleMissingModel = useCallback12(() => {
7244
+ if (onNeedsInstallRef.current) {
7245
+ onNeedsInstallRef.current();
7246
+ return;
7247
+ }
7248
+ emitError("Install a local dictation model from Settings before recording.");
7249
+ }, [emitError]);
7199
7250
  const cleanupAudio = useCallback12(() => {
7200
7251
  if (processorRef.current) {
7201
7252
  processorRef.current.onaudioprocess = null;
@@ -7290,7 +7341,7 @@ function useVoiceInput({
7290
7341
  const status = await apiClient.getDictationStatus();
7291
7342
  const model = status.models.find((item) => item.id === status.defaultModel);
7292
7343
  if (!model?.installed) {
7293
- emitError("Install a local dictation model from Settings before recording.");
7344
+ handleMissingModel();
7294
7345
  return;
7295
7346
  }
7296
7347
  const session = await apiClient.createDictationSession({
@@ -7298,7 +7349,7 @@ function useVoiceInput({
7298
7349
  language: toLanguageCode(lang)
7299
7350
  });
7300
7351
  if (!session.modelInstalled) {
7301
- emitError("Install a local dictation model from Settings before recording.");
7352
+ handleMissingModel();
7302
7353
  return;
7303
7354
  }
7304
7355
  const socket = new WebSocket(session.wsUrl);
@@ -7382,7 +7433,14 @@ function useVoiceInput({
7382
7433
  emitError(msg);
7383
7434
  cleanup();
7384
7435
  }
7385
- }, [cleanup, emitError, handleAudioProcess, isSupported, lang]);
7436
+ }, [
7437
+ cleanup,
7438
+ emitError,
7439
+ handleAudioProcess,
7440
+ handleMissingModel,
7441
+ isSupported,
7442
+ lang
7443
+ ]);
7386
7444
  useEffect19(() => cleanup, [cleanup]);
7387
7445
  return {
7388
7446
  isListening,
@@ -7532,6 +7590,7 @@ export {
7532
7590
  useSkillFileContent,
7533
7591
  useSkillDetail,
7534
7592
  useShareStatus,
7593
+ useSetSessionPinned,
7535
7594
  useSessionsInfinite,
7536
7595
  useSessions,
7537
7596
  useSessionStream,
@@ -7599,4 +7658,4 @@ export {
7599
7658
  normalizeQueueState
7600
7659
  };
7601
7660
 
7602
- //# debugId=A9770107614A950A64756E2164756E21
7661
+ //# debugId=21BA48969B41542064756E2164756E21