@skillsgate/tui 0.1.12 → 0.1.14

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.
@@ -4,31 +4,22 @@ import { useStore, useDispatch } from "../store/context.js"
4
4
  import { useSearch } from "../data/use-search.js"
5
5
  import { useSkillActions } from "../data/use-skill-actions.js"
6
6
  import { ConfirmDialog } from "../components/confirm-dialog.js"
7
- import type { CatalogSkill, SearchMode } from "../data/api-client.js"
7
+ import type { CatalogSkill } from "../data/api-client.js"
8
8
  import { colors } from "../utils/colors.js"
9
9
 
10
10
  /**
11
- * Discover view: two-column layout with search mode toggle.
12
- * LEFT - Search input + mode toggle + results list (40%)
11
+ * Discover view: two-column layout with search results.
12
+ * LEFT - Search input + results list (40%)
13
13
  * RIGHT - Selected result detail (flexGrow)
14
- *
15
- * Search modes:
16
- * - Keyword (public, no auth): ILIKE pattern matching, unlimited
17
- * - Semantic (auth required): AI-powered vector search, 30/day limit
18
- * Toggle with 'm' key.
19
14
  */
20
15
  export function DiscoverView() {
21
16
  const state = useStore()
22
17
  const dispatch = useDispatch()
23
18
  const [query, setQuery] = useState("")
24
- const [searchMode, setSearchMode] = useState<SearchMode>("keyword")
25
19
  const [selectedIndex, setSelectedIndex] = useState(0)
26
20
  const [installTarget, setInstallTarget] = useState<CatalogSkill | null>(null)
27
21
  const [previewSkill, setPreviewSkill] = useState<CatalogSkill | null>(null)
28
22
 
29
- const token = state.auth?.token ?? null
30
- const isAuthenticated = !!state.auth
31
-
32
23
  // Auto-focus search input when Discover view mounts
33
24
  useEffect(() => {
34
25
  if (state.activeView === "discover") {
@@ -36,8 +27,8 @@ export function DiscoverView() {
36
27
  }
37
28
  }, [state.activeView])
38
29
 
39
- const { results, loading, error, total, hasMore, loadMore, remainingSearches } =
40
- useSearch(query, searchMode, token)
30
+ const { results, loading, error, total, hasMore, loadMore } =
31
+ useSearch(query)
41
32
  const { installSkill } = useSkillActions()
42
33
 
43
34
  // Update preview when selection changes
@@ -94,24 +85,6 @@ export function DiscoverView() {
94
85
  setInstallTarget(results[selectedIndex])
95
86
  return
96
87
  }
97
-
98
- // m to toggle search mode
99
- if (key.name === "m") {
100
- if (searchMode === "keyword") {
101
- if (!isAuthenticated) {
102
- dispatch({
103
- type: "SHOW_NOTIFICATION",
104
- notification: { type: "info", message: "Sign in to use AI search (press l)" },
105
- })
106
- return
107
- }
108
- setSearchMode("semantic")
109
- } else {
110
- setSearchMode("keyword")
111
- }
112
- setSelectedIndex(0)
113
- return
114
- }
115
88
  })
116
89
 
117
90
  // Confirm dialog for install
@@ -142,17 +115,11 @@ export function DiscoverView() {
142
115
  paddingLeft: 1,
143
116
  paddingRight: 1,
144
117
  }}
145
- title={state.focusedPane === "search"
146
- ? (searchMode === "semantic" ? "AI Search" : "Keyword Search")
147
- : "/ to search"}
118
+ title={state.focusedPane === "search" ? "Search" : "/ to search"}
148
119
  >
