@uniqueli/openwork 0.2.4 → 0.4.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/README.md +152 -7
- package/out/main/index.js +6645 -1166
- package/out/preload/index.js +41 -0
- package/out/renderer/assets/{index-B2t12qbx.css → index-BUG0lOAH.css} +64 -0
- package/out/renderer/assets/{index-Be3u7LN6.js → index-CloINEXy.js} +818 -57
- package/out/renderer/index.html +2 -2
- package/package.json +3 -1
|
@@ -12813,10 +12813,20 @@ const Pencil = createLucideIcon("Pencil", [
|
|
|
12813
12813
|
],
|
|
12814
12814
|
["path", { d: "m15 5 4 4", key: "1mk7zo" }]
|
|
12815
12815
|
]);
|
|
12816
|
+
const Plug = createLucideIcon("Plug", [
|
|
12817
|
+
["path", { d: "M12 22v-5", key: "1ega77" }],
|
|
12818
|
+
["path", { d: "M9 8V2", key: "14iosj" }],
|
|
12819
|
+
["path", { d: "M15 8V2", key: "18g5xt" }],
|
|
12820
|
+
["path", { d: "M18 8v5a4 4 0 0 1-4 4h-4a4 4 0 0 1-4-4V8Z", key: "osxo6l" }]
|
|
12821
|
+
]);
|
|
12816
12822
|
const Plus = createLucideIcon("Plus", [
|
|
12817
12823
|
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
12818
12824
|
["path", { d: "M12 5v14", key: "s699le" }]
|
|
12819
12825
|
]);
|
|
12826
|
+
const Power = createLucideIcon("Power", [
|
|
12827
|
+
["path", { d: "M12 2v10", key: "mnfbl" }],
|
|
12828
|
+
["path", { d: "M18.4 6.6a9 9 0 1 1-12.77.04", key: "obofu9" }]
|
|
12829
|
+
]);
|
|
12820
12830
|
const RotateCw = createLucideIcon("RotateCw", [
|
|
12821
12831
|
["path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8", key: "1p45f6" }],
|
|
12822
12832
|
["path", { d: "M21 3v5h-5", key: "1q7to0" }]
|
|
@@ -17995,6 +18005,13 @@ function convertToV1FromResponses(message) {
|
|
|
17995
18005
|
};
|
|
17996
18006
|
continue;
|
|
17997
18007
|
} else if (_isContentBlock(toolOutput, "image_generation_call")) {
|
|
18008
|
+
if (_isString(toolOutput.result)) yield {
|
|
18009
|
+
type: "image",
|
|
18010
|
+
mimeType: "image/png",
|
|
18011
|
+
data: toolOutput.result,
|
|
18012
|
+
id: _isString(toolOutput.id) ? toolOutput.id : void 0,
|
|
18013
|
+
metadata: { status: _isString(toolOutput.status) ? toolOutput.status : void 0 }
|
|
18014
|
+
};
|
|
17998
18015
|
yield {
|
|
17999
18016
|
type: "non_standard",
|
|
18000
18017
|
value: toolOutput
|
|
@@ -18238,8 +18255,8 @@ const DEFAULT_MERGE_IGNORE_KEYS = [
|
|
|
18238
18255
|
];
|
|
18239
18256
|
function _mergeDicts(left, right, options) {
|
|
18240
18257
|
const ignoreKeys = options?.ignoreKeys ?? DEFAULT_MERGE_IGNORE_KEYS;
|
|
18241
|
-
if (left
|
|
18242
|
-
if (left
|
|
18258
|
+
if (left == null && right == null) return void 0;
|
|
18259
|
+
if (left == null || right == null) return left ?? right;
|
|
18243
18260
|
const merged = { ...left };
|
|
18244
18261
|
for (const [key2, value] of Object.entries(right)) if (merged[key2] == null) merged[key2] = value;
|
|
18245
18262
|
else if (value == null) continue;
|
|
@@ -18264,8 +18281,8 @@ function _mergeDicts(left, right, options) {
|
|
|
18264
18281
|
return merged;
|
|
18265
18282
|
}
|
|
18266
18283
|
function _mergeLists(left, right, options) {
|
|
18267
|
-
if (left
|
|
18268
|
-
else if (left
|
|
18284
|
+
if (left == null && right == null) return void 0;
|
|
18285
|
+
else if (left == null || right == null) return left || right;
|
|
18269
18286
|
else {
|
|
18270
18287
|
const merged = [...left];
|
|
18271
18288
|
for (const item of right) if (typeof item === "object" && item !== null && "index" in item && typeof item.index === "number") {
|
|
@@ -18284,8 +18301,8 @@ function _mergeLists(left, right, options) {
|
|
|
18284
18301
|
}
|
|
18285
18302
|
}
|
|
18286
18303
|
function _mergeObj(left, right, options) {
|
|
18287
|
-
if (left
|
|
18288
|
-
if (left
|
|
18304
|
+
if (left == null && right == null) return void 0;
|
|
18305
|
+
if (left == null || right == null) return left ?? right;
|
|
18289
18306
|
else if (typeof left !== typeof right) throw new Error(`Cannot merge objects of different types.
|
|
18290
18307
|
Left ${typeof left}
|
|
18291
18308
|
Right ${typeof right}`);
|
|
@@ -30375,7 +30392,7 @@ var CallbackManager = class CallbackManager2 extends BaseCallbackManager {
|
|
|
30375
30392
|
callbackManager = callbackManager.copy(Array.isArray(localHandlers) ? localHandlers.map(ensureHandler) : localHandlers?.handlers, false);
|
|
30376
30393
|
}
|
|
30377
30394
|
const verboseEnabled = getEnvironmentVariable$2("LANGCHAIN_VERBOSE") === "true" || options?.verbose;
|
|
30378
|
-
const tracingV2Enabled = LangChainTracer.getTraceableRunTree()?.tracingEnabled
|
|
30395
|
+
const tracingV2Enabled = LangChainTracer.getTraceableRunTree()?.tracingEnabled ?? isTracingEnabled();
|
|
30379
30396
|
const tracingEnabled = tracingV2Enabled || (getEnvironmentVariable$2("LANGCHAIN_TRACING") ?? false);
|
|
30380
30397
|
if (verboseEnabled || tracingEnabled) {
|
|
30381
30398
|
if (!callbackManager) callbackManager = new CallbackManager2();
|
|
@@ -31950,7 +31967,9 @@ const defaultFailedAttemptHandler = (error) => {
|
|
|
31950
31967
|
if (typeof error !== "object" || error === null) return;
|
|
31951
31968
|
if ("message" in error && typeof error.message === "string" && (error.message.startsWith("Cancel") || error.message.startsWith("AbortError")) || "name" in error && typeof error.name === "string" && error.name === "AbortError") throw error;
|
|
31952
31969
|
if ("code" in error && typeof error.code === "string" && error.code === "ECONNABORTED") throw error;
|
|
31953
|
-
const
|
|
31970
|
+
const responseStatus = "response" in error && typeof error.response === "object" && error.response !== null && "status" in error.response && typeof error.response.status === "number" ? error.response.status : void 0;
|
|
31971
|
+
const directStatus = "status" in error && typeof error.status === "number" ? error.status : void 0;
|
|
31972
|
+
const status = responseStatus ?? directStatus;
|
|
31954
31973
|
if (status && STATUS_NO_RETRY$1.includes(+status)) throw error;
|
|
31955
31974
|
const code2 = "error" in error && typeof error.error === "object" && error.error !== null && "code" in error.error && typeof error.error.code === "string" ? error.error.code : void 0;
|
|
31956
31975
|
if (code2 === "insufficient_quota") {
|
|
@@ -41351,14 +41370,15 @@ var StreamManager = class {
|
|
|
41351
41370
|
};
|
|
41352
41371
|
getMutateFn = (kind, historyValues) => {
|
|
41353
41372
|
return (update) => {
|
|
41373
|
+
const stateValues = (this.state.values ?? [null, "stream"])[0];
|
|
41354
41374
|
const prev = {
|
|
41355
41375
|
...historyValues,
|
|
41356
|
-
...
|
|
41376
|
+
...stateValues ?? {}
|
|
41357
41377
|
};
|
|
41358
41378
|
const next = typeof update === "function" ? update(prev) : update;
|
|
41359
41379
|
this.setStreamValues({
|
|
41360
41380
|
...prev,
|
|
41361
|
-
...next
|
|
41381
|
+
...next ?? {}
|
|
41362
41382
|
}, kind);
|
|
41363
41383
|
};
|
|
41364
41384
|
};
|
|
@@ -41395,8 +41415,8 @@ var StreamManager = class {
|
|
|
41395
41415
|
if (this.matchEventType("checkpoints", event, data)) options.callbacks.onCheckpointEvent?.(data, { namespace });
|
|
41396
41416
|
if (this.matchEventType("tasks", event, data)) options.callbacks.onTaskEvent?.(data, { namespace });
|
|
41397
41417
|
if (this.matchEventType("debug", event, data)) options.callbacks.onDebugEvent?.(data, { namespace });
|
|
41398
|
-
if (event === "values") if ("__interrupt__" in data) this.setStreamValues((prev) => ({
|
|
41399
|
-
...prev,
|
|
41418
|
+
if (event === "values") if (data != null && typeof data === "object" && "__interrupt__" in data) this.setStreamValues((prev) => ({
|
|
41419
|
+
...prev ?? {},
|
|
41400
41420
|
...data
|
|
41401
41421
|
}));
|
|
41402
41422
|
else this.setStreamValues(data);
|
|
@@ -41410,7 +41430,7 @@ var StreamManager = class {
|
|
|
41410
41430
|
this.setStreamValues((streamValues) => {
|
|
41411
41431
|
const values$1 = {
|
|
41412
41432
|
...options.initialValues,
|
|
41413
|
-
...streamValues
|
|
41433
|
+
...streamValues ?? {}
|
|
41414
41434
|
};
|
|
41415
41435
|
let messages = options.getMessages(values$1).slice();
|
|
41416
41436
|
const { chunk, index: index2 } = this.messages.get(messageId, messages.length) ?? {};
|
|
@@ -42976,7 +42996,7 @@ var BaseClient = class {
|
|
|
42976
42996
|
const [url, init] = this.prepareFetchOptions(path2, options);
|
|
42977
42997
|
let finalInit = init;
|
|
42978
42998
|
if (this.onRequest) finalInit = await this.onRequest(url, init);
|
|
42979
|
-
const response = await this.asyncCaller.fetch(url, finalInit);
|
|
42999
|
+
const response = await this.asyncCaller.fetch(url.toString(), finalInit);
|
|
42980
43000
|
const body2 = (() => {
|
|
42981
43001
|
if (response.status === 202 || response.status === 204) return;
|
|
42982
43002
|
return response.json();
|
|
@@ -43006,7 +43026,7 @@ var BaseClient = class {
|
|
|
43006
43026
|
json: isReconnect ? void 0 : config2.json
|
|
43007
43027
|
});
|
|
43008
43028
|
if (this.onRequest != null) init = await this.onRequest(url, init);
|
|
43009
|
-
const response = await this.asyncCaller.fetch(url, init);
|
|
43029
|
+
const response = await this.asyncCaller.fetch(url.toString(), init);
|
|
43010
43030
|
if (!isReconnect && config2.onInitialResponse) await config2.onInitialResponse(response);
|
|
43011
43031
|
return {
|
|
43012
43032
|
response,
|
|
@@ -43973,7 +43993,7 @@ var UiClient = class UiClient2 extends BaseClient {
|
|
|
43973
43993
|
json: { name: agentName }
|
|
43974
43994
|
});
|
|
43975
43995
|
if (this.onRequest != null) init = await this.onRequest(url, init);
|
|
43976
|
-
return (await this.asyncCaller.fetch(url, init)).text();
|
|
43996
|
+
return (await this.asyncCaller.fetch(url.toString(), init)).text();
|
|
43977
43997
|
});
|
|
43978
43998
|
}
|
|
43979
43999
|
};
|
|
@@ -44038,6 +44058,13 @@ function unique(array) {
|
|
|
44038
44058
|
function findLast(array, predicate) {
|
|
44039
44059
|
for (let i2 = array.length - 1; i2 >= 0; i2 -= 1) if (predicate(array[i2])) return array[i2];
|
|
44040
44060
|
}
|
|
44061
|
+
async function* filterStream(stream, filter) {
|
|
44062
|
+
while (true) {
|
|
44063
|
+
const { value, done } = await stream.next();
|
|
44064
|
+
if (done) return value;
|
|
44065
|
+
if (filter(value)) yield value;
|
|
44066
|
+
}
|
|
44067
|
+
}
|
|
44041
44068
|
function getBranchSequence(history) {
|
|
44042
44069
|
const nodeIds = /* @__PURE__ */ new Set();
|
|
44043
44070
|
const childrenMap = {};
|
|
@@ -44497,11 +44524,12 @@ function useStreamLGP(options) {
|
|
|
44497
44524
|
};
|
|
44498
44525
|
await stream.start(async (signal) => {
|
|
44499
44526
|
threadIdStreamingRef.current = threadId;
|
|
44500
|
-
|
|
44527
|
+
const stream$1 = client2.runs.joinStream(threadId, runId, {
|
|
44501
44528
|
signal,
|
|
44502
44529
|
lastEventId,
|
|
44503
44530
|
streamMode: joinOptions?.streamMode
|
|
44504
44531
|
});
|
|
44532
|
+
return joinOptions?.filter != null ? filterStream(stream$1, joinOptions.filter) : stream$1;
|
|
44505
44533
|
}, {
|
|
44506
44534
|
getMessages,
|
|
44507
44535
|
setMessages,
|
|
@@ -76278,7 +76306,14 @@ function TabbedPanel({ threadId, showTabBar = true }) {
|
|
|
76278
76306
|
) })
|
|
76279
76307
|
] });
|
|
76280
76308
|
}
|
|
76281
|
-
function Switch({
|
|
76309
|
+
function Switch({
|
|
76310
|
+
checked = false,
|
|
76311
|
+
onCheckedChange,
|
|
76312
|
+
disabled = false,
|
|
76313
|
+
className,
|
|
76314
|
+
onClick,
|
|
76315
|
+
...props
|
|
76316
|
+
}) {
|
|
76282
76317
|
const handleClick = (e) => {
|
|
76283
76318
|
onClick?.(e);
|
|
76284
76319
|
if (!disabled) {
|
|
@@ -76611,19 +76646,20 @@ function CreateSkillDialog({ open, onClose, onCreate }) {
|
|
|
76611
76646
|
};
|
|
76612
76647
|
const currentTemplate = SKILL_TEMPLATES.find((t) => t.id === selectedTemplate);
|
|
76613
76648
|
if (!open) return null;
|
|
76614
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full max-w-
|
|
76615
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-white/5", children: [
|
|
76649
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full max-w-2xl bg-[#1A1A1D] rounded-lg shadow-xl border border-white/10 flex flex-col max-h-[90vh]", children: [
|
|
76650
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-white/5 flex-shrink-0", children: [
|
|
76616
76651
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-lg font-semibold text-white", children: "Create Custom Skill" }),
|
|
76617
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
76618
|
-
"
|
|
76652
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-gray-400 hover:text-white transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
76653
|
+
"path",
|
|
76619
76654
|
{
|
|
76620
|
-
|
|
76621
|
-
|
|
76622
|
-
|
|
76655
|
+
strokeLinecap: "round",
|
|
76656
|
+
strokeLinejoin: "round",
|
|
76657
|
+
strokeWidth: 2,
|
|
76658
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
76623
76659
|
}
|
|
76624
|
-
)
|
|
76660
|
+
) }) })
|
|
76625
76661
|
] }),
|
|
76626
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 px-6 py-3 border-b border-white/5", children: [
|
|
76662
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 px-6 py-3 border-b border-white/5 flex-shrink-0", children: [
|
|
76627
76663
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
76628
76664
|
"button",
|
|
76629
76665
|
{
|
|
@@ -76643,7 +76679,7 @@ function CreateSkillDialog({ open, onClose, onCreate }) {
|
|
|
76643
76679
|
}
|
|
76644
76680
|
)
|
|
76645
76681
|
] }),
|
|
76646
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("form", { onSubmit: handleSubmit, className: "p-6 space-y-4", children: [
|
|
76682
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("form", { onSubmit: handleSubmit, className: "p-6 space-y-4 overflow-y-auto flex-1", children: [
|
|
76647
76683
|
mode === "template" && /* Template Selection */
|
|
76648
76684
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
76649
76685
|
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-medium text-gray-300 mb-2", children: "Choose Template" }),
|
|
@@ -76749,7 +76785,7 @@ function CreateSkillDialog({ open, onClose, onCreate }) {
|
|
|
76749
76785
|
),
|
|
76750
76786
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "mt-1 text-xs text-gray-500", children: "This prompt will be loaded when the agent activates this skill, providing specialized knowledge and instructions." })
|
|
76751
76787
|
] }),
|
|
76752
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-3 pt-4 border-t border-white/5", children: [
|
|
76788
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-3 pt-4 border-t border-white/5 flex-shrink-0", children: [
|
|
76753
76789
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
76754
76790
|
"button",
|
|
76755
76791
|
{
|
|
@@ -76780,7 +76816,13 @@ const categoryColors = {
|
|
|
76780
76816
|
system: "bg-orange-500/10 text-orange-500 border-orange-500/20",
|
|
76781
76817
|
custom: "bg-cyan-500/10 text-cyan-500 border-cyan-500/20"
|
|
76782
76818
|
};
|
|
76783
|
-
function SkillDetailDialog({
|
|
76819
|
+
function SkillDetailDialog({
|
|
76820
|
+
skill,
|
|
76821
|
+
open,
|
|
76822
|
+
onClose,
|
|
76823
|
+
onToggle,
|
|
76824
|
+
onDelete
|
|
76825
|
+
}) {
|
|
76784
76826
|
if (!open) return null;
|
|
76785
76827
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full max-w-3xl mx-4 max-h-[80vh] bg-[#1A1A1D] rounded-lg shadow-xl border border-white/10 flex flex-col", children: [
|
|
76786
76828
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-start justify-between px-6 py-4 border-b border-white/5", children: [
|
|
@@ -76803,7 +76845,15 @@ function SkillDetailDialog({ skill, open, onClose, onToggle, onDelete }) {
|
|
|
76803
76845
|
{
|
|
76804
76846
|
onClick: onClose,
|
|
76805
76847
|
className: "ml-4 text-gray-400 hover:text-white transition-colors",
|
|
76806
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
76848
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
76849
|
+
"path",
|
|
76850
|
+
{
|
|
76851
|
+
strokeLinecap: "round",
|
|
76852
|
+
strokeLinejoin: "round",
|
|
76853
|
+
strokeWidth: 2,
|
|
76854
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
76855
|
+
}
|
|
76856
|
+
) })
|
|
76807
76857
|
}
|
|
76808
76858
|
)
|
|
76809
76859
|
] }),
|
|
@@ -77053,6 +77103,639 @@ function SkillsPanel(_props) {
|
|
|
77053
77103
|
)
|
|
77054
77104
|
] });
|
|
77055
77105
|
}
|
|
77106
|
+
const TRANSPORT_TYPES = [
|
|
77107
|
+
{ value: "stdio", label: "STDIO", description: "标准输入/输出 (本地进程)" },
|
|
77108
|
+
{ value: "sse", label: "SSE", description: "服务器发送事件 (HTTP端点)" }
|
|
77109
|
+
];
|
|
77110
|
+
const CATEGORIES = [
|
|
77111
|
+
{ value: "filesystem", label: "文件系统", description: "文件操作工具" },
|
|
77112
|
+
{ value: "database", label: "数据库", description: "数据库访问工具" },
|
|
77113
|
+
{ value: "api", label: "API", description: "外部API集成" },
|
|
77114
|
+
{ value: "development", label: "开发", description: "开发工具" },
|
|
77115
|
+
{ value: "productivity", label: "生产力", description: "生产力工具" },
|
|
77116
|
+
{ value: "custom", label: "自定义", description: "其他工具" }
|
|
77117
|
+
];
|
|
77118
|
+
function CreateMCPServerDialog({ open, onClose, onCreated }) {
|
|
77119
|
+
const [formData, setFormData] = reactExports.useState({
|
|
77120
|
+
id: "",
|
|
77121
|
+
name: "",
|
|
77122
|
+
type: "stdio",
|
|
77123
|
+
command: "",
|
|
77124
|
+
args: "",
|
|
77125
|
+
url: "",
|
|
77126
|
+
description: "",
|
|
77127
|
+
category: "custom",
|
|
77128
|
+
enabled: true,
|
|
77129
|
+
env: {}
|
|
77130
|
+
});
|
|
77131
|
+
const [envVars, setEnvVars] = reactExports.useState([{ key: "", value: "" }]);
|
|
77132
|
+
const [errors, setErrors] = reactExports.useState({});
|
|
77133
|
+
const [testing, setTesting] = reactExports.useState(false);
|
|
77134
|
+
const [testResult, setTestResult] = reactExports.useState(null);
|
|
77135
|
+
const handleEnvVarChange = (index2, field, value) => {
|
|
77136
|
+
const newEnvVars = [...envVars];
|
|
77137
|
+
newEnvVars[index2][field] = value;
|
|
77138
|
+
setEnvVars(newEnvVars);
|
|
77139
|
+
const env2 = {};
|
|
77140
|
+
newEnvVars.forEach((envVar) => {
|
|
77141
|
+
if (envVar.key.trim()) {
|
|
77142
|
+
env2[envVar.key.trim()] = envVar.value;
|
|
77143
|
+
}
|
|
77144
|
+
});
|
|
77145
|
+
setFormData({ ...formData, env: env2 });
|
|
77146
|
+
};
|
|
77147
|
+
const addEnvVar = () => {
|
|
77148
|
+
setEnvVars([...envVars, { key: "", value: "" }]);
|
|
77149
|
+
};
|
|
77150
|
+
const removeEnvVar = (index2) => {
|
|
77151
|
+
const newEnvVars = envVars.filter((_2, i2) => i2 !== index2);
|
|
77152
|
+
setEnvVars(newEnvVars);
|
|
77153
|
+
const env2 = {};
|
|
77154
|
+
newEnvVars.forEach((envVar) => {
|
|
77155
|
+
if (envVar.key.trim()) {
|
|
77156
|
+
env2[envVar.key.trim()] = envVar.value;
|
|
77157
|
+
}
|
|
77158
|
+
});
|
|
77159
|
+
setFormData({ ...formData, env: env2 });
|
|
77160
|
+
};
|
|
77161
|
+
if (!open) return null;
|
|
77162
|
+
const validateForm = () => {
|
|
77163
|
+
const newErrors = {};
|
|
77164
|
+
if (!formData.id.trim()) {
|
|
77165
|
+
newErrors.id = "ID不能为空";
|
|
77166
|
+
} else if (!/^[a-z0-9-]+$/.test(formData.id)) {
|
|
77167
|
+
newErrors.id = "ID只能包含小写字母、数字和连字符";
|
|
77168
|
+
}
|
|
77169
|
+
if (!formData.name.trim()) {
|
|
77170
|
+
newErrors.name = "名称不能为空";
|
|
77171
|
+
}
|
|
77172
|
+
if (formData.type === "stdio" && !formData.command.trim()) {
|
|
77173
|
+
newErrors.command = "STDIO类型需要命令";
|
|
77174
|
+
}
|
|
77175
|
+
if (formData.type === "sse") {
|
|
77176
|
+
try {
|
|
77177
|
+
new URL(formData.url);
|
|
77178
|
+
} catch {
|
|
77179
|
+
newErrors.url = "请输入有效的URL";
|
|
77180
|
+
}
|
|
77181
|
+
}
|
|
77182
|
+
setErrors(newErrors);
|
|
77183
|
+
return Object.keys(newErrors).length === 0;
|
|
77184
|
+
};
|
|
77185
|
+
const handleSubmit = async (e) => {
|
|
77186
|
+
e.preventDefault();
|
|
77187
|
+
if (!validateForm()) return;
|
|
77188
|
+
try {
|
|
77189
|
+
const argsArray = formData.args.split(" ").map((arg) => arg.trim()).filter(Boolean);
|
|
77190
|
+
const result = await window.api.mcp.create({
|
|
77191
|
+
id: formData.id.trim(),
|
|
77192
|
+
name: formData.name.trim(),
|
|
77193
|
+
type: formData.type,
|
|
77194
|
+
command: formData.type === "stdio" ? formData.command.trim() : void 0,
|
|
77195
|
+
args: formData.type === "stdio" && argsArray.length > 0 ? argsArray : void 0,
|
|
77196
|
+
url: formData.type === "sse" ? formData.url.trim() : void 0,
|
|
77197
|
+
description: formData.description.trim() || void 0,
|
|
77198
|
+
category: formData.category,
|
|
77199
|
+
enabled: formData.enabled,
|
|
77200
|
+
env: Object.keys(formData.env).length > 0 ? formData.env : void 0
|
|
77201
|
+
});
|
|
77202
|
+
if (result.success) {
|
|
77203
|
+
onCreated();
|
|
77204
|
+
onClose();
|
|
77205
|
+
} else {
|
|
77206
|
+
setErrors({ id: result.error || "创建失败" });
|
|
77207
|
+
}
|
|
77208
|
+
} catch (error) {
|
|
77209
|
+
console.error("[CreateMCPServerDialog] Create error:", error);
|
|
77210
|
+
setErrors({ id: "创建失败,请重试" });
|
|
77211
|
+
}
|
|
77212
|
+
};
|
|
77213
|
+
const handleTest = async () => {
|
|
77214
|
+
if (formData.type === "stdio" && !formData.command.trim()) {
|
|
77215
|
+
setErrors({ command: "请先输入命令" });
|
|
77216
|
+
return;
|
|
77217
|
+
}
|
|
77218
|
+
if (formData.type === "sse" && !formData.url.trim()) {
|
|
77219
|
+
setErrors({ url: "请先输入URL" });
|
|
77220
|
+
return;
|
|
77221
|
+
}
|
|
77222
|
+
setTesting(true);
|
|
77223
|
+
setTestResult(null);
|
|
77224
|
+
try {
|
|
77225
|
+
const argsArray = formData.args.split(" ").map((arg) => arg.trim()).filter(Boolean);
|
|
77226
|
+
const result = await window.api.mcp.test({
|
|
77227
|
+
type: formData.type,
|
|
77228
|
+
command: formData.type === "stdio" ? formData.command.trim() : void 0,
|
|
77229
|
+
args: formData.type === "stdio" && argsArray.length > 0 ? argsArray : void 0,
|
|
77230
|
+
url: formData.type === "sse" ? formData.url.trim() : void 0,
|
|
77231
|
+
env: Object.keys(formData.env).length > 0 ? formData.env : void 0
|
|
77232
|
+
});
|
|
77233
|
+
setTestResult({
|
|
77234
|
+
success: result.success,
|
|
77235
|
+
message: result.success ? `连接成功!发现 ${result.tools || 0} 个工具` : result.error || "连接失败",
|
|
77236
|
+
tools: result.tools
|
|
77237
|
+
});
|
|
77238
|
+
} catch (error) {
|
|
77239
|
+
setTestResult({
|
|
77240
|
+
success: false,
|
|
77241
|
+
message: error instanceof Error ? error.message : "测试失败"
|
|
77242
|
+
});
|
|
77243
|
+
} finally {
|
|
77244
|
+
setTesting(false);
|
|
77245
|
+
}
|
|
77246
|
+
};
|
|
77247
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "w-full max-w-2xl bg-[#1A1A1D] rounded-lg shadow-xl border border-white/10 flex flex-col max-h-[90vh]", children: [
|
|
77248
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-white/5 flex-shrink-0", children: [
|
|
77249
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-lg font-semibold text-white", children: "添加MCP服务器" }),
|
|
77250
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-gray-400 hover:text-white transition-colors", children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-5 h-5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77251
|
+
"path",
|
|
77252
|
+
{
|
|
77253
|
+
strokeLinecap: "round",
|
|
77254
|
+
strokeLinejoin: "round",
|
|
77255
|
+
strokeWidth: 2,
|
|
77256
|
+
d: "M6 18L18 6M6 6l12 12"
|
|
77257
|
+
}
|
|
77258
|
+
) }) })
|
|
77259
|
+
] }),
|
|
77260
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("form", { onSubmit: handleSubmit, className: "p-6 space-y-4 overflow-y-auto flex-1", children: [
|
|
77261
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
77262
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-sm font-medium text-gray-300 mb-2", children: [
|
|
77263
|
+
"传输类型 ",
|
|
77264
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
|
|
77265
|
+
] }),
|
|
77266
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-2 gap-2", children: TRANSPORT_TYPES.map((type) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
77267
|
+
"button",
|
|
77268
|
+
{
|
|
77269
|
+
type: "button",
|
|
77270
|
+
onClick: () => setFormData({ ...formData, type: type.value }),
|
|
77271
|
+
className: `px-3 py-2 text-left text-sm rounded-md transition-colors ${formData.type === type.value ? "bg-blue-500/20 text-blue-400 border border-blue-500/50" : "bg-white/5 text-gray-400 border border-white/10 hover:bg-white/10"}`,
|
|
77272
|
+
children: [
|
|
77273
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: type.label }),
|
|
77274
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs opacity-75", children: type.description })
|
|
77275
|
+
]
|
|
77276
|
+
},
|
|
77277
|
+
type.value
|
|
77278
|
+
)) })
|
|
77279
|
+
] }),
|
|
77280
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
77281
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-sm font-medium text-gray-300 mb-1", children: [
|
|
77282
|
+
"服务器ID ",
|
|
77283
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
|
|
77284
|
+
] }),
|
|
77285
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77286
|
+
"input",
|
|
77287
|
+
{
|
|
77288
|
+
type: "text",
|
|
77289
|
+
value: formData.id,
|
|
77290
|
+
onChange: (e) => setFormData({ ...formData, id: e.target.value }),
|
|
77291
|
+
placeholder: "例如: filesystem-server",
|
|
77292
|
+
className: "w-full px-3 py-2 text-sm text-white placeholder-gray-500 bg-white/5 border border-white/10 rounded-md focus:outline-none focus:border-blue-500",
|
|
77293
|
+
required: true
|
|
77294
|
+
}
|
|
77295
|
+
),
|
|
77296
|
+
errors.id && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-status-critical mt-1", children: errors.id }),
|
|
77297
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-gray-500 mt-1", children: "唯一标识符,只能包含小写字母、数字和连字符" })
|
|
77298
|
+
] }),
|
|
77299
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
77300
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-sm font-medium text-gray-300 mb-1", children: [
|
|
77301
|
+
"显示名称 ",
|
|
77302
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
|
|
77303
|
+
] }),
|
|
77304
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77305
|
+
"input",
|
|
77306
|
+
{
|
|
77307
|
+
type: "text",
|
|
77308
|
+
value: formData.name,
|
|
77309
|
+
onChange: (e) => setFormData({ ...formData, name: e.target.value }),
|
|
77310
|
+
placeholder: "例如: 文件系统服务器",
|
|
77311
|
+
className: "w-full px-3 py-2 text-sm text-white placeholder-gray-500 bg-white/5 border border-white/10 rounded-md focus:outline-none focus:border-blue-500",
|
|
77312
|
+
required: true
|
|
77313
|
+
}
|
|
77314
|
+
),
|
|
77315
|
+
errors.name && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-status-critical mt-1", children: errors.name })
|
|
77316
|
+
] }),
|
|
77317
|
+
formData.type === "stdio" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
77318
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-sm font-medium text-gray-300 mb-1", children: [
|
|
77319
|
+
"命令 ",
|
|
77320
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
|
|
77321
|
+
] }),
|
|
77322
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77323
|
+
"input",
|
|
77324
|
+
{
|
|
77325
|
+
type: "text",
|
|
77326
|
+
value: formData.command,
|
|
77327
|
+
onChange: (e) => setFormData({ ...formData, command: e.target.value }),
|
|
77328
|
+
placeholder: "例如: npx",
|
|
77329
|
+
className: "w-full px-3 py-2 text-sm text-white placeholder-gray-500 bg-white/5 border border-white/10 rounded-md focus:outline-none focus:border-blue-500",
|
|
77330
|
+
required: formData.type === "stdio"
|
|
77331
|
+
}
|
|
77332
|
+
),
|
|
77333
|
+
errors.command && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-status-critical mt-1", children: errors.command })
|
|
77334
|
+
] }),
|
|
77335
|
+
formData.type === "stdio" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
77336
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-medium text-gray-300 mb-1", children: "命令参数" }),
|
|
77337
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77338
|
+
"input",
|
|
77339
|
+
{
|
|
77340
|
+
type: "text",
|
|
77341
|
+
value: formData.args,
|
|
77342
|
+
onChange: (e) => setFormData({ ...formData, args: e.target.value }),
|
|
77343
|
+
placeholder: "例如: @modelcontextprotocol/server-filesystem /path/to/dir",
|
|
77344
|
+
className: "w-full px-3 py-2 text-sm text-white placeholder-gray-500 bg-white/5 border border-white/10 rounded-md focus:outline-none focus:border-blue-500"
|
|
77345
|
+
}
|
|
77346
|
+
),
|
|
77347
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-gray-500 mt-1", children: "多个参数用空格分隔" })
|
|
77348
|
+
] }),
|
|
77349
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
77350
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-medium text-gray-300 mb-2", children: "环境变量" }),
|
|
77351
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "space-y-2", children: envVars.map((envVar, index2) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
|
|
77352
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77353
|
+
"input",
|
|
77354
|
+
{
|
|
77355
|
+
type: "text",
|
|
77356
|
+
value: envVar.key,
|
|
77357
|
+
onChange: (e) => handleEnvVarChange(index2, "key", e.target.value),
|
|
77358
|
+
placeholder: "变量名 (如: YAPI_BASE_URL)",
|
|
77359
|
+
className: "flex-1 px-3 py-2 text-sm text-white placeholder-gray-500 bg-white/5 border border-white/10 rounded-md focus:outline-none focus:border-blue-500"
|
|
77360
|
+
}
|
|
77361
|
+
),
|
|
77362
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77363
|
+
"input",
|
|
77364
|
+
{
|
|
77365
|
+
type: "text",
|
|
77366
|
+
value: envVar.value,
|
|
77367
|
+
onChange: (e) => handleEnvVarChange(index2, "value", e.target.value),
|
|
77368
|
+
placeholder: "值 (不要包含引号)",
|
|
77369
|
+
className: "flex-1 px-3 py-2 text-sm text-white placeholder-gray-500 bg-white/5 border border-white/10 rounded-md focus:outline-none focus:border-blue-500"
|
|
77370
|
+
}
|
|
77371
|
+
),
|
|
77372
|
+
envVars.length > 1 && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77373
|
+
"button",
|
|
77374
|
+
{
|
|
77375
|
+
type: "button",
|
|
77376
|
+
onClick: () => removeEnvVar(index2),
|
|
77377
|
+
className: "px-2 py-1 text-status-critical hover:bg-status-critical/20 rounded-md transition-colors",
|
|
77378
|
+
title: "删除",
|
|
77379
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { className: "w-4 h-4", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) })
|
|
77380
|
+
}
|
|
77381
|
+
)
|
|
77382
|
+
] }, index2)) }),
|
|
77383
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77384
|
+
"button",
|
|
77385
|
+
{
|
|
77386
|
+
type: "button",
|
|
77387
|
+
onClick: addEnvVar,
|
|
77388
|
+
className: "mt-2 text-xs text-blue-400 hover:text-blue-300 transition-colors",
|
|
77389
|
+
children: "+ 添加环境变量"
|
|
77390
|
+
}
|
|
77391
|
+
),
|
|
77392
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-gray-500 mt-1", children: "可选,用于传递敏感信息或配置参数。直接输入值即可,不要包含引号或JSON格式" })
|
|
77393
|
+
] }),
|
|
77394
|
+
formData.type === "sse" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
77395
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "block text-sm font-medium text-gray-300 mb-1", children: [
|
|
77396
|
+
"服务器URL ",
|
|
77397
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-500", children: "*" })
|
|
77398
|
+
] }),
|
|
77399
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77400
|
+
"input",
|
|
77401
|
+
{
|
|
77402
|
+
type: "text",
|
|
77403
|
+
value: formData.url,
|
|
77404
|
+
onChange: (e) => setFormData({ ...formData, url: e.target.value }),
|
|
77405
|
+
placeholder: "例如: http://localhost:3000/sse",
|
|
77406
|
+
className: "w-full px-3 py-2 text-sm text-white placeholder-gray-500 bg-white/5 border border-white/10 rounded-md focus:outline-none focus:border-blue-500",
|
|
77407
|
+
required: formData.type === "sse"
|
|
77408
|
+
}
|
|
77409
|
+
),
|
|
77410
|
+
errors.url && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-status-critical mt-1", children: errors.url })
|
|
77411
|
+
] }),
|
|
77412
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
77413
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-medium text-gray-300 mb-1", children: "描述" }),
|
|
77414
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77415
|
+
"input",
|
|
77416
|
+
{
|
|
77417
|
+
type: "text",
|
|
77418
|
+
value: formData.description,
|
|
77419
|
+
onChange: (e) => setFormData({ ...formData, description: e.target.value }),
|
|
77420
|
+
placeholder: "可选的服务器描述",
|
|
77421
|
+
className: "w-full px-3 py-2 text-sm text-white placeholder-gray-500 bg-white/5 border border-white/10 rounded-md focus:outline-none focus:border-blue-500"
|
|
77422
|
+
}
|
|
77423
|
+
)
|
|
77424
|
+
] }),
|
|
77425
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
77426
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "block text-sm font-medium text-gray-300 mb-2", children: "分类" }),
|
|
77427
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "grid grid-cols-3 gap-2", children: CATEGORIES.map((cat) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
77428
|
+
"button",
|
|
77429
|
+
{
|
|
77430
|
+
type: "button",
|
|
77431
|
+
onClick: () => setFormData({ ...formData, category: cat.value }),
|
|
77432
|
+
className: `px-3 py-2 text-left text-sm rounded-md transition-colors ${formData.category === cat.value ? "bg-blue-500/20 text-blue-400 border border-blue-500/50" : "bg-white/5 text-gray-400 border border-white/10 hover:bg-white/10"}`,
|
|
77433
|
+
children: [
|
|
77434
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-medium", children: cat.label }),
|
|
77435
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-xs opacity-75", children: cat.description })
|
|
77436
|
+
]
|
|
77437
|
+
},
|
|
77438
|
+
cat.value
|
|
77439
|
+
)) })
|
|
77440
|
+
] }),
|
|
77441
|
+
testResult && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77442
|
+
"div",
|
|
77443
|
+
{
|
|
77444
|
+
className: `p-3 rounded-md text-sm ${testResult.success ? "bg-status-nominal/20 text-status-nominal border border-status-nominal/50" : "bg-status-critical/20 text-status-critical border border-status-critical/50"}`,
|
|
77445
|
+
children: testResult.message
|
|
77446
|
+
}
|
|
77447
|
+
)
|
|
77448
|
+
] }),
|
|
77449
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-end gap-3 px-6 py-4 border-t border-white/5 flex-shrink-0", children: [
|
|
77450
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77451
|
+
Button,
|
|
77452
|
+
{
|
|
77453
|
+
type: "button",
|
|
77454
|
+
variant: "ghost",
|
|
77455
|
+
onClick: handleTest,
|
|
77456
|
+
disabled: testing,
|
|
77457
|
+
className: "text-xs",
|
|
77458
|
+
children: testing ? "测试中..." : "测试连接"
|
|
77459
|
+
}
|
|
77460
|
+
),
|
|
77461
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1" }),
|
|
77462
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Button, { type: "button", variant: "ghost", onClick: onClose, children: "取消" }),
|
|
77463
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Button, { type: "button", onClick: handleSubmit, children: "创建服务器" })
|
|
77464
|
+
] })
|
|
77465
|
+
] }) });
|
|
77466
|
+
}
|
|
77467
|
+
function MCPPanel() {
|
|
77468
|
+
const [servers, setServers] = reactExports.useState([]);
|
|
77469
|
+
const [loading, setLoading] = reactExports.useState(true);
|
|
77470
|
+
const [showCreateDialog, setShowCreateDialog] = reactExports.useState(false);
|
|
77471
|
+
reactExports.useEffect(() => {
|
|
77472
|
+
loadServers();
|
|
77473
|
+
}, []);
|
|
77474
|
+
reactExports.useEffect(() => {
|
|
77475
|
+
const interval = setInterval(async () => {
|
|
77476
|
+
const result = await window.api.mcp.getAllStates();
|
|
77477
|
+
if (result.success && result.states) {
|
|
77478
|
+
const stateMap = /* @__PURE__ */ new Map();
|
|
77479
|
+
result.states.forEach((state) => {
|
|
77480
|
+
stateMap.set(state.serverId, state);
|
|
77481
|
+
});
|
|
77482
|
+
setServers(
|
|
77483
|
+
(prev) => prev.map((server) => {
|
|
77484
|
+
const state = stateMap.get(server.id);
|
|
77485
|
+
return {
|
|
77486
|
+
...server,
|
|
77487
|
+
connectionStatus: state?.status,
|
|
77488
|
+
toolCount: state?.tools?.length || 0
|
|
77489
|
+
};
|
|
77490
|
+
})
|
|
77491
|
+
);
|
|
77492
|
+
}
|
|
77493
|
+
}, 2e3);
|
|
77494
|
+
return () => clearInterval(interval);
|
|
77495
|
+
}, []);
|
|
77496
|
+
async function loadServers() {
|
|
77497
|
+
setLoading(true);
|
|
77498
|
+
try {
|
|
77499
|
+
const result = await window.api.mcp.list();
|
|
77500
|
+
if (result.success && result.servers) {
|
|
77501
|
+
const statesResult = await window.api.mcp.getAllStates();
|
|
77502
|
+
const stateMap = /* @__PURE__ */ new Map();
|
|
77503
|
+
if (statesResult.success && statesResult.states) {
|
|
77504
|
+
statesResult.states.forEach((state) => {
|
|
77505
|
+
stateMap.set(state.serverId, state);
|
|
77506
|
+
});
|
|
77507
|
+
}
|
|
77508
|
+
setServers(
|
|
77509
|
+
result.servers.map((server) => ({
|
|
77510
|
+
...server,
|
|
77511
|
+
connectionStatus: stateMap.get(server.id)?.status,
|
|
77512
|
+
toolCount: stateMap.get(server.id)?.tools?.length || 0
|
|
77513
|
+
}))
|
|
77514
|
+
);
|
|
77515
|
+
}
|
|
77516
|
+
} catch (error) {
|
|
77517
|
+
console.error("[MCPPanel] Failed to load servers:", error);
|
|
77518
|
+
} finally {
|
|
77519
|
+
setLoading(false);
|
|
77520
|
+
}
|
|
77521
|
+
}
|
|
77522
|
+
async function handleToggleServer(serverId, currentEnabled) {
|
|
77523
|
+
console.log("[MCPPanel] Toggling server:", serverId, "from", currentEnabled, "to", !currentEnabled);
|
|
77524
|
+
try {
|
|
77525
|
+
const result = await window.api.mcp.toggle(serverId, !currentEnabled);
|
|
77526
|
+
console.log("[MCPPanel] Toggle result:", result);
|
|
77527
|
+
if (result.success) {
|
|
77528
|
+
setServers(
|
|
77529
|
+
(prev) => prev.map(
|
|
77530
|
+
(s2) => s2.id === serverId ? { ...s2, enabled: !currentEnabled } : s2
|
|
77531
|
+
)
|
|
77532
|
+
);
|
|
77533
|
+
await loadServers();
|
|
77534
|
+
} else {
|
|
77535
|
+
alert(`切换失败: ${result.error}`);
|
|
77536
|
+
}
|
|
77537
|
+
} catch (error) {
|
|
77538
|
+
console.error("[MCPPanel] Failed to toggle server:", error);
|
|
77539
|
+
alert(`切换失败: ${error instanceof Error ? error.message : "未知错误"}`);
|
|
77540
|
+
}
|
|
77541
|
+
}
|
|
77542
|
+
async function handleDeleteServer(serverId) {
|
|
77543
|
+
if (!confirm("确定要删除这个MCP服务器吗?")) return;
|
|
77544
|
+
console.log("[MCPPanel] Deleting server:", serverId);
|
|
77545
|
+
try {
|
|
77546
|
+
const result = await window.api.mcp.delete(serverId);
|
|
77547
|
+
console.log("[MCPPanel] Delete result:", result);
|
|
77548
|
+
if (result.success) {
|
|
77549
|
+
setServers((prev) => prev.filter((s2) => s2.id !== serverId));
|
|
77550
|
+
await loadServers();
|
|
77551
|
+
} else {
|
|
77552
|
+
alert(`删除失败: ${result.error}`);
|
|
77553
|
+
}
|
|
77554
|
+
} catch (error) {
|
|
77555
|
+
console.error("[MCPPanel] Failed to delete server:", error);
|
|
77556
|
+
alert(`删除失败: ${error instanceof Error ? error.message : "未知错误"}`);
|
|
77557
|
+
}
|
|
77558
|
+
}
|
|
77559
|
+
async function handleConnect(serverId) {
|
|
77560
|
+
console.log("[MCPPanel] Connecting to server:", serverId, "type:", typeof serverId);
|
|
77561
|
+
try {
|
|
77562
|
+
setServers(
|
|
77563
|
+
(prev) => prev.map(
|
|
77564
|
+
(s2) => s2.id === serverId ? { ...s2, connectionStatus: "connecting" } : s2
|
|
77565
|
+
)
|
|
77566
|
+
);
|
|
77567
|
+
console.log("[MCPPanel] Calling window.api.mcp.connect with:", serverId);
|
|
77568
|
+
const result = await window.api.mcp.connect(serverId);
|
|
77569
|
+
console.log("[MCPPanel] Connect result:", result);
|
|
77570
|
+
if (result.success) {
|
|
77571
|
+
await loadServers();
|
|
77572
|
+
} else {
|
|
77573
|
+
alert(`连接失败: ${result.error}`);
|
|
77574
|
+
await loadServers();
|
|
77575
|
+
}
|
|
77576
|
+
} catch (error) {
|
|
77577
|
+
console.error("[MCPPanel] Failed to connect:", error);
|
|
77578
|
+
alert(`连接失败: ${error instanceof Error ? error.message : "未知错误"}`);
|
|
77579
|
+
await loadServers();
|
|
77580
|
+
}
|
|
77581
|
+
}
|
|
77582
|
+
async function handleDisconnect(serverId) {
|
|
77583
|
+
console.log("[MCPPanel] Disconnecting from server:", serverId);
|
|
77584
|
+
try {
|
|
77585
|
+
const result = await window.api.mcp.disconnect(serverId);
|
|
77586
|
+
console.log("[MCPPanel] Disconnect result:", result);
|
|
77587
|
+
if (result.success) {
|
|
77588
|
+
setServers(
|
|
77589
|
+
(prev) => prev.map(
|
|
77590
|
+
(s2) => s2.id === serverId ? { ...s2, connectionStatus: "disconnected", toolCount: 0 } : s2
|
|
77591
|
+
)
|
|
77592
|
+
);
|
|
77593
|
+
await loadServers();
|
|
77594
|
+
} else {
|
|
77595
|
+
alert(`断开连接失败: ${result.error}`);
|
|
77596
|
+
}
|
|
77597
|
+
} catch (error) {
|
|
77598
|
+
console.error("[MCPPanel] Failed to disconnect:", error);
|
|
77599
|
+
alert(`断开连接失败: ${error instanceof Error ? error.message : "未知错误"}`);
|
|
77600
|
+
}
|
|
77601
|
+
}
|
|
77602
|
+
if (loading) {
|
|
77603
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-40", children: /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-5 animate-spin text-muted-foreground" }) });
|
|
77604
|
+
}
|
|
77605
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full", children: [
|
|
77606
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-3 py-2 border-b border-border/50 bg-background/30", children: [
|
|
77607
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] text-muted-foreground", children: [
|
|
77608
|
+
servers.filter((s2) => s2.enabled).length,
|
|
77609
|
+
" / ",
|
|
77610
|
+
servers.length,
|
|
77611
|
+
" 启用"
|
|
77612
|
+
] }),
|
|
77613
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
77614
|
+
Button,
|
|
77615
|
+
{
|
|
77616
|
+
variant: "ghost",
|
|
77617
|
+
size: "sm",
|
|
77618
|
+
onClick: () => setShowCreateDialog(true),
|
|
77619
|
+
className: "h-5 px-1.5 text-[10px]",
|
|
77620
|
+
children: [
|
|
77621
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Plus, { className: "size-3" }),
|
|
77622
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-1", children: "添加" })
|
|
77623
|
+
]
|
|
77624
|
+
}
|
|
77625
|
+
)
|
|
77626
|
+
] }),
|
|
77627
|
+
servers.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center text-center text-sm text-muted-foreground py-8 px-4 flex-1", children: [
|
|
77628
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Plug, { className: "size-8 mb-2 opacity-50" }),
|
|
77629
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "没有MCP服务器" }),
|
|
77630
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs mt-1", children: '点击"添加"配置服务器' })
|
|
77631
|
+
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "py-2 overflow-auto flex-1", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 space-y-2", children: servers.map((server) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77632
|
+
ServerCard,
|
|
77633
|
+
{
|
|
77634
|
+
server,
|
|
77635
|
+
onToggle: handleToggleServer,
|
|
77636
|
+
onDelete: handleDeleteServer,
|
|
77637
|
+
onConnect: handleConnect,
|
|
77638
|
+
onDisconnect: handleDisconnect
|
|
77639
|
+
},
|
|
77640
|
+
server.id
|
|
77641
|
+
)) }) }),
|
|
77642
|
+
showCreateDialog && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77643
|
+
CreateMCPServerDialog,
|
|
77644
|
+
{
|
|
77645
|
+
open: showCreateDialog,
|
|
77646
|
+
onClose: () => setShowCreateDialog(false),
|
|
77647
|
+
onCreated: loadServers
|
|
77648
|
+
}
|
|
77649
|
+
)
|
|
77650
|
+
] });
|
|
77651
|
+
}
|
|
77652
|
+
function ServerCard({ server, onToggle, onDelete, onConnect, onDisconnect }) {
|
|
77653
|
+
const getStatusIcon = () => {
|
|
77654
|
+
if (!server.enabled) {
|
|
77655
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Circle, { className: "size-3 text-muted-foreground" });
|
|
77656
|
+
}
|
|
77657
|
+
switch (server.connectionStatus) {
|
|
77658
|
+
case "connected":
|
|
77659
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleCheck, { className: "size-3 text-status-nominal" });
|
|
77660
|
+
case "connecting":
|
|
77661
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3 animate-spin text-status-info" });
|
|
77662
|
+
case "error":
|
|
77663
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "size-3 text-status-critical" });
|
|
77664
|
+
default:
|
|
77665
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(Circle, { className: "size-3 text-muted-foreground" });
|
|
77666
|
+
}
|
|
77667
|
+
};
|
|
77668
|
+
const getStatusText = () => {
|
|
77669
|
+
if (!server.enabled) return "已禁用";
|
|
77670
|
+
switch (server.connectionStatus) {
|
|
77671
|
+
case "connected":
|
|
77672
|
+
return "已连接";
|
|
77673
|
+
case "connecting":
|
|
77674
|
+
return "连接中";
|
|
77675
|
+
case "error":
|
|
77676
|
+
return "错误";
|
|
77677
|
+
default:
|
|
77678
|
+
return "未连接";
|
|
77679
|
+
}
|
|
77680
|
+
};
|
|
77681
|
+
const getTransportTypeLabel = () => {
|
|
77682
|
+
return server.type === "stdio" ? "STDIO" : "SSE";
|
|
77683
|
+
};
|
|
77684
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "p-3 rounded-sm border border-border bg-background/50 hover:bg-background transition-colors", children: [
|
|
77685
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mb-2", children: [
|
|
77686
|
+
getStatusIcon(),
|
|
77687
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 text-sm font-medium truncate", children: server.name }),
|
|
77688
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Badge, { variant: "outline", className: "text-[9px] px-1 py-0 h-4", children: getTransportTypeLabel() })
|
|
77689
|
+
] }),
|
|
77690
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "text-xs text-muted-foreground mb-2 space-y-0.5", children: [
|
|
77691
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
77692
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "状态:" }),
|
|
77693
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: server.connectionStatus === "connected" ? "text-status-nominal" : "", children: getStatusText() })
|
|
77694
|
+
] }),
|
|
77695
|
+
server.connectionStatus === "connected" && server.toolCount !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
77696
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "工具:" }),
|
|
77697
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: server.toolCount })
|
|
77698
|
+
] }),
|
|
77699
|
+
server.description && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] truncate", title: server.description, children: server.description })
|
|
77700
|
+
] }),
|
|
77701
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1 mt-2", children: [
|
|
77702
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77703
|
+
Button,
|
|
77704
|
+
{
|
|
77705
|
+
variant: "ghost",
|
|
77706
|
+
size: "sm",
|
|
77707
|
+
onClick: () => onToggle(server.id, server.enabled),
|
|
77708
|
+
className: `h-6 px-2 text-[10px] flex-1 ${server.enabled ? "text-status-nominal hover:text-status-nominal" : ""}`,
|
|
77709
|
+
title: server.enabled ? "禁用" : "启用",
|
|
77710
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Power, { className: "size-3" })
|
|
77711
|
+
}
|
|
77712
|
+
),
|
|
77713
|
+
server.enabled && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77714
|
+
Button,
|
|
77715
|
+
{
|
|
77716
|
+
variant: "ghost",
|
|
77717
|
+
size: "sm",
|
|
77718
|
+
onClick: () => server.connectionStatus === "connected" ? onDisconnect(server.id) : onConnect(server.id),
|
|
77719
|
+
className: "h-6 px-2 text-[10px] flex-1",
|
|
77720
|
+
disabled: server.connectionStatus === "connecting",
|
|
77721
|
+
title: server.connectionStatus === "connected" ? "断开" : "连接",
|
|
77722
|
+
children: server.connectionStatus === "connecting" ? /* @__PURE__ */ jsxRuntimeExports.jsx(LoaderCircle, { className: "size-3 animate-spin" }) : server.connectionStatus === "connected" ? /* @__PURE__ */ jsxRuntimeExports.jsx(CircleX, { className: "size-3" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Plug, { className: "size-3" })
|
|
77723
|
+
}
|
|
77724
|
+
),
|
|
77725
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77726
|
+
Button,
|
|
77727
|
+
{
|
|
77728
|
+
variant: "ghost",
|
|
77729
|
+
size: "sm",
|
|
77730
|
+
onClick: () => onDelete(server.id),
|
|
77731
|
+
className: "h-6 px-2 text-[10px] text-status-critical hover:text-status-critical",
|
|
77732
|
+
title: "删除",
|
|
77733
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx(Trash2, { className: "size-3" })
|
|
77734
|
+
}
|
|
77735
|
+
)
|
|
77736
|
+
] })
|
|
77737
|
+
] });
|
|
77738
|
+
}
|
|
77056
77739
|
const HEADER_HEIGHT = 40;
|
|
77057
77740
|
const HANDLE_HEIGHT = 6;
|
|
77058
77741
|
const MIN_CONTENT_HEIGHT = 60;
|
|
@@ -77131,31 +77814,34 @@ function RightPanel() {
|
|
|
77131
77814
|
const [filesOpen, setFilesOpen] = reactExports.useState(true);
|
|
77132
77815
|
const [agentsOpen, setAgentsOpen] = reactExports.useState(true);
|
|
77133
77816
|
const [skillsOpen, setSkillsOpen] = reactExports.useState(false);
|
|
77817
|
+
const [mcpOpen, setMcpOpen] = reactExports.useState(false);
|
|
77134
77818
|
const [tasksHeight, setTasksHeight] = reactExports.useState(null);
|
|
77135
77819
|
const [filesHeight, setFilesHeight] = reactExports.useState(null);
|
|
77136
77820
|
const [agentsHeight, setAgentsHeight] = reactExports.useState(null);
|
|
77137
77821
|
const [skillsHeight, setSkillsHeight] = reactExports.useState(null);
|
|
77822
|
+
const [mcpHeight, setMcpHeight] = reactExports.useState(null);
|
|
77138
77823
|
const dragStartHeights = reactExports.useRef(null);
|
|
77139
77824
|
const getAvailableContentHeight = reactExports.useCallback(() => {
|
|
77140
77825
|
if (!containerRef.current) return 0;
|
|
77141
77826
|
const totalHeight = containerRef.current.clientHeight;
|
|
77142
|
-
let used = HEADER_HEIGHT *
|
|
77143
|
-
const openPanels = [tasksOpen, filesOpen, agentsOpen, skillsOpen].filter(Boolean).length;
|
|
77827
|
+
let used = HEADER_HEIGHT * 5;
|
|
77828
|
+
const openPanels = [tasksOpen, filesOpen, agentsOpen, skillsOpen, mcpOpen].filter(Boolean).length;
|
|
77144
77829
|
used += HANDLE_HEIGHT * (openPanels - 1);
|
|
77145
77830
|
return Math.max(0, totalHeight - used);
|
|
77146
|
-
}, [tasksOpen, filesOpen, agentsOpen, skillsOpen]);
|
|
77831
|
+
}, [tasksOpen, filesOpen, agentsOpen, skillsOpen, mcpOpen]);
|
|
77147
77832
|
const getContentHeights = reactExports.useCallback(() => {
|
|
77148
77833
|
const available = getAvailableContentHeight();
|
|
77149
|
-
const openCount = [tasksOpen, filesOpen, agentsOpen, skillsOpen].filter(Boolean).length;
|
|
77834
|
+
const openCount = [tasksOpen, filesOpen, agentsOpen, skillsOpen, mcpOpen].filter(Boolean).length;
|
|
77150
77835
|
if (openCount === 0) {
|
|
77151
|
-
return { tasks: 0, files: 0, agents: 0, skills: 0 };
|
|
77836
|
+
return { tasks: 0, files: 0, agents: 0, skills: 0, mcp: 0 };
|
|
77152
77837
|
}
|
|
77153
77838
|
const defaultHeight = available / openCount;
|
|
77154
77839
|
return {
|
|
77155
77840
|
tasks: tasksOpen ? tasksHeight ?? defaultHeight : 0,
|
|
77156
77841
|
files: filesOpen ? filesHeight ?? defaultHeight : 0,
|
|
77157
77842
|
agents: agentsOpen ? agentsHeight ?? defaultHeight : 0,
|
|
77158
|
-
skills: skillsOpen ? skillsHeight ?? defaultHeight : 0
|
|
77843
|
+
skills: skillsOpen ? skillsHeight ?? defaultHeight : 0,
|
|
77844
|
+
mcp: mcpOpen ? mcpHeight ?? defaultHeight : 0
|
|
77159
77845
|
};
|
|
77160
77846
|
}, [
|
|
77161
77847
|
getAvailableContentHeight,
|
|
@@ -77163,10 +77849,12 @@ function RightPanel() {
|
|
|
77163
77849
|
filesOpen,
|
|
77164
77850
|
agentsOpen,
|
|
77165
77851
|
skillsOpen,
|
|
77852
|
+
mcpOpen,
|
|
77166
77853
|
tasksHeight,
|
|
77167
77854
|
filesHeight,
|
|
77168
77855
|
agentsHeight,
|
|
77169
|
-
skillsHeight
|
|
77856
|
+
skillsHeight,
|
|
77857
|
+
mcpHeight
|
|
77170
77858
|
]);
|
|
77171
77859
|
const handleTasksResize = reactExports.useCallback(
|
|
77172
77860
|
(totalDelta) => {
|
|
@@ -77215,7 +77903,15 @@ function RightPanel() {
|
|
|
77215
77903
|
else if (nextPanel === "skills") setSkillsOpen(false);
|
|
77216
77904
|
}
|
|
77217
77905
|
},
|
|
77218
|
-
[
|
|
77906
|
+
[
|
|
77907
|
+
getContentHeights,
|
|
77908
|
+
getAvailableContentHeight,
|
|
77909
|
+
filesOpen,
|
|
77910
|
+
agentsOpen,
|
|
77911
|
+
skillsOpen,
|
|
77912
|
+
agentsHeight,
|
|
77913
|
+
skillsHeight
|
|
77914
|
+
]
|
|
77219
77915
|
);
|
|
77220
77916
|
const handleFilesResize = reactExports.useCallback(
|
|
77221
77917
|
(totalDelta) => {
|
|
@@ -77270,38 +77966,86 @@ function RightPanel() {
|
|
|
77270
77966
|
}
|
|
77271
77967
|
const start = dragStartHeights.current;
|
|
77272
77968
|
const available = getAvailableContentHeight();
|
|
77273
|
-
const tasksH = tasksOpen ? tasksHeight ?? available /
|
|
77274
|
-
const filesH = filesOpen ? filesHeight ?? available /
|
|
77969
|
+
const tasksH = tasksOpen ? tasksHeight ?? available / 5 : 0;
|
|
77970
|
+
const filesH = filesOpen ? filesHeight ?? available / 5 : 0;
|
|
77275
77971
|
const aboveHeight = tasksH + filesH;
|
|
77276
|
-
|
|
77972
|
+
let nextPanel = null;
|
|
77973
|
+
if (skillsOpen) nextPanel = "skills";
|
|
77974
|
+
else if (mcpOpen) nextPanel = "mcp";
|
|
77975
|
+
if (!nextPanel) return;
|
|
77976
|
+
const maxForAgentsAndNext = available - aboveHeight;
|
|
77277
77977
|
let newAgentsHeight = start.agents + totalDelta;
|
|
77278
|
-
let
|
|
77978
|
+
let newNextHeight = start[nextPanel] - totalDelta;
|
|
77279
77979
|
if (newAgentsHeight < MIN_CONTENT_HEIGHT) {
|
|
77280
77980
|
newAgentsHeight = MIN_CONTENT_HEIGHT;
|
|
77281
|
-
|
|
77981
|
+
newNextHeight = start[nextPanel] + (start.agents - MIN_CONTENT_HEIGHT);
|
|
77282
77982
|
}
|
|
77283
|
-
if (
|
|
77284
|
-
|
|
77285
|
-
newAgentsHeight = start.agents + (start
|
|
77983
|
+
if (newNextHeight < MIN_CONTENT_HEIGHT) {
|
|
77984
|
+
newNextHeight = MIN_CONTENT_HEIGHT;
|
|
77985
|
+
newAgentsHeight = start.agents + (start[nextPanel] - MIN_CONTENT_HEIGHT);
|
|
77286
77986
|
}
|
|
77287
|
-
if (newAgentsHeight +
|
|
77288
|
-
const excess = newAgentsHeight +
|
|
77987
|
+
if (newAgentsHeight + newNextHeight > maxForAgentsAndNext) {
|
|
77988
|
+
const excess = newAgentsHeight + newNextHeight - maxForAgentsAndNext;
|
|
77289
77989
|
if (totalDelta > 0) {
|
|
77290
|
-
|
|
77990
|
+
newNextHeight = Math.max(MIN_CONTENT_HEIGHT, newNextHeight - excess);
|
|
77291
77991
|
} else {
|
|
77292
77992
|
newAgentsHeight = Math.max(MIN_CONTENT_HEIGHT, newAgentsHeight - excess);
|
|
77293
77993
|
}
|
|
77294
77994
|
}
|
|
77295
77995
|
setAgentsHeight(newAgentsHeight);
|
|
77296
|
-
setSkillsHeight(
|
|
77996
|
+
if (nextPanel === "skills") setSkillsHeight(newNextHeight);
|
|
77997
|
+
else if (nextPanel === "mcp") setMcpHeight(newNextHeight);
|
|
77297
77998
|
if (newAgentsHeight < COLLAPSE_THRESHOLD) {
|
|
77298
77999
|
setAgentsOpen(false);
|
|
77299
78000
|
}
|
|
78001
|
+
if (newNextHeight < COLLAPSE_THRESHOLD) {
|
|
78002
|
+
if (nextPanel === "skills") setSkillsOpen(false);
|
|
78003
|
+
else if (nextPanel === "mcp") setMcpOpen(false);
|
|
78004
|
+
}
|
|
78005
|
+
},
|
|
78006
|
+
[getContentHeights, getAvailableContentHeight, tasksOpen, filesOpen, tasksHeight, filesHeight, skillsOpen, mcpOpen]
|
|
78007
|
+
);
|
|
78008
|
+
const handleSkillsResize = reactExports.useCallback(
|
|
78009
|
+
(totalDelta) => {
|
|
78010
|
+
if (!dragStartHeights.current) {
|
|
78011
|
+
const heights2 = getContentHeights();
|
|
78012
|
+
dragStartHeights.current = { ...heights2 };
|
|
78013
|
+
}
|
|
78014
|
+
const start = dragStartHeights.current;
|
|
78015
|
+
const available = getAvailableContentHeight();
|
|
78016
|
+
const tasksH = tasksOpen ? tasksHeight ?? available / 5 : 0;
|
|
78017
|
+
const filesH = filesOpen ? filesHeight ?? available / 5 : 0;
|
|
78018
|
+
const agentsH = agentsOpen ? agentsHeight ?? available / 5 : 0;
|
|
78019
|
+
const aboveHeight = tasksH + filesH + agentsH;
|
|
78020
|
+
const maxForSkillsAndMcp = available - aboveHeight;
|
|
78021
|
+
let newSkillsHeight = start.skills + totalDelta;
|
|
78022
|
+
let newMcpHeight = start.mcp - totalDelta;
|
|
78023
|
+
if (newSkillsHeight < MIN_CONTENT_HEIGHT) {
|
|
78024
|
+
newSkillsHeight = MIN_CONTENT_HEIGHT;
|
|
78025
|
+
newMcpHeight = start.mcp + (start.skills - MIN_CONTENT_HEIGHT);
|
|
78026
|
+
}
|
|
78027
|
+
if (newMcpHeight < MIN_CONTENT_HEIGHT) {
|
|
78028
|
+
newMcpHeight = MIN_CONTENT_HEIGHT;
|
|
78029
|
+
newSkillsHeight = start.skills + (start.mcp - MIN_CONTENT_HEIGHT);
|
|
78030
|
+
}
|
|
78031
|
+
if (newSkillsHeight + newMcpHeight > maxForSkillsAndMcp) {
|
|
78032
|
+
const excess = newSkillsHeight + newMcpHeight - maxForSkillsAndMcp;
|
|
78033
|
+
if (totalDelta > 0) {
|
|
78034
|
+
newMcpHeight = Math.max(MIN_CONTENT_HEIGHT, newMcpHeight - excess);
|
|
78035
|
+
} else {
|
|
78036
|
+
newSkillsHeight = Math.max(MIN_CONTENT_HEIGHT, newSkillsHeight - excess);
|
|
78037
|
+
}
|
|
78038
|
+
}
|
|
78039
|
+
setSkillsHeight(newSkillsHeight);
|
|
78040
|
+
setMcpHeight(newMcpHeight);
|
|
77300
78041
|
if (newSkillsHeight < COLLAPSE_THRESHOLD) {
|
|
77301
78042
|
setSkillsOpen(false);
|
|
77302
78043
|
}
|
|
78044
|
+
if (newMcpHeight < COLLAPSE_THRESHOLD) {
|
|
78045
|
+
setMcpOpen(false);
|
|
78046
|
+
}
|
|
77303
78047
|
},
|
|
77304
|
-
[getContentHeights, getAvailableContentHeight, tasksOpen, filesOpen, tasksHeight, filesHeight]
|
|
78048
|
+
[getContentHeights, getAvailableContentHeight, tasksOpen, filesOpen, agentsOpen, tasksHeight, filesHeight, agentsHeight]
|
|
77305
78049
|
);
|
|
77306
78050
|
reactExports.useEffect(() => {
|
|
77307
78051
|
const handleMouseUp = () => {
|
|
@@ -77315,8 +78059,9 @@ function RightPanel() {
|
|
|
77315
78059
|
setFilesHeight(null);
|
|
77316
78060
|
setAgentsHeight(null);
|
|
77317
78061
|
setSkillsHeight(null);
|
|
77318
|
-
|
|
77319
|
-
|
|
78062
|
+
setMcpHeight(null);
|
|
78063
|
+
}, [tasksOpen, filesOpen, agentsOpen, skillsOpen, mcpOpen]);
|
|
78064
|
+
const [heights, setHeights] = reactExports.useState({ tasks: 0, files: 0, agents: 0, skills: 0, mcp: 0 });
|
|
77320
78065
|
reactExports.useEffect(() => {
|
|
77321
78066
|
setHeights(getContentHeights());
|
|
77322
78067
|
}, [getContentHeights]);
|
|
@@ -77367,8 +78112,8 @@ function RightPanel() {
|
|
|
77367
78112
|
),
|
|
77368
78113
|
agentsOpen && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-auto", style: { height: heights.agents }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(AgentsContent, {}) })
|
|
77369
78114
|
] }),
|
|
77370
|
-
agentsOpen && skillsOpen && /* @__PURE__ */ jsxRuntimeExports.jsx(ResizeHandle$1, { onDrag: handleAgentsResize }),
|
|
77371
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col shrink-0", children: [
|
|
78115
|
+
agentsOpen && (skillsOpen || mcpOpen) && /* @__PURE__ */ jsxRuntimeExports.jsx(ResizeHandle$1, { onDrag: handleAgentsResize }),
|
|
78116
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col shrink-0 border-b border-border", children: [
|
|
77372
78117
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
77373
78118
|
SectionHeader,
|
|
77374
78119
|
{
|
|
@@ -77379,6 +78124,19 @@ function RightPanel() {
|
|
|
77379
78124
|
}
|
|
77380
78125
|
),
|
|
77381
78126
|
skillsOpen && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-auto", style: { height: heights.skills }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(SkillsContent, {}) })
|
|
78127
|
+
] }),
|
|
78128
|
+
skillsOpen && mcpOpen && /* @__PURE__ */ jsxRuntimeExports.jsx(ResizeHandle$1, { onDrag: handleSkillsResize }),
|
|
78129
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col shrink-0", children: [
|
|
78130
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
78131
|
+
SectionHeader,
|
|
78132
|
+
{
|
|
78133
|
+
title: "MCP",
|
|
78134
|
+
icon: Plug,
|
|
78135
|
+
isOpen: mcpOpen,
|
|
78136
|
+
onToggle: () => setMcpOpen((prev) => !prev)
|
|
78137
|
+
}
|
|
78138
|
+
),
|
|
78139
|
+
mcpOpen && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "overflow-auto", style: { height: heights.mcp }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(MCPContent, {}) })
|
|
77382
78140
|
] })
|
|
77383
78141
|
]
|
|
77384
78142
|
}
|
|
@@ -77803,6 +78561,9 @@ function AgentsContent() {
|
|
|
77803
78561
|
function SkillsContent() {
|
|
77804
78562
|
return /* @__PURE__ */ jsxRuntimeExports.jsx(SkillsPanel, {});
|
|
77805
78563
|
}
|
|
78564
|
+
function MCPContent() {
|
|
78565
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx(MCPPanel, {});
|
|
78566
|
+
}
|
|
77806
78567
|
function formatSize(bytes) {
|
|
77807
78568
|
if (bytes < 1024) return `${bytes}B`;
|
|
77808
78569
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
|
|
@@ -78201,7 +78962,7 @@ function App() {
|
|
|
78201
78962
|
},
|
|
78202
78963
|
children: [
|
|
78203
78964
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "app-badge-name", children: "OPENWORK" }),
|
|
78204
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "app-badge-version", children: "0.
|
|
78965
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "app-badge-version", children: "0.4.0" })
|
|
78205
78966
|
]
|
|
78206
78967
|
}
|
|
78207
78968
|
),
|