@qredence/fleet 0.5.10 → 0.6.0
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/CHANGELOG.md +22 -0
- package/dist/web/client/assets/agent-activity-CwMDU7aP.js +1 -0
- package/dist/web/client/assets/artifacts-panel-CJ75gQub.js +1 -0
- package/dist/web/client/assets/chat-Ci2cEQrR.js +52 -0
- package/dist/web/client/assets/{chat-command-palette-DfYSPPXI.js → chat-command-palette-CkISHfKE.js} +1 -1
- package/dist/web/client/assets/{citations-BQ_pr_9_.js → citations-C_tPOJE_.js} +1 -1
- package/dist/web/client/assets/{command-DPfiaYUL.js → command-_WjnervL.js} +1 -1
- package/dist/web/client/assets/fleet-message-queue-BCno4XP-.js +1 -0
- package/dist/web/client/assets/{fleet-pi-tool-renderer-AJoMbXBa.js → fleet-pi-tool-renderer-BEDIO3al.js} +4 -4
- package/dist/web/client/assets/fleet-reasoning-panel-CbkO7u-v.js +1 -0
- package/dist/web/client/assets/{fleet-subagent-list-BnRnrWKS.js → fleet-subagent-list-iKUtLJKZ.js} +1 -1
- package/dist/web/client/assets/fleet-tool-timeline-C8heL7ae.js +1 -0
- package/dist/web/client/assets/{fork-picker-dialog-CkcSekBl.js → fork-picker-dialog-ByBOGVsa.js} +1 -1
- package/dist/web/client/assets/globals-B_I1Eq1u.css +2 -0
- package/dist/web/client/assets/horizontal-resize-CwoDojST.js +1 -0
- package/dist/web/client/assets/{index-DlnHLDpx.js → index-DJ1fFbQu.js} +3 -3
- package/dist/web/client/assets/input-group-Tb5TYbzi.js +1 -0
- package/dist/web/client/assets/{ipython-tool-BrMePqD-.js → ipython-tool-ldJ9F1Cw.js} +1 -1
- package/dist/web/client/assets/model-selector-list-Ch05B2nZ.js +1 -0
- package/dist/web/client/assets/{openui-renderer-DwYFJdbe.js → openui-renderer-Bf60nxNi.js} +4 -4
- package/dist/web/client/assets/pencil-DcUwsKLn.js +1 -0
- package/dist/web/client/assets/prompt-input-qPIXZ-Rb.js +1 -0
- package/dist/web/client/assets/prompt-suggestions-Cc--lSNR.js +1 -0
- package/dist/web/client/assets/{provider-label-BCJh04J5.js → provider-label-DDLRnZyC.js} +1 -1
- package/dist/web/client/assets/repl-panel-DsPX04Xr.js +1 -0
- package/dist/web/client/assets/{resources-panel-Bo8dfUdm.js → resources-panel-D867-goy.js} +1 -1
- package/dist/web/client/assets/right-panel-registry-Dp8yX-oL.js +2 -0
- package/dist/web/client/assets/routes-DpgMJZ5n.js +16 -0
- package/dist/web/client/assets/safe-storage-s25GrfpH.js +1 -0
- package/dist/web/client/assets/session-insights-panel-YnaXvTpi.js +1 -0
- package/dist/web/client/assets/settings-dialog-YJkvt5EB.js +2 -0
- package/dist/web/client/assets/skeleton-loaders-C9vHwAYV.js +1 -0
- package/dist/web/client/assets/{subagent-chat-panel-DseoO31p.js → subagent-chat-panel-Yujplxpb.js} +1 -1
- package/dist/web/client/assets/subagent-transcript-CnI-mqN0.js +1 -0
- package/dist/web/client/assets/subagents-panel-CjXEdimj.js +1 -0
- package/dist/web/client/assets/{surfaces-cW-gp56p.js → surfaces-DI-U-_2a.js} +1 -1
- package/dist/web/client/assets/tool-result-DfnPN0FQ.js +4 -0
- package/dist/web/client/assets/ui-preferences-CImQGZm_.js +1 -0
- package/dist/web/client/assets/virtualized-turn-list--Vynre4D.js +6 -0
- package/dist/web/client/assets/{workspace-panel-DI1W3ce9.js → workspace-panel-CPPIznT9.js} +1 -1
- package/dist/web/client/bundle-budget.json +6 -6
- package/dist/web/server/{_tanstack-start-manifest_v-Cdx6hy2i-I7A5YJRU.js → _tanstack-start-manifest_v-DS_CSIFQ-WB3VTKF3.js} +15 -13
- package/dist/web/server/{agent-activity-B-JMvecd-SLE3GGY2.js → agent-activity-CS2rbF_C-A3R26CYH.js} +2 -2
- package/dist/web/server/{artifacts-panel-DLMK1O8P-42T45JMA.js → artifacts-panel-CaKrX2XC-R37I4BHF.js} +12 -12
- package/dist/web/server/{chat-command-palette-CdYwoTMe-4LBAZF7K.js → chat-command-palette-7gbqEnm9-6XICQZN7.js} +4 -4
- package/dist/web/server/{chunk-EBCYJSBR.js → chunk-7SD2ZSEA.js} +3 -3
- package/dist/web/server/{chunk-6AW2XFTZ.js → chunk-BBBS5AS7.js} +194 -10
- package/dist/web/server/{chunk-EOVMHQ2H.js → chunk-CNXJN5HN.js} +7 -7
- package/dist/web/server/{chunk-XKKXXG6N.js → chunk-DI7XRK2H.js} +2 -2
- package/dist/web/server/{chunk-KNJUSMBT.js → chunk-DZ2IC3FH.js} +2 -2
- package/dist/web/server/{chunk-K5ESTT4A.js → chunk-EAE2QXRK.js} +11 -3
- package/dist/web/server/{chunk-VHBFU4TG.js → chunk-EH4BZ6QM.js} +123 -16
- package/dist/web/server/{chunk-54II5QXQ.js → chunk-ETTDO4UO.js} +6 -3
- package/dist/web/server/{chunk-EHNIN245.js → chunk-GETSIVNU.js} +5 -5
- package/dist/web/server/{chunk-X2R5YPQZ.js → chunk-IJPCV6DH.js} +3 -2
- package/dist/web/server/{chunk-AJJ2S5FF.js → chunk-JQDLJ7KI.js} +20 -20
- package/dist/web/server/{chunk-M564UIEY.js → chunk-KELEYPVK.js} +8 -8
- package/dist/web/server/{chunk-OB5OSYJK.js → chunk-LXJD6IGW.js} +53 -29
- package/dist/web/server/chunk-M5RSPNYN.js +22 -0
- package/dist/web/server/{chunk-2TRF62K5.js → chunk-N6NOTURM.js} +3 -3
- package/dist/web/server/{chunk-5XX7RKJ6.js → chunk-NXJ32VFR.js} +5 -5
- package/dist/web/server/{chunk-P7H2OPKF.js → chunk-PIOFZUOU.js} +9 -1
- package/dist/web/server/chunk-PTCKOR23.js +39 -0
- package/dist/web/server/chunk-SZJUXVWG.js +40 -0
- package/dist/web/server/{chunk-TCH3U26B.js → chunk-TWYHHG5N.js} +2 -10
- package/dist/web/server/{chunk-FED63ZHU.js → chunk-WHBVQJ4K.js} +11 -6
- package/dist/web/server/{chunk-ANL4B775.js → chunk-XLNCWZMZ.js} +2 -2
- package/dist/web/server/{chunk-GM32R7JW.js → chunk-YKVGQBZA.js} +10 -8
- package/dist/web/server/{chunk-NRDG2ISJ.js → chunk-YNUWKMNQ.js} +59 -52
- package/dist/web/server/{chunk-3PIUR75R.js → chunk-YXXRP3NS.js} +9 -9
- package/dist/web/server/fleet-message-queue-BS-cZ56r-GLZXUKDF.js +152 -0
- package/dist/web/server/{fleet-pi-tool-renderer-RIeVlM9J-D6MISCQC.js → fleet-pi-tool-renderer-umKunT3K-O4GBH35V.js} +5 -5
- package/dist/web/server/{fleet-reasoning-panel-D_K48UOT-GN2PA6KT.js → fleet-reasoning-panel-BxC2COxi-GPLMQSTT.js} +9 -9
- package/dist/web/server/{fleet-subagent-list-5luKtpds-3OTVFHJQ.js → fleet-subagent-list-CpSYzCIq-JDH2LHSS.js} +1 -1
- package/dist/web/server/{fleet-tool-timeline-DwRqQgOj-HUFLGMDV.js → fleet-tool-timeline-IB36_PB2-XJENTO6I.js} +1 -1
- package/dist/web/server/{fork-picker-dialog-B9yGc8Au-IL63F2DN.js → fork-picker-dialog-DlINz9UQ-UWIXFDJX.js} +3 -3
- package/dist/web/server/{model-selector-list-cb2-ewoA-KIVU6LD3.js → model-selector-list-jBTZc2Mu-OXJOS5NA.js} +7 -7
- package/dist/web/server/{openui-renderer-Czy5Vo2L-BLXPJD65.js → openui-renderer-Biyyjhjn-SJOEKPTJ.js} +4 -4
- package/dist/web/server/{prompt-suggestions-BOmHi4-J-C563CHFU.js → prompt-suggestions-D4AEEY7K-RZSP7PWV.js} +3 -3
- package/dist/web/server/{repl-panel-yyxhwe4c-7U6HXYPS.js → repl-panel-D5KsoJik-BQKO53JO.js} +9 -9
- package/dist/web/server/{resources-panel-j4fAIi9g-5C267IXV.js → resources-panel-CE5pD4vy-V5FXBTYC.js} +2 -2
- package/dist/web/server/{router-CgSWrAYc-5UBYSZTJ.js → router-DWALoX_M-I5CBL7FQ.js} +1461 -515
- package/dist/web/server/{routes-CP_BBhD0-BAWQYGKY.js → routes-BBVirYfL-5WXMOT7M.js} +908 -566
- package/dist/web/server/server.js +2 -2
- package/dist/web/server/{session-insights-panel-BHZyKDTo-LRMAMA3O.js → session-insights-panel-CUhdgvRt-VB2HUCQP.js} +4 -4
- package/dist/web/server/{settings-dialog-CxHe8nym-KKXDPTIW.js → settings-dialog-DndPbM-v-RFNXXEAN.js} +902 -575
- package/dist/web/server/{subagent-chat-panel-DlSsM59d-DBW7DI3T.js → subagent-chat-panel-C0RpnXav-J7VYO7QY.js} +11 -11
- package/dist/web/server/{subagents-panel-Txzk8oDb-NRKLASYN.js → subagents-panel-jDqIn9Nh-YEV6QLUY.js} +13 -13
- package/dist/web/server/{workspace-panel-BOs-58Cv-SWQBMZSB.js → workspace-panel-CX_Vo6As-EWO6AMPI.js} +5 -4
- package/package.json +1 -1
- package/dist/web/client/assets/agent-activity-CDcDNVC6.js +0 -1
- package/dist/web/client/assets/artifacts-panel-CObI-DMt.js +0 -1
- package/dist/web/client/assets/chat-C8XDWWXz.js +0 -52
- package/dist/web/client/assets/fleet-message-queue-zWM5-y18.js +0 -1
- package/dist/web/client/assets/fleet-reasoning-panel-MtbSdoCv.js +0 -1
- package/dist/web/client/assets/fleet-tool-timeline-COzPrwr8.js +0 -1
- package/dist/web/client/assets/generative-text-renderer-CDKHv-v_.js +0 -6
- package/dist/web/client/assets/globals-DisQPFtV.css +0 -2
- package/dist/web/client/assets/horizontal-resize-Bl3AyBJg.js +0 -1
- package/dist/web/client/assets/input-group-BFDsCVS9.js +0 -1
- package/dist/web/client/assets/model-selector-list-DQaPFUYt.js +0 -1
- package/dist/web/client/assets/prompt-input-DZ4cho_e.js +0 -1
- package/dist/web/client/assets/prompt-suggestions-CXM6knMK.js +0 -1
- package/dist/web/client/assets/repl-panel-BDQ5MEgV.js +0 -1
- package/dist/web/client/assets/right-panel-registry-VVRPktV3.js +0 -2
- package/dist/web/client/assets/routes-DAikUNzO.js +0 -16
- package/dist/web/client/assets/session-insights-panel-CQdT90Op.js +0 -1
- package/dist/web/client/assets/settings-dialog-DS64KmwC.js +0 -1
- package/dist/web/client/assets/skeleton-loaders-DjGv9LLA.js +0 -1
- package/dist/web/client/assets/subagent-transcript-cxVKYnh9.js +0 -1
- package/dist/web/client/assets/subagents-panel-CHC96I68.js +0 -1
- package/dist/web/client/assets/tool-result-Baj3CdL_.js +0 -4
- package/dist/web/client/assets/ui-preferences-DUEFuJFj.js +0 -1
- package/dist/web/server/chunk-QK4CHLVV.js +0 -17
- package/dist/web/server/fleet-message-queue-BxycG26e-2XLOTCLP.js +0 -75
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
HIT_AREA_EXPAND_CLASS,
|
|
13
13
|
HIT_AREA_EXPAND_DENSE_CLASS,
|
|
14
14
|
PROVIDER_METADATA,
|
|
15
|
-
Pencil,
|
|
16
15
|
ProviderBrandIcon,
|
|
17
16
|
Settings,
|
|
18
17
|
Spinner,
|
|
@@ -25,17 +24,20 @@ import {
|
|
|
25
24
|
useHoverInteractionSharedState,
|
|
26
25
|
useHoverReferenceInteraction,
|
|
27
26
|
usePopupHandleStore
|
|
28
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-TWYHHG5N.js";
|
|
29
28
|
import {
|
|
30
29
|
UI_PREFERENCES_KEY,
|
|
31
30
|
isModelPatternEnabled,
|
|
32
31
|
modelMatchesPattern,
|
|
33
32
|
modelPattern,
|
|
34
33
|
readUiPreferences
|
|
35
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-ETTDO4UO.js";
|
|
36
35
|
import {
|
|
37
36
|
MessageSquare
|
|
38
37
|
} from "./chunk-GL6HWDJB.js";
|
|
38
|
+
import {
|
|
39
|
+
Pencil
|
|
40
|
+
} from "./chunk-M5RSPNYN.js";
|
|
39
41
|
import {
|
|
40
42
|
Keyboard,
|
|
41
43
|
Monitor,
|
|
@@ -73,12 +75,16 @@ import {
|
|
|
73
75
|
import {
|
|
74
76
|
HardDrive
|
|
75
77
|
} from "./chunk-D7ELZVTI.js";
|
|
78
|
+
import {
|
|
79
|
+
writeStoredValue
|
|
80
|
+
} from "./chunk-SZJUXVWG.js";
|
|
76
81
|
import {
|
|
77
82
|
InputGroup,
|
|
78
83
|
InputGroupAddon,
|
|
79
84
|
InputGroupButton,
|
|
80
|
-
InputGroupInput
|
|
81
|
-
|
|
85
|
+
InputGroupInput,
|
|
86
|
+
Textarea
|
|
87
|
+
} from "./chunk-PIOFZUOU.js";
|
|
82
88
|
import {
|
|
83
89
|
Search
|
|
84
90
|
} from "./chunk-JIULUYHT.js";
|
|
@@ -207,7 +213,9 @@ import {
|
|
|
207
213
|
useRenderElement,
|
|
208
214
|
useStableCallback
|
|
209
215
|
} from "./chunk-C5X6G26O.js";
|
|
210
|
-
import
|
|
216
|
+
import {
|
|
217
|
+
Plug
|
|
218
|
+
} from "./chunk-AHTO6GDS.js";
|
|
211
219
|
import "./chunk-EAJTWMK5.js";
|
|
212
220
|
import "./chunk-HFQZLPU2.js";
|
|
213
221
|
import {
|
|
@@ -220,7 +228,7 @@ import "./chunk-JDCCC7A7.js";
|
|
|
220
228
|
import "./chunk-L547YHC4.js";
|
|
221
229
|
import "./chunk-MLKGABMK.js";
|
|
222
230
|
|
|
223
|
-
// web/app/dist/server/assets/settings-dialog-
|
|
231
|
+
// web/app/dist/server/assets/settings-dialog-DndPbM-v.js
|
|
224
232
|
import * as React$1 from "react";
|
|
225
233
|
import { useCallback as useCallback2, useEffect as useEffect2, useId, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
226
234
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -2281,6 +2289,44 @@ function PersonalizationSection({ onThemePreferenceChange, themePreference }) {
|
|
|
2281
2289
|
})]
|
|
2282
2290
|
});
|
|
2283
2291
|
}
|
|
2292
|
+
function RowSurface({ className, interactive, padding, tone, ...props }) {
|
|
2293
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2294
|
+
className: cn(fleetPiRowSurface({
|
|
2295
|
+
interactive,
|
|
2296
|
+
padding,
|
|
2297
|
+
tone
|
|
2298
|
+
}), className),
|
|
2299
|
+
...props
|
|
2300
|
+
});
|
|
2301
|
+
}
|
|
2302
|
+
function ItemRow({ icon, title, subtitle, trailing, className, interactive = true, tone = "default" }) {
|
|
2303
|
+
return /* @__PURE__ */ jsxs(RowSurface, {
|
|
2304
|
+
tone,
|
|
2305
|
+
padding: "md",
|
|
2306
|
+
interactive,
|
|
2307
|
+
className: cn("items-center gap-3", className),
|
|
2308
|
+
children: [
|
|
2309
|
+
icon ? /* @__PURE__ */ jsx("div", {
|
|
2310
|
+
className: "flex size-8 shrink-0 items-center justify-center rounded-md border border-border/40 bg-background/60 text-foreground/70",
|
|
2311
|
+
children: icon
|
|
2312
|
+
}) : null,
|
|
2313
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2314
|
+
className: "min-w-0 flex-1",
|
|
2315
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
2316
|
+
className: "truncate text-sm font-medium text-foreground",
|
|
2317
|
+
children: title
|
|
2318
|
+
}), subtitle ? /* @__PURE__ */ jsx("div", {
|
|
2319
|
+
className: "mt-0.5 truncate text-xs text-muted-foreground",
|
|
2320
|
+
children: subtitle
|
|
2321
|
+
}) : null]
|
|
2322
|
+
}),
|
|
2323
|
+
trailing ? /* @__PURE__ */ jsx("div", {
|
|
2324
|
+
className: "flex shrink-0 items-center gap-1.5",
|
|
2325
|
+
children: trailing
|
|
2326
|
+
}) : null
|
|
2327
|
+
]
|
|
2328
|
+
});
|
|
2329
|
+
}
|
|
2284
2330
|
function SettingsPane({ actions, children, description, title }) {
|
|
2285
2331
|
return /* @__PURE__ */ jsxs("div", {
|
|
2286
2332
|
className: "flex flex-col gap-4",
|
|
@@ -2328,393 +2374,11 @@ function SettingsCommitActions({ dirty, disabled: disabled2, onRevert, onSave, s
|
|
|
2328
2374
|
}) : /* @__PURE__ */ jsx(Save, { "data-icon": "inline-start" }), "Commit"]
|
|
2329
2375
|
})] });
|
|
2330
2376
|
}
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
const invalid = isFieldInvalid(value, attemptedSave, required);
|
|
2337
|
-
return /* @__PURE__ */ jsxs(Field, {
|
|
2338
|
-
"data-invalid": invalid || void 0,
|
|
2339
|
-
children: [/* @__PURE__ */ jsx(FieldLabel, {
|
|
2340
|
-
htmlFor: controlId,
|
|
2341
|
-
children: label
|
|
2342
|
-
}), /* @__PURE__ */ jsxs(InputGroup, { children: [
|
|
2343
|
-
/* @__PURE__ */ jsx(InputGroupAddon, {
|
|
2344
|
-
align: "inline-start",
|
|
2345
|
-
children: /* @__PURE__ */ jsx(Lock, {})
|
|
2346
|
-
}),
|
|
2347
|
-
/* @__PURE__ */ jsx(InputGroupInput, {
|
|
2348
|
-
id: controlId,
|
|
2349
|
-
type: showPassword ? "text" : "password",
|
|
2350
|
-
placeholder,
|
|
2351
|
-
value,
|
|
2352
|
-
onChange: (event) => onChange(event.target.value),
|
|
2353
|
-
"aria-label": label,
|
|
2354
|
-
"aria-invalid": invalid || void 0
|
|
2355
|
-
}),
|
|
2356
|
-
/* @__PURE__ */ jsx(InputGroupAddon, {
|
|
2357
|
-
align: "inline-end",
|
|
2358
|
-
children: /* @__PURE__ */ jsx(InputGroupButton, {
|
|
2359
|
-
size: "icon-xs",
|
|
2360
|
-
className: cn(HIT_AREA_EXPAND_CLASS, "transition-[background-color,transform] duration-150 active:scale-[0.96]"),
|
|
2361
|
-
"aria-label": showPassword ? "Hide value" : "Show value",
|
|
2362
|
-
onClick: onToggleVisibility,
|
|
2363
|
-
children: showPassword ? /* @__PURE__ */ jsx(EyeOff, {}) : /* @__PURE__ */ jsx(Eye, {})
|
|
2364
|
-
})
|
|
2365
|
-
})
|
|
2366
|
-
] })]
|
|
2367
|
-
});
|
|
2368
|
-
}
|
|
2369
|
-
function TextCredentialField({ attemptedSave, icon: Icon, inputType = "text", label, onChange, placeholder, required = true, value }) {
|
|
2370
|
-
const controlId = useId();
|
|
2371
|
-
const invalid = isFieldInvalid(value, attemptedSave, required);
|
|
2372
|
-
return /* @__PURE__ */ jsxs(Field, {
|
|
2373
|
-
"data-invalid": invalid || void 0,
|
|
2374
|
-
children: [/* @__PURE__ */ jsx(FieldLabel, {
|
|
2375
|
-
htmlFor: controlId,
|
|
2376
|
-
children: label
|
|
2377
|
-
}), /* @__PURE__ */ jsxs(InputGroup, { children: [/* @__PURE__ */ jsx(InputGroupAddon, {
|
|
2378
|
-
align: "inline-start",
|
|
2379
|
-
children: /* @__PURE__ */ jsx(Icon, {})
|
|
2380
|
-
}), /* @__PURE__ */ jsx(InputGroupInput, {
|
|
2381
|
-
id: controlId,
|
|
2382
|
-
type: inputType,
|
|
2383
|
-
placeholder,
|
|
2384
|
-
value,
|
|
2385
|
-
onChange: (event) => onChange(event.target.value),
|
|
2386
|
-
"aria-label": label,
|
|
2387
|
-
"aria-invalid": invalid || void 0
|
|
2388
|
-
})] })]
|
|
2389
|
-
});
|
|
2390
|
-
}
|
|
2391
|
-
var OPENAI_CHAT_BASE_URL_PLACEHOLDER = "https://opencode.ai/zen/v1";
|
|
2392
|
-
var OPENAI_CHAT_MODEL_PLACEHOLDER = "qwen35-122b-a10b";
|
|
2393
|
-
var OPENAI_CHAT_NAME_PLACEHOLDER = "e.g. OpenCode Zen, Nebius, Groq\u2026";
|
|
2394
|
-
var CUSTOM_MODELS_PLACEHOLDER = "model-a, model-b (comma-separated)";
|
|
2395
|
-
var CUSTOM_PROVIDER_API_OPTIONS = [
|
|
2396
|
-
{
|
|
2397
|
-
value: "openai-completions",
|
|
2398
|
-
label: "OpenAI Chat Completions"
|
|
2399
|
-
},
|
|
2400
|
-
{
|
|
2401
|
-
value: "openai-responses",
|
|
2402
|
-
label: "OpenAI Responses"
|
|
2403
|
-
},
|
|
2404
|
-
{
|
|
2405
|
-
value: "anthropic-messages",
|
|
2406
|
-
label: "Anthropic Messages"
|
|
2407
|
-
},
|
|
2408
|
-
{
|
|
2409
|
-
value: "google-genai",
|
|
2410
|
-
label: "Google Generative AI"
|
|
2411
|
-
}
|
|
2412
|
-
];
|
|
2413
|
-
function ProviderCredentialFields({ attemptedSave, apiKey, api, baseUrl, modelId, models, displayName, isCustom, onApiKeyChange, onApiChange, onBaseUrlChange, onModelIdChange, onModelsChange, onDisplayNameChange, onTogglePassword, openAiChat, placeholder, showPassword }) {
|
|
2414
|
-
const showApiSelector = isCustom && onApiChange;
|
|
2415
|
-
const showMultiModels = isCustom && onModelsChange;
|
|
2416
|
-
return /* @__PURE__ */ jsxs(FieldGroup, {
|
|
2417
|
-
className: "gap-2",
|
|
2418
|
-
children: [
|
|
2419
|
-
(openAiChat || isCustom) && onDisplayNameChange ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
2420
|
-
attemptedSave,
|
|
2421
|
-
icon: Tag,
|
|
2422
|
-
label: "Provider name",
|
|
2423
|
-
placeholder: OPENAI_CHAT_NAME_PLACEHOLDER,
|
|
2424
|
-
value: displayName ?? "",
|
|
2425
|
-
onChange: onDisplayNameChange
|
|
2426
|
-
}) : null,
|
|
2427
|
-
showApiSelector ? /* @__PURE__ */ jsx(ApiSelector, {
|
|
2428
|
-
value: api ?? "openai-completions",
|
|
2429
|
-
onChange: onApiChange
|
|
2430
|
-
}) : null,
|
|
2431
|
-
/* @__PURE__ */ jsx(SecretCredentialField, {
|
|
2432
|
-
attemptedSave,
|
|
2433
|
-
label: "API key",
|
|
2434
|
-
placeholder,
|
|
2435
|
-
value: apiKey,
|
|
2436
|
-
showPassword,
|
|
2437
|
-
onChange: onApiKeyChange,
|
|
2438
|
-
onToggleVisibility: onTogglePassword
|
|
2439
|
-
}),
|
|
2440
|
-
openAiChat || isCustom ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
2441
|
-
attemptedSave,
|
|
2442
|
-
icon: Globe,
|
|
2443
|
-
inputType: "url",
|
|
2444
|
-
label: "Base URL",
|
|
2445
|
-
placeholder: OPENAI_CHAT_BASE_URL_PLACEHOLDER,
|
|
2446
|
-
value: baseUrl,
|
|
2447
|
-
onChange: onBaseUrlChange
|
|
2448
|
-
}) : null,
|
|
2449
|
-
showMultiModels ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
2450
|
-
attemptedSave,
|
|
2451
|
-
icon: Layers,
|
|
2452
|
-
label: "Model ids",
|
|
2453
|
-
placeholder: CUSTOM_MODELS_PLACEHOLDER,
|
|
2454
|
-
value: models ?? "",
|
|
2455
|
-
onChange: onModelsChange
|
|
2456
|
-
}) : null,
|
|
2457
|
-
openAiChat && !showMultiModels ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
2458
|
-
attemptedSave,
|
|
2459
|
-
icon: Box,
|
|
2460
|
-
label: "Model name",
|
|
2461
|
-
placeholder: OPENAI_CHAT_MODEL_PLACEHOLDER,
|
|
2462
|
-
value: modelId,
|
|
2463
|
-
onChange: onModelIdChange
|
|
2464
|
-
}) : null
|
|
2465
|
-
]
|
|
2466
|
-
});
|
|
2467
|
-
}
|
|
2468
|
-
function ApiSelector({ value, onChange }) {
|
|
2469
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
2470
|
-
className: "flex flex-col gap-1",
|
|
2471
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
2472
|
-
className: "text-xs font-medium text-muted-foreground",
|
|
2473
|
-
children: "API family"
|
|
2474
|
-
}), /* @__PURE__ */ jsx(Select, {
|
|
2475
|
-
"aria-label": "API family",
|
|
2476
|
-
value,
|
|
2477
|
-
options: CUSTOM_PROVIDER_API_OPTIONS,
|
|
2478
|
-
placeholder: "Select API family",
|
|
2479
|
-
onValueChange: (next) => onChange(next)
|
|
2480
|
-
})]
|
|
2481
|
-
});
|
|
2482
|
-
}
|
|
2483
|
-
function isOAuthProvider(provider) {
|
|
2484
|
-
return provider.authType === "oauth";
|
|
2485
|
-
}
|
|
2486
|
-
function supportsOAuth(provider) {
|
|
2487
|
-
return provider.supportsOAuth === true;
|
|
2488
|
-
}
|
|
2489
|
-
var CUSTOM_PROVIDER_PICKER_ROW = {
|
|
2490
|
-
id: "custom",
|
|
2491
|
-
name: "Custom provider",
|
|
2492
|
-
isConfigured: false,
|
|
2493
|
-
envVarName: "CUSTOM_PROVIDER_API_KEY",
|
|
2494
|
-
displayName: "Custom provider"
|
|
2495
|
-
};
|
|
2496
|
-
function parseCustomProviderModels(raw) {
|
|
2497
|
-
return raw.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
2498
|
-
}
|
|
2499
|
-
function useProviderCredentialsController({ onRemoveProvider, onUpdateProvider, providers }) {
|
|
2500
|
-
const [editingProvider, setEditingProvider] = useState2(null);
|
|
2501
|
-
const [editingIsNewOccInstance, setEditingIsNewOccInstance] = useState2(false);
|
|
2502
|
-
const [apiKey, setApiKey] = useState2("");
|
|
2503
|
-
const [baseUrl, setBaseUrl] = useState2("");
|
|
2504
|
-
const [modelId, setModelId] = useState2("");
|
|
2505
|
-
const [models, setModels] = useState2("");
|
|
2506
|
-
const [api, setApi] = useState2("openai-completions");
|
|
2507
|
-
const [displayName, setDisplayName] = useState2("");
|
|
2508
|
-
const [showPassword, setShowPassword] = useState2(false);
|
|
2509
|
-
const [attemptedSave, setAttemptedSave] = useState2(false);
|
|
2510
|
-
const [searchQuery, setSearchQuery] = useState2("");
|
|
2511
|
-
const [addPickerOpen, setAddPickerOpen] = useState2(false);
|
|
2512
|
-
const [addPickerQuery, setAddPickerQuery] = useState2("");
|
|
2513
|
-
const [confirmRemoveProvider, setConfirmRemoveProvider] = useState2(null);
|
|
2514
|
-
const credentialProviders = useMemo2(() => {
|
|
2515
|
-
return [...providers.filter((provider) => provider.id !== CUSTOM_PROVIDER_PICKER_ROW.id), CUSTOM_PROVIDER_PICKER_ROW];
|
|
2516
|
-
}, [providers]);
|
|
2517
|
-
const activeProviders = useMemo2(() => credentialProviders.filter((provider) => provider.isConfigured), [credentialProviders]);
|
|
2518
|
-
const unconfiguredProviders = useMemo2(() => credentialProviders.filter((provider) => !provider.isConfigured || provider.id === "openai-chat-completions" && provider.providerFamily === void 0), [credentialProviders]);
|
|
2519
|
-
const filteredActiveProviders = useMemo2(() => {
|
|
2520
|
-
const query = searchQuery.trim().toLowerCase();
|
|
2521
|
-
if (!query) return activeProviders;
|
|
2522
|
-
return activeProviders.filter((provider) => providerMatchesQuery(provider, query));
|
|
2523
|
-
}, [activeProviders, searchQuery]);
|
|
2524
|
-
const filteredPickerAvailable = useMemo2(() => {
|
|
2525
|
-
const query = addPickerQuery.trim().toLowerCase();
|
|
2526
|
-
return unconfiguredProviders.filter((provider) => providerMatchesQuery(provider, query));
|
|
2527
|
-
}, [addPickerQuery, unconfiguredProviders]);
|
|
2528
|
-
const filteredPickerConfigured = useMemo2(() => {
|
|
2529
|
-
const query = addPickerQuery.trim().toLowerCase();
|
|
2530
|
-
return activeProviders.filter((provider) => providerMatchesQuery(provider, query));
|
|
2531
|
-
}, [activeProviders, addPickerQuery]);
|
|
2532
|
-
const pickerHasResults = filteredPickerAvailable.length > 0 || filteredPickerConfigured.length > 0;
|
|
2533
|
-
const editingUnconfiguredProvider = editingProvider && !activeProviders.some((provider) => provider.id === editingProvider) ? credentialProviders.find((entry) => entry.id === editingProvider) ?? null : null;
|
|
2534
|
-
const resetEditor = () => {
|
|
2535
|
-
setApiKey("");
|
|
2536
|
-
setBaseUrl("");
|
|
2537
|
-
setModelId("");
|
|
2538
|
-
setModels("");
|
|
2539
|
-
setApi("openai-completions");
|
|
2540
|
-
setDisplayName("");
|
|
2541
|
-
setShowPassword(false);
|
|
2542
|
-
setAttemptedSave(false);
|
|
2543
|
-
};
|
|
2544
|
-
const closeEditor = () => {
|
|
2545
|
-
setEditingProvider(null);
|
|
2546
|
-
setEditingIsNewOccInstance(false);
|
|
2547
|
-
resetEditor();
|
|
2548
|
-
};
|
|
2549
|
-
const openEditor = (providerId, opts) => {
|
|
2550
|
-
setAddPickerOpen(false);
|
|
2551
|
-
setAddPickerQuery("");
|
|
2552
|
-
setEditingProvider(providerId);
|
|
2553
|
-
setEditingIsNewOccInstance(opts?.newOccInstance === true);
|
|
2554
|
-
resetEditor();
|
|
2555
|
-
const existing = providers.find((provider) => provider.id === providerId);
|
|
2556
|
-
setBaseUrl(existing?.baseUrl ?? "");
|
|
2557
|
-
setDisplayName(existing?.displayName ?? (isCustomProviderId(providerId) ? existing?.name ?? "" : ""));
|
|
2558
|
-
setApi(existing?.api ?? "openai-completions");
|
|
2559
|
-
setModels((existing?.modelIds ?? []).join(", "));
|
|
2560
|
-
setModelId(existing?.modelIds?.[0] ?? "");
|
|
2561
|
-
};
|
|
2562
|
-
const openAddPicker = () => {
|
|
2563
|
-
closeEditor();
|
|
2564
|
-
setAddPickerQuery("");
|
|
2565
|
-
setAddPickerOpen(true);
|
|
2566
|
-
};
|
|
2567
|
-
const closeAddPicker = () => {
|
|
2568
|
-
setAddPickerOpen(false);
|
|
2569
|
-
setAddPickerQuery("");
|
|
2570
|
-
};
|
|
2571
|
-
const selectProviderFromPicker = (providerId) => {
|
|
2572
|
-
openEditor(providerId, { newOccInstance: isOccProviderId(providerId) });
|
|
2573
|
-
};
|
|
2574
|
-
const handleSave = async (providerId) => {
|
|
2575
|
-
if (!onUpdateProvider) return;
|
|
2576
|
-
setAttemptedSave(true);
|
|
2577
|
-
const isCustomEditor = providerId === "custom" || isCustomProviderId(providerId);
|
|
2578
|
-
const openAiChat = isOccProviderId(providerId);
|
|
2579
|
-
if (isCustomEditor) {
|
|
2580
|
-
const modelList = parseCustomProviderModels(models);
|
|
2581
|
-
if (!apiKey.trim() || !baseUrl.trim() || !displayName.trim()) return;
|
|
2582
|
-
if (modelList.length === 0) return;
|
|
2583
|
-
try {
|
|
2584
|
-
await onUpdateProvider({
|
|
2585
|
-
providerId,
|
|
2586
|
-
apiKey: apiKey.trim(),
|
|
2587
|
-
baseUrl: baseUrl.trim(),
|
|
2588
|
-
displayName: displayName.trim(),
|
|
2589
|
-
api,
|
|
2590
|
-
models: modelList,
|
|
2591
|
-
...providerId === "custom" ? { createOccInstance: true } : {}
|
|
2592
|
-
});
|
|
2593
|
-
notify.success("Provider credentials applied to your active sessions.");
|
|
2594
|
-
closeEditor();
|
|
2595
|
-
closeAddPicker();
|
|
2596
|
-
} catch (error) {
|
|
2597
|
-
notify.error(error instanceof Error ? error.message : "Failed to update provider");
|
|
2598
|
-
}
|
|
2599
|
-
return;
|
|
2600
|
-
}
|
|
2601
|
-
const isNamedOcc = openAiChat && isNamedOccInstanceId(providerId);
|
|
2602
|
-
const isOccLike = openAiChat && (isNamedOcc || editingIsNewOccInstance);
|
|
2603
|
-
if (!apiKey.trim()) return;
|
|
2604
|
-
if (openAiChat && (!baseUrl.trim() || !modelId.trim())) return;
|
|
2605
|
-
if (isOccLike && !displayName.trim()) return;
|
|
2606
|
-
try {
|
|
2607
|
-
await onUpdateProvider({
|
|
2608
|
-
providerId,
|
|
2609
|
-
apiKey: apiKey.trim(),
|
|
2610
|
-
...openAiChat ? {
|
|
2611
|
-
baseUrl: baseUrl.trim(),
|
|
2612
|
-
modelId: modelId.trim(),
|
|
2613
|
-
...isOccLike ? { displayName: displayName.trim() } : {},
|
|
2614
|
-
...editingIsNewOccInstance ? { createOccInstance: true } : {}
|
|
2615
|
-
} : {}
|
|
2616
|
-
});
|
|
2617
|
-
notify.success("Provider credentials applied to your active sessions.");
|
|
2618
|
-
closeEditor();
|
|
2619
|
-
closeAddPicker();
|
|
2620
|
-
} catch (error) {
|
|
2621
|
-
notify.error(error instanceof Error ? error.message : "Failed to update provider");
|
|
2622
|
-
}
|
|
2623
|
-
};
|
|
2624
|
-
const handleRemove = async (provider) => {
|
|
2625
|
-
if (!onRemoveProvider) return;
|
|
2626
|
-
try {
|
|
2627
|
-
await onRemoveProvider({ providerId: provider.id });
|
|
2628
|
-
if (editingProvider === provider.id) closeEditor();
|
|
2629
|
-
notify.success(`${provider.name} removed from your configured providers.`);
|
|
2630
|
-
setConfirmRemoveProvider(null);
|
|
2631
|
-
} catch (error) {
|
|
2632
|
-
notify.error(error instanceof Error ? error.message : "Failed to remove provider");
|
|
2633
|
-
}
|
|
2634
|
-
};
|
|
2635
|
-
return {
|
|
2636
|
-
activeProviders,
|
|
2637
|
-
addPickerOpen,
|
|
2638
|
-
addPickerQuery,
|
|
2639
|
-
api,
|
|
2640
|
-
apiKey,
|
|
2641
|
-
attemptedSave,
|
|
2642
|
-
baseUrl,
|
|
2643
|
-
canSave: useMemo2(() => {
|
|
2644
|
-
if (apiKey.trim().length === 0) return false;
|
|
2645
|
-
if (!editingProvider) return true;
|
|
2646
|
-
if (editingProvider === "custom" || isCustomProviderId(editingProvider)) {
|
|
2647
|
-
if (baseUrl.trim().length === 0) return false;
|
|
2648
|
-
if (parseCustomProviderModels(models).length === 0) return false;
|
|
2649
|
-
return displayName.trim().length > 0;
|
|
2650
|
-
}
|
|
2651
|
-
if (!isOccProviderId(editingProvider)) return true;
|
|
2652
|
-
if (baseUrl.trim().length === 0 || modelId.trim().length === 0) return false;
|
|
2653
|
-
if (isNamedOccInstanceId(editingProvider) || editingIsNewOccInstance) return displayName.trim().length > 0;
|
|
2654
|
-
return true;
|
|
2655
|
-
}, [
|
|
2656
|
-
apiKey,
|
|
2657
|
-
baseUrl,
|
|
2658
|
-
modelId,
|
|
2659
|
-
models,
|
|
2660
|
-
displayName,
|
|
2661
|
-
editingProvider,
|
|
2662
|
-
editingIsNewOccInstance
|
|
2663
|
-
]),
|
|
2664
|
-
closeAddPicker,
|
|
2665
|
-
closeEditor,
|
|
2666
|
-
confirmRemoveProvider,
|
|
2667
|
-
credentialProviders,
|
|
2668
|
-
displayName,
|
|
2669
|
-
editingIsNewOccInstance,
|
|
2670
|
-
editingProvider,
|
|
2671
|
-
editingUnconfiguredProvider,
|
|
2672
|
-
filteredActiveProviders,
|
|
2673
|
-
filteredPickerAvailable,
|
|
2674
|
-
filteredPickerConfigured,
|
|
2675
|
-
handleRemove,
|
|
2676
|
-
handleSave,
|
|
2677
|
-
modelId,
|
|
2678
|
-
models,
|
|
2679
|
-
openAddPicker,
|
|
2680
|
-
openEditor,
|
|
2681
|
-
pickerHasResults,
|
|
2682
|
-
resetEditor,
|
|
2683
|
-
searchQuery,
|
|
2684
|
-
selectProviderFromPicker,
|
|
2685
|
-
setAddPickerOpen,
|
|
2686
|
-
setAddPickerQuery,
|
|
2687
|
-
setApi,
|
|
2688
|
-
setApiKey,
|
|
2689
|
-
setAttemptedSave,
|
|
2690
|
-
setBaseUrl,
|
|
2691
|
-
setConfirmRemoveProvider,
|
|
2692
|
-
setDisplayName,
|
|
2693
|
-
setEditingIsNewOccInstance,
|
|
2694
|
-
setEditingProvider,
|
|
2695
|
-
setModelId,
|
|
2696
|
-
setModels,
|
|
2697
|
-
setSearchQuery,
|
|
2698
|
-
setShowPassword,
|
|
2699
|
-
showPassword,
|
|
2700
|
-
unconfiguredProviders
|
|
2701
|
-
};
|
|
2702
|
-
}
|
|
2703
|
-
function providerMatchesQuery(provider, query) {
|
|
2704
|
-
if (!query) return true;
|
|
2705
|
-
const keywords = supportsOAuth(provider) ? isOAuthProvider(provider) ? "oauth sign-in login" : "api key oauth sign-in login" : provider.id === "custom" || isCustomProviderId(provider.id) ? "custom provider endpoint openai anthropic google compatible" : isOccProviderId(provider.id) ? "api key base url model name chat completions" : "";
|
|
2706
|
-
return [
|
|
2707
|
-
provider.name,
|
|
2708
|
-
provider.envVarName,
|
|
2709
|
-
provider.id,
|
|
2710
|
-
keywords
|
|
2711
|
-
].join(" ").toLowerCase().includes(query);
|
|
2712
|
-
}
|
|
2713
|
-
var OAUTH_POLL_MS = 1500;
|
|
2714
|
-
var STALE_LOGIN_ERROR = "Unknown or expired OAuth login";
|
|
2715
|
-
function delay(ms) {
|
|
2716
|
-
return new Promise((resolve) => {
|
|
2717
|
-
setTimeout(resolve, ms);
|
|
2377
|
+
var OAUTH_POLL_MS = 1500;
|
|
2378
|
+
var STALE_LOGIN_ERROR = "Unknown or expired OAuth login";
|
|
2379
|
+
function delay(ms) {
|
|
2380
|
+
return new Promise((resolve) => {
|
|
2381
|
+
setTimeout(resolve, ms);
|
|
2718
2382
|
});
|
|
2719
2383
|
}
|
|
2720
2384
|
function useOAuthLoginFlow({ onConfigured, onOAuthLogin, providerId }) {
|
|
@@ -2884,141 +2548,819 @@ function useOAuthLoginFlow({ onConfigured, onOAuthLogin, providerId }) {
|
|
|
2884
2548
|
login?.status
|
|
2885
2549
|
]);
|
|
2886
2550
|
return {
|
|
2887
|
-
busy,
|
|
2888
|
-
cancel,
|
|
2889
|
-
canStart: Boolean(onOAuthLogin),
|
|
2890
|
-
login,
|
|
2891
|
-
promptAnswer,
|
|
2892
|
-
setPromptAnswer,
|
|
2893
|
-
start,
|
|
2894
|
-
submitPrompt
|
|
2551
|
+
busy,
|
|
2552
|
+
cancel,
|
|
2553
|
+
canStart: Boolean(onOAuthLogin),
|
|
2554
|
+
login,
|
|
2555
|
+
promptAnswer,
|
|
2556
|
+
setPromptAnswer,
|
|
2557
|
+
start,
|
|
2558
|
+
submitPrompt
|
|
2559
|
+
};
|
|
2560
|
+
}
|
|
2561
|
+
function ProviderOAuthSignIn({ onConfigured, onOAuthLogin, provider }) {
|
|
2562
|
+
const { busy, cancel, canStart, login, promptAnswer, setPromptAnswer, start, submitPrompt } = useOAuthLoginFlow({
|
|
2563
|
+
onConfigured,
|
|
2564
|
+
onOAuthLogin,
|
|
2565
|
+
providerId: provider.id
|
|
2566
|
+
});
|
|
2567
|
+
const waiting = login?.status === "waiting";
|
|
2568
|
+
const error = login?.status === "error" ? login.error : void 0;
|
|
2569
|
+
const authUrl = waiting ? login?.authUrl : void 0;
|
|
2570
|
+
const userCode = waiting ? login?.userCode : void 0;
|
|
2571
|
+
const instructions = waiting ? login?.instructions : void 0;
|
|
2572
|
+
const prompt = waiting ? login?.prompt : void 0;
|
|
2573
|
+
const oauthOnly = provider.authType === "oauth";
|
|
2574
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2575
|
+
className: "flex flex-col gap-3",
|
|
2576
|
+
children: [provider.isConfigured && oauthOnly && !waiting ? /* @__PURE__ */ jsxs("div", {
|
|
2577
|
+
className: "flex items-center gap-2 text-sm",
|
|
2578
|
+
children: [/* @__PURE__ */ jsx(Check, { className: "size-3.5 text-muted-foreground" }), /* @__PURE__ */ jsx("span", { children: "Connected" })]
|
|
2579
|
+
}) : null, waiting ? /* @__PURE__ */ jsxs("div", {
|
|
2580
|
+
className: "flex flex-col gap-2",
|
|
2581
|
+
children: [
|
|
2582
|
+
/* @__PURE__ */ jsxs("p", {
|
|
2583
|
+
className: "text-sm",
|
|
2584
|
+
children: [
|
|
2585
|
+
"Sign in with ",
|
|
2586
|
+
provider.name,
|
|
2587
|
+
" to store OAuth credentials for this account."
|
|
2588
|
+
]
|
|
2589
|
+
}),
|
|
2590
|
+
userCode ? /* @__PURE__ */ jsxs("p", {
|
|
2591
|
+
className: "text-sm",
|
|
2592
|
+
children: [
|
|
2593
|
+
"Enter this code:",
|
|
2594
|
+
" ",
|
|
2595
|
+
/* @__PURE__ */ jsx("span", {
|
|
2596
|
+
className: "font-mono text-foreground",
|
|
2597
|
+
children: userCode
|
|
2598
|
+
})
|
|
2599
|
+
]
|
|
2600
|
+
}) : null,
|
|
2601
|
+
instructions && !userCode ? /* @__PURE__ */ jsx("p", {
|
|
2602
|
+
className: "text-xs text-pretty text-muted-foreground",
|
|
2603
|
+
children: instructions
|
|
2604
|
+
}) : null,
|
|
2605
|
+
authUrl ? /* @__PURE__ */ jsxs(Button, {
|
|
2606
|
+
type: "button",
|
|
2607
|
+
size: "sm",
|
|
2608
|
+
onClick: () => {
|
|
2609
|
+
window.open(authUrl, "_blank", "noopener,noreferrer");
|
|
2610
|
+
},
|
|
2611
|
+
children: [/* @__PURE__ */ jsx(ExternalLink, { "data-icon": "inline-start" }), "Open sign-in page"]
|
|
2612
|
+
}) : prompt ? null : /* @__PURE__ */ jsxs("div", {
|
|
2613
|
+
className: "flex items-center gap-2 text-xs text-muted-foreground",
|
|
2614
|
+
children: [/* @__PURE__ */ jsx(Spinner, { className: "size-3" }), "Waiting for sign-in\u2026"]
|
|
2615
|
+
}),
|
|
2616
|
+
prompt ? /* @__PURE__ */ jsxs("div", {
|
|
2617
|
+
className: "flex flex-col gap-2",
|
|
2618
|
+
children: [
|
|
2619
|
+
/* @__PURE__ */ jsx("p", {
|
|
2620
|
+
className: "text-xs text-pretty text-muted-foreground",
|
|
2621
|
+
children: prompt.message
|
|
2622
|
+
}),
|
|
2623
|
+
/* @__PURE__ */ jsx(Input, {
|
|
2624
|
+
value: promptAnswer,
|
|
2625
|
+
placeholder: prompt.placeholder,
|
|
2626
|
+
onChange: (event) => setPromptAnswer(event.target.value),
|
|
2627
|
+
"aria-label": prompt.message
|
|
2628
|
+
}),
|
|
2629
|
+
/* @__PURE__ */ jsx("div", {
|
|
2630
|
+
className: "flex justify-end",
|
|
2631
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
2632
|
+
type: "button",
|
|
2633
|
+
size: "sm",
|
|
2634
|
+
disabled: busy || !prompt.allowEmpty && !promptAnswer.trim(),
|
|
2635
|
+
onClick: () => {
|
|
2636
|
+
submitPrompt();
|
|
2637
|
+
},
|
|
2638
|
+
children: [busy ? /* @__PURE__ */ jsx(Spinner, { "data-icon": "inline-start" }) : null, "Continue"]
|
|
2639
|
+
})
|
|
2640
|
+
})
|
|
2641
|
+
]
|
|
2642
|
+
}) : null,
|
|
2643
|
+
/* @__PURE__ */ jsx("div", {
|
|
2644
|
+
className: "flex justify-end",
|
|
2645
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
2646
|
+
type: "button",
|
|
2647
|
+
variant: "ghost",
|
|
2648
|
+
size: "sm",
|
|
2649
|
+
disabled: busy,
|
|
2650
|
+
onClick: () => {
|
|
2651
|
+
cancel();
|
|
2652
|
+
},
|
|
2653
|
+
children: "Cancel sign-in"
|
|
2654
|
+
})
|
|
2655
|
+
})
|
|
2656
|
+
]
|
|
2657
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
2658
|
+
className: "flex flex-col gap-2",
|
|
2659
|
+
children: [error ? /* @__PURE__ */ jsx(Alert, {
|
|
2660
|
+
className: "px-3 py-2",
|
|
2661
|
+
children: /* @__PURE__ */ jsx(AlertDescription, {
|
|
2662
|
+
className: "text-xs text-pretty",
|
|
2663
|
+
children: error
|
|
2664
|
+
})
|
|
2665
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
2666
|
+
className: "text-xs text-pretty text-muted-foreground",
|
|
2667
|
+
children: oauthOnly && provider.isConfigured ? `Sign in again with ${provider.name} to refresh OAuth credentials.` : oauthOnly ? `Sign in with ${provider.name}. No API key is stored; credentials are saved to auth.json.` : `Sign in with ${provider.name} to use OAuth credentials; API-key editing remains available above.`
|
|
2668
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2669
|
+
className: "flex justify-end",
|
|
2670
|
+
children: /* @__PURE__ */ jsxs(Button, {
|
|
2671
|
+
type: "button",
|
|
2672
|
+
size: "sm",
|
|
2673
|
+
disabled: busy || !canStart,
|
|
2674
|
+
onClick: () => {
|
|
2675
|
+
start();
|
|
2676
|
+
},
|
|
2677
|
+
children: [
|
|
2678
|
+
busy ? /* @__PURE__ */ jsx(Spinner, { "data-icon": "inline-start" }) : null,
|
|
2679
|
+
"Sign in with ",
|
|
2680
|
+
provider.name
|
|
2681
|
+
]
|
|
2682
|
+
})
|
|
2683
|
+
})]
|
|
2684
|
+
})]
|
|
2685
|
+
});
|
|
2686
|
+
}
|
|
2687
|
+
function statusLabel(connection) {
|
|
2688
|
+
switch (connection.status) {
|
|
2689
|
+
case "connected":
|
|
2690
|
+
return "Connected";
|
|
2691
|
+
case "anonymous":
|
|
2692
|
+
return "Available without sign-in";
|
|
2693
|
+
case "needs_auth":
|
|
2694
|
+
return "Sign-in required";
|
|
2695
|
+
case "disabled":
|
|
2696
|
+
return "Disabled";
|
|
2697
|
+
default:
|
|
2698
|
+
return connection.status;
|
|
2699
|
+
}
|
|
2700
|
+
}
|
|
2701
|
+
function connectionSubtitle(connection) {
|
|
2702
|
+
const details = connection.transport === "http" ? connection.url : connection.commandPreview;
|
|
2703
|
+
return [
|
|
2704
|
+
connection.source === "builtin" ? "Built-in" : "User",
|
|
2705
|
+
connection.transport === "http" ? "HTTP" : "stdio",
|
|
2706
|
+
statusLabel(connection),
|
|
2707
|
+
details
|
|
2708
|
+
].filter((part) => Boolean(part)).join(" \xB7 ");
|
|
2709
|
+
}
|
|
2710
|
+
function McpConnectionsSection({ connections, isLoading, isPending, onOAuth, onRemove, onUpsert }) {
|
|
2711
|
+
const [adding, setAdding] = useState2(false);
|
|
2712
|
+
const [transport, setTransport] = useState2("http");
|
|
2713
|
+
const [name, setName] = useState2("");
|
|
2714
|
+
const [url, setUrl] = useState2("");
|
|
2715
|
+
const [oauth, setOauth] = useState2(true);
|
|
2716
|
+
const [bearerTokenEnvVar, setBearerTokenEnvVar] = useState2("");
|
|
2717
|
+
const [command, setCommand] = useState2("");
|
|
2718
|
+
const [args, setArgs] = useState2("");
|
|
2719
|
+
const [cwd, setCwd] = useState2("");
|
|
2720
|
+
const [envLines, setEnvLines] = useState2("");
|
|
2721
|
+
const [confirmRemove, setConfirmRemove] = useState2(null);
|
|
2722
|
+
const resetAddForm = () => {
|
|
2723
|
+
setName("");
|
|
2724
|
+
setUrl("");
|
|
2725
|
+
setOauth(true);
|
|
2726
|
+
setBearerTokenEnvVar("");
|
|
2727
|
+
setCommand("");
|
|
2728
|
+
setArgs("");
|
|
2729
|
+
setCwd("");
|
|
2730
|
+
setEnvLines("");
|
|
2731
|
+
setTransport("http");
|
|
2732
|
+
setAdding(false);
|
|
2733
|
+
};
|
|
2734
|
+
const handleAdd = async () => {
|
|
2735
|
+
if (!onUpsert) return;
|
|
2736
|
+
const trimmedName = name.trim();
|
|
2737
|
+
try {
|
|
2738
|
+
if (transport === "http") await onUpsert({
|
|
2739
|
+
name: trimmedName,
|
|
2740
|
+
transport: "http",
|
|
2741
|
+
url: url.trim(),
|
|
2742
|
+
...oauth ? { oauth: true } : {},
|
|
2743
|
+
...bearerTokenEnvVar.trim() ? { bearerTokenEnvVar: bearerTokenEnvVar.trim() } : {},
|
|
2744
|
+
force: true
|
|
2745
|
+
});
|
|
2746
|
+
else {
|
|
2747
|
+
const parsedArgs = args.split(/\s+/).map((part) => part.trim()).filter(Boolean);
|
|
2748
|
+
const env = envLines.split("\n").map((line) => line.trim()).filter(Boolean).flatMap((line) => {
|
|
2749
|
+
const equals = line.indexOf("=");
|
|
2750
|
+
if (equals <= 0) return [];
|
|
2751
|
+
const child = line.slice(0, equals).trim();
|
|
2752
|
+
const source = line.slice(equals + 1).trim();
|
|
2753
|
+
if (!child || !source) return [];
|
|
2754
|
+
return [{
|
|
2755
|
+
child,
|
|
2756
|
+
source
|
|
2757
|
+
}];
|
|
2758
|
+
});
|
|
2759
|
+
await onUpsert({
|
|
2760
|
+
name: trimmedName,
|
|
2761
|
+
transport: "stdio",
|
|
2762
|
+
command: command.trim(),
|
|
2763
|
+
...parsedArgs.length > 0 ? { args: parsedArgs } : {},
|
|
2764
|
+
...cwd.trim() ? { cwd: cwd.trim() } : {},
|
|
2765
|
+
...env.length > 0 ? { env } : {},
|
|
2766
|
+
force: true
|
|
2767
|
+
});
|
|
2768
|
+
}
|
|
2769
|
+
notify.success("MCP connection saved");
|
|
2770
|
+
resetAddForm();
|
|
2771
|
+
} catch (error) {
|
|
2772
|
+
notify.error(error instanceof Error ? error.message : "Could not save MCP connection");
|
|
2773
|
+
}
|
|
2774
|
+
};
|
|
2775
|
+
const handleRemove = async (connectionName) => {
|
|
2776
|
+
if (!onRemove) return;
|
|
2777
|
+
try {
|
|
2778
|
+
await onRemove({ name: connectionName });
|
|
2779
|
+
notify.success(`Removed ${connectionName}`);
|
|
2780
|
+
setConfirmRemove(null);
|
|
2781
|
+
} catch (error) {
|
|
2782
|
+
notify.error(error instanceof Error ? error.message : "Could not remove MCP connection");
|
|
2783
|
+
}
|
|
2784
|
+
};
|
|
2785
|
+
const handleLogout = async (connectionName) => {
|
|
2786
|
+
if (!onOAuth) return;
|
|
2787
|
+
try {
|
|
2788
|
+
await onOAuth({
|
|
2789
|
+
name: connectionName,
|
|
2790
|
+
action: "logout"
|
|
2791
|
+
});
|
|
2792
|
+
notify.success(`Signed out of ${connectionName}`);
|
|
2793
|
+
} catch (error) {
|
|
2794
|
+
notify.error(error instanceof Error ? error.message : "Could not sign out");
|
|
2795
|
+
}
|
|
2796
|
+
};
|
|
2797
|
+
const oauthAdapter = useMemo2(() => {
|
|
2798
|
+
if (!onOAuth) return void 0;
|
|
2799
|
+
return (connection) => async (request) => {
|
|
2800
|
+
const starting = !request.loginId && !request.cancel;
|
|
2801
|
+
return await onOAuth({
|
|
2802
|
+
name: connection.name,
|
|
2803
|
+
action: starting && connection.status === "connected" ? "reconnect" : "login",
|
|
2804
|
+
loginId: request.loginId,
|
|
2805
|
+
promptAnswer: request.promptAnswer,
|
|
2806
|
+
cancel: request.cancel
|
|
2807
|
+
});
|
|
2808
|
+
};
|
|
2809
|
+
}, [onOAuth]);
|
|
2810
|
+
return /* @__PURE__ */ jsxs(SettingsPane, {
|
|
2811
|
+
title: "MCP",
|
|
2812
|
+
description: "Connect built-in and user MCP servers. Tokens stay on the server; this list only shows status and environment-variable names.",
|
|
2813
|
+
actions: /* @__PURE__ */ jsxs(Button, {
|
|
2814
|
+
type: "button",
|
|
2815
|
+
size: "sm",
|
|
2816
|
+
variant: "outline",
|
|
2817
|
+
disabled: isPending || adding,
|
|
2818
|
+
onClick: () => setAdding(true),
|
|
2819
|
+
children: [/* @__PURE__ */ jsx(Plus, { "data-icon": "inline-start" }), "Add server"]
|
|
2820
|
+
}),
|
|
2821
|
+
children: [
|
|
2822
|
+
isLoading ? /* @__PURE__ */ jsxs("div", {
|
|
2823
|
+
className: "flex items-center gap-2 text-sm text-muted-foreground",
|
|
2824
|
+
children: [/* @__PURE__ */ jsx(Spinner, { className: "size-3.5" }), "Loading MCP connections\u2026"]
|
|
2825
|
+
}) : null,
|
|
2826
|
+
adding ? /* @__PURE__ */ jsxs("div", {
|
|
2827
|
+
className: "flex flex-col gap-3 rounded-xl border p-4",
|
|
2828
|
+
children: [
|
|
2829
|
+
/* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsx(FieldLabel, { children: "Name" }), /* @__PURE__ */ jsx(Input, {
|
|
2830
|
+
value: name,
|
|
2831
|
+
onChange: (event) => setName(event.target.value),
|
|
2832
|
+
"aria-label": "MCP server name"
|
|
2833
|
+
})] }),
|
|
2834
|
+
/* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsx(FieldLabel, { children: "Transport" }), /* @__PURE__ */ jsx(Select, {
|
|
2835
|
+
value: transport,
|
|
2836
|
+
onValueChange: (value) => setTransport(value),
|
|
2837
|
+
options: [{
|
|
2838
|
+
label: "HTTP",
|
|
2839
|
+
value: "http"
|
|
2840
|
+
}, {
|
|
2841
|
+
label: "stdio",
|
|
2842
|
+
value: "stdio"
|
|
2843
|
+
}]
|
|
2844
|
+
})] }),
|
|
2845
|
+
transport === "http" ? /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
2846
|
+
/* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsx(FieldLabel, { children: "URL" }), /* @__PURE__ */ jsx(Input, {
|
|
2847
|
+
value: url,
|
|
2848
|
+
onChange: (event) => setUrl(event.target.value),
|
|
2849
|
+
"aria-label": "MCP server URL"
|
|
2850
|
+
})] }),
|
|
2851
|
+
/* @__PURE__ */ jsxs(Field, {
|
|
2852
|
+
orientation: "horizontal",
|
|
2853
|
+
className: "items-center justify-between",
|
|
2854
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsx(FieldLabel, { children: "OAuth" }), /* @__PURE__ */ jsx(FieldDescription, { children: "Use the browser sign-in flow for this server." })] }), /* @__PURE__ */ jsx(Switch, {
|
|
2855
|
+
checked: oauth,
|
|
2856
|
+
onCheckedChange: (checked) => setOauth(checked),
|
|
2857
|
+
"aria-label": "Use OAuth"
|
|
2858
|
+
})]
|
|
2859
|
+
}),
|
|
2860
|
+
!oauth ? /* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsx(FieldLabel, { children: "Bearer token environment variable" }), /* @__PURE__ */ jsx(Input, {
|
|
2861
|
+
value: bearerTokenEnvVar,
|
|
2862
|
+
onChange: (event) => setBearerTokenEnvVar(event.target.value),
|
|
2863
|
+
"aria-label": "Bearer token environment variable",
|
|
2864
|
+
placeholder: "MCP_BEARER_TOKEN"
|
|
2865
|
+
})] }) : null
|
|
2866
|
+
] }) : /* @__PURE__ */ jsxs(Fragment$1, { children: [
|
|
2867
|
+
/* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsx(FieldLabel, { children: "Command" }), /* @__PURE__ */ jsx(Input, {
|
|
2868
|
+
value: command,
|
|
2869
|
+
onChange: (event) => setCommand(event.target.value),
|
|
2870
|
+
"aria-label": "MCP command"
|
|
2871
|
+
})] }),
|
|
2872
|
+
/* @__PURE__ */ jsxs(Field, { children: [/* @__PURE__ */ jsx(FieldLabel, { children: "Arguments" }), /* @__PURE__ */ jsx(Input, {
|
|
2873
|
+
value: args,
|
|
2874
|
+
onChange: (event) => setArgs(event.target.value),
|
|
2875
|
+
"aria-label": "MCP command arguments"
|
|
2876
|
+
})] }),
|
|
2877
|
+
/* @__PURE__ */ jsxs(Field, { children: [
|
|
2878
|
+
/* @__PURE__ */ jsx(FieldLabel, { children: "Working directory" }),
|
|
2879
|
+
/* @__PURE__ */ jsx(Input, {
|
|
2880
|
+
value: cwd,
|
|
2881
|
+
onChange: (event) => setCwd(event.target.value),
|
|
2882
|
+
"aria-label": "MCP working directory"
|
|
2883
|
+
}),
|
|
2884
|
+
/* @__PURE__ */ jsx(FieldDescription, { children: "Must stay inside the current workspace." })
|
|
2885
|
+
] }),
|
|
2886
|
+
/* @__PURE__ */ jsxs(Field, { children: [
|
|
2887
|
+
/* @__PURE__ */ jsx(FieldLabel, { children: "Environment mappings" }),
|
|
2888
|
+
/* @__PURE__ */ jsx(Textarea, {
|
|
2889
|
+
value: envLines,
|
|
2890
|
+
onChange: (event) => setEnvLines(event.target.value),
|
|
2891
|
+
"aria-label": "MCP environment mappings",
|
|
2892
|
+
placeholder: "CHILD=SOURCE"
|
|
2893
|
+
}),
|
|
2894
|
+
/* @__PURE__ */ jsx(FieldDescription, { children: "One CHILD=SOURCE pair per line. Only variable names are stored." })
|
|
2895
|
+
] })
|
|
2896
|
+
] }),
|
|
2897
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2898
|
+
className: "flex justify-end gap-2",
|
|
2899
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
2900
|
+
type: "button",
|
|
2901
|
+
size: "sm",
|
|
2902
|
+
variant: "ghost",
|
|
2903
|
+
onClick: resetAddForm,
|
|
2904
|
+
children: "Cancel"
|
|
2905
|
+
}), /* @__PURE__ */ jsxs(Button, {
|
|
2906
|
+
type: "button",
|
|
2907
|
+
size: "sm",
|
|
2908
|
+
disabled: isPending || !name.trim(),
|
|
2909
|
+
onClick: () => void handleAdd(),
|
|
2910
|
+
children: [isPending ? /* @__PURE__ */ jsx(Spinner, { "data-icon": "inline-start" }) : null, "Save"]
|
|
2911
|
+
})]
|
|
2912
|
+
})
|
|
2913
|
+
]
|
|
2914
|
+
}) : null,
|
|
2915
|
+
!isLoading && connections.length === 0 && !adding ? /* @__PURE__ */ jsx("p", {
|
|
2916
|
+
className: "text-sm text-muted-foreground",
|
|
2917
|
+
children: "No MCP connections yet."
|
|
2918
|
+
}) : null,
|
|
2919
|
+
/* @__PURE__ */ jsx("div", {
|
|
2920
|
+
className: "flex flex-col gap-2",
|
|
2921
|
+
children: connections.map((connection) => /* @__PURE__ */ jsxs("div", {
|
|
2922
|
+
className: "flex flex-col gap-2",
|
|
2923
|
+
children: [
|
|
2924
|
+
/* @__PURE__ */ jsx(ItemRow, {
|
|
2925
|
+
icon: /* @__PURE__ */ jsx(Plug, { className: "size-4" }),
|
|
2926
|
+
title: connection.label,
|
|
2927
|
+
subtitle: connectionSubtitle(connection),
|
|
2928
|
+
trailing: /* @__PURE__ */ jsxs("div", {
|
|
2929
|
+
className: "flex items-center gap-1.5",
|
|
2930
|
+
children: [connection.usesOAuth && connection.status !== "needs_auth" ? /* @__PURE__ */ jsx(Button, {
|
|
2931
|
+
type: "button",
|
|
2932
|
+
size: "sm",
|
|
2933
|
+
variant: "ghost",
|
|
2934
|
+
disabled: isPending || !onOAuth,
|
|
2935
|
+
onClick: () => {
|
|
2936
|
+
handleLogout(connection.name);
|
|
2937
|
+
},
|
|
2938
|
+
children: "Sign out"
|
|
2939
|
+
}) : null, connection.source === "user" ? confirmRemove === connection.name ? /* @__PURE__ */ jsx(Button, {
|
|
2940
|
+
type: "button",
|
|
2941
|
+
size: "sm",
|
|
2942
|
+
variant: "destructive",
|
|
2943
|
+
disabled: isPending,
|
|
2944
|
+
onClick: () => {
|
|
2945
|
+
handleRemove(connection.name);
|
|
2946
|
+
},
|
|
2947
|
+
children: "Confirm remove"
|
|
2948
|
+
}) : /* @__PURE__ */ jsx(Button, {
|
|
2949
|
+
type: "button",
|
|
2950
|
+
size: "sm",
|
|
2951
|
+
variant: "ghost",
|
|
2952
|
+
disabled: isPending || !onRemove,
|
|
2953
|
+
"aria-label": `Remove ${connection.name}`,
|
|
2954
|
+
onClick: () => setConfirmRemove(connection.name),
|
|
2955
|
+
children: /* @__PURE__ */ jsx(Trash2, { className: "size-3.5" })
|
|
2956
|
+
}) : null]
|
|
2957
|
+
})
|
|
2958
|
+
}),
|
|
2959
|
+
connection.error ? /* @__PURE__ */ jsx(Alert, {
|
|
2960
|
+
className: "px-3 py-2",
|
|
2961
|
+
children: /* @__PURE__ */ jsx(AlertDescription, {
|
|
2962
|
+
className: "text-xs text-pretty",
|
|
2963
|
+
children: connection.error
|
|
2964
|
+
})
|
|
2965
|
+
}) : null,
|
|
2966
|
+
connection.usesOAuth && oauthAdapter ? /* @__PURE__ */ jsx(ProviderOAuthSignIn, {
|
|
2967
|
+
provider: {
|
|
2968
|
+
id: connection.name,
|
|
2969
|
+
name: connection.label,
|
|
2970
|
+
isConfigured: connection.status === "connected",
|
|
2971
|
+
envVarName: "",
|
|
2972
|
+
authType: "oauth",
|
|
2973
|
+
supportsOAuth: true
|
|
2974
|
+
},
|
|
2975
|
+
onOAuthLogin: oauthAdapter(connection)
|
|
2976
|
+
}) : null
|
|
2977
|
+
]
|
|
2978
|
+
}, `${connection.source}:${connection.name}`))
|
|
2979
|
+
})
|
|
2980
|
+
]
|
|
2981
|
+
});
|
|
2982
|
+
}
|
|
2983
|
+
function isFieldInvalid(value, attemptedSave, required = true) {
|
|
2984
|
+
return attemptedSave && required && value.trim().length === 0;
|
|
2985
|
+
}
|
|
2986
|
+
function SecretCredentialField({ attemptedSave, label, onChange, onToggleVisibility, placeholder, required = true, showPassword, value }) {
|
|
2987
|
+
const controlId = useId();
|
|
2988
|
+
const invalid = isFieldInvalid(value, attemptedSave, required);
|
|
2989
|
+
return /* @__PURE__ */ jsxs(Field, {
|
|
2990
|
+
"data-invalid": invalid || void 0,
|
|
2991
|
+
children: [/* @__PURE__ */ jsx(FieldLabel, {
|
|
2992
|
+
htmlFor: controlId,
|
|
2993
|
+
children: label
|
|
2994
|
+
}), /* @__PURE__ */ jsxs(InputGroup, { children: [
|
|
2995
|
+
/* @__PURE__ */ jsx(InputGroupAddon, {
|
|
2996
|
+
align: "inline-start",
|
|
2997
|
+
children: /* @__PURE__ */ jsx(Lock, {})
|
|
2998
|
+
}),
|
|
2999
|
+
/* @__PURE__ */ jsx(InputGroupInput, {
|
|
3000
|
+
id: controlId,
|
|
3001
|
+
type: showPassword ? "text" : "password",
|
|
3002
|
+
placeholder,
|
|
3003
|
+
value,
|
|
3004
|
+
onChange: (event) => onChange(event.target.value),
|
|
3005
|
+
"aria-label": label,
|
|
3006
|
+
"aria-invalid": invalid || void 0
|
|
3007
|
+
}),
|
|
3008
|
+
/* @__PURE__ */ jsx(InputGroupAddon, {
|
|
3009
|
+
align: "inline-end",
|
|
3010
|
+
children: /* @__PURE__ */ jsx(InputGroupButton, {
|
|
3011
|
+
size: "icon-xs",
|
|
3012
|
+
className: cn(HIT_AREA_EXPAND_CLASS, "transition-[background-color,transform] duration-150 active:scale-[0.96]"),
|
|
3013
|
+
"aria-label": showPassword ? "Hide value" : "Show value",
|
|
3014
|
+
onClick: onToggleVisibility,
|
|
3015
|
+
children: showPassword ? /* @__PURE__ */ jsx(EyeOff, {}) : /* @__PURE__ */ jsx(Eye, {})
|
|
3016
|
+
})
|
|
3017
|
+
})
|
|
3018
|
+
] })]
|
|
3019
|
+
});
|
|
3020
|
+
}
|
|
3021
|
+
function TextCredentialField({ attemptedSave, icon: Icon, inputType = "text", label, onChange, placeholder, required = true, value }) {
|
|
3022
|
+
const controlId = useId();
|
|
3023
|
+
const invalid = isFieldInvalid(value, attemptedSave, required);
|
|
3024
|
+
return /* @__PURE__ */ jsxs(Field, {
|
|
3025
|
+
"data-invalid": invalid || void 0,
|
|
3026
|
+
children: [/* @__PURE__ */ jsx(FieldLabel, {
|
|
3027
|
+
htmlFor: controlId,
|
|
3028
|
+
children: label
|
|
3029
|
+
}), /* @__PURE__ */ jsxs(InputGroup, { children: [/* @__PURE__ */ jsx(InputGroupAddon, {
|
|
3030
|
+
align: "inline-start",
|
|
3031
|
+
children: /* @__PURE__ */ jsx(Icon, {})
|
|
3032
|
+
}), /* @__PURE__ */ jsx(InputGroupInput, {
|
|
3033
|
+
id: controlId,
|
|
3034
|
+
type: inputType,
|
|
3035
|
+
placeholder,
|
|
3036
|
+
value,
|
|
3037
|
+
onChange: (event) => onChange(event.target.value),
|
|
3038
|
+
"aria-label": label,
|
|
3039
|
+
"aria-invalid": invalid || void 0
|
|
3040
|
+
})] })]
|
|
3041
|
+
});
|
|
3042
|
+
}
|
|
3043
|
+
var OPENAI_CHAT_BASE_URL_PLACEHOLDER = "https://opencode.ai/zen/v1";
|
|
3044
|
+
var OPENAI_CHAT_MODEL_PLACEHOLDER = "qwen35-122b-a10b";
|
|
3045
|
+
var OPENAI_CHAT_NAME_PLACEHOLDER = "e.g. OpenCode Zen, Nebius, Groq\u2026";
|
|
3046
|
+
var CUSTOM_MODELS_PLACEHOLDER = "model-a, model-b (comma-separated)";
|
|
3047
|
+
var CUSTOM_PROVIDER_API_OPTIONS = [
|
|
3048
|
+
{
|
|
3049
|
+
value: "openai-completions",
|
|
3050
|
+
label: "OpenAI Chat Completions"
|
|
3051
|
+
},
|
|
3052
|
+
{
|
|
3053
|
+
value: "openai-responses",
|
|
3054
|
+
label: "OpenAI Responses"
|
|
3055
|
+
},
|
|
3056
|
+
{
|
|
3057
|
+
value: "anthropic-messages",
|
|
3058
|
+
label: "Anthropic Messages"
|
|
3059
|
+
},
|
|
3060
|
+
{
|
|
3061
|
+
value: "google-genai",
|
|
3062
|
+
label: "Google Generative AI"
|
|
3063
|
+
}
|
|
3064
|
+
];
|
|
3065
|
+
function ProviderCredentialFields({ attemptedSave, apiKey, api, baseUrl, modelId, models, displayName, isCustom, onApiKeyChange, onApiChange, onBaseUrlChange, onModelIdChange, onModelsChange, onDisplayNameChange, onTogglePassword, openAiChat, placeholder, showPassword }) {
|
|
3066
|
+
const showApiSelector = isCustom && onApiChange;
|
|
3067
|
+
const showMultiModels = isCustom && onModelsChange;
|
|
3068
|
+
return /* @__PURE__ */ jsxs(FieldGroup, {
|
|
3069
|
+
className: "gap-2",
|
|
3070
|
+
children: [
|
|
3071
|
+
(openAiChat || isCustom) && onDisplayNameChange ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
3072
|
+
attemptedSave,
|
|
3073
|
+
icon: Tag,
|
|
3074
|
+
label: "Provider name",
|
|
3075
|
+
placeholder: OPENAI_CHAT_NAME_PLACEHOLDER,
|
|
3076
|
+
value: displayName ?? "",
|
|
3077
|
+
onChange: onDisplayNameChange
|
|
3078
|
+
}) : null,
|
|
3079
|
+
showApiSelector ? /* @__PURE__ */ jsx(ApiSelector, {
|
|
3080
|
+
value: api ?? "openai-completions",
|
|
3081
|
+
onChange: onApiChange
|
|
3082
|
+
}) : null,
|
|
3083
|
+
/* @__PURE__ */ jsx(SecretCredentialField, {
|
|
3084
|
+
attemptedSave,
|
|
3085
|
+
label: "API key",
|
|
3086
|
+
placeholder,
|
|
3087
|
+
value: apiKey,
|
|
3088
|
+
showPassword,
|
|
3089
|
+
onChange: onApiKeyChange,
|
|
3090
|
+
onToggleVisibility: onTogglePassword
|
|
3091
|
+
}),
|
|
3092
|
+
openAiChat || isCustom ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
3093
|
+
attemptedSave,
|
|
3094
|
+
icon: Globe,
|
|
3095
|
+
inputType: "url",
|
|
3096
|
+
label: "Base URL",
|
|
3097
|
+
placeholder: OPENAI_CHAT_BASE_URL_PLACEHOLDER,
|
|
3098
|
+
value: baseUrl,
|
|
3099
|
+
onChange: onBaseUrlChange
|
|
3100
|
+
}) : null,
|
|
3101
|
+
showMultiModels ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
3102
|
+
attemptedSave,
|
|
3103
|
+
icon: Layers,
|
|
3104
|
+
label: "Model ids",
|
|
3105
|
+
placeholder: CUSTOM_MODELS_PLACEHOLDER,
|
|
3106
|
+
value: models ?? "",
|
|
3107
|
+
onChange: onModelsChange
|
|
3108
|
+
}) : null,
|
|
3109
|
+
openAiChat && !showMultiModels ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
3110
|
+
attemptedSave,
|
|
3111
|
+
icon: Box,
|
|
3112
|
+
label: "Model name",
|
|
3113
|
+
placeholder: OPENAI_CHAT_MODEL_PLACEHOLDER,
|
|
3114
|
+
value: modelId,
|
|
3115
|
+
onChange: onModelIdChange
|
|
3116
|
+
}) : null
|
|
3117
|
+
]
|
|
3118
|
+
});
|
|
3119
|
+
}
|
|
3120
|
+
function ApiSelector({ value, onChange }) {
|
|
3121
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
3122
|
+
className: "flex flex-col gap-1",
|
|
3123
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
3124
|
+
className: "text-xs font-medium text-muted-foreground",
|
|
3125
|
+
children: "API family"
|
|
3126
|
+
}), /* @__PURE__ */ jsx(Select, {
|
|
3127
|
+
"aria-label": "API family",
|
|
3128
|
+
value,
|
|
3129
|
+
options: CUSTOM_PROVIDER_API_OPTIONS,
|
|
3130
|
+
placeholder: "Select API family",
|
|
3131
|
+
onValueChange: (next) => onChange(next)
|
|
3132
|
+
})]
|
|
3133
|
+
});
|
|
3134
|
+
}
|
|
3135
|
+
function isOAuthProvider(provider) {
|
|
3136
|
+
return provider.authType === "oauth";
|
|
3137
|
+
}
|
|
3138
|
+
function supportsOAuth(provider) {
|
|
3139
|
+
return provider.supportsOAuth === true;
|
|
3140
|
+
}
|
|
3141
|
+
var CUSTOM_PROVIDER_PICKER_ROW = {
|
|
3142
|
+
id: "custom",
|
|
3143
|
+
name: "Custom provider",
|
|
3144
|
+
isConfigured: false,
|
|
3145
|
+
envVarName: "CUSTOM_PROVIDER_API_KEY",
|
|
3146
|
+
displayName: "Custom provider"
|
|
3147
|
+
};
|
|
3148
|
+
function parseCustomProviderModels(raw) {
|
|
3149
|
+
return raw.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
3150
|
+
}
|
|
3151
|
+
function useProviderCredentialsController({ onRemoveProvider, onUpdateProvider, providers }) {
|
|
3152
|
+
const [editingProvider, setEditingProvider] = useState2(null);
|
|
3153
|
+
const [editingIsNewOccInstance, setEditingIsNewOccInstance] = useState2(false);
|
|
3154
|
+
const [apiKey, setApiKey] = useState2("");
|
|
3155
|
+
const [baseUrl, setBaseUrl] = useState2("");
|
|
3156
|
+
const [modelId, setModelId] = useState2("");
|
|
3157
|
+
const [models, setModels] = useState2("");
|
|
3158
|
+
const [api, setApi] = useState2("openai-completions");
|
|
3159
|
+
const [displayName, setDisplayName] = useState2("");
|
|
3160
|
+
const [showPassword, setShowPassword] = useState2(false);
|
|
3161
|
+
const [attemptedSave, setAttemptedSave] = useState2(false);
|
|
3162
|
+
const [searchQuery, setSearchQuery] = useState2("");
|
|
3163
|
+
const [addPickerOpen, setAddPickerOpen] = useState2(false);
|
|
3164
|
+
const [addPickerQuery, setAddPickerQuery] = useState2("");
|
|
3165
|
+
const [confirmRemoveProvider, setConfirmRemoveProvider] = useState2(null);
|
|
3166
|
+
const credentialProviders = useMemo2(() => {
|
|
3167
|
+
return [...providers.filter((provider) => provider.id !== CUSTOM_PROVIDER_PICKER_ROW.id), CUSTOM_PROVIDER_PICKER_ROW];
|
|
3168
|
+
}, [providers]);
|
|
3169
|
+
const activeProviders = useMemo2(() => credentialProviders.filter((provider) => provider.isConfigured), [credentialProviders]);
|
|
3170
|
+
const unconfiguredProviders = useMemo2(() => credentialProviders.filter((provider) => !provider.isConfigured || provider.id === "openai-chat-completions" && provider.providerFamily === void 0), [credentialProviders]);
|
|
3171
|
+
const filteredActiveProviders = useMemo2(() => {
|
|
3172
|
+
const query = searchQuery.trim().toLowerCase();
|
|
3173
|
+
if (!query) return activeProviders;
|
|
3174
|
+
return activeProviders.filter((provider) => providerMatchesQuery(provider, query));
|
|
3175
|
+
}, [activeProviders, searchQuery]);
|
|
3176
|
+
const filteredPickerAvailable = useMemo2(() => {
|
|
3177
|
+
const query = addPickerQuery.trim().toLowerCase();
|
|
3178
|
+
return unconfiguredProviders.filter((provider) => providerMatchesQuery(provider, query));
|
|
3179
|
+
}, [addPickerQuery, unconfiguredProviders]);
|
|
3180
|
+
const filteredPickerConfigured = useMemo2(() => {
|
|
3181
|
+
const query = addPickerQuery.trim().toLowerCase();
|
|
3182
|
+
return activeProviders.filter((provider) => providerMatchesQuery(provider, query));
|
|
3183
|
+
}, [activeProviders, addPickerQuery]);
|
|
3184
|
+
const pickerHasResults = filteredPickerAvailable.length > 0 || filteredPickerConfigured.length > 0;
|
|
3185
|
+
const editingUnconfiguredProvider = editingProvider && !activeProviders.some((provider) => provider.id === editingProvider) ? credentialProviders.find((entry) => entry.id === editingProvider) ?? null : null;
|
|
3186
|
+
const resetEditor = () => {
|
|
3187
|
+
setApiKey("");
|
|
3188
|
+
setBaseUrl("");
|
|
3189
|
+
setModelId("");
|
|
3190
|
+
setModels("");
|
|
3191
|
+
setApi("openai-completions");
|
|
3192
|
+
setDisplayName("");
|
|
3193
|
+
setShowPassword(false);
|
|
3194
|
+
setAttemptedSave(false);
|
|
3195
|
+
};
|
|
3196
|
+
const closeEditor = () => {
|
|
3197
|
+
setEditingProvider(null);
|
|
3198
|
+
setEditingIsNewOccInstance(false);
|
|
3199
|
+
resetEditor();
|
|
3200
|
+
};
|
|
3201
|
+
const openEditor = (providerId, opts) => {
|
|
3202
|
+
setAddPickerOpen(false);
|
|
3203
|
+
setAddPickerQuery("");
|
|
3204
|
+
setEditingProvider(providerId);
|
|
3205
|
+
setEditingIsNewOccInstance(opts?.newOccInstance === true);
|
|
3206
|
+
resetEditor();
|
|
3207
|
+
const existing = providers.find((provider) => provider.id === providerId);
|
|
3208
|
+
setBaseUrl(existing?.baseUrl ?? "");
|
|
3209
|
+
setDisplayName(existing?.displayName ?? (isCustomProviderId(providerId) ? existing?.name ?? "" : ""));
|
|
3210
|
+
setApi(existing?.api ?? "openai-completions");
|
|
3211
|
+
setModels((existing?.modelIds ?? []).join(", "));
|
|
3212
|
+
setModelId(existing?.modelIds?.[0] ?? "");
|
|
3213
|
+
};
|
|
3214
|
+
const openAddPicker = () => {
|
|
3215
|
+
closeEditor();
|
|
3216
|
+
setAddPickerQuery("");
|
|
3217
|
+
setAddPickerOpen(true);
|
|
3218
|
+
};
|
|
3219
|
+
const closeAddPicker = () => {
|
|
3220
|
+
setAddPickerOpen(false);
|
|
3221
|
+
setAddPickerQuery("");
|
|
3222
|
+
};
|
|
3223
|
+
const selectProviderFromPicker = (providerId) => {
|
|
3224
|
+
openEditor(providerId, { newOccInstance: isOccProviderId(providerId) });
|
|
3225
|
+
};
|
|
3226
|
+
const handleSave = async (providerId) => {
|
|
3227
|
+
if (!onUpdateProvider) return;
|
|
3228
|
+
setAttemptedSave(true);
|
|
3229
|
+
const isCustomEditor = providerId === "custom" || isCustomProviderId(providerId);
|
|
3230
|
+
const openAiChat = isOccProviderId(providerId);
|
|
3231
|
+
if (isCustomEditor) {
|
|
3232
|
+
const modelList = parseCustomProviderModels(models);
|
|
3233
|
+
if (!apiKey.trim() || !baseUrl.trim() || !displayName.trim()) return;
|
|
3234
|
+
if (modelList.length === 0) return;
|
|
3235
|
+
try {
|
|
3236
|
+
await onUpdateProvider({
|
|
3237
|
+
providerId,
|
|
3238
|
+
apiKey: apiKey.trim(),
|
|
3239
|
+
baseUrl: baseUrl.trim(),
|
|
3240
|
+
displayName: displayName.trim(),
|
|
3241
|
+
api,
|
|
3242
|
+
models: modelList,
|
|
3243
|
+
...providerId === "custom" ? { createOccInstance: true } : {}
|
|
3244
|
+
});
|
|
3245
|
+
notify.success("Provider credentials applied to your active sessions.");
|
|
3246
|
+
closeEditor();
|
|
3247
|
+
closeAddPicker();
|
|
3248
|
+
} catch (error) {
|
|
3249
|
+
notify.error(error instanceof Error ? error.message : "Failed to update provider");
|
|
3250
|
+
}
|
|
3251
|
+
return;
|
|
3252
|
+
}
|
|
3253
|
+
const isNamedOcc = openAiChat && isNamedOccInstanceId(providerId);
|
|
3254
|
+
const isOccLike = openAiChat && (isNamedOcc || editingIsNewOccInstance);
|
|
3255
|
+
if (!apiKey.trim()) return;
|
|
3256
|
+
if (openAiChat && (!baseUrl.trim() || !modelId.trim())) return;
|
|
3257
|
+
if (isOccLike && !displayName.trim()) return;
|
|
3258
|
+
try {
|
|
3259
|
+
await onUpdateProvider({
|
|
3260
|
+
providerId,
|
|
3261
|
+
apiKey: apiKey.trim(),
|
|
3262
|
+
...openAiChat ? {
|
|
3263
|
+
baseUrl: baseUrl.trim(),
|
|
3264
|
+
modelId: modelId.trim(),
|
|
3265
|
+
...isOccLike ? { displayName: displayName.trim() } : {},
|
|
3266
|
+
...editingIsNewOccInstance ? { createOccInstance: true } : {}
|
|
3267
|
+
} : {}
|
|
3268
|
+
});
|
|
3269
|
+
notify.success("Provider credentials applied to your active sessions.");
|
|
3270
|
+
closeEditor();
|
|
3271
|
+
closeAddPicker();
|
|
3272
|
+
} catch (error) {
|
|
3273
|
+
notify.error(error instanceof Error ? error.message : "Failed to update provider");
|
|
3274
|
+
}
|
|
3275
|
+
};
|
|
3276
|
+
const handleRemove = async (provider) => {
|
|
3277
|
+
if (!onRemoveProvider) return;
|
|
3278
|
+
try {
|
|
3279
|
+
await onRemoveProvider({ providerId: provider.id });
|
|
3280
|
+
if (editingProvider === provider.id) closeEditor();
|
|
3281
|
+
notify.success(`${provider.name} removed from your configured providers.`);
|
|
3282
|
+
setConfirmRemoveProvider(null);
|
|
3283
|
+
} catch (error) {
|
|
3284
|
+
notify.error(error instanceof Error ? error.message : "Failed to remove provider");
|
|
3285
|
+
}
|
|
3286
|
+
};
|
|
3287
|
+
return {
|
|
3288
|
+
activeProviders,
|
|
3289
|
+
addPickerOpen,
|
|
3290
|
+
addPickerQuery,
|
|
3291
|
+
api,
|
|
3292
|
+
apiKey,
|
|
3293
|
+
attemptedSave,
|
|
3294
|
+
baseUrl,
|
|
3295
|
+
canSave: useMemo2(() => {
|
|
3296
|
+
if (apiKey.trim().length === 0) return false;
|
|
3297
|
+
if (!editingProvider) return true;
|
|
3298
|
+
if (editingProvider === "custom" || isCustomProviderId(editingProvider)) {
|
|
3299
|
+
if (baseUrl.trim().length === 0) return false;
|
|
3300
|
+
if (parseCustomProviderModels(models).length === 0) return false;
|
|
3301
|
+
return displayName.trim().length > 0;
|
|
3302
|
+
}
|
|
3303
|
+
if (!isOccProviderId(editingProvider)) return true;
|
|
3304
|
+
if (baseUrl.trim().length === 0 || modelId.trim().length === 0) return false;
|
|
3305
|
+
if (isNamedOccInstanceId(editingProvider) || editingIsNewOccInstance) return displayName.trim().length > 0;
|
|
3306
|
+
return true;
|
|
3307
|
+
}, [
|
|
3308
|
+
apiKey,
|
|
3309
|
+
baseUrl,
|
|
3310
|
+
modelId,
|
|
3311
|
+
models,
|
|
3312
|
+
displayName,
|
|
3313
|
+
editingProvider,
|
|
3314
|
+
editingIsNewOccInstance
|
|
3315
|
+
]),
|
|
3316
|
+
closeAddPicker,
|
|
3317
|
+
closeEditor,
|
|
3318
|
+
confirmRemoveProvider,
|
|
3319
|
+
credentialProviders,
|
|
3320
|
+
displayName,
|
|
3321
|
+
editingIsNewOccInstance,
|
|
3322
|
+
editingProvider,
|
|
3323
|
+
editingUnconfiguredProvider,
|
|
3324
|
+
filteredActiveProviders,
|
|
3325
|
+
filteredPickerAvailable,
|
|
3326
|
+
filteredPickerConfigured,
|
|
3327
|
+
handleRemove,
|
|
3328
|
+
handleSave,
|
|
3329
|
+
modelId,
|
|
3330
|
+
models,
|
|
3331
|
+
openAddPicker,
|
|
3332
|
+
openEditor,
|
|
3333
|
+
pickerHasResults,
|
|
3334
|
+
resetEditor,
|
|
3335
|
+
searchQuery,
|
|
3336
|
+
selectProviderFromPicker,
|
|
3337
|
+
setAddPickerOpen,
|
|
3338
|
+
setAddPickerQuery,
|
|
3339
|
+
setApi,
|
|
3340
|
+
setApiKey,
|
|
3341
|
+
setAttemptedSave,
|
|
3342
|
+
setBaseUrl,
|
|
3343
|
+
setConfirmRemoveProvider,
|
|
3344
|
+
setDisplayName,
|
|
3345
|
+
setEditingIsNewOccInstance,
|
|
3346
|
+
setEditingProvider,
|
|
3347
|
+
setModelId,
|
|
3348
|
+
setModels,
|
|
3349
|
+
setSearchQuery,
|
|
3350
|
+
setShowPassword,
|
|
3351
|
+
showPassword,
|
|
3352
|
+
unconfiguredProviders
|
|
2895
3353
|
};
|
|
2896
3354
|
}
|
|
2897
|
-
function
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
const userCode = waiting ? login?.userCode : void 0;
|
|
2907
|
-
const instructions = waiting ? login?.instructions : void 0;
|
|
2908
|
-
const prompt = waiting ? login?.prompt : void 0;
|
|
2909
|
-
const oauthOnly = provider.authType === "oauth";
|
|
2910
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
2911
|
-
className: "flex flex-col gap-3",
|
|
2912
|
-
children: [provider.isConfigured && oauthOnly && !waiting ? /* @__PURE__ */ jsxs("div", {
|
|
2913
|
-
className: "flex items-center gap-2 text-sm",
|
|
2914
|
-
children: [/* @__PURE__ */ jsx(Check, { className: "size-3.5 text-muted-foreground" }), /* @__PURE__ */ jsx("span", { children: "Connected" })]
|
|
2915
|
-
}) : null, waiting ? /* @__PURE__ */ jsxs("div", {
|
|
2916
|
-
className: "flex flex-col gap-2",
|
|
2917
|
-
children: [
|
|
2918
|
-
/* @__PURE__ */ jsxs("p", {
|
|
2919
|
-
className: "text-sm",
|
|
2920
|
-
children: [
|
|
2921
|
-
"Sign in with ",
|
|
2922
|
-
provider.name,
|
|
2923
|
-
" to store OAuth credentials for this account."
|
|
2924
|
-
]
|
|
2925
|
-
}),
|
|
2926
|
-
userCode ? /* @__PURE__ */ jsxs("p", {
|
|
2927
|
-
className: "text-sm",
|
|
2928
|
-
children: [
|
|
2929
|
-
"Enter this code:",
|
|
2930
|
-
" ",
|
|
2931
|
-
/* @__PURE__ */ jsx("span", {
|
|
2932
|
-
className: "font-mono text-foreground",
|
|
2933
|
-
children: userCode
|
|
2934
|
-
})
|
|
2935
|
-
]
|
|
2936
|
-
}) : null,
|
|
2937
|
-
instructions && !userCode ? /* @__PURE__ */ jsx("p", {
|
|
2938
|
-
className: "text-xs text-pretty text-muted-foreground",
|
|
2939
|
-
children: instructions
|
|
2940
|
-
}) : null,
|
|
2941
|
-
authUrl ? /* @__PURE__ */ jsxs(Button, {
|
|
2942
|
-
type: "button",
|
|
2943
|
-
size: "sm",
|
|
2944
|
-
onClick: () => {
|
|
2945
|
-
window.open(authUrl, "_blank", "noopener,noreferrer");
|
|
2946
|
-
},
|
|
2947
|
-
children: [/* @__PURE__ */ jsx(ExternalLink, { "data-icon": "inline-start" }), "Open sign-in page"]
|
|
2948
|
-
}) : prompt ? null : /* @__PURE__ */ jsxs("div", {
|
|
2949
|
-
className: "flex items-center gap-2 text-xs text-muted-foreground",
|
|
2950
|
-
children: [/* @__PURE__ */ jsx(Spinner, { className: "size-3" }), "Waiting for sign-in\u2026"]
|
|
2951
|
-
}),
|
|
2952
|
-
prompt ? /* @__PURE__ */ jsxs("div", {
|
|
2953
|
-
className: "flex flex-col gap-2",
|
|
2954
|
-
children: [
|
|
2955
|
-
/* @__PURE__ */ jsx("p", {
|
|
2956
|
-
className: "text-xs text-pretty text-muted-foreground",
|
|
2957
|
-
children: prompt.message
|
|
2958
|
-
}),
|
|
2959
|
-
/* @__PURE__ */ jsx(Input, {
|
|
2960
|
-
value: promptAnswer,
|
|
2961
|
-
placeholder: prompt.placeholder,
|
|
2962
|
-
onChange: (event) => setPromptAnswer(event.target.value),
|
|
2963
|
-
"aria-label": prompt.message
|
|
2964
|
-
}),
|
|
2965
|
-
/* @__PURE__ */ jsx("div", {
|
|
2966
|
-
className: "flex justify-end",
|
|
2967
|
-
children: /* @__PURE__ */ jsxs(Button, {
|
|
2968
|
-
type: "button",
|
|
2969
|
-
size: "sm",
|
|
2970
|
-
disabled: busy || !prompt.allowEmpty && !promptAnswer.trim(),
|
|
2971
|
-
onClick: () => {
|
|
2972
|
-
submitPrompt();
|
|
2973
|
-
},
|
|
2974
|
-
children: [busy ? /* @__PURE__ */ jsx(Spinner, { "data-icon": "inline-start" }) : null, "Continue"]
|
|
2975
|
-
})
|
|
2976
|
-
})
|
|
2977
|
-
]
|
|
2978
|
-
}) : null,
|
|
2979
|
-
/* @__PURE__ */ jsx("div", {
|
|
2980
|
-
className: "flex justify-end",
|
|
2981
|
-
children: /* @__PURE__ */ jsx(Button, {
|
|
2982
|
-
type: "button",
|
|
2983
|
-
variant: "ghost",
|
|
2984
|
-
size: "sm",
|
|
2985
|
-
disabled: busy,
|
|
2986
|
-
onClick: () => {
|
|
2987
|
-
cancel();
|
|
2988
|
-
},
|
|
2989
|
-
children: "Cancel sign-in"
|
|
2990
|
-
})
|
|
2991
|
-
})
|
|
2992
|
-
]
|
|
2993
|
-
}) : /* @__PURE__ */ jsxs("div", {
|
|
2994
|
-
className: "flex flex-col gap-2",
|
|
2995
|
-
children: [error ? /* @__PURE__ */ jsx(Alert, {
|
|
2996
|
-
className: "px-3 py-2",
|
|
2997
|
-
children: /* @__PURE__ */ jsx(AlertDescription, {
|
|
2998
|
-
className: "text-xs text-pretty",
|
|
2999
|
-
children: error
|
|
3000
|
-
})
|
|
3001
|
-
}) : /* @__PURE__ */ jsx("p", {
|
|
3002
|
-
className: "text-xs text-pretty text-muted-foreground",
|
|
3003
|
-
children: oauthOnly && provider.isConfigured ? `Sign in again with ${provider.name} to refresh OAuth credentials.` : oauthOnly ? `Sign in with ${provider.name}. No API key is stored; credentials are saved to auth.json.` : `Sign in with ${provider.name} to use OAuth credentials; API-key editing remains available above.`
|
|
3004
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
3005
|
-
className: "flex justify-end",
|
|
3006
|
-
children: /* @__PURE__ */ jsxs(Button, {
|
|
3007
|
-
type: "button",
|
|
3008
|
-
size: "sm",
|
|
3009
|
-
disabled: busy || !canStart,
|
|
3010
|
-
onClick: () => {
|
|
3011
|
-
start();
|
|
3012
|
-
},
|
|
3013
|
-
children: [
|
|
3014
|
-
busy ? /* @__PURE__ */ jsx(Spinner, { "data-icon": "inline-start" }) : null,
|
|
3015
|
-
"Sign in with ",
|
|
3016
|
-
provider.name
|
|
3017
|
-
]
|
|
3018
|
-
})
|
|
3019
|
-
})]
|
|
3020
|
-
})]
|
|
3021
|
-
});
|
|
3355
|
+
function providerMatchesQuery(provider, query) {
|
|
3356
|
+
if (!query) return true;
|
|
3357
|
+
const keywords = supportsOAuth(provider) ? isOAuthProvider(provider) ? "oauth sign-in login" : "api key oauth sign-in login" : provider.id === "custom" || isCustomProviderId(provider.id) ? "custom provider endpoint openai anthropic google compatible" : isOccProviderId(provider.id) ? "api key base url model name chat completions" : "";
|
|
3358
|
+
return [
|
|
3359
|
+
provider.name,
|
|
3360
|
+
provider.envVarName,
|
|
3361
|
+
provider.id,
|
|
3362
|
+
keywords
|
|
3363
|
+
].join(" ").toLowerCase().includes(query);
|
|
3022
3364
|
}
|
|
3023
3365
|
function AddProviderPickerPanel({ addPickerQuery, credentialProvidersLength, filteredPickerAvailable, filteredPickerConfigured, pickerHasResults, onClose, onQueryChange, onSelect }) {
|
|
3024
3366
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -3071,7 +3413,7 @@ function AddProviderPickerPanel({ addPickerQuery, credentialProvidersLength, fil
|
|
|
3071
3413
|
}) : null, filteredPickerConfigured.length > 0 ? /* @__PURE__ */ jsxs("div", {
|
|
3072
3414
|
className: "flex flex-col gap-1",
|
|
3073
3415
|
children: [filteredPickerAvailable.length > 0 ? /* @__PURE__ */ jsx("p", {
|
|
3074
|
-
className: "px-2 pt-1 text-[
|
|
3416
|
+
className: "px-2 pt-1 text-[0.6875rem] font-medium tracking-wide text-muted-foreground uppercase",
|
|
3075
3417
|
children: "Already configured"
|
|
3076
3418
|
}) : null, filteredPickerConfigured.map((provider) => /* @__PURE__ */ jsx(ProviderPickerRow, {
|
|
3077
3419
|
provider,
|
|
@@ -3248,44 +3590,6 @@ function ProviderPickerRow({ configured, onSelect, provider }) {
|
|
|
3248
3590
|
})]
|
|
3249
3591
|
});
|
|
3250
3592
|
}
|
|
3251
|
-
function RowSurface({ className, interactive, padding, tone, ...props }) {
|
|
3252
|
-
return /* @__PURE__ */ jsx("div", {
|
|
3253
|
-
className: cn(fleetPiRowSurface({
|
|
3254
|
-
interactive,
|
|
3255
|
-
padding,
|
|
3256
|
-
tone
|
|
3257
|
-
}), className),
|
|
3258
|
-
...props
|
|
3259
|
-
});
|
|
3260
|
-
}
|
|
3261
|
-
function ItemRow({ icon, title, subtitle, trailing, className, interactive = true, tone = "default" }) {
|
|
3262
|
-
return /* @__PURE__ */ jsxs(RowSurface, {
|
|
3263
|
-
tone,
|
|
3264
|
-
padding: "md",
|
|
3265
|
-
interactive,
|
|
3266
|
-
className: cn("items-center gap-3", className),
|
|
3267
|
-
children: [
|
|
3268
|
-
icon ? /* @__PURE__ */ jsx("div", {
|
|
3269
|
-
className: "flex size-8 shrink-0 items-center justify-center rounded-md border border-border/40 bg-background/60 text-foreground/70",
|
|
3270
|
-
children: icon
|
|
3271
|
-
}) : null,
|
|
3272
|
-
/* @__PURE__ */ jsxs("div", {
|
|
3273
|
-
className: "min-w-0 flex-1",
|
|
3274
|
-
children: [/* @__PURE__ */ jsx("div", {
|
|
3275
|
-
className: "truncate text-sm font-medium text-foreground",
|
|
3276
|
-
children: title
|
|
3277
|
-
}), subtitle ? /* @__PURE__ */ jsx("div", {
|
|
3278
|
-
className: "mt-0.5 truncate text-xs text-muted-foreground",
|
|
3279
|
-
children: subtitle
|
|
3280
|
-
}) : null]
|
|
3281
|
-
}),
|
|
3282
|
-
trailing ? /* @__PURE__ */ jsx("div", {
|
|
3283
|
-
className: "flex shrink-0 items-center gap-1.5",
|
|
3284
|
-
children: trailing
|
|
3285
|
-
}) : null
|
|
3286
|
-
]
|
|
3287
|
-
});
|
|
3288
|
-
}
|
|
3289
3593
|
function ActiveProviderList({ providers, editingProvider, form, operation, actions, onEdit, onCancelEdit, onSave, onRemove, onOAuthLogin, onConfigured }) {
|
|
3290
3594
|
const { api, apiKey, baseUrl, modelId, models, displayName, showPassword, attemptedSave, canSave } = form;
|
|
3291
3595
|
const { isPending, canRemove } = operation;
|
|
@@ -3569,7 +3873,7 @@ function searchableModelText(model) {
|
|
|
3569
3873
|
model.id
|
|
3570
3874
|
].join(" ").toLowerCase();
|
|
3571
3875
|
}
|
|
3572
|
-
function AddModelsDialog({ configuredProviderIds, discoverableProviderIds, discoveringProviderId, enabledModels, modelOptions, onAddModels, onDiscoverProvider, onOpenChange, providerLabel = formatProviderLabel }) {
|
|
3876
|
+
function AddModelsDialog({ configuredProviderIds, discoverableProviderIds, discoveringProviderId, enabledModels, modelOptions, onAddModels, onDiscoverProvider, onOpenChange, open, providerLabel = formatProviderLabel }) {
|
|
3573
3877
|
const [filter, setFilter] = useState2("");
|
|
3574
3878
|
const [selectedKeys, setSelectedKeys] = useState2(/* @__PURE__ */ new Set());
|
|
3575
3879
|
const normalizedFilter = filter.trim().toLowerCase();
|
|
@@ -3621,7 +3925,7 @@ function AddModelsDialog({ configuredProviderIds, discoverableProviderIds, disco
|
|
|
3621
3925
|
onOpenChange(false);
|
|
3622
3926
|
};
|
|
3623
3927
|
return /* @__PURE__ */ jsx(Dialog, {
|
|
3624
|
-
open
|
|
3928
|
+
open,
|
|
3625
3929
|
onOpenChange,
|
|
3626
3930
|
children: /* @__PURE__ */ jsxs(DialogContent, {
|
|
3627
3931
|
className: "max-w-lg",
|
|
@@ -3682,7 +3986,7 @@ function AddModelsDialog({ configuredProviderIds, discoverableProviderIds, disco
|
|
|
3682
3986
|
children: groupedCandidates.map(([provider, models]) => /* @__PURE__ */ jsxs("div", {
|
|
3683
3987
|
className: "flex flex-col gap-1",
|
|
3684
3988
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
3685
|
-
className: "px-2 text-[
|
|
3989
|
+
className: "px-2 text-[0.6875rem] font-medium tracking-wide text-muted-foreground uppercase",
|
|
3686
3990
|
children: [providerLabel(provider), (activeCountByProvider.get(provider) ?? 0) > 0 ? /* @__PURE__ */ jsxs("span", {
|
|
3687
3991
|
className: "ml-1 font-normal normal-case tabular-nums",
|
|
3688
3992
|
children: [
|
|
@@ -3924,7 +4228,8 @@ function ModelDefaultsSection({ draft, discoveringProviderId, modelDirty, modelF
|
|
|
3924
4228
|
}, model.id))]
|
|
3925
4229
|
}, provider))
|
|
3926
4230
|
}),
|
|
3927
|
-
|
|
4231
|
+
/* @__PURE__ */ jsx(AddModelsDialog, {
|
|
4232
|
+
open: addOpen,
|
|
3928
4233
|
configuredProviderIds,
|
|
3929
4234
|
discoverableProviderIds,
|
|
3930
4235
|
discoveringProviderId,
|
|
@@ -3934,7 +4239,7 @@ function ModelDefaultsSection({ draft, discoveringProviderId, modelDirty, modelF
|
|
|
3934
4239
|
onDiscoverProvider,
|
|
3935
4240
|
onOpenChange: setAddOpen,
|
|
3936
4241
|
providerLabel
|
|
3937
|
-
})
|
|
4242
|
+
})
|
|
3938
4243
|
]
|
|
3939
4244
|
});
|
|
3940
4245
|
}
|
|
@@ -4675,6 +4980,14 @@ var SETTINGS_SECTION_REGISTRY = {
|
|
|
4675
4980
|
icon: MessageSquare,
|
|
4676
4981
|
group: "workspace"
|
|
4677
4982
|
},
|
|
4983
|
+
mcp: {
|
|
4984
|
+
id: "mcp",
|
|
4985
|
+
order: 25,
|
|
4986
|
+
title: "MCP",
|
|
4987
|
+
ariaLabel: "MCP connection settings",
|
|
4988
|
+
icon: Plug,
|
|
4989
|
+
group: "workspace"
|
|
4990
|
+
},
|
|
4678
4991
|
sandbox: {
|
|
4679
4992
|
id: "sandbox",
|
|
4680
4993
|
order: 30,
|
|
@@ -4764,7 +5077,7 @@ function PreferenceRow({ children, description, label }) {
|
|
|
4764
5077
|
});
|
|
4765
5078
|
}
|
|
4766
5079
|
function useSettingsForm() {
|
|
4767
|
-
const { isLoadingProviders, isUpdatingProvider, modelCatalog, onDiscoverModels, onOAuthLogin, onRemoveProvider, onThemePreferenceChange, onUpdateProvider, providers = [], saveSettings, settings, settingsLoading, themePreference } = useSettingsActionsContext();
|
|
5080
|
+
const { isLoadingMcp, isLoadingProviders, isUpdatingMcp, isUpdatingProvider, mcpConnections = [], modelCatalog, onDiscoverModels, onMcpOAuth, onOAuthLogin, onRemoveMcp, onRemoveProvider, onThemePreferenceChange, onUpdateMcp, onUpdateProvider, providers = [], saveSettings, settings, settingsLoading, themePreference } = useSettingsActionsContext();
|
|
4768
5081
|
const { models, resources } = useChatPanelDataContext();
|
|
4769
5082
|
const [draft, setDraft] = useState2(null);
|
|
4770
5083
|
const [savingSection, setSavingSection] = useState2(null);
|
|
@@ -4828,11 +5141,17 @@ function useSettingsForm() {
|
|
|
4828
5141
|
return "close";
|
|
4829
5142
|
};
|
|
4830
5143
|
return {
|
|
5144
|
+
isLoadingMcp,
|
|
4831
5145
|
isLoadingProviders,
|
|
5146
|
+
isUpdatingMcp,
|
|
4832
5147
|
isUpdatingProvider,
|
|
4833
|
-
|
|
5148
|
+
mcpConnections,
|
|
5149
|
+
onMcpOAuth,
|
|
4834
5150
|
onOAuthLogin,
|
|
5151
|
+
onRemoveMcp,
|
|
4835
5152
|
onRemoveProvider,
|
|
5153
|
+
onThemePreferenceChange,
|
|
5154
|
+
onUpdateMcp,
|
|
4836
5155
|
onUpdateProvider,
|
|
4837
5156
|
providers,
|
|
4838
5157
|
resources,
|
|
@@ -4903,7 +5222,7 @@ function SettingsDialogSession({ initialTab, onOpenChange, open }) {
|
|
|
4903
5222
|
});
|
|
4904
5223
|
}
|
|
4905
5224
|
function SettingsDialogPaneContent({ activeTab, form, preferences, updatePreference }) {
|
|
4906
|
-
const { isLoadingProviders, isUpdatingProvider,
|
|
5225
|
+
const { isLoadingMcp, isLoadingProviders, isUpdatingMcp, isUpdatingProvider, mcpConnections, onMcpOAuth, onOAuthLogin, onRemoveMcp, onRemoveProvider, onThemePreferenceChange, onUpdateMcp, onUpdateProvider, providers, resources, settingsLoading, themePreference, draft, savingSection, packageRows, packageError, modelFilter, setModelFilter, resourceSummary, modelOptions, modelDirty, resourceDirty, revertResourceDraft, revertModelDraft, updateDraft, handlePackageRowsChange, addModels, removeModel, setDefaultModel, discoverProvider, discoveringProviderId, saveSection } = form;
|
|
4907
5226
|
const resourcesPane = (scope) => /* @__PURE__ */ jsx(ResourcesSection, {
|
|
4908
5227
|
scope,
|
|
4909
5228
|
draft,
|
|
@@ -5013,6 +5332,14 @@ function SettingsDialogPaneContent({ activeTab, form, preferences, updatePrefere
|
|
|
5013
5332
|
})
|
|
5014
5333
|
})]
|
|
5015
5334
|
}),
|
|
5335
|
+
mcp: () => /* @__PURE__ */ jsx(McpConnectionsSection, {
|
|
5336
|
+
connections: mcpConnections,
|
|
5337
|
+
isLoading: isLoadingMcp ?? false,
|
|
5338
|
+
isPending: isUpdatingMcp ?? false,
|
|
5339
|
+
onOAuth: onMcpOAuth,
|
|
5340
|
+
onRemove: onRemoveMcp,
|
|
5341
|
+
onUpsert: onUpdateMcp
|
|
5342
|
+
}),
|
|
5016
5343
|
sandbox: () => /* @__PURE__ */ jsx(SandboxProviderSection, {
|
|
5017
5344
|
isLoading: isLoadingProviders ?? false,
|
|
5018
5345
|
isPending: isUpdatingProvider ?? false,
|
|
@@ -5101,7 +5428,7 @@ function SettingsDialogBody({ initialTab, onCloseAttemptRef, onOpenChange }) {
|
|
|
5101
5428
|
const [activeTab, setActiveTab] = useState2(() => initialTab ?? "appearance");
|
|
5102
5429
|
const [preferences, setPreferences] = useState2(readUiPreferences);
|
|
5103
5430
|
useEffect2(() => {
|
|
5104
|
-
|
|
5431
|
+
writeStoredValue(UI_PREFERENCES_KEY, JSON.stringify(preferences));
|
|
5105
5432
|
document.documentElement.dataset.density = preferences.density;
|
|
5106
5433
|
document.documentElement.classList.toggle("reduce-motion", preferences.motion === "reduced");
|
|
5107
5434
|
}, [preferences]);
|