@qredence/fleet 0.5.11 → 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 +7 -0
- package/dist/web/client/assets/{artifacts-panel-CQmFEF_H.js → artifacts-panel-CJ75gQub.js} +1 -1
- package/dist/web/client/assets/chat-Ci2cEQrR.js +52 -0
- package/dist/web/client/assets/{chat-command-palette-CmHTS3rs.js → chat-command-palette-CkISHfKE.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/{horizontal-resize-qK6eRhIG.js → horizontal-resize-CwoDojST.js} +1 -1
- package/dist/web/client/assets/{index-C1zOjrMK.js → index-DJ1fFbQu.js} +2 -2
- package/dist/web/client/assets/input-group-Tb5TYbzi.js +1 -0
- package/dist/web/client/assets/{model-selector-list-DsKTuAgS.js → model-selector-list-Ch05B2nZ.js} +1 -1
- package/dist/web/client/assets/{openui-renderer-J3dhPpL4.js → openui-renderer-Bf60nxNi.js} +5 -5
- package/dist/web/client/assets/pencil-DcUwsKLn.js +1 -0
- package/dist/web/client/assets/{provider-label-Dpr7djG9.js → provider-label-DDLRnZyC.js} +1 -1
- package/dist/web/client/assets/{right-panel-registry-DewpBWHM.js → right-panel-registry-Dp8yX-oL.js} +2 -2
- package/dist/web/client/assets/routes-DpgMJZ5n.js +16 -0
- package/dist/web/client/assets/settings-dialog-YJkvt5EB.js +2 -0
- package/dist/web/client/assets/{subagent-chat-panel-DkVUumrP.js → subagent-chat-panel-Yujplxpb.js} +1 -1
- package/dist/web/client/assets/{subagent-transcript-D8wmQxXe.js → subagent-transcript-CnI-mqN0.js} +1 -1
- package/dist/web/client/assets/{subagents-panel-BMp2Ego0.js → subagents-panel-CjXEdimj.js} +1 -1
- package/dist/web/client/assets/{virtualized-turn-list-DMJENRY0.js → virtualized-turn-list--Vynre4D.js} +2 -2
- package/dist/web/client/assets/{workspace-panel-G6yMpKJ8.js → workspace-panel-CPPIznT9.js} +1 -1
- package/dist/web/client/bundle-budget.json +6 -6
- package/dist/web/server/{_tanstack-start-manifest_v-po4woX6g-AUGCOEZ2.js → _tanstack-start-manifest_v-DS_CSIFQ-WB3VTKF3.js} +10 -9
- package/dist/web/server/{artifacts-panel-8GGUCtOd-X5TNKTY2.js → artifacts-panel-CaKrX2XC-R37I4BHF.js} +5 -5
- package/dist/web/server/{chat-command-palette-Dgl5tqWn-72LLEWUD.js → chat-command-palette-7gbqEnm9-6XICQZN7.js} +4 -4
- package/dist/web/server/{chunk-WILCIZYU.js → chunk-BBBS5AS7.js} +2 -2
- package/dist/web/server/{chunk-O4OTWWPF.js → chunk-CNXJN5HN.js} +4 -4
- package/dist/web/server/{chunk-XKKXXG6N.js → chunk-DI7XRK2H.js} +2 -2
- package/dist/web/server/{chunk-BXWAUTTH.js → chunk-DZ2IC3FH.js} +2 -2
- package/dist/web/server/{chunk-7MDZVLIY.js → chunk-EAE2QXRK.js} +1 -1
- package/dist/web/server/{chunk-JUROEEWM.js → chunk-EH4BZ6QM.js} +82 -4
- package/dist/web/server/{chunk-ABBWBBSS.js → chunk-KELEYPVK.js} +4 -4
- package/dist/web/server/{chunk-RNOJACWQ.js → chunk-LXJD6IGW.js} +2 -2
- package/dist/web/server/chunk-M5RSPNYN.js +22 -0
- 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-MIW4LJTV.js → chunk-TWYHHG5N.js} +1 -9
- package/dist/web/server/{chunk-WKV2Z4KO.js → chunk-WHBVQJ4K.js} +2 -2
- package/dist/web/server/{chunk-GGT2ZKDB.js → chunk-YNUWKMNQ.js} +11 -4
- package/dist/web/server/fleet-message-queue-BS-cZ56r-GLZXUKDF.js +152 -0
- package/dist/web/server/{model-selector-list-OYnzNbyu-HBGCNF2L.js → model-selector-list-jBTZc2Mu-OXJOS5NA.js} +3 -3
- package/dist/web/server/{openui-renderer-Cj7kfqyL-EKJ6JTTQ.js → openui-renderer-Biyyjhjn-SJOEKPTJ.js} +4 -4
- package/dist/web/server/{router-Ci1wxI7I-E2AYMNON.js → router-DWALoX_M-I5CBL7FQ.js} +1228 -459
- package/dist/web/server/{routes-CRpm9-Sa-IYK6MUJO.js → routes-BBVirYfL-5WXMOT7M.js} +223 -49
- package/dist/web/server/server.js +2 -2
- package/dist/web/server/{settings-dialog-BvkgNflv-GPJ6COQO.js → settings-dialog-DndPbM-v-RFNXXEAN.js} +890 -567
- package/dist/web/server/{subagent-chat-panel-CMuvW9Sd-M5TEEGQW.js → subagent-chat-panel-C0RpnXav-J7VYO7QY.js} +3 -3
- package/dist/web/server/{subagents-panel-DgfB6_Yy-4INEPE3Y.js → subagents-panel-jDqIn9Nh-YEV6QLUY.js} +3 -3
- package/dist/web/server/{workspace-panel-bpwj-Veu-Q2CEJMN4.js → workspace-panel-CX_Vo6As-EWO6AMPI.js} +3 -3
- package/package.json +1 -1
- package/dist/web/client/assets/chat-yh02zgA7.js +0 -52
- package/dist/web/client/assets/fleet-message-queue-DUz6Hfrf.js +0 -1
- package/dist/web/client/assets/input-group-BFDsCVS9.js +0 -1
- package/dist/web/client/assets/routes-vNkVToAF.js +0 -16
- package/dist/web/client/assets/settings-dialog-B-v4me3Y.js +0 -1
- package/dist/web/server/chunk-QK4CHLVV.js +0 -17
- package/dist/web/server/fleet-message-queue-j0DCU5Xy-5HKBHMPV.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,7 +24,7 @@ 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,
|
|
@@ -36,6 +35,9 @@ import {
|
|
|
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,
|
|
@@ -80,8 +82,9 @@ import {
|
|
|
80
82
|
InputGroup,
|
|
81
83
|
InputGroupAddon,
|
|
82
84
|
InputGroupButton,
|
|
83
|
-
InputGroupInput
|
|
84
|
-
|
|
85
|
+
InputGroupInput,
|
|
86
|
+
Textarea
|
|
87
|
+
} from "./chunk-PIOFZUOU.js";
|
|
85
88
|
import {
|
|
86
89
|
Search
|
|
87
90
|
} from "./chunk-JIULUYHT.js";
|
|
@@ -210,7 +213,9 @@ import {
|
|
|
210
213
|
useRenderElement,
|
|
211
214
|
useStableCallback
|
|
212
215
|
} from "./chunk-C5X6G26O.js";
|
|
213
|
-
import
|
|
216
|
+
import {
|
|
217
|
+
Plug
|
|
218
|
+
} from "./chunk-AHTO6GDS.js";
|
|
214
219
|
import "./chunk-EAJTWMK5.js";
|
|
215
220
|
import "./chunk-HFQZLPU2.js";
|
|
216
221
|
import {
|
|
@@ -223,7 +228,7 @@ import "./chunk-JDCCC7A7.js";
|
|
|
223
228
|
import "./chunk-L547YHC4.js";
|
|
224
229
|
import "./chunk-MLKGABMK.js";
|
|
225
230
|
|
|
226
|
-
// web/app/dist/server/assets/settings-dialog-
|
|
231
|
+
// web/app/dist/server/assets/settings-dialog-DndPbM-v.js
|
|
227
232
|
import * as React$1 from "react";
|
|
228
233
|
import { useCallback as useCallback2, useEffect as useEffect2, useId, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
|
|
229
234
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
@@ -2284,6 +2289,44 @@ function PersonalizationSection({ onThemePreferenceChange, themePreference }) {
|
|
|
2284
2289
|
})]
|
|
2285
2290
|
});
|
|
2286
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
|
+
}
|
|
2287
2330
|
function SettingsPane({ actions, children, description, title }) {
|
|
2288
2331
|
return /* @__PURE__ */ jsxs("div", {
|
|
2289
2332
|
className: "flex flex-col gap-4",
|
|
@@ -2331,393 +2374,11 @@ function SettingsCommitActions({ dirty, disabled: disabled2, onRevert, onSave, s
|
|
|
2331
2374
|
}) : /* @__PURE__ */ jsx(Save, { "data-icon": "inline-start" }), "Commit"]
|
|
2332
2375
|
})] });
|
|
2333
2376
|
}
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
const invalid = isFieldInvalid(value, attemptedSave, required);
|
|
2340
|
-
return /* @__PURE__ */ jsxs(Field, {
|
|
2341
|
-
"data-invalid": invalid || void 0,
|
|
2342
|
-
children: [/* @__PURE__ */ jsx(FieldLabel, {
|
|
2343
|
-
htmlFor: controlId,
|
|
2344
|
-
children: label
|
|
2345
|
-
}), /* @__PURE__ */ jsxs(InputGroup, { children: [
|
|
2346
|
-
/* @__PURE__ */ jsx(InputGroupAddon, {
|
|
2347
|
-
align: "inline-start",
|
|
2348
|
-
children: /* @__PURE__ */ jsx(Lock, {})
|
|
2349
|
-
}),
|
|
2350
|
-
/* @__PURE__ */ jsx(InputGroupInput, {
|
|
2351
|
-
id: controlId,
|
|
2352
|
-
type: showPassword ? "text" : "password",
|
|
2353
|
-
placeholder,
|
|
2354
|
-
value,
|
|
2355
|
-
onChange: (event) => onChange(event.target.value),
|
|
2356
|
-
"aria-label": label,
|
|
2357
|
-
"aria-invalid": invalid || void 0
|
|
2358
|
-
}),
|
|
2359
|
-
/* @__PURE__ */ jsx(InputGroupAddon, {
|
|
2360
|
-
align: "inline-end",
|
|
2361
|
-
children: /* @__PURE__ */ jsx(InputGroupButton, {
|
|
2362
|
-
size: "icon-xs",
|
|
2363
|
-
className: cn(HIT_AREA_EXPAND_CLASS, "transition-[background-color,transform] duration-150 active:scale-[0.96]"),
|
|
2364
|
-
"aria-label": showPassword ? "Hide value" : "Show value",
|
|
2365
|
-
onClick: onToggleVisibility,
|
|
2366
|
-
children: showPassword ? /* @__PURE__ */ jsx(EyeOff, {}) : /* @__PURE__ */ jsx(Eye, {})
|
|
2367
|
-
})
|
|
2368
|
-
})
|
|
2369
|
-
] })]
|
|
2370
|
-
});
|
|
2371
|
-
}
|
|
2372
|
-
function TextCredentialField({ attemptedSave, icon: Icon, inputType = "text", label, onChange, placeholder, required = true, value }) {
|
|
2373
|
-
const controlId = useId();
|
|
2374
|
-
const invalid = isFieldInvalid(value, attemptedSave, required);
|
|
2375
|
-
return /* @__PURE__ */ jsxs(Field, {
|
|
2376
|
-
"data-invalid": invalid || void 0,
|
|
2377
|
-
children: [/* @__PURE__ */ jsx(FieldLabel, {
|
|
2378
|
-
htmlFor: controlId,
|
|
2379
|
-
children: label
|
|
2380
|
-
}), /* @__PURE__ */ jsxs(InputGroup, { children: [/* @__PURE__ */ jsx(InputGroupAddon, {
|
|
2381
|
-
align: "inline-start",
|
|
2382
|
-
children: /* @__PURE__ */ jsx(Icon, {})
|
|
2383
|
-
}), /* @__PURE__ */ jsx(InputGroupInput, {
|
|
2384
|
-
id: controlId,
|
|
2385
|
-
type: inputType,
|
|
2386
|
-
placeholder,
|
|
2387
|
-
value,
|
|
2388
|
-
onChange: (event) => onChange(event.target.value),
|
|
2389
|
-
"aria-label": label,
|
|
2390
|
-
"aria-invalid": invalid || void 0
|
|
2391
|
-
})] })]
|
|
2392
|
-
});
|
|
2393
|
-
}
|
|
2394
|
-
var OPENAI_CHAT_BASE_URL_PLACEHOLDER = "https://opencode.ai/zen/v1";
|
|
2395
|
-
var OPENAI_CHAT_MODEL_PLACEHOLDER = "qwen35-122b-a10b";
|
|
2396
|
-
var OPENAI_CHAT_NAME_PLACEHOLDER = "e.g. OpenCode Zen, Nebius, Groq\u2026";
|
|
2397
|
-
var CUSTOM_MODELS_PLACEHOLDER = "model-a, model-b (comma-separated)";
|
|
2398
|
-
var CUSTOM_PROVIDER_API_OPTIONS = [
|
|
2399
|
-
{
|
|
2400
|
-
value: "openai-completions",
|
|
2401
|
-
label: "OpenAI Chat Completions"
|
|
2402
|
-
},
|
|
2403
|
-
{
|
|
2404
|
-
value: "openai-responses",
|
|
2405
|
-
label: "OpenAI Responses"
|
|
2406
|
-
},
|
|
2407
|
-
{
|
|
2408
|
-
value: "anthropic-messages",
|
|
2409
|
-
label: "Anthropic Messages"
|
|
2410
|
-
},
|
|
2411
|
-
{
|
|
2412
|
-
value: "google-genai",
|
|
2413
|
-
label: "Google Generative AI"
|
|
2414
|
-
}
|
|
2415
|
-
];
|
|
2416
|
-
function ProviderCredentialFields({ attemptedSave, apiKey, api, baseUrl, modelId, models, displayName, isCustom, onApiKeyChange, onApiChange, onBaseUrlChange, onModelIdChange, onModelsChange, onDisplayNameChange, onTogglePassword, openAiChat, placeholder, showPassword }) {
|
|
2417
|
-
const showApiSelector = isCustom && onApiChange;
|
|
2418
|
-
const showMultiModels = isCustom && onModelsChange;
|
|
2419
|
-
return /* @__PURE__ */ jsxs(FieldGroup, {
|
|
2420
|
-
className: "gap-2",
|
|
2421
|
-
children: [
|
|
2422
|
-
(openAiChat || isCustom) && onDisplayNameChange ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
2423
|
-
attemptedSave,
|
|
2424
|
-
icon: Tag,
|
|
2425
|
-
label: "Provider name",
|
|
2426
|
-
placeholder: OPENAI_CHAT_NAME_PLACEHOLDER,
|
|
2427
|
-
value: displayName ?? "",
|
|
2428
|
-
onChange: onDisplayNameChange
|
|
2429
|
-
}) : null,
|
|
2430
|
-
showApiSelector ? /* @__PURE__ */ jsx(ApiSelector, {
|
|
2431
|
-
value: api ?? "openai-completions",
|
|
2432
|
-
onChange: onApiChange
|
|
2433
|
-
}) : null,
|
|
2434
|
-
/* @__PURE__ */ jsx(SecretCredentialField, {
|
|
2435
|
-
attemptedSave,
|
|
2436
|
-
label: "API key",
|
|
2437
|
-
placeholder,
|
|
2438
|
-
value: apiKey,
|
|
2439
|
-
showPassword,
|
|
2440
|
-
onChange: onApiKeyChange,
|
|
2441
|
-
onToggleVisibility: onTogglePassword
|
|
2442
|
-
}),
|
|
2443
|
-
openAiChat || isCustom ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
2444
|
-
attemptedSave,
|
|
2445
|
-
icon: Globe,
|
|
2446
|
-
inputType: "url",
|
|
2447
|
-
label: "Base URL",
|
|
2448
|
-
placeholder: OPENAI_CHAT_BASE_URL_PLACEHOLDER,
|
|
2449
|
-
value: baseUrl,
|
|
2450
|
-
onChange: onBaseUrlChange
|
|
2451
|
-
}) : null,
|
|
2452
|
-
showMultiModels ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
2453
|
-
attemptedSave,
|
|
2454
|
-
icon: Layers,
|
|
2455
|
-
label: "Model ids",
|
|
2456
|
-
placeholder: CUSTOM_MODELS_PLACEHOLDER,
|
|
2457
|
-
value: models ?? "",
|
|
2458
|
-
onChange: onModelsChange
|
|
2459
|
-
}) : null,
|
|
2460
|
-
openAiChat && !showMultiModels ? /* @__PURE__ */ jsx(TextCredentialField, {
|
|
2461
|
-
attemptedSave,
|
|
2462
|
-
icon: Box,
|
|
2463
|
-
label: "Model name",
|
|
2464
|
-
placeholder: OPENAI_CHAT_MODEL_PLACEHOLDER,
|
|
2465
|
-
value: modelId,
|
|
2466
|
-
onChange: onModelIdChange
|
|
2467
|
-
}) : null
|
|
2468
|
-
]
|
|
2469
|
-
});
|
|
2470
|
-
}
|
|
2471
|
-
function ApiSelector({ value, onChange }) {
|
|
2472
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
2473
|
-
className: "flex flex-col gap-1",
|
|
2474
|
-
children: [/* @__PURE__ */ jsx("span", {
|
|
2475
|
-
className: "text-xs font-medium text-muted-foreground",
|
|
2476
|
-
children: "API family"
|
|
2477
|
-
}), /* @__PURE__ */ jsx(Select, {
|
|
2478
|
-
"aria-label": "API family",
|
|
2479
|
-
value,
|
|
2480
|
-
options: CUSTOM_PROVIDER_API_OPTIONS,
|
|
2481
|
-
placeholder: "Select API family",
|
|
2482
|
-
onValueChange: (next) => onChange(next)
|
|
2483
|
-
})]
|
|
2484
|
-
});
|
|
2485
|
-
}
|
|
2486
|
-
function isOAuthProvider(provider) {
|
|
2487
|
-
return provider.authType === "oauth";
|
|
2488
|
-
}
|
|
2489
|
-
function supportsOAuth(provider) {
|
|
2490
|
-
return provider.supportsOAuth === true;
|
|
2491
|
-
}
|
|
2492
|
-
var CUSTOM_PROVIDER_PICKER_ROW = {
|
|
2493
|
-
id: "custom",
|
|
2494
|
-
name: "Custom provider",
|
|
2495
|
-
isConfigured: false,
|
|
2496
|
-
envVarName: "CUSTOM_PROVIDER_API_KEY",
|
|
2497
|
-
displayName: "Custom provider"
|
|
2498
|
-
};
|
|
2499
|
-
function parseCustomProviderModels(raw) {
|
|
2500
|
-
return raw.split(",").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
2501
|
-
}
|
|
2502
|
-
function useProviderCredentialsController({ onRemoveProvider, onUpdateProvider, providers }) {
|
|
2503
|
-
const [editingProvider, setEditingProvider] = useState2(null);
|
|
2504
|
-
const [editingIsNewOccInstance, setEditingIsNewOccInstance] = useState2(false);
|
|
2505
|
-
const [apiKey, setApiKey] = useState2("");
|
|
2506
|
-
const [baseUrl, setBaseUrl] = useState2("");
|
|
2507
|
-
const [modelId, setModelId] = useState2("");
|
|
2508
|
-
const [models, setModels] = useState2("");
|
|
2509
|
-
const [api, setApi] = useState2("openai-completions");
|
|
2510
|
-
const [displayName, setDisplayName] = useState2("");
|
|
2511
|
-
const [showPassword, setShowPassword] = useState2(false);
|
|
2512
|
-
const [attemptedSave, setAttemptedSave] = useState2(false);
|
|
2513
|
-
const [searchQuery, setSearchQuery] = useState2("");
|
|
2514
|
-
const [addPickerOpen, setAddPickerOpen] = useState2(false);
|
|
2515
|
-
const [addPickerQuery, setAddPickerQuery] = useState2("");
|
|
2516
|
-
const [confirmRemoveProvider, setConfirmRemoveProvider] = useState2(null);
|
|
2517
|
-
const credentialProviders = useMemo2(() => {
|
|
2518
|
-
return [...providers.filter((provider) => provider.id !== CUSTOM_PROVIDER_PICKER_ROW.id), CUSTOM_PROVIDER_PICKER_ROW];
|
|
2519
|
-
}, [providers]);
|
|
2520
|
-
const activeProviders = useMemo2(() => credentialProviders.filter((provider) => provider.isConfigured), [credentialProviders]);
|
|
2521
|
-
const unconfiguredProviders = useMemo2(() => credentialProviders.filter((provider) => !provider.isConfigured || provider.id === "openai-chat-completions" && provider.providerFamily === void 0), [credentialProviders]);
|
|
2522
|
-
const filteredActiveProviders = useMemo2(() => {
|
|
2523
|
-
const query = searchQuery.trim().toLowerCase();
|
|
2524
|
-
if (!query) return activeProviders;
|
|
2525
|
-
return activeProviders.filter((provider) => providerMatchesQuery(provider, query));
|
|
2526
|
-
}, [activeProviders, searchQuery]);
|
|
2527
|
-
const filteredPickerAvailable = useMemo2(() => {
|
|
2528
|
-
const query = addPickerQuery.trim().toLowerCase();
|
|
2529
|
-
return unconfiguredProviders.filter((provider) => providerMatchesQuery(provider, query));
|
|
2530
|
-
}, [addPickerQuery, unconfiguredProviders]);
|
|
2531
|
-
const filteredPickerConfigured = useMemo2(() => {
|
|
2532
|
-
const query = addPickerQuery.trim().toLowerCase();
|
|
2533
|
-
return activeProviders.filter((provider) => providerMatchesQuery(provider, query));
|
|
2534
|
-
}, [activeProviders, addPickerQuery]);
|
|
2535
|
-
const pickerHasResults = filteredPickerAvailable.length > 0 || filteredPickerConfigured.length > 0;
|
|
2536
|
-
const editingUnconfiguredProvider = editingProvider && !activeProviders.some((provider) => provider.id === editingProvider) ? credentialProviders.find((entry) => entry.id === editingProvider) ?? null : null;
|
|
2537
|
-
const resetEditor = () => {
|
|
2538
|
-
setApiKey("");
|
|
2539
|
-
setBaseUrl("");
|
|
2540
|
-
setModelId("");
|
|
2541
|
-
setModels("");
|
|
2542
|
-
setApi("openai-completions");
|
|
2543
|
-
setDisplayName("");
|
|
2544
|
-
setShowPassword(false);
|
|
2545
|
-
setAttemptedSave(false);
|
|
2546
|
-
};
|
|
2547
|
-
const closeEditor = () => {
|
|
2548
|
-
setEditingProvider(null);
|
|
2549
|
-
setEditingIsNewOccInstance(false);
|
|
2550
|
-
resetEditor();
|
|
2551
|
-
};
|
|
2552
|
-
const openEditor = (providerId, opts) => {
|
|
2553
|
-
setAddPickerOpen(false);
|
|
2554
|
-
setAddPickerQuery("");
|
|
2555
|
-
setEditingProvider(providerId);
|
|
2556
|
-
setEditingIsNewOccInstance(opts?.newOccInstance === true);
|
|
2557
|
-
resetEditor();
|
|
2558
|
-
const existing = providers.find((provider) => provider.id === providerId);
|
|
2559
|
-
setBaseUrl(existing?.baseUrl ?? "");
|
|
2560
|
-
setDisplayName(existing?.displayName ?? (isCustomProviderId(providerId) ? existing?.name ?? "" : ""));
|
|
2561
|
-
setApi(existing?.api ?? "openai-completions");
|
|
2562
|
-
setModels((existing?.modelIds ?? []).join(", "));
|
|
2563
|
-
setModelId(existing?.modelIds?.[0] ?? "");
|
|
2564
|
-
};
|
|
2565
|
-
const openAddPicker = () => {
|
|
2566
|
-
closeEditor();
|
|
2567
|
-
setAddPickerQuery("");
|
|
2568
|
-
setAddPickerOpen(true);
|
|
2569
|
-
};
|
|
2570
|
-
const closeAddPicker = () => {
|
|
2571
|
-
setAddPickerOpen(false);
|
|
2572
|
-
setAddPickerQuery("");
|
|
2573
|
-
};
|
|
2574
|
-
const selectProviderFromPicker = (providerId) => {
|
|
2575
|
-
openEditor(providerId, { newOccInstance: isOccProviderId(providerId) });
|
|
2576
|
-
};
|
|
2577
|
-
const handleSave = async (providerId) => {
|
|
2578
|
-
if (!onUpdateProvider) return;
|
|
2579
|
-
setAttemptedSave(true);
|
|
2580
|
-
const isCustomEditor = providerId === "custom" || isCustomProviderId(providerId);
|
|
2581
|
-
const openAiChat = isOccProviderId(providerId);
|
|
2582
|
-
if (isCustomEditor) {
|
|
2583
|
-
const modelList = parseCustomProviderModels(models);
|
|
2584
|
-
if (!apiKey.trim() || !baseUrl.trim() || !displayName.trim()) return;
|
|
2585
|
-
if (modelList.length === 0) return;
|
|
2586
|
-
try {
|
|
2587
|
-
await onUpdateProvider({
|
|
2588
|
-
providerId,
|
|
2589
|
-
apiKey: apiKey.trim(),
|
|
2590
|
-
baseUrl: baseUrl.trim(),
|
|
2591
|
-
displayName: displayName.trim(),
|
|
2592
|
-
api,
|
|
2593
|
-
models: modelList,
|
|
2594
|
-
...providerId === "custom" ? { createOccInstance: true } : {}
|
|
2595
|
-
});
|
|
2596
|
-
notify.success("Provider credentials applied to your active sessions.");
|
|
2597
|
-
closeEditor();
|
|
2598
|
-
closeAddPicker();
|
|
2599
|
-
} catch (error) {
|
|
2600
|
-
notify.error(error instanceof Error ? error.message : "Failed to update provider");
|
|
2601
|
-
}
|
|
2602
|
-
return;
|
|
2603
|
-
}
|
|
2604
|
-
const isNamedOcc = openAiChat && isNamedOccInstanceId(providerId);
|
|
2605
|
-
const isOccLike = openAiChat && (isNamedOcc || editingIsNewOccInstance);
|
|
2606
|
-
if (!apiKey.trim()) return;
|
|
2607
|
-
if (openAiChat && (!baseUrl.trim() || !modelId.trim())) return;
|
|
2608
|
-
if (isOccLike && !displayName.trim()) return;
|
|
2609
|
-
try {
|
|
2610
|
-
await onUpdateProvider({
|
|
2611
|
-
providerId,
|
|
2612
|
-
apiKey: apiKey.trim(),
|
|
2613
|
-
...openAiChat ? {
|
|
2614
|
-
baseUrl: baseUrl.trim(),
|
|
2615
|
-
modelId: modelId.trim(),
|
|
2616
|
-
...isOccLike ? { displayName: displayName.trim() } : {},
|
|
2617
|
-
...editingIsNewOccInstance ? { createOccInstance: true } : {}
|
|
2618
|
-
} : {}
|
|
2619
|
-
});
|
|
2620
|
-
notify.success("Provider credentials applied to your active sessions.");
|
|
2621
|
-
closeEditor();
|
|
2622
|
-
closeAddPicker();
|
|
2623
|
-
} catch (error) {
|
|
2624
|
-
notify.error(error instanceof Error ? error.message : "Failed to update provider");
|
|
2625
|
-
}
|
|
2626
|
-
};
|
|
2627
|
-
const handleRemove = async (provider) => {
|
|
2628
|
-
if (!onRemoveProvider) return;
|
|
2629
|
-
try {
|
|
2630
|
-
await onRemoveProvider({ providerId: provider.id });
|
|
2631
|
-
if (editingProvider === provider.id) closeEditor();
|
|
2632
|
-
notify.success(`${provider.name} removed from your configured providers.`);
|
|
2633
|
-
setConfirmRemoveProvider(null);
|
|
2634
|
-
} catch (error) {
|
|
2635
|
-
notify.error(error instanceof Error ? error.message : "Failed to remove provider");
|
|
2636
|
-
}
|
|
2637
|
-
};
|
|
2638
|
-
return {
|
|
2639
|
-
activeProviders,
|
|
2640
|
-
addPickerOpen,
|
|
2641
|
-
addPickerQuery,
|
|
2642
|
-
api,
|
|
2643
|
-
apiKey,
|
|
2644
|
-
attemptedSave,
|
|
2645
|
-
baseUrl,
|
|
2646
|
-
canSave: useMemo2(() => {
|
|
2647
|
-
if (apiKey.trim().length === 0) return false;
|
|
2648
|
-
if (!editingProvider) return true;
|
|
2649
|
-
if (editingProvider === "custom" || isCustomProviderId(editingProvider)) {
|
|
2650
|
-
if (baseUrl.trim().length === 0) return false;
|
|
2651
|
-
if (parseCustomProviderModels(models).length === 0) return false;
|
|
2652
|
-
return displayName.trim().length > 0;
|
|
2653
|
-
}
|
|
2654
|
-
if (!isOccProviderId(editingProvider)) return true;
|
|
2655
|
-
if (baseUrl.trim().length === 0 || modelId.trim().length === 0) return false;
|
|
2656
|
-
if (isNamedOccInstanceId(editingProvider) || editingIsNewOccInstance) return displayName.trim().length > 0;
|
|
2657
|
-
return true;
|
|
2658
|
-
}, [
|
|
2659
|
-
apiKey,
|
|
2660
|
-
baseUrl,
|
|
2661
|
-
modelId,
|
|
2662
|
-
models,
|
|
2663
|
-
displayName,
|
|
2664
|
-
editingProvider,
|
|
2665
|
-
editingIsNewOccInstance
|
|
2666
|
-
]),
|
|
2667
|
-
closeAddPicker,
|
|
2668
|
-
closeEditor,
|
|
2669
|
-
confirmRemoveProvider,
|
|
2670
|
-
credentialProviders,
|
|
2671
|
-
displayName,
|
|
2672
|
-
editingIsNewOccInstance,
|
|
2673
|
-
editingProvider,
|
|
2674
|
-
editingUnconfiguredProvider,
|
|
2675
|
-
filteredActiveProviders,
|
|
2676
|
-
filteredPickerAvailable,
|
|
2677
|
-
filteredPickerConfigured,
|
|
2678
|
-
handleRemove,
|
|
2679
|
-
handleSave,
|
|
2680
|
-
modelId,
|
|
2681
|
-
models,
|
|
2682
|
-
openAddPicker,
|
|
2683
|
-
openEditor,
|
|
2684
|
-
pickerHasResults,
|
|
2685
|
-
resetEditor,
|
|
2686
|
-
searchQuery,
|
|
2687
|
-
selectProviderFromPicker,
|
|
2688
|
-
setAddPickerOpen,
|
|
2689
|
-
setAddPickerQuery,
|
|
2690
|
-
setApi,
|
|
2691
|
-
setApiKey,
|
|
2692
|
-
setAttemptedSave,
|
|
2693
|
-
setBaseUrl,
|
|
2694
|
-
setConfirmRemoveProvider,
|
|
2695
|
-
setDisplayName,
|
|
2696
|
-
setEditingIsNewOccInstance,
|
|
2697
|
-
setEditingProvider,
|
|
2698
|
-
setModelId,
|
|
2699
|
-
setModels,
|
|
2700
|
-
setSearchQuery,
|
|
2701
|
-
setShowPassword,
|
|
2702
|
-
showPassword,
|
|
2703
|
-
unconfiguredProviders
|
|
2704
|
-
};
|
|
2705
|
-
}
|
|
2706
|
-
function providerMatchesQuery(provider, query) {
|
|
2707
|
-
if (!query) return true;
|
|
2708
|
-
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" : "";
|
|
2709
|
-
return [
|
|
2710
|
-
provider.name,
|
|
2711
|
-
provider.envVarName,
|
|
2712
|
-
provider.id,
|
|
2713
|
-
keywords
|
|
2714
|
-
].join(" ").toLowerCase().includes(query);
|
|
2715
|
-
}
|
|
2716
|
-
var OAUTH_POLL_MS = 1500;
|
|
2717
|
-
var STALE_LOGIN_ERROR = "Unknown or expired OAuth login";
|
|
2718
|
-
function delay(ms) {
|
|
2719
|
-
return new Promise((resolve) => {
|
|
2720
|
-
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);
|
|
2721
2382
|
});
|
|
2722
2383
|
}
|
|
2723
2384
|
function useOAuthLoginFlow({ onConfigured, onOAuthLogin, providerId }) {
|
|
@@ -2887,141 +2548,819 @@ function useOAuthLoginFlow({ onConfigured, onOAuthLogin, providerId }) {
|
|
|
2887
2548
|
login?.status
|
|
2888
2549
|
]);
|
|
2889
2550
|
return {
|
|
2890
|
-
busy,
|
|
2891
|
-
cancel,
|
|
2892
|
-
canStart: Boolean(onOAuthLogin),
|
|
2893
|
-
login,
|
|
2894
|
-
promptAnswer,
|
|
2895
|
-
setPromptAnswer,
|
|
2896
|
-
start,
|
|
2897
|
-
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
|
|
2898
3353
|
};
|
|
2899
3354
|
}
|
|
2900
|
-
function
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
const userCode = waiting ? login?.userCode : void 0;
|
|
2910
|
-
const instructions = waiting ? login?.instructions : void 0;
|
|
2911
|
-
const prompt = waiting ? login?.prompt : void 0;
|
|
2912
|
-
const oauthOnly = provider.authType === "oauth";
|
|
2913
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
2914
|
-
className: "flex flex-col gap-3",
|
|
2915
|
-
children: [provider.isConfigured && oauthOnly && !waiting ? /* @__PURE__ */ jsxs("div", {
|
|
2916
|
-
className: "flex items-center gap-2 text-sm",
|
|
2917
|
-
children: [/* @__PURE__ */ jsx(Check, { className: "size-3.5 text-muted-foreground" }), /* @__PURE__ */ jsx("span", { children: "Connected" })]
|
|
2918
|
-
}) : null, waiting ? /* @__PURE__ */ jsxs("div", {
|
|
2919
|
-
className: "flex flex-col gap-2",
|
|
2920
|
-
children: [
|
|
2921
|
-
/* @__PURE__ */ jsxs("p", {
|
|
2922
|
-
className: "text-sm",
|
|
2923
|
-
children: [
|
|
2924
|
-
"Sign in with ",
|
|
2925
|
-
provider.name,
|
|
2926
|
-
" to store OAuth credentials for this account."
|
|
2927
|
-
]
|
|
2928
|
-
}),
|
|
2929
|
-
userCode ? /* @__PURE__ */ jsxs("p", {
|
|
2930
|
-
className: "text-sm",
|
|
2931
|
-
children: [
|
|
2932
|
-
"Enter this code:",
|
|
2933
|
-
" ",
|
|
2934
|
-
/* @__PURE__ */ jsx("span", {
|
|
2935
|
-
className: "font-mono text-foreground",
|
|
2936
|
-
children: userCode
|
|
2937
|
-
})
|
|
2938
|
-
]
|
|
2939
|
-
}) : null,
|
|
2940
|
-
instructions && !userCode ? /* @__PURE__ */ jsx("p", {
|
|
2941
|
-
className: "text-xs text-pretty text-muted-foreground",
|
|
2942
|
-
children: instructions
|
|
2943
|
-
}) : null,
|
|
2944
|
-
authUrl ? /* @__PURE__ */ jsxs(Button, {
|
|
2945
|
-
type: "button",
|
|
2946
|
-
size: "sm",
|
|
2947
|
-
onClick: () => {
|
|
2948
|
-
window.open(authUrl, "_blank", "noopener,noreferrer");
|
|
2949
|
-
},
|
|
2950
|
-
children: [/* @__PURE__ */ jsx(ExternalLink, { "data-icon": "inline-start" }), "Open sign-in page"]
|
|
2951
|
-
}) : prompt ? null : /* @__PURE__ */ jsxs("div", {
|
|
2952
|
-
className: "flex items-center gap-2 text-xs text-muted-foreground",
|
|
2953
|
-
children: [/* @__PURE__ */ jsx(Spinner, { className: "size-3" }), "Waiting for sign-in\u2026"]
|
|
2954
|
-
}),
|
|
2955
|
-
prompt ? /* @__PURE__ */ jsxs("div", {
|
|
2956
|
-
className: "flex flex-col gap-2",
|
|
2957
|
-
children: [
|
|
2958
|
-
/* @__PURE__ */ jsx("p", {
|
|
2959
|
-
className: "text-xs text-pretty text-muted-foreground",
|
|
2960
|
-
children: prompt.message
|
|
2961
|
-
}),
|
|
2962
|
-
/* @__PURE__ */ jsx(Input, {
|
|
2963
|
-
value: promptAnswer,
|
|
2964
|
-
placeholder: prompt.placeholder,
|
|
2965
|
-
onChange: (event) => setPromptAnswer(event.target.value),
|
|
2966
|
-
"aria-label": prompt.message
|
|
2967
|
-
}),
|
|
2968
|
-
/* @__PURE__ */ jsx("div", {
|
|
2969
|
-
className: "flex justify-end",
|
|
2970
|
-
children: /* @__PURE__ */ jsxs(Button, {
|
|
2971
|
-
type: "button",
|
|
2972
|
-
size: "sm",
|
|
2973
|
-
disabled: busy || !prompt.allowEmpty && !promptAnswer.trim(),
|
|
2974
|
-
onClick: () => {
|
|
2975
|
-
submitPrompt();
|
|
2976
|
-
},
|
|
2977
|
-
children: [busy ? /* @__PURE__ */ jsx(Spinner, { "data-icon": "inline-start" }) : null, "Continue"]
|
|
2978
|
-
})
|
|
2979
|
-
})
|
|
2980
|
-
]
|
|
2981
|
-
}) : null,
|
|
2982
|
-
/* @__PURE__ */ jsx("div", {
|
|
2983
|
-
className: "flex justify-end",
|
|
2984
|
-
children: /* @__PURE__ */ jsx(Button, {
|
|
2985
|
-
type: "button",
|
|
2986
|
-
variant: "ghost",
|
|
2987
|
-
size: "sm",
|
|
2988
|
-
disabled: busy,
|
|
2989
|
-
onClick: () => {
|
|
2990
|
-
cancel();
|
|
2991
|
-
},
|
|
2992
|
-
children: "Cancel sign-in"
|
|
2993
|
-
})
|
|
2994
|
-
})
|
|
2995
|
-
]
|
|
2996
|
-
}) : /* @__PURE__ */ jsxs("div", {
|
|
2997
|
-
className: "flex flex-col gap-2",
|
|
2998
|
-
children: [error ? /* @__PURE__ */ jsx(Alert, {
|
|
2999
|
-
className: "px-3 py-2",
|
|
3000
|
-
children: /* @__PURE__ */ jsx(AlertDescription, {
|
|
3001
|
-
className: "text-xs text-pretty",
|
|
3002
|
-
children: error
|
|
3003
|
-
})
|
|
3004
|
-
}) : /* @__PURE__ */ jsx("p", {
|
|
3005
|
-
className: "text-xs text-pretty text-muted-foreground",
|
|
3006
|
-
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.`
|
|
3007
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
3008
|
-
className: "flex justify-end",
|
|
3009
|
-
children: /* @__PURE__ */ jsxs(Button, {
|
|
3010
|
-
type: "button",
|
|
3011
|
-
size: "sm",
|
|
3012
|
-
disabled: busy || !canStart,
|
|
3013
|
-
onClick: () => {
|
|
3014
|
-
start();
|
|
3015
|
-
},
|
|
3016
|
-
children: [
|
|
3017
|
-
busy ? /* @__PURE__ */ jsx(Spinner, { "data-icon": "inline-start" }) : null,
|
|
3018
|
-
"Sign in with ",
|
|
3019
|
-
provider.name
|
|
3020
|
-
]
|
|
3021
|
-
})
|
|
3022
|
-
})]
|
|
3023
|
-
})]
|
|
3024
|
-
});
|
|
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);
|
|
3025
3364
|
}
|
|
3026
3365
|
function AddProviderPickerPanel({ addPickerQuery, credentialProvidersLength, filteredPickerAvailable, filteredPickerConfigured, pickerHasResults, onClose, onQueryChange, onSelect }) {
|
|
3027
3366
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -3251,44 +3590,6 @@ function ProviderPickerRow({ configured, onSelect, provider }) {
|
|
|
3251
3590
|
})]
|
|
3252
3591
|
});
|
|
3253
3592
|
}
|
|
3254
|
-
function RowSurface({ className, interactive, padding, tone, ...props }) {
|
|
3255
|
-
return /* @__PURE__ */ jsx("div", {
|
|
3256
|
-
className: cn(fleetPiRowSurface({
|
|
3257
|
-
interactive,
|
|
3258
|
-
padding,
|
|
3259
|
-
tone
|
|
3260
|
-
}), className),
|
|
3261
|
-
...props
|
|
3262
|
-
});
|
|
3263
|
-
}
|
|
3264
|
-
function ItemRow({ icon, title, subtitle, trailing, className, interactive = true, tone = "default" }) {
|
|
3265
|
-
return /* @__PURE__ */ jsxs(RowSurface, {
|
|
3266
|
-
tone,
|
|
3267
|
-
padding: "md",
|
|
3268
|
-
interactive,
|
|
3269
|
-
className: cn("items-center gap-3", className),
|
|
3270
|
-
children: [
|
|
3271
|
-
icon ? /* @__PURE__ */ jsx("div", {
|
|
3272
|
-
className: "flex size-8 shrink-0 items-center justify-center rounded-md border border-border/40 bg-background/60 text-foreground/70",
|
|
3273
|
-
children: icon
|
|
3274
|
-
}) : null,
|
|
3275
|
-
/* @__PURE__ */ jsxs("div", {
|
|
3276
|
-
className: "min-w-0 flex-1",
|
|
3277
|
-
children: [/* @__PURE__ */ jsx("div", {
|
|
3278
|
-
className: "truncate text-sm font-medium text-foreground",
|
|
3279
|
-
children: title
|
|
3280
|
-
}), subtitle ? /* @__PURE__ */ jsx("div", {
|
|
3281
|
-
className: "mt-0.5 truncate text-xs text-muted-foreground",
|
|
3282
|
-
children: subtitle
|
|
3283
|
-
}) : null]
|
|
3284
|
-
}),
|
|
3285
|
-
trailing ? /* @__PURE__ */ jsx("div", {
|
|
3286
|
-
className: "flex shrink-0 items-center gap-1.5",
|
|
3287
|
-
children: trailing
|
|
3288
|
-
}) : null
|
|
3289
|
-
]
|
|
3290
|
-
});
|
|
3291
|
-
}
|
|
3292
3593
|
function ActiveProviderList({ providers, editingProvider, form, operation, actions, onEdit, onCancelEdit, onSave, onRemove, onOAuthLogin, onConfigured }) {
|
|
3293
3594
|
const { api, apiKey, baseUrl, modelId, models, displayName, showPassword, attemptedSave, canSave } = form;
|
|
3294
3595
|
const { isPending, canRemove } = operation;
|
|
@@ -4679,6 +4980,14 @@ var SETTINGS_SECTION_REGISTRY = {
|
|
|
4679
4980
|
icon: MessageSquare,
|
|
4680
4981
|
group: "workspace"
|
|
4681
4982
|
},
|
|
4983
|
+
mcp: {
|
|
4984
|
+
id: "mcp",
|
|
4985
|
+
order: 25,
|
|
4986
|
+
title: "MCP",
|
|
4987
|
+
ariaLabel: "MCP connection settings",
|
|
4988
|
+
icon: Plug,
|
|
4989
|
+
group: "workspace"
|
|
4990
|
+
},
|
|
4682
4991
|
sandbox: {
|
|
4683
4992
|
id: "sandbox",
|
|
4684
4993
|
order: 30,
|
|
@@ -4768,7 +5077,7 @@ function PreferenceRow({ children, description, label }) {
|
|
|
4768
5077
|
});
|
|
4769
5078
|
}
|
|
4770
5079
|
function useSettingsForm() {
|
|
4771
|
-
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();
|
|
4772
5081
|
const { models, resources } = useChatPanelDataContext();
|
|
4773
5082
|
const [draft, setDraft] = useState2(null);
|
|
4774
5083
|
const [savingSection, setSavingSection] = useState2(null);
|
|
@@ -4832,11 +5141,17 @@ function useSettingsForm() {
|
|
|
4832
5141
|
return "close";
|
|
4833
5142
|
};
|
|
4834
5143
|
return {
|
|
5144
|
+
isLoadingMcp,
|
|
4835
5145
|
isLoadingProviders,
|
|
5146
|
+
isUpdatingMcp,
|
|
4836
5147
|
isUpdatingProvider,
|
|
4837
|
-
|
|
5148
|
+
mcpConnections,
|
|
5149
|
+
onMcpOAuth,
|
|
4838
5150
|
onOAuthLogin,
|
|
5151
|
+
onRemoveMcp,
|
|
4839
5152
|
onRemoveProvider,
|
|
5153
|
+
onThemePreferenceChange,
|
|
5154
|
+
onUpdateMcp,
|
|
4840
5155
|
onUpdateProvider,
|
|
4841
5156
|
providers,
|
|
4842
5157
|
resources,
|
|
@@ -4907,7 +5222,7 @@ function SettingsDialogSession({ initialTab, onOpenChange, open }) {
|
|
|
4907
5222
|
});
|
|
4908
5223
|
}
|
|
4909
5224
|
function SettingsDialogPaneContent({ activeTab, form, preferences, updatePreference }) {
|
|
4910
|
-
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;
|
|
4911
5226
|
const resourcesPane = (scope) => /* @__PURE__ */ jsx(ResourcesSection, {
|
|
4912
5227
|
scope,
|
|
4913
5228
|
draft,
|
|
@@ -5017,6 +5332,14 @@ function SettingsDialogPaneContent({ activeTab, form, preferences, updatePrefere
|
|
|
5017
5332
|
})
|
|
5018
5333
|
})]
|
|
5019
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
|
+
}),
|
|
5020
5343
|
sandbox: () => /* @__PURE__ */ jsx(SandboxProviderSection, {
|
|
5021
5344
|
isLoading: isLoadingProviders ?? false,
|
|
5022
5345
|
isPending: isUpdatingProvider ?? false,
|