149
120
  {state.focusedPane === "search" ? (
150
121
  <input
151
- placeholder={
152
- searchMode === "semantic"
153
- ? 'AI search -- try "audit website performance" (Enter to search)'
154
- : "Search by keyword... (Enter to search)"
155
- }
122
+ placeholder="Search skills... (Enter to search)"
156
123
  focused={state.activeView === "discover" && !state.showHelp}
157
124
  onSubmit={((value: string) => {
158
125
  setQuery(value)
@@ -164,7 +131,7 @@ export function DiscoverView() {
164
131
  )}
165
132
  </box>
166
133
 
167
- {/* Status line: mode toggle + results + remaining */}
134
+ {/* Status line */}
168
135
  <box
169
136
  style={{
170
137
  height: 1,
@@ -174,37 +141,16 @@ export function DiscoverView() {
174
141
  flexDirection: "row",
175
142
  }}
176
143
  >
177
- {/* Mode toggle: show both options, highlight active */}
178
- <text fg={searchMode === "keyword" ? colors.primary : colors.textDim}>
179
- {searchMode === "keyword" ? "[Keyword]" : " Keyword "}
180
- </text>
181
- <text fg={colors.textDim}>{" | "}</text>
182
- <text fg={searchMode === "semantic" ? colors.warning : colors.textDim}>
183
- {searchMode === "semantic" ? "[AI Search]" : (isAuthenticated ? " AI Search " : " AI Search (login) ")}
184
- </text>
185
- <text fg={colors.textDim}>{" m=switch "}</text>
186
-
187
144
  {/* Results info */}
188
145
  <text fg={colors.textDim}>
189
146
  {loading
190
147
  ? "Loading..."
191
148
  : error
192
- ? error === "AUTH_EXPIRED"
193
- ? "Session expired -- press l to re-login"
194
- : error === "RATE_LIMIT"
195
- ? "Daily limit reached -- switch to keyword (m)"
196
- : `Error: ${error}`
149
+ ? `Error: ${error}`
197
150
  : query.trim()
198
151
  ? `${results.length} result${results.length !== 1 ? "s" : ""}`
199
152
  : `${results.length}/${total} skills`}
200
153
  </text>
201
-
202
- {/* Remaining searches (semantic only) */}
203
- {searchMode === "semantic" && remainingSearches !== null ? (
204
- <text fg={remainingSearches <= 5 ? colors.error : colors.textDim}>
205
- {` ${remainingSearches} left today`}
206
- </text>
207
- ) : null}
208
154
  </box>
209
155
 
210
156
  {/* Two-column content: results list | detail */}
@@ -250,7 +196,7 @@ export function DiscoverView() {
250
196
  >
251
197
  {results.map((skill, i) => (
252
198
  <box
253
- key={skill.id ?? `${skill.slug}-${i}`}
199
+ key={skill.id ?? `${skill.skillId}-${i}`}
254
200
  style={{
255
201
  width: "100%",
256
202
  paddingLeft: 1,
@@ -297,11 +243,6 @@ interface DiscoverDetailPanelProps {
297
243
  }
298
244
 
299
245
  function DiscoverDetailPanel({ skill }: DiscoverDetailPanelProps) {
300
- const description = skill.summary || skill.description || ""
301
- const categories = skill.categories?.join(", ") ?? ""
302
- const capabilities = skill.capabilities?.join(", ") ?? ""
303
- const keywords = skill.keywords?.join(", ") ?? ""
304
-
305
246
  return (
306
247
  <scrollbox
307
248
  focused={false}
@@ -325,58 +266,25 @@ function DiscoverDetailPanel({ skill }: DiscoverDetailPanelProps) {
325
266
  <strong>{skill.name}</strong>
326
267
  </text>
327
268
 
328
- {/* Description */}
329
- <text fg={colors.text}>{description}</text>
330
- <text>{" "}</text>
331
-
332
- {/* Categories */}
333
- {categories ? (
334
- <box style={{ flexDirection: "row", height: 1 }}>
335
- <text fg={colors.textDim}>Categories: </text>
336
- <text fg={colors.secondary}>{categories}</text>
337
- </box>
338
- ) : null}
339
-
340
- {/* Capabilities */}
341
- {capabilities ? (
342
- <box style={{ flexDirection: "row", height: 1 }}>
343
- <text fg={colors.textDim}>Capabilities: </text>
344
- <text fg={colors.secondary}>{capabilities}</text>
345
- </box>
346
- ) : null}
347
-
348
- {/* Keywords */}
349
- {keywords ? (
350
- <box style={{ flexDirection: "row", height: 1 }}>
351
- <text fg={colors.textDim}>Keywords: </text>
352
- <text fg={colors.secondary}>{keywords}</text>
353
- </box>
354
- ) : null}
355
-
356
- {/* Score (semantic search only) */}
357
- {skill.score ? (
358
- <box style={{ flexDirection: "row", height: 1 }}>
359
- <text fg={colors.textDim}>Score: </text>
360
- <text fg={colors.success}>{skill.score.toFixed(3)}</text>
361
- </box>
362
- ) : null}
269
+ {/* Skill ID */}
270
+ <box style={{ flexDirection: "row", height: 1 }}>
271
+ <text fg={colors.textDim}>ID: </text>
272
+ <text fg={colors.text}>{skill.skillId}</text>
273
+ </box>
363
274
 
364
- {/* GitHub URL */}
365
- {skill.githubUrl ? (
275
+ {/* Source (owner/repo) */}
276
+ {skill.source ? (
366
277
  <box style={{ flexDirection: "row", height: 1 }}>
367
- <text fg={colors.textDim}>GitHub: </text>
368
- <text fg={colors.primary}>{skill.githubUrl}</text>
278
+ <text fg={colors.textDim}>Source: </text>
279
+ <text fg={colors.primary}>{skill.source}</text>
369
280
  </box>
370
281
  ) : null}
371
282
 
372
- {/* Install command */}
373
- {skill.installCommand ? (
374
- <>
375
- <text>{" "}</text>
376
- <text fg={colors.textDim}>Install:</text>
377
- <text fg={colors.success}> {skill.installCommand}</text>
378
- </>
379
- ) : null}
283
+ {/* Installs */}
284
+ <box style={{ flexDirection: "row", height: 1 }}>
285
+ <text fg={colors.textDim}>Installs: </text>
286
+ <text fg={colors.success}>{skill.installs.toLocaleString()}</text>
287
+ </box>
380
288
 
381
289
  <text>{" "}</text>
382
290
  <text fg={colors.textDim}>v=full detail i=install Tab=switch pane</text>
@@ -392,9 +300,11 @@ function DiscoverDetailPanel({ skill }: DiscoverDetailPanelProps) {
392
300
  * Since catalog skills don't have a local file, we provide a placeholder.
393
301
  */
394
302
  function catalogSkillToEnriched(skill: CatalogSkill): import("../store/types.js").EnrichedSkill {
303
+ const githubUrl = skill.source ? `https://github.com/${skill.source}` : undefined
304
+
395
305
  return {
396
306
  name: skill.name,
397
- description: skill.summary || skill.description || "",
307
+ description: "",
398
308
  filePath: "", // No local file for catalog items
399
309
  canonicalPath: "",
400
310
  agents: [],
@@ -403,18 +313,15 @@ function catalogSkillToEnriched(skill: CatalogSkill): import("../store/types.js"
403
313
  hasSupportingFiles: false,
404
314
  supportingFiles: [],
405
315
  metadata: {
406
- categories: skill.categories,
407
- capabilities: skill.capabilities,
408
- keywords: skill.keywords,
409
- githubUrl: skill.githubUrl,
410
- installCommand: skill.installCommand,
411
- urlPath: skill.urlPath,
316
+ source: skill.source,
317
+ skillId: skill.skillId,
318
+ installs: skill.installs,
412
319
  },
413
- lock: skill.githubUrl
320
+ lock: skill.source
414
321
  ? {
415
- source: skill.githubUrl,
322
+ source: skill.source,
416
323
  sourceType: "github" as const,
417
- originalUrl: skill.githubUrl,
324
+ originalUrl: githubUrl ?? "",
418
325
  skillFolderHash: "",
419
326
  installedAt: "",
420
327
  updatedAt: "",
@@ -1,363 +1,19 @@
1
- import { useState, useMemo, useEffect } from "react"
2
- import { useKeyboard } from "@opentui/react"
3
- import { useStore, useDispatch } from "../store/context.js"
4
- import { useFavorites } from "../data/use-favorites.js"
5
- import { useSkillActions } from "../data/use-skill-actions.js"
6
- import { ConfirmDialog } from "../components/confirm-dialog.js"
7
1
  import { colors } from "../utils/colors.js"
8
- import type { CatalogSkill } from "../data/api-client.js"
9
- import type { EnrichedSkill } from "../store/types.js"
10
2
 
11
3
  /**
12
- * Favorites view: two-column layout.
13
- * LEFT - Favorites list (40%)
14
- * RIGHT - Selected favorite detail (flexGrow)
15
- *
16
- * Requires authentication. Shows a prompt to login if not authenticated.
4
+ * Favorites view: Coming soon placeholder.
5
+ * Favorites require authentication which is not yet available in the public TUI.
17
6
  */
18
7
  export function FavoritesView() {
19
- const state = useStore()
20
- const dispatch = useDispatch()
21
- const { favorites, loading, error, toggle } = useFavorites()
22
- const { installSkill } = useSkillActions()
23
- const [selectedIndex, setSelectedIndex] = useState(0)
24
- const [installTarget, setInstallTarget] = useState<CatalogSkill | null>(null)
25
- const [previewSkill, setPreviewSkill] = useState<CatalogSkill | null>(null)
26
-
27
- // Build a set of installed skill names for the "installed" badge
28
- const installedNames = useMemo(() => {
29
- return new Set(state.installedSkills.map((s) => s.name.toLowerCase()))
30
- }, [state.installedSkills])
31
-
32
- // Update preview when selection changes
33
- useEffect(() => {
34
- if (favorites[selectedIndex]) {
35
- setPreviewSkill(favorites[selectedIndex])
36
- } else {
37
- setPreviewSkill(null)
38
- }
39
- }, [selectedIndex, favorites])
40
-
41
- // Keyboard navigation for the favorites list
42
- useKeyboard((key) => {
43
- if (state.activeView !== "favorites") return
44
- if (state.showHelp) return
45
- if (!state.auth) return // No navigation when not logged in
46
- if (installTarget) return // Block navigation during confirm dialog
47
-
48
- // j/k or arrow keys
49
- if (key.name === "up" || (key.name === "k" && !key.ctrl)) {
50
- setSelectedIndex((i) => Math.max(0, i - 1))
51
- }
52
- if (key.name === "down" || (key.name === "j" && !key.ctrl)) {
53
- setSelectedIndex((i) => Math.min(favorites.length - 1, i + 1))
54
- }
55
-
56
- // g = first, G = last
57
- if (key.name === "g" && !key.shift) {
58
- setSelectedIndex(0)
59
- }
60
- if (key.name === "g" && key.shift) {
61
- setSelectedIndex(Math.max(0, favorites.length - 1))
62
- }
63
-
64
- // v to view full detail
65
- if (key.name === "v" && favorites[selectedIndex]) {
66
- const skill = favorites[selectedIndex]
67
- dispatch({
68
- type: "SELECT_SKILL",
69
- skill: catalogSkillToEnriched(skill, installedNames),
70
- })
71
- return
72
- }
73
-
74
- // x to unfavorite
75
- if (key.name === "x" && favorites[selectedIndex]) {
76
- const skill = favorites[selectedIndex]
77
- toggle(skill.id)
78
- dispatch({
79
- type: "SHOW_NOTIFICATION",
80
- notification: { type: "info", message: `Removed "${skill.name}" from favorites` },
81
- })
82
- // Adjust selection if we removed the last item
83
- if (selectedIndex >= favorites.length - 1 && selectedIndex > 0) {
84
- setSelectedIndex(selectedIndex - 1)
85
- }
86
- return
87
- }
88
-
89
- // i to install
90
- if (key.name === "i" && favorites[selectedIndex]) {
91
- setInstallTarget(favorites[selectedIndex])
92
- return
93
- }
94
- })
95
-
96
- // Confirm dialog for install
97
- if (installTarget) {
98
- return (
99
- <ConfirmDialog
100
- message={`Install "${installTarget.name}"?`}
101
- onConfirm={async () => {
102
- const skill = catalogSkillToEnriched(installTarget, installedNames)
103
- setInstallTarget(null)
104
- await installSkill(skill)
105
- }}
106
- onCancel={() => setInstallTarget(null)}
107
- />
108
- )
109
- }
110
-
111
- // Not authenticated
112
- if (!state.auth) {
113
- return (
114
- <box style={{ flexDirection: "column", padding: 2 }}>
115
- <text fg={colors.text}>
116
- Sign in to view your favorites
117
- </text>
118
- <text>{" "}</text>
119
- <text fg={colors.textDim}>
120
- Press <span fg={colors.primary}>l</span> to login
121
- </text>
122
- </box>
123
- )
124
- }
125
-
126
- // Loading state
127
- if (loading && favorites.length === 0) {
128
- return (
129
- <box style={{ padding: 1 }}>
130
- <text fg={colors.textDim}>Loading favorites...</text>
131
- </box>
132
- )
133
- }
134
-
135
- // Error state
136
- if (error && favorites.length === 0) {
137
- return (
138
- <box style={{ padding: 1 }}>
139
- <text fg={colors.error}>Error: {error}</text>
140
- </box>
141
- )
142
- }
143
-
144
8
  return (
145
- <box style={{ flexDirection: "column", width: "100%", flexGrow: 1 }}>
146
- {/* Status line */}
147
- <box
148
- style={{
149
- height: 1,
150
- width: "100%",
151
- paddingLeft: 1,
152
- backgroundColor: colors.bgAlt,
153
- }}
154
- >
155
- <text fg={colors.textDim}>
156
- {favorites.length} favorite{favorites.length !== 1 ? "s" : ""}
157
- {loading ? " (refreshing...)" : ""}
158
- </text>
159
- </box>
160
-
161
- {/* Two-column content: list | detail */}
162
- <box style={{ flexDirection: "row", flexGrow: 1, width: "100%" }}>
163
- {/* LEFT: Favorites list */}
164
- <box
165
- style={{
166
- width: "40%",
167
- border: true,
168
- borderColor: colors.border,
169
- flexDirection: "column",
170
- } as any}
171
- >
172
- {/* List header */}
173
- <box style={{ height: 1, paddingLeft: 1, backgroundColor: colors.bgAlt }}>
174
- <text fg={colors.textDim}>FAVORITES</text>
175
- </box>
176
-
177
- {favorites.length === 0 ? (
178
- <box style={{ padding: 1 }}>
179
- <text fg={colors.textDim}>
180
- No favorites yet. Browse the Discover tab to find and favorite skills.
181
- </text>
182
- </box>
183
- ) : (
184
- <scrollbox
185
- focused={state.activeView === "favorites" && !state.showHelp}
186
- style={{
187
- width: "100%",
188
- flexGrow: 1,
189
- rootOptions: { backgroundColor: colors.bg },
190
- viewportOptions: { backgroundColor: colors.bg },
191
- contentOptions: { backgroundColor: colors.bg },
192
- scrollbarOptions: {
193
- trackOptions: {
194
- foregroundColor: colors.primary,
195
- backgroundColor: colors.border,
196
- },
197
- },
198
- }}
199
- >
200
- {favorites.map((skill, i) => {
201
- const isInstalled = installedNames.has(skill.name?.toLowerCase() ?? "")
202
- return (
203
- <box
204
- key={skill.id ?? `${skill.slug}-${i}`}
205
- style={{
206
- width: "100%",
207
- paddingLeft: 1,
208
- paddingRight: 1,
209
- flexDirection: "row",
210
- backgroundColor: i === selectedIndex ? colors.bgAlt : "transparent",
211
- }}
212
- >
213
- <text fg={i === selectedIndex ? colors.primary : colors.text}>
214
- {skill.name}
215
- </text>
216
- {isInstalled ? (
217
- <text fg={colors.success}> *</text>
218
- ) : null}
219
- </box>
220
- )
221
- })}
222
- </scrollbox>
223
- )}
224
- </box>
225
-
226
- {/* RIGHT: Detail panel */}
227
- <box style={{ flexGrow: 1, flexDirection: "column" }}>
228
- {previewSkill ? (
229
- <FavoriteDetailPanel
230
- skill={previewSkill}
231
- isInstalled={installedNames.has(previewSkill.name?.toLowerCase() ?? "")}
232
- />
233
- ) : (
234
- <box style={{ padding: 1 }}>
235
- <text fg={colors.textDim}>Select a favorite to view details</text>
236
- </box>
237
- )}
238
- </box>
239
- </box>
9
+ <box style={{ flexDirection: "column", padding: 2 }}>
10
+ <text fg={colors.primary}>
11
+ <strong>Favorites</strong>
12
+ </text>
13
+ <text>{" "}</text>
14
+ <text fg={colors.text}>
15
+ Coming soon. Favorites will be available once accounts are launched.
16
+ </text>
240
17
  </box>
241
18
  )
242
19
  }
243
-
244
- // ---------- Inline Detail Panel ----------
245
-
246
- interface FavoriteDetailPanelProps {
247
- skill: CatalogSkill
248
- isInstalled: boolean
249
- }
250
-
251
- function FavoriteDetailPanel({ skill, isInstalled }: FavoriteDetailPanelProps) {
252
- const description = skill.summary || skill.description || ""
253
- const categories = skill.categories?.join(", ") ?? ""
254
- const sourceLabel = skill.githubUrl ? "github" : "skillsgate"
255
-
256
- return (
257
- <scrollbox
258
- focused={false}
259
- style={{
260
- width: "100%",
261
- flexGrow: 1,
262
- rootOptions: { backgroundColor: colors.bg },
263
- viewportOptions: { backgroundColor: colors.bg },
264
- contentOptions: { backgroundColor: colors.bg },
265
- scrollbarOptions: {
266
- trackOptions: {
267
- foregroundColor: colors.primary,
268
- backgroundColor: colors.border,
269
- },
270
- },
271
- }}
272
- >
273
- <box style={{ paddingLeft: 1, paddingRight: 1, flexDirection: "column" }}>
274
- {/* Name */}
275
- <text fg={colors.primary}>
276
- <strong>{skill.name}</strong>
277
- </text>
278
-
279
- {/* Status */}
280
- {isInstalled ? (
281
- <text fg={colors.success}>Installed</text>
282
- ) : (
283
- <text fg={colors.textDim}>Not installed</text>
284
- )}
285
- <text>{" "}</text>
286
-
287
- {/* Description */}
288
- <text fg={colors.text}>{description}</text>
289
- <text>{" "}</text>
290
-
291
- {/* Source */}
292
- <box style={{ flexDirection: "row", height: 1 }}>
293
- <text fg={colors.textDim}>Source: </text>
294
- <text fg={colors.secondary}>{sourceLabel}</text>
295
- </box>
296
-
297
- {/* Categories */}
298
- {categories ? (
299
- <box style={{ flexDirection: "row", height: 1 }}>
300
- <text fg={colors.textDim}>Categories: </text>
301
- <text fg={colors.secondary}>{categories}</text>
302
- </box>
303
- ) : null}
304
-
305
- {/* GitHub URL */}
306
- {skill.githubUrl ? (
307
- <box style={{ flexDirection: "row", height: 1 }}>
308
- <text fg={colors.textDim}>GitHub: </text>
309
- <text fg={colors.primary}>{skill.githubUrl}</text>
310
- </box>
311
- ) : null}
312
-
313
- {/* Install command */}
314
- {skill.installCommand ? (
315
- <>
316
- <text>{" "}</text>
317
- <text fg={colors.textDim}>Install:</text>
318
- <text fg={colors.success}> {skill.installCommand}</text>
319
- </>
320
- ) : null}
321
-
322
- <text>{" "}</text>
323
- <text fg={colors.textDim}>v=full detail x=unfavorite i=install</text>
324
- </box>
325
- </scrollbox>
326
- )
327
- }
328
-
329
- // ---------- Helpers ----------
330
-
331
- function catalogSkillToEnriched(
332
- skill: CatalogSkill,
333
- installedNames: Set<string>
334
- ): EnrichedSkill {
335
- return {
336
- name: skill.name,
337
- description: skill.summary || skill.description || "",
338
- filePath: "",
339
- canonicalPath: "",
340
- agents: [],
341
- scope: "custom",
342
- projectName: null,
343
- hasSupportingFiles: false,
344
- supportingFiles: [],
345
- metadata: {
346
- categories: skill.categories,
347
- capabilities: skill.capabilities,
348
- keywords: skill.keywords,
349
- githubUrl: skill.githubUrl,
350
- installCommand: skill.installCommand,
351
- },
352
- lock: skill.githubUrl
353
- ? {
354
- source: skill.githubUrl,
355
- sourceType: "github" as const,
356
- originalUrl: skill.githubUrl,
357
- skillFolderHash: "",
358
- installedAt: "",
359
- updatedAt: "",
360
- }
361
- : undefined,
362
- }
363
- }
@@ -34,12 +34,6 @@ const SETTING_DEFS: SettingDef[] = [
34
34
  options: ["dark", "light", "system"],
35
35
  defaultValue: "dark",
36
36
  },
37
- {
38
- key: "search.preferSemantic",
39
- label: "Prefer semantic search",
40
- type: "toggle",
41
- defaultValue: true,
42
- },
43
37
  {
44
38
  key: "telemetry.enabled",
45
39
  label: "Anonymous telemetry",