dsh-magpie-connect 0.2.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/LICENSE +21 -0
- package/README.md +133 -0
- package/cordis.patch.yml +23 -0
- package/dsh.plugin.json +9 -0
- package/lib/client.js +744 -0
- package/lib/index.js +1638 -0
- package/lib/index.js.map +7 -0
- package/lib/types/adapter/catalog.d.ts +189 -0
- package/lib/types/adapter/events.d.ts +164 -0
- package/lib/types/adapter/magpie-adapter.d.ts +173 -0
- package/lib/types/adapter/messages.d.ts +196 -0
- package/lib/types/adapter/watchdog.d.ts +27 -0
- package/lib/types/client/i18n.d.ts +15 -0
- package/lib/types/client/index.d.ts +31 -0
- package/lib/types/client/model-list.d.ts +53 -0
- package/lib/types/client/model-visibility.d.ts +65 -0
- package/lib/types/client/nav-icon.d.ts +45 -0
- package/lib/types/client/page.d.ts +6 -0
- package/lib/types/client/write-queue.d.ts +25 -0
- package/lib/types/config.d.ts +66 -0
- package/lib/types/index.d.ts +88 -0
- package/lib/types/settings.d.ts +59 -0
- package/package.json +81 -0
package/lib/client.js
ADDED
|
@@ -0,0 +1,744 @@
|
|
|
1
|
+
window.__ModuleLoader__.load({
|
|
2
|
+
id: "dsh-magpie-connect",
|
|
3
|
+
factory: (require) => {
|
|
4
|
+
var module = { exports: {} };
|
|
5
|
+
var exports = module.exports;
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
"use strict";
|
|
8
|
+
var __defProp = Object.defineProperty;
|
|
9
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
10
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
11
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
25
|
+
|
|
26
|
+
// src/client/index.ts
|
|
27
|
+
var index_exports = {};
|
|
28
|
+
__export(index_exports, {
|
|
29
|
+
NS: () => NS,
|
|
30
|
+
apply: () => apply,
|
|
31
|
+
inject: () => inject
|
|
32
|
+
});
|
|
33
|
+
module.exports = __toCommonJS(index_exports);
|
|
34
|
+
|
|
35
|
+
// src/client/i18n.ts
|
|
36
|
+
var import_react = require("react");
|
|
37
|
+
var NS = "magpie-connect";
|
|
38
|
+
var EN = {
|
|
39
|
+
nav: "Magpie",
|
|
40
|
+
title: "Magpie gateway",
|
|
41
|
+
intro: "Connect DSH to the Magpie LAN model gateway. Changes save to this machine and apply immediately \u2014 no restart needed.",
|
|
42
|
+
connection: "Connection",
|
|
43
|
+
baseUrl: "API URL",
|
|
44
|
+
baseUrlPlaceholder: "http://api.lan/v1",
|
|
45
|
+
apiKey: "API key",
|
|
46
|
+
apiKeyPlaceholder: "required",
|
|
47
|
+
requiredNote: "API URL and API key are both required. Include the version segment (e.g. /v1) \u2014 the URL is used exactly as written.",
|
|
48
|
+
test: "Test connection",
|
|
49
|
+
testing: "Testing\u2026",
|
|
50
|
+
save: "Save",
|
|
51
|
+
saving: "Saving\u2026",
|
|
52
|
+
saved: "Saved \u2014 live already.",
|
|
53
|
+
savingModels: "Saving models\u2026",
|
|
54
|
+
modelsSaved: "Models saved \u2014 the picker is up to date.",
|
|
55
|
+
testOk: "Connection OK: {count} models found.",
|
|
56
|
+
models: "Models",
|
|
57
|
+
enabled: "{count} enabled in the picker.",
|
|
58
|
+
allHidden: "Every model is hidden \u2014 fetch available models to bring some back.",
|
|
59
|
+
remove: "Remove",
|
|
60
|
+
removeHint: "Hide this model from the picker. Fetch available models to bring it back.",
|
|
61
|
+
search: "Filter models\u2026",
|
|
62
|
+
fetchModels: "Fetch available models",
|
|
63
|
+
fetching: "Fetching\u2026",
|
|
64
|
+
fetchTitle: "Available models",
|
|
65
|
+
fetchDescription: "Models the gateway currently serves. Tick the ones the model picker should offer.",
|
|
66
|
+
fetchSearch: "Search models\u2026",
|
|
67
|
+
fetchSelectAll: "Select all",
|
|
68
|
+
fetchDeselectAll: "Deselect all",
|
|
69
|
+
fetchAdopt: "Apply selection",
|
|
70
|
+
fetchEmpty: "The gateway listed no models.",
|
|
71
|
+
fetchNoMatches: "No matching models.",
|
|
72
|
+
fetchNeedsConfig: "Set the API URL and key before fetching.",
|
|
73
|
+
fetchFound: "{count} models found \u2014 {picked} selected.",
|
|
74
|
+
cancel: "Cancel",
|
|
75
|
+
close: "Close",
|
|
76
|
+
image: "image",
|
|
77
|
+
responses: "responses",
|
|
78
|
+
reasoning: "reasoning",
|
|
79
|
+
context: "{window} ctx",
|
|
80
|
+
saveHint: "These are the models the picker offers. Changes save on their own \u2014 the credential fields above still need Save.",
|
|
81
|
+
notConfigured: "Not fully configured: the model picker stays empty and calls fail until both fields are saved.",
|
|
82
|
+
pluginVersion: "Plugin version:",
|
|
83
|
+
loadFailed: "Failed to load settings: {message}",
|
|
84
|
+
requestFailed: "Request failed (HTTP {status})",
|
|
85
|
+
requestTimeout: "Request timed out. Check the gateway address and try again."
|
|
86
|
+
};
|
|
87
|
+
var ZH = {
|
|
88
|
+
nav: "Magpie \u7F51\u5173",
|
|
89
|
+
title: "Magpie \u7F51\u5173",
|
|
90
|
+
intro: "\u628A DSH \u63A5\u5165 Magpie \u5C40\u57DF\u7F51\u6A21\u578B\u7F51\u5173\u3002\u4FEE\u6539\u4FDD\u5B58\u5728\u672C\u673A\u5E76\u7ACB\u5373\u751F\u6548\uFF0C\u65E0\u9700\u91CD\u542F\u3002",
|
|
91
|
+
connection: "\u8FDE\u63A5",
|
|
92
|
+
baseUrl: "API \u5730\u5740",
|
|
93
|
+
baseUrlPlaceholder: "http://api.lan/v1",
|
|
94
|
+
apiKey: "API Key",
|
|
95
|
+
apiKeyPlaceholder: "\u5FC5\u586B",
|
|
96
|
+
requiredNote: "API \u5730\u5740\u4E0E Key \u5747\u4E3A\u5FC5\u586B\u3002\u5730\u5740\u9700\u5305\u542B\u7248\u672C\u6BB5\uFF08\u5982 /v1\uFF09\uFF0C\u63D2\u4EF6\u6309\u4F60\u586B\u5199\u7684\u539F\u6837\u4F7F\u7528\u3002",
|
|
97
|
+
test: "\u6D4B\u8BD5\u8FDE\u63A5",
|
|
98
|
+
testing: "\u6D4B\u8BD5\u4E2D\u2026",
|
|
99
|
+
save: "\u4FDD\u5B58",
|
|
100
|
+
saving: "\u4FDD\u5B58\u4E2D\u2026",
|
|
101
|
+
saved: "\u5DF2\u4FDD\u5B58\u5E76\u5B9E\u65F6\u751F\u6548\u3002",
|
|
102
|
+
savingModels: "\u6B63\u5728\u4FDD\u5B58\u6A21\u578B\u2026",
|
|
103
|
+
modelsSaved: "\u6A21\u578B\u5DF2\u4FDD\u5B58\uFF0C\u9009\u62E9\u5668\u5DF2\u66F4\u65B0\u3002",
|
|
104
|
+
testOk: "\u8FDE\u63A5\u6B63\u5E38\uFF0C\u5171\u53D1\u73B0 {count} \u4E2A\u6A21\u578B\u3002",
|
|
105
|
+
models: "\u6A21\u578B\u5217\u8868",
|
|
106
|
+
enabled: "\u9009\u62E9\u5668\u4E2D\u5DF2\u542F\u7528 {count} \u4E2A\u3002",
|
|
107
|
+
allHidden: "\u6240\u6709\u6A21\u578B\u90FD\u5DF2\u9690\u85CF\u2014\u2014\u7528\u201C\u83B7\u53D6\u53EF\u7528\u6A21\u578B\u201D\u628A\u5B83\u4EEC\u52A0\u56DE\u6765\u3002",
|
|
108
|
+
remove: "\u5220\u9664",
|
|
109
|
+
removeHint: "\u4ECE\u9009\u62E9\u5668\u4E2D\u9690\u85CF\u8BE5\u6A21\u578B\uFF0C\u53EF\u7528\u201C\u83B7\u53D6\u53EF\u7528\u6A21\u578B\u201D\u91CD\u65B0\u52A0\u56DE\u3002",
|
|
110
|
+
search: "\u7B5B\u9009\u6A21\u578B\u2026",
|
|
111
|
+
fetchModels: "\u83B7\u53D6\u53EF\u7528\u6A21\u578B",
|
|
112
|
+
fetching: "\u83B7\u53D6\u4E2D\u2026",
|
|
113
|
+
fetchTitle: "\u53EF\u7528\u6A21\u578B",
|
|
114
|
+
fetchDescription: "\u7F51\u5173\u5F53\u524D\u63D0\u4F9B\u7684\u6A21\u578B\u3002\u52FE\u9009\u9700\u8981\u51FA\u73B0\u5728\u6A21\u578B\u9009\u62E9\u5668\u4E2D\u7684\u90A3\u4E9B\u3002",
|
|
115
|
+
fetchSearch: "\u641C\u7D22\u6A21\u578B\u2026",
|
|
116
|
+
fetchSelectAll: "\u5168\u9009",
|
|
117
|
+
fetchDeselectAll: "\u53D6\u6D88\u5168\u9009",
|
|
118
|
+
fetchAdopt: "\u5E94\u7528\u9009\u62E9",
|
|
119
|
+
fetchEmpty: "\u7F51\u5173\u6CA1\u6709\u5217\u51FA\u4EFB\u4F55\u6A21\u578B\u3002",
|
|
120
|
+
fetchNoMatches: "\u6CA1\u6709\u5339\u914D\u7684\u6A21\u578B\u3002",
|
|
121
|
+
fetchNeedsConfig: "\u8BF7\u5148\u586B\u5199 API \u5730\u5740\u4E0E Key\u3002",
|
|
122
|
+
fetchFound: "\u5171\u53D1\u73B0 {count} \u4E2A\u6A21\u578B\uFF0C\u5DF2\u9009 {picked} \u4E2A\u3002",
|
|
123
|
+
cancel: "\u53D6\u6D88",
|
|
124
|
+
close: "\u5173\u95ED",
|
|
125
|
+
image: "\u56FE\u7247",
|
|
126
|
+
responses: "responses",
|
|
127
|
+
reasoning: "\u601D\u8003",
|
|
128
|
+
context: "{window} \u4E0A\u4E0B\u6587",
|
|
129
|
+
saveHint: "\u4EE5\u4E0B\u5373\u9009\u62E9\u5668\u4E2D\u53EF\u7528\u7684\u6A21\u578B\uFF0C\u6539\u52A8\u4F1A\u81EA\u52A8\u4FDD\u5B58\uFF1B\u4E0A\u65B9\u7684\u5730\u5740\u4E0E Key \u4ECD\u9700\u70B9\u201C\u4FDD\u5B58\u201D\u3002",
|
|
130
|
+
notConfigured: "\u914D\u7F6E\u4E0D\u5B8C\u6574\uFF1A\u4E24\u4E2A\u5B57\u6BB5\u90FD\u4FDD\u5B58\u540E\uFF0C\u6A21\u578B\u9009\u62E9\u5668\u624D\u4F1A\u6709\u5185\u5BB9\uFF0C\u8C03\u7528\u624D\u4F1A\u653E\u884C\u3002",
|
|
131
|
+
pluginVersion: "\u63D2\u4EF6\u7248\u672C\uFF1A",
|
|
132
|
+
loadFailed: "\u52A0\u8F7D\u8BBE\u7F6E\u5931\u8D25\uFF1A{message}",
|
|
133
|
+
requestFailed: "\u8BF7\u6C42\u5931\u8D25\uFF08HTTP {status}\uFF09",
|
|
134
|
+
requestTimeout: "\u8BF7\u6C42\u8D85\u65F6\uFF0C\u8BF7\u68C0\u67E5\u7F51\u5173\u5730\u5740\u540E\u91CD\u8BD5\u3002"
|
|
135
|
+
};
|
|
136
|
+
var localeRuntime;
|
|
137
|
+
function setLocaleRuntime(runtime) {
|
|
138
|
+
localeRuntime = runtime;
|
|
139
|
+
}
|
|
140
|
+
function format(template, params) {
|
|
141
|
+
if (!params) return template;
|
|
142
|
+
return template.replace(/\{([^}]+)\}/g, (match, key) => key in params ? String(params[key]) : match);
|
|
143
|
+
}
|
|
144
|
+
function text(key, params) {
|
|
145
|
+
const active = localeRuntime?.getSnapshot().active;
|
|
146
|
+
const dictionary = active === "zh" ? ZH : EN;
|
|
147
|
+
return format(dictionary[key] ?? EN[key] ?? key, params);
|
|
148
|
+
}
|
|
149
|
+
function subscribe(listener) {
|
|
150
|
+
return localeRuntime === void 0 ? () => {
|
|
151
|
+
} : localeRuntime.subscribe(listener);
|
|
152
|
+
}
|
|
153
|
+
function snapshot() {
|
|
154
|
+
return localeRuntime?.getSnapshot().revision ?? 0;
|
|
155
|
+
}
|
|
156
|
+
function useLocaleRevision() {
|
|
157
|
+
(0, import_react.useSyncExternalStore)(subscribe, snapshot, () => 0);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// src/client/nav-icon.ts
|
|
161
|
+
var NAV_ICON_MARKER = "data-dsh-magpie-nav-icon";
|
|
162
|
+
var NAV_ROW_SELECTOR = '[role="dialog"] nav button';
|
|
163
|
+
var BIRD_PATH = "M1.5 5.5C1.3 5.7 1.2 6.5 1.2 6.9C1.2 6.9 1.2 7 1.2 7.1C1.1 7.4 1.3 8 1.4 8.3C1.4 8.4 1.5 8.5 1.5 8.7C1.5 8.9 1.7 9 1.8 9.3C2.2 9.9 2.2 10 2.3 10.1C2.4 10.2 2.5 10.3 2.6 10.5C2.8 10.8 3 11.1 3.2 11.3C3.3 11.3 3.4 11.6 3.6 11.8C3.8 12 4.1 12.4 4.2 12.5C4.7 13 5.2 13.7 5.4 13.9C6 14.5 6.5 15.1 6.7 15.3C6.7 15.4 6.9 15.5 6.9 15.7C7.3 15.9 7.7 16.5 7.9 16.8C7.9 16.8 8 16.9 8 16.9C8.1 16.9 8.2 17.2 8.2 17.3C8.2 17.3 8.1 17.2 8.1 17.1C7.9 16.9 7.9 16.9 7.6 16.6C7.5 16.5 7.4 16.5 7.4 16.3C7.2 16.2 6.7 15.7 6.3 15.2C6.1 15.1 6 14.9 6 14.9C5.9 14.8 5.7 14.7 5.7 14.6C5.6 14.5 5.4 14.3 5.3 14.2C5.1 14.1 4.9 13.8 4.7 13.5C4.5 13.3 4.2 13.1 4.1 12.9C4.1 12.9 3.8 12.7 3.8 12.5C3.5 12.3 3 11.8 2.8 11.4C1.8 10.5 0.9 9.6 0.7 9.6C0.6 9.7 0.6 9.8 0.5 10C0.5 10.1 0.6 10.2 0.5 10.3C0.5 10.4 0.6 10.5 0.6 10.6C0.5 10.7 0.5 10.9 0.6 11C0.5 11.1 0.6 11.4 0.6 11.5C0.9 12.9 1.3 13.8 2.8 14.9C2.9 15.1 3.3 15.3 3.4 15.4C3.4 15.5 3.6 15.6 3.7 15.7C4.2 16 6.4 17.8 7 18.4C7.4 18.8 7.4 18.8 7.5 18.9C7.6 19 7.7 19 7.7 19.1C7.7 19.2 7.8 19.2 7.9 19.2C7.9 19.3 8.1 19.4 8.1 19.5C8.2 19.6 8.2 19.7 8.3 19.7C8.3 19.7 8.3 19.7 8.2 19.7C8.2 19.6 8.1 19.6 8 19.6C7.9 19.5 7.9 19.4 7.8 19.4C7.7 19.3 7.6 19.2 7.6 19.2C7.6 19.1 7.5 19 7.3 18.9C7.2 18.9 6.9 18.6 6.7 18.4C6.1 17.8 4.5 16.6 3.5 16C3.4 15.8 3 15.6 2.9 15.5C2.6 15.3 1.5 14.6 0.9 14.3C0.7 14.1 0.6 14.1 0.6 14.2C0.5 14.5 0.8 15.9 0.9 16.1C0.9 16.2 1 16.2 0.9 16.3C1.2 16.8 1.9 17.6 2.7 18.3C2.8 18.5 4 19.2 4.7 19.5C6.2 20.5 6.6 20.7 7.4 21.5C8.2 22.2 8.7 22.7 9.3 23.6C9.5 24.1 9.9 24.4 10.3 25.3C10.4 25.5 10.5 25.8 10.5 25.8C10.7 25.8 10.8 25.7 11 25.4C11.6 25 11.9 24.6 12.3 24.3C12.8 24 13 23.8 13 23.7C13.1 23.7 13.1 23.8 13 24C12 24.8 11 26 10.2 26.9C10.1 27.1 9.9 27.5 9.7 27.7C9.5 27.8 9.4 28 9.4 28C9.4 28 9.3 28.3 9.1 28.5C8.6 29.2 7.7 30.8 7.7 30.9C7.7 31 7.8 31 8.3 30.8C9 30.4 9.5 30.2 10.4 30C11.7 29.6 12.5 29.6 11.6 30C10.5 30.2 9.7 30.6 9.2 31.2C8.8 31.7 8.8 31.7 9.3 31.7C10.1 31.8 10.9 31.9 11.6 32.2C12.8 32.7 13.5 33.1 15.5 34.8C16.4 35.5 17.3 36.2 17.8 36.4C17.9 36.5 18.1 36.7 18.2 36.8C19.1 37.3 21.2 38.1 22.3 38.3C22.4 38.3 22.7 38.3 22.8 38.3C22.8 38.5 23 38.5 23 38.5C23.1 38.5 23.2 38.5 23.3 38.5C23.6 38.6 25.9 38.6 26.1 38.5C26.2 38.5 26.3 38.5 26.4 38.5C26.5 38.5 26.6 38.5 26.7 38.3C26.7 38.3 27 38.3 27.1 38.3C28.3 38.1 30.2 37.3 31.4 36.7C31.5 36.7 31.7 36.4 31.8 36.4C32.2 36.2 33.2 35.4 33.4 35.2C34.2 34.5 35.5 33 35.8 32.6C35.8 32.5 36 32.2 36.1 32C36.4 31.8 36.6 31.4 36.6 31.2C36.7 31.1 36.8 30.9 36.9 30.8C37.2 30.4 37.5 29.6 37.7 29.2C37.7 29.1 37.8 28.7 37.9 28.7C38.1 28.5 38.4 27.1 38.5 26.8C39 25.2 39.1 23.7 39 22.4C39 22.2 38.9 21.9 38.9 21.8C38.9 21.7 38.9 21.6 38.9 21.4C38.6 20.5 38.5 19.9 38.2 19C37.9 18.5 37.5 17.5 37.3 17.2C37 16.8 36.8 15.8 36.8 15.2C36.8 13.8 37.7 12.7 39.6 12.2C40.1 12.1 41.3 11.8 42.1 11.7C43.5 11.5 43.5 11.5 43.4 11.3C42.9 10.7 40.9 9.9 39.2 9.7C37.9 9.5 38.1 9.5 37.6 9C37 8.6 36.4 8 36 7.9C36 7.8 35.8 7.8 35.7 7.7C35.1 7.3 34.2 7 33.1 6.9C32.6 6.7 31.6 6.9 31 7C29.6 7.3 28.3 8 27.3 9.2C26.7 9.8 26.2 10.8 25.7 11.7C25.5 12.1 24.8 13.4 24.7 13.7C24.6 13.9 24.5 14.1 24.1 14.7C23.5 15.7 22.1 16.9 20.6 17.8C20.5 18 20.3 18.2 20.1 18.3C19.7 18.5 19.4 18.8 19.1 19C18.9 19.1 18.7 19.3 18.5 19.4C18 19.8 17.2 20.3 17 20.5C16.9 20.5 16.8 20.6 16.7 20.7C16.3 20.8 16.1 20.9 16 20.9C15.5 20.8 14.9 20.5 14.2 20.2C13.7 19.8 12.7 18.9 12.4 18.6C12.3 18.5 12.2 18.4 12.1 18.2C11.9 18 11.2 17.1 11 16.6C10.9 16.5 10.8 16.4 10.7 16.3C10.7 16.2 10.6 16.1 10.6 15.9C10.5 15.9 10.4 15.7 10.4 15.6C10.3 15.5 10.2 15.2 10.1 15C10 14.8 9.8 14.4 9.7 14.2C9.6 14 9.5 13.7 9.4 13.6C9.4 13.4 9.3 13.2 9.2 13C9.2 12.8 9 12.6 9 12.5C8.9 12.3 8.7 12.1 8.7 12C8.7 12 8.5 11.7 8.5 11.7C8.3 11.2 8.2 10.9 7.5 10C6.4 8.3 4.2 6.4 2.7 5.8C2 5.5 1.6 5.4 1.5 5.5ZM28.4 16.7C29.2 16.9 29.7 17.2 29.9 17.7C30.1 18.2 30 18.9 29.6 19.4C29.2 19.9 28.2 20.9 27.6 21.2C26.8 21.7 25.3 22.4 24.2 22.7C23.9 22.8 23.6 22.9 23.5 22.9C22.8 23.2 20.7 23.7 19.6 24C19 24.2 18.4 24.3 18.1 24.4C17.9 24.4 16.1 24.9 15.3 25.1C14.6 25.2 14.7 25.1 15.7 23.6C16.4 22.7 18.5 20.6 19.4 19.9C20.8 18.8 21.4 18.4 23.2 17.6C23.8 17.4 25.6 16.8 25.9 16.8C25.9 16.8 26.3 16.8 26.6 16.7C26.8 16.7 28.2 16.7 28.4 16.7ZM30.4 20.2C30.5 20.3 30.6 20.6 30.6 20.7C31.7 23.1 33.4 24.6 35.6 25.3C36.1 25.5 36.7 25.7 37.2 25.8C37.7 25.8 37.8 25.9 37.8 26.1C37.7 26.2 37.7 26.3 37.7 26.5C37.7 26.6 37.7 26.8 37.6 27C37.4 28.5 36.8 29.9 36.1 31C36.1 31.2 35.9 31.4 35.9 31.6C35.7 31.9 35.2 32.6 34.7 33.3C32.6 35.6 29.7 37.3 26.6 37.8C26.5 37.8 26.3 37.9 26.2 37.9C25.8 37.9 23.7 37.9 23.3 37.9C23.2 37.9 23 37.8 22.9 37.8C21.1 37.6 19.3 36.8 18 35.7C17.7 35.4 17 34.7 16.8 34.5C16.3 33.8 16.1 33 16.3 32.5C16.5 31.8 16.8 31.6 17.9 31.1C19.1 30.5 19.4 30.4 20.2 30C21.4 29.4 23.2 28.4 23.9 27.9C23.9 27.8 24.2 27.7 24.5 27.6C26.3 26.3 28 24.6 28.9 22.9C29.5 22.2 29.7 21.6 29.9 20.7C30.1 20 30.2 19.9 30.4 20.2Z";
|
|
164
|
+
function birdMaskSvg() {
|
|
165
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 44 44" fill="#000"><path fill-rule="evenodd" d="${BIRD_PATH}"/></svg>`;
|
|
166
|
+
}
|
|
167
|
+
function birdMaskUrl(svg = birdMaskSvg()) {
|
|
168
|
+
return `data:image/svg+xml,${encodeURIComponent(svg)}`;
|
|
169
|
+
}
|
|
170
|
+
function isOwnNavRow(rowText, wantedLabel) {
|
|
171
|
+
const wanted = String(wantedLabel ?? "").trim();
|
|
172
|
+
if (wanted.length === 0) return false;
|
|
173
|
+
return String(rowText ?? "").trim() === wanted;
|
|
174
|
+
}
|
|
175
|
+
function navIconCss(maskUrl) {
|
|
176
|
+
return [
|
|
177
|
+
`[${NAV_ICON_MARKER}] > svg { display: none; }`,
|
|
178
|
+
`[${NAV_ICON_MARKER}]::before {`,
|
|
179
|
+
` content: '';`,
|
|
180
|
+
` flex: none;`,
|
|
181
|
+
` width: 18px;`,
|
|
182
|
+
` height: 18px;`,
|
|
183
|
+
` background-color: currentColor;`,
|
|
184
|
+
` -webkit-mask-image: url("${maskUrl}");`,
|
|
185
|
+
` mask-image: url("${maskUrl}");`,
|
|
186
|
+
` -webkit-mask-repeat: no-repeat;`,
|
|
187
|
+
` mask-repeat: no-repeat;`,
|
|
188
|
+
` -webkit-mask-position: center;`,
|
|
189
|
+
` mask-position: center;`,
|
|
190
|
+
` -webkit-mask-size: 18px 18px;`,
|
|
191
|
+
` mask-size: 18px 18px;`,
|
|
192
|
+
`}`
|
|
193
|
+
].join("\n");
|
|
194
|
+
}
|
|
195
|
+
function installSettingsNavIcon(ctx, resolveLabel) {
|
|
196
|
+
if (typeof document === "undefined") return;
|
|
197
|
+
ctx.effect(() => {
|
|
198
|
+
const tag = document.createElement("style");
|
|
199
|
+
tag.dataset.plugin = "dsh-magpie-connect";
|
|
200
|
+
tag.dataset.pluginCss = "dsh-magpie-connect/settings-nav-icon";
|
|
201
|
+
tag.textContent = navIconCss(birdMaskUrl());
|
|
202
|
+
document.head.appendChild(tag);
|
|
203
|
+
let disposed = false;
|
|
204
|
+
let scheduled = false;
|
|
205
|
+
const sync = () => {
|
|
206
|
+
scheduled = false;
|
|
207
|
+
if (disposed) return;
|
|
208
|
+
const wanted = resolveLabel();
|
|
209
|
+
for (const row of Array.from(document.querySelectorAll(NAV_ROW_SELECTOR))) {
|
|
210
|
+
if (isOwnNavRow(row.textContent, wanted)) row.setAttribute(NAV_ICON_MARKER, "");
|
|
211
|
+
else row.removeAttribute(NAV_ICON_MARKER);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
const schedule = () => {
|
|
215
|
+
if (scheduled || disposed) return;
|
|
216
|
+
scheduled = true;
|
|
217
|
+
queueMicrotask(sync);
|
|
218
|
+
};
|
|
219
|
+
sync();
|
|
220
|
+
const observer = new MutationObserver(schedule);
|
|
221
|
+
observer.observe(document.body, { childList: true, subtree: true, characterData: true });
|
|
222
|
+
return () => {
|
|
223
|
+
disposed = true;
|
|
224
|
+
observer.disconnect();
|
|
225
|
+
for (const row of Array.from(document.querySelectorAll(`[${NAV_ICON_MARKER}]`))) row.removeAttribute(NAV_ICON_MARKER);
|
|
226
|
+
tag.remove();
|
|
227
|
+
};
|
|
228
|
+
}, "dsh-magpie-connect: settings nav icon");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// src/client/page.tsx
|
|
232
|
+
var import_react3 = require("react");
|
|
233
|
+
var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
234
|
+
|
|
235
|
+
// src/client/model-list.tsx
|
|
236
|
+
var import_react2 = require("react");
|
|
237
|
+
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
238
|
+
|
|
239
|
+
// src/client/model-visibility.ts
|
|
240
|
+
function initialPicked(candidates, visibleIds) {
|
|
241
|
+
return new Set(candidates.filter((candidate) => visibleIds.has(candidate.id)).map((candidate) => candidate.id));
|
|
242
|
+
}
|
|
243
|
+
function hiddenAfterAdopt(candidates, picked) {
|
|
244
|
+
return candidates.filter((candidate) => !picked.has(candidate.id)).map((candidate) => candidate.id);
|
|
245
|
+
}
|
|
246
|
+
function hideOne(hidden, id) {
|
|
247
|
+
return hidden.includes(id) ? [...hidden] : [...hidden, id];
|
|
248
|
+
}
|
|
249
|
+
function toggleAllPicked(current, visible) {
|
|
250
|
+
const next = new Set(current);
|
|
251
|
+
if (visible.length > 0 && visible.every((candidate) => current.has(candidate.id))) {
|
|
252
|
+
for (const candidate of visible) next.delete(candidate.id);
|
|
253
|
+
return next;
|
|
254
|
+
}
|
|
255
|
+
for (const candidate of visible) next.add(candidate.id);
|
|
256
|
+
return next;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// src/client/model-list.tsx
|
|
260
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
261
|
+
var css = {
|
|
262
|
+
card: { display: "flex", flexDirection: "column", gap: 14, padding: 18, border: "1px solid var(--dsw-alias-border-l2)", borderRadius: 12, background: "var(--dsw-alias-bg-layer-1)" },
|
|
263
|
+
head: { display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 12 },
|
|
264
|
+
heading: { display: "flex", flexDirection: "column", gap: 2 },
|
|
265
|
+
cardTitle: { margin: 0, fontSize: 15, lineHeight: "22px", fontWeight: 600, color: "var(--dsw-alias-label-primary)" },
|
|
266
|
+
meta: { margin: 0, fontSize: 12, lineHeight: "18px", color: "var(--dsw-alias-label-tertiary)" },
|
|
267
|
+
linkButton: { border: "none", background: "transparent", color: "var(--dsw-alias-brand-primary)", cursor: "pointer", padding: "2px 6px", borderRadius: 6, fontSize: 12, lineHeight: "18px", flex: "none" },
|
|
268
|
+
row: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" },
|
|
269
|
+
hint: { margin: 0, fontSize: 13, lineHeight: "20px", color: "var(--dsw-alias-label-tertiary)" },
|
|
270
|
+
error: { margin: 0, whiteSpace: "pre-wrap", color: "var(--dsw-alias-label-error, var(--dsw-alias-state-danger-label))" },
|
|
271
|
+
ok: { margin: 0, fontSize: 13, lineHeight: "20px", color: "var(--dsw-alias-state-success-label, var(--dsw-alias-label-primary))" },
|
|
272
|
+
list: { display: "flex", flexDirection: "column", gap: 4, maxHeight: 420, overflowY: "auto", paddingRight: 4 },
|
|
273
|
+
empty: { margin: 0, fontSize: 13, lineHeight: "20px", color: "var(--dsw-alias-label-tertiary)", textAlign: "center", padding: "12px 0" },
|
|
274
|
+
item: { display: "flex", alignItems: "center", gap: 10, padding: "8px 10px", borderRadius: 8, background: "transparent" },
|
|
275
|
+
removeButton: { border: "1px solid var(--dsw-alias-border-l2)", background: "transparent", color: "var(--dsw-alias-label-secondary)", cursor: "pointer", padding: "3px 10px", borderRadius: 6, fontSize: 12, lineHeight: "18px", flex: "none" },
|
|
276
|
+
itemMain: { display: "flex", flexDirection: "column", gap: 2, minWidth: 0, flex: 1 },
|
|
277
|
+
itemId: { fontSize: 13, lineHeight: "20px", fontWeight: 500, color: "var(--dsw-alias-label-primary)", overflowWrap: "anywhere", fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" },
|
|
278
|
+
chips: { display: "flex", gap: 6, flexWrap: "wrap" },
|
|
279
|
+
chip: { fontSize: 11, lineHeight: "18px", padding: "0 7px", borderRadius: 999, border: "1px solid var(--dsw-alias-border-l2)", color: "var(--dsw-alias-label-secondary)", whiteSpace: "nowrap" },
|
|
280
|
+
candidateToolbar: { display: "flex", alignItems: "center", gap: 8, marginBottom: 6 },
|
|
281
|
+
candidateSearch: { flex: 1, minWidth: 0 },
|
|
282
|
+
candidateList: { display: "flex", flexDirection: "column", gap: 2, maxHeight: 320, margin: 0, padding: 0, listStyle: "none", overflowY: "auto" },
|
|
283
|
+
candidate: { borderRadius: 8 },
|
|
284
|
+
// Mirrors the list's `item`: checkbox and a two-line text column (id, then
|
|
285
|
+
// chips) so a candidate reads the same as an enabled row.
|
|
286
|
+
candidateLabel: { display: "flex", alignItems: "center", gap: 10, padding: "8px 10px", cursor: "pointer" },
|
|
287
|
+
candidateCheckbox: { width: 15, height: 15, accentColor: "var(--dsw-alias-brand-primary)", flex: "none", cursor: "pointer" },
|
|
288
|
+
candidateText: { display: "flex", flexDirection: "column", gap: 2, minWidth: 0, flex: 1 },
|
|
289
|
+
candidateId: { fontSize: 13, lineHeight: "20px", fontWeight: 500, color: "var(--dsw-alias-label-primary)", overflowWrap: "anywhere", fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" },
|
|
290
|
+
candidateEmpty: { margin: "24px 0", textAlign: "center", fontSize: 13, lineHeight: "20px", color: "var(--dsw-alias-label-secondary)" }
|
|
291
|
+
};
|
|
292
|
+
function formatWindow(value) {
|
|
293
|
+
if (value === void 0) return "";
|
|
294
|
+
if (value >= 1e6) return `${(value / 1e6).toFixed(value % 1e6 === 0 ? 0 : 1)}M`;
|
|
295
|
+
if (value >= 1e3) return `${Math.round(value / 1e3)}k`;
|
|
296
|
+
return String(value);
|
|
297
|
+
}
|
|
298
|
+
function chipsFor(row) {
|
|
299
|
+
const chips = [];
|
|
300
|
+
if (row.image) chips.push({ key: "image", label: text("image") });
|
|
301
|
+
if (row.responsesOnly) chips.push({ key: "responses", label: text("responses") });
|
|
302
|
+
if (row.reasoning) chips.push({ key: "reasoning", label: `${text("reasoning")} \xB7 ${row.efforts.length}` });
|
|
303
|
+
if (row.contextWindow !== void 0) chips.push({ key: "context", label: text("context", { window: formatWindow(row.contextWindow) }) });
|
|
304
|
+
return chips;
|
|
305
|
+
}
|
|
306
|
+
function ModelListEditor(props) {
|
|
307
|
+
const { models, visibleIds, onFetch, onRemove, onHiddenChange, disabled, fetchable, status } = props;
|
|
308
|
+
const [filter, setFilter] = (0, import_react2.useState)("");
|
|
309
|
+
const [busy, setBusy] = (0, import_react2.useState)(false);
|
|
310
|
+
const [fetchFailure, setFetchFailure] = (0, import_react2.useState)(void 0);
|
|
311
|
+
const [candidates, setCandidates] = (0, import_react2.useState)(void 0);
|
|
312
|
+
const [picked, setPicked] = (0, import_react2.useState)(/* @__PURE__ */ new Set());
|
|
313
|
+
const [candidateQuery, setCandidateQuery] = (0, import_react2.useState)("");
|
|
314
|
+
const enabledRows = (0, import_react2.useMemo)(() => models.filter((row) => visibleIds.has(row.id)), [models, visibleIds]);
|
|
315
|
+
const visibleRows = (0, import_react2.useMemo)(() => {
|
|
316
|
+
const needle = filter.trim().toLowerCase();
|
|
317
|
+
if (needle === "") return enabledRows;
|
|
318
|
+
return enabledRows.filter((row) => row.id.toLowerCase().includes(needle) || row.displayName.toLowerCase().includes(needle));
|
|
319
|
+
}, [enabledRows, filter]);
|
|
320
|
+
const togglePicked = (id) => {
|
|
321
|
+
setPicked((current) => {
|
|
322
|
+
const next = new Set(current);
|
|
323
|
+
if (!next.delete(id)) next.add(id);
|
|
324
|
+
return next;
|
|
325
|
+
});
|
|
326
|
+
};
|
|
327
|
+
const visibleCandidates = (0, import_react2.useMemo)(() => {
|
|
328
|
+
const needle = candidateQuery.trim().toLowerCase();
|
|
329
|
+
if (candidates === void 0) return [];
|
|
330
|
+
if (needle === "") return candidates;
|
|
331
|
+
return candidates.filter(
|
|
332
|
+
(candidate) => candidate.id.toLowerCase().includes(needle) || candidate.displayName.toLowerCase().includes(needle)
|
|
333
|
+
);
|
|
334
|
+
}, [candidates, candidateQuery]);
|
|
335
|
+
const allVisiblePicked = visibleCandidates.length > 0 && visibleCandidates.every((candidate) => picked.has(candidate.id));
|
|
336
|
+
const closePicker = () => {
|
|
337
|
+
setCandidates(void 0);
|
|
338
|
+
setPicked(/* @__PURE__ */ new Set());
|
|
339
|
+
setCandidateQuery("");
|
|
340
|
+
};
|
|
341
|
+
const fetchModels = async () => {
|
|
342
|
+
setBusy(true);
|
|
343
|
+
setFetchFailure(void 0);
|
|
344
|
+
try {
|
|
345
|
+
const found = await onFetch();
|
|
346
|
+
if (found.length === 0) {
|
|
347
|
+
setFetchFailure(text("fetchEmpty"));
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
setCandidateQuery("");
|
|
351
|
+
setCandidates(found);
|
|
352
|
+
setPicked(initialPicked(found, visibleIds));
|
|
353
|
+
} catch (cause) {
|
|
354
|
+
setFetchFailure(cause instanceof Error ? cause.message : String(cause));
|
|
355
|
+
} finally {
|
|
356
|
+
setBusy(false);
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
const adoptPicked = () => {
|
|
360
|
+
if (candidates === void 0) return;
|
|
361
|
+
onHiddenChange(hiddenAfterAdopt(candidates, picked));
|
|
362
|
+
closePicker();
|
|
363
|
+
};
|
|
364
|
+
const working = disabled || busy;
|
|
365
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: css.card, children: [
|
|
366
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: css.head, children: [
|
|
367
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: css.heading, children: [
|
|
368
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: css.cardTitle, children: text("models") }),
|
|
369
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: css.meta, children: text("enabled", { count: enabledRows.length }) })
|
|
370
|
+
] }),
|
|
371
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
372
|
+
"button",
|
|
373
|
+
{
|
|
374
|
+
type: "button",
|
|
375
|
+
style: { ...css.linkButton, ...working || !fetchable ? { opacity: 0.5, cursor: "default" } : {} },
|
|
376
|
+
disabled: working || !fetchable,
|
|
377
|
+
title: fetchable ? void 0 : text("fetchNeedsConfig"),
|
|
378
|
+
onClick: () => void fetchModels(),
|
|
379
|
+
children: busy ? text("fetching") : text("fetchModels")
|
|
380
|
+
}
|
|
381
|
+
)
|
|
382
|
+
] }),
|
|
383
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: css.hint, children: text("saveHint") }),
|
|
384
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
385
|
+
import_dsh_client_ui_primitives.Input,
|
|
386
|
+
{
|
|
387
|
+
value: filter,
|
|
388
|
+
placeholder: text("search"),
|
|
389
|
+
disabled,
|
|
390
|
+
onChange: (event) => setFilter(event.currentTarget.value)
|
|
391
|
+
}
|
|
392
|
+
),
|
|
393
|
+
enabledRows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: css.empty, children: models.length === 0 ? text("fetchEmpty") : text("allHidden") }) : null,
|
|
394
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: css.list, children: visibleRows.map((row) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: css.item, children: [
|
|
395
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: css.itemMain, children: [
|
|
396
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: css.itemId, children: row.id }),
|
|
397
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: css.chips, children: chipsFor(row).map((chip) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: css.chip, children: chip.label }, chip.key)) })
|
|
398
|
+
] }),
|
|
399
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
400
|
+
"button",
|
|
401
|
+
{
|
|
402
|
+
type: "button",
|
|
403
|
+
style: { ...css.removeButton, ...disabled ? { opacity: 0.5, cursor: "default" } : {} },
|
|
404
|
+
disabled,
|
|
405
|
+
title: text("removeHint"),
|
|
406
|
+
"aria-label": `${text("remove")} ${row.id}`,
|
|
407
|
+
onClick: () => onRemove(row.id),
|
|
408
|
+
children: text("remove")
|
|
409
|
+
}
|
|
410
|
+
)
|
|
411
|
+
] }, row.id)) }),
|
|
412
|
+
fetchFailure === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", style: css.error, children: fetchFailure }),
|
|
413
|
+
status === "saving" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: css.hint, children: text("savingModels") }) : null,
|
|
414
|
+
status === "saved" ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: css.ok, children: text("modelsSaved") }) : null,
|
|
415
|
+
status === "error" && props.failure !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { role: "alert", style: css.error, children: props.failure }) : null,
|
|
416
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
417
|
+
import_dsh_client_ui_primitives.Modal,
|
|
418
|
+
{
|
|
419
|
+
open: candidates !== void 0,
|
|
420
|
+
onClose: closePicker,
|
|
421
|
+
title: text("fetchTitle"),
|
|
422
|
+
closeLabel: text("close"),
|
|
423
|
+
description: text("fetchDescription"),
|
|
424
|
+
footer: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
425
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "outline", onClick: closePicker, children: text("cancel") }),
|
|
426
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "primary", onClick: adoptPicked, children: text("fetchAdopt") })
|
|
427
|
+
] }),
|
|
428
|
+
children: [
|
|
429
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: css.candidateToolbar, children: [
|
|
430
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
431
|
+
import_dsh_client_ui_primitives.Input,
|
|
432
|
+
{
|
|
433
|
+
type: "search",
|
|
434
|
+
value: candidateQuery,
|
|
435
|
+
placeholder: text("fetchSearch"),
|
|
436
|
+
"aria-label": text("fetchSearch"),
|
|
437
|
+
onChange: (event) => setCandidateQuery(event.currentTarget.value),
|
|
438
|
+
style: css.candidateSearch
|
|
439
|
+
}
|
|
440
|
+
),
|
|
441
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_dsh_client_ui_primitives.Button, { variant: "ghost", size: "sm", disabled: visibleCandidates.length === 0, onClick: () => setPicked((current) => toggleAllPicked(current, visibleCandidates)), children: allVisiblePicked ? text("fetchDeselectAll") : text("fetchSelectAll") })
|
|
442
|
+
] }),
|
|
443
|
+
visibleCandidates.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: css.candidateEmpty, role: "status", children: text("fetchNoMatches") }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { style: css.candidateList, children: visibleCandidates.map((candidate) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("li", { style: css.candidate, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: css.candidateLabel, children: [
|
|
444
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
445
|
+
"input",
|
|
446
|
+
{
|
|
447
|
+
type: "checkbox",
|
|
448
|
+
style: css.candidateCheckbox,
|
|
449
|
+
checked: picked.has(candidate.id),
|
|
450
|
+
onChange: () => togglePicked(candidate.id)
|
|
451
|
+
}
|
|
452
|
+
),
|
|
453
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: css.candidateText, children: [
|
|
454
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: css.candidateId, title: candidate.id, children: candidate.id }),
|
|
455
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: css.chips, children: chipsFor(candidate).map((chip) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: css.chip, children: chip.label }, chip.key)) })
|
|
456
|
+
] })
|
|
457
|
+
] }) }, candidate.id)) })
|
|
458
|
+
]
|
|
459
|
+
}
|
|
460
|
+
)
|
|
461
|
+
] });
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// src/client/write-queue.ts
|
|
465
|
+
function createWriteQueue(write, onSettled) {
|
|
466
|
+
let inFlight;
|
|
467
|
+
let queued;
|
|
468
|
+
let idleWaiters = [];
|
|
469
|
+
const settleIdle = () => {
|
|
470
|
+
if (inFlight !== void 0 || queued !== void 0) return;
|
|
471
|
+
const waiters = idleWaiters;
|
|
472
|
+
idleWaiters = [];
|
|
473
|
+
for (const waiter of waiters) waiter();
|
|
474
|
+
};
|
|
475
|
+
const drain = () => {
|
|
476
|
+
const next = queued;
|
|
477
|
+
queued = void 0;
|
|
478
|
+
if (next === void 0) {
|
|
479
|
+
settleIdle();
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
const run = write(next.value);
|
|
483
|
+
inFlight = run.then(
|
|
484
|
+
() => {
|
|
485
|
+
inFlight = void 0;
|
|
486
|
+
onSettled?.({ ok: true });
|
|
487
|
+
drain();
|
|
488
|
+
},
|
|
489
|
+
(error) => {
|
|
490
|
+
inFlight = void 0;
|
|
491
|
+
onSettled?.({ ok: false, error });
|
|
492
|
+
drain();
|
|
493
|
+
}
|
|
494
|
+
);
|
|
495
|
+
};
|
|
496
|
+
return {
|
|
497
|
+
push(value) {
|
|
498
|
+
queued = { value };
|
|
499
|
+
if (inFlight === void 0) drain();
|
|
500
|
+
},
|
|
501
|
+
idle() {
|
|
502
|
+
if (inFlight === void 0 && queued === void 0) return Promise.resolve();
|
|
503
|
+
return new Promise((resolve) => {
|
|
504
|
+
idleWaiters.push(resolve);
|
|
505
|
+
});
|
|
506
|
+
},
|
|
507
|
+
pending() {
|
|
508
|
+
return inFlight !== void 0 || queued !== void 0;
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// src/client/page.tsx
|
|
514
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
515
|
+
var PLUGIN_VERSION = "0.2.0";
|
|
516
|
+
var css2 = {
|
|
517
|
+
section: { display: "flex", flexDirection: "column", gap: 16, maxWidth: 780, paddingBottom: 32 },
|
|
518
|
+
title: { margin: 0, fontSize: 22, lineHeight: "30px", fontWeight: 600, color: "var(--dsw-alias-label-primary)" },
|
|
519
|
+
intro: { margin: 0, fontSize: 14, lineHeight: "22px", color: "var(--dsw-alias-label-secondary)" },
|
|
520
|
+
card: { display: "flex", flexDirection: "column", gap: 14, padding: 18, border: "1px solid var(--dsw-alias-border-l2)", borderRadius: 12, background: "var(--dsw-alias-bg-layer-1)" },
|
|
521
|
+
cardTitle: { margin: 0, fontSize: 15, lineHeight: "22px", fontWeight: 600, color: "var(--dsw-alias-label-primary)" },
|
|
522
|
+
row: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" },
|
|
523
|
+
field: { display: "flex", flexDirection: "column", gap: 8 },
|
|
524
|
+
label: { fontSize: 13, fontWeight: 500, color: "var(--dsw-alias-label-secondary)" },
|
|
525
|
+
hint: { margin: 0, fontSize: 13, lineHeight: "20px", color: "var(--dsw-alias-label-tertiary)" },
|
|
526
|
+
error: { margin: 0, whiteSpace: "pre-wrap", color: "var(--dsw-alias-label-error, var(--dsw-alias-state-danger-label))" },
|
|
527
|
+
ok: { margin: 0, fontSize: 13, lineHeight: "20px", color: "var(--dsw-alias-state-success-label, var(--dsw-alias-label-primary))" }
|
|
528
|
+
};
|
|
529
|
+
var REQUEST_TIMEOUT_MS = 3e4;
|
|
530
|
+
async function request(path, method = "GET", body) {
|
|
531
|
+
const controller = new AbortController();
|
|
532
|
+
const timer = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
|
|
533
|
+
let response;
|
|
534
|
+
try {
|
|
535
|
+
response = await fetch(path, {
|
|
536
|
+
method,
|
|
537
|
+
headers: { accept: "application/json", ...body !== void 0 ? { "content-type": "application/json" } : {} },
|
|
538
|
+
cache: "no-store",
|
|
539
|
+
signal: controller.signal,
|
|
540
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
541
|
+
});
|
|
542
|
+
} catch (cause) {
|
|
543
|
+
throw new Error(cause instanceof Error && cause.name === "AbortError" ? text("requestTimeout") : String(cause));
|
|
544
|
+
} finally {
|
|
545
|
+
clearTimeout(timer);
|
|
546
|
+
}
|
|
547
|
+
let payload;
|
|
548
|
+
try {
|
|
549
|
+
payload = await response.json();
|
|
550
|
+
} catch {
|
|
551
|
+
throw new Error(text("requestFailed", { status: response.status }));
|
|
552
|
+
}
|
|
553
|
+
if (!response.ok || payload?.ok !== true) {
|
|
554
|
+
throw new Error(typeof payload?.error === "string" ? payload.error : text("requestFailed", { status: response.status }));
|
|
555
|
+
}
|
|
556
|
+
return payload.value;
|
|
557
|
+
}
|
|
558
|
+
async function saveHiddenModels(hidden) {
|
|
559
|
+
await request("/api/magpie-settings", "POST", { hiddenModels: hidden });
|
|
560
|
+
}
|
|
561
|
+
function MagpieSettings() {
|
|
562
|
+
useLocaleRevision();
|
|
563
|
+
const [baseUrl, setBaseUrl] = (0, import_react3.useState)("");
|
|
564
|
+
const [apiKey, setApiKey] = (0, import_react3.useState)("");
|
|
565
|
+
const [hidden, setHidden] = (0, import_react3.useState)([]);
|
|
566
|
+
const [models, setModels] = (0, import_react3.useState)([]);
|
|
567
|
+
const [busy, setBusy] = (0, import_react3.useState)("idle");
|
|
568
|
+
const [error, setError] = (0, import_react3.useState)(void 0);
|
|
569
|
+
const [notice, setNotice] = (0, import_react3.useState)(void 0);
|
|
570
|
+
const [modelsStatus, setModelsStatus] = (0, import_react3.useState)("idle");
|
|
571
|
+
const [modelsError, setModelsError] = (0, import_react3.useState)(void 0);
|
|
572
|
+
const [loaded, setLoaded] = (0, import_react3.useState)(false);
|
|
573
|
+
const modelsQueue = (0, import_react3.useRef)(
|
|
574
|
+
createWriteQueue((next) => saveHiddenModels(next), (outcome) => {
|
|
575
|
+
if (outcome.ok) {
|
|
576
|
+
setModelsStatus("saved");
|
|
577
|
+
setModelsError(void 0);
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
setModelsStatus("error");
|
|
581
|
+
setModelsError(outcome.error instanceof Error ? outcome.error.message : String(outcome.error));
|
|
582
|
+
})
|
|
583
|
+
).current;
|
|
584
|
+
(0, import_react3.useEffect)(() => {
|
|
585
|
+
let alive = true;
|
|
586
|
+
Promise.all([request("/api/magpie-settings"), request("/api/magpie-models")]).then(
|
|
587
|
+
([settingsValue, modelsValue]) => {
|
|
588
|
+
if (!alive) return;
|
|
589
|
+
const settings = settingsValue;
|
|
590
|
+
const listed = modelsValue.models ?? [];
|
|
591
|
+
setBaseUrl(settings.baseUrl ?? "");
|
|
592
|
+
setApiKey(settings.apiKey ?? "");
|
|
593
|
+
setHidden(settings.hiddenModels ?? []);
|
|
594
|
+
setModels(listed);
|
|
595
|
+
setLoaded(true);
|
|
596
|
+
},
|
|
597
|
+
(cause) => {
|
|
598
|
+
if (!alive) return;
|
|
599
|
+
setError(text("loadFailed", { message: cause instanceof Error ? cause.message : String(cause) }));
|
|
600
|
+
setLoaded(true);
|
|
601
|
+
}
|
|
602
|
+
);
|
|
603
|
+
return () => {
|
|
604
|
+
alive = false;
|
|
605
|
+
};
|
|
606
|
+
}, []);
|
|
607
|
+
const hiddenSet = (0, import_react3.useMemo)(() => new Set(hidden), [hidden]);
|
|
608
|
+
const visibleIds = (0, import_react3.useMemo)(() => new Set(models.filter((row) => !hiddenSet.has(row.id)).map((row) => row.id)), [models, hiddenSet]);
|
|
609
|
+
const fetchCandidates = async () => {
|
|
610
|
+
const result = await request("/api/magpie-discover", "POST", { baseUrl, apiKey });
|
|
611
|
+
return result.models ?? [];
|
|
612
|
+
};
|
|
613
|
+
const applyHidden = (next) => {
|
|
614
|
+
setHidden(next);
|
|
615
|
+
setNotice(void 0);
|
|
616
|
+
setModelsStatus("saving");
|
|
617
|
+
setModelsError(void 0);
|
|
618
|
+
modelsQueue.push(next);
|
|
619
|
+
};
|
|
620
|
+
const save = async () => {
|
|
621
|
+
setBusy("saving");
|
|
622
|
+
setError(void 0);
|
|
623
|
+
setNotice(void 0);
|
|
624
|
+
try {
|
|
625
|
+
const saved = await request("/api/magpie-settings", "POST", { baseUrl, apiKey, hiddenModels: hidden });
|
|
626
|
+
setBaseUrl(saved.baseUrl);
|
|
627
|
+
setApiKey(saved.apiKey);
|
|
628
|
+
setHidden(saved.hiddenModels ?? []);
|
|
629
|
+
const modelsValue = await request("/api/magpie-models");
|
|
630
|
+
setModels(modelsValue.models ?? []);
|
|
631
|
+
setNotice(text("saved"));
|
|
632
|
+
} catch (cause) {
|
|
633
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
634
|
+
} finally {
|
|
635
|
+
setBusy("idle");
|
|
636
|
+
}
|
|
637
|
+
};
|
|
638
|
+
const testConnection = async () => {
|
|
639
|
+
setBusy("testing");
|
|
640
|
+
setError(void 0);
|
|
641
|
+
setNotice(void 0);
|
|
642
|
+
try {
|
|
643
|
+
const result = await request("/api/magpie-test", "POST", { baseUrl, apiKey });
|
|
644
|
+
setNotice(text("testOk", { count: result.count }));
|
|
645
|
+
} catch (cause) {
|
|
646
|
+
setError(cause instanceof Error ? cause.message : String(cause));
|
|
647
|
+
} finally {
|
|
648
|
+
setBusy("idle");
|
|
649
|
+
}
|
|
650
|
+
};
|
|
651
|
+
const working = busy !== "idle";
|
|
652
|
+
const incomplete = baseUrl.trim() === "" || apiKey.trim() === "";
|
|
653
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { style: css2.section, children: [
|
|
654
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: css2.title, children: text("title") }),
|
|
655
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: css2.intro, children: text("intro") }),
|
|
656
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: css2.card, children: [
|
|
657
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: css2.cardTitle, children: text("connection") }),
|
|
658
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: css2.hint, children: text("requiredNote") }),
|
|
659
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: css2.field, children: [
|
|
660
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: css2.label, children: text("baseUrl") }),
|
|
661
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Input, { value: baseUrl, placeholder: text("baseUrlPlaceholder"), disabled: working, onChange: (event) => setBaseUrl(event.currentTarget.value) })
|
|
662
|
+
] }),
|
|
663
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: css2.field, children: [
|
|
664
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: css2.label, children: text("apiKey") }),
|
|
665
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Input, { type: "password", value: apiKey, placeholder: text("apiKeyPlaceholder"), disabled: working, onChange: (event) => setApiKey(event.currentTarget.value) })
|
|
666
|
+
] }),
|
|
667
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: css2.row, children: [
|
|
668
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "primary", disabled: working || incomplete, onClick: () => void save(), children: busy === "saving" ? text("saving") : text("save") }),
|
|
669
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_dsh_client_ui_primitives2.Button, { variant: "outline", disabled: working || incomplete, onClick: () => void testConnection(), children: busy === "testing" ? text("testing") : text("test") })
|
|
670
|
+
] }),
|
|
671
|
+
error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { role: "alert", style: css2.error, children: error }),
|
|
672
|
+
notice === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: css2.ok, children: notice }),
|
|
673
|
+
loaded && incomplete ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: css2.hint, children: text("notConfigured") }) : null
|
|
674
|
+
] }),
|
|
675
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
676
|
+
ModelListEditor,
|
|
677
|
+
{
|
|
678
|
+
models,
|
|
679
|
+
visibleIds,
|
|
680
|
+
onFetch: fetchCandidates,
|
|
681
|
+
onRemove: (id) => applyHidden(hideOne(hidden, id)),
|
|
682
|
+
onHiddenChange: applyHidden,
|
|
683
|
+
disabled: !loaded || working,
|
|
684
|
+
fetchable: !incomplete,
|
|
685
|
+
status: modelsStatus,
|
|
686
|
+
failure: modelsError
|
|
687
|
+
}
|
|
688
|
+
),
|
|
689
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { style: css2.hint, children: [
|
|
690
|
+
text("pluginVersion"),
|
|
691
|
+
" dsh-magpie-connect v",
|
|
692
|
+
PLUGIN_VERSION
|
|
693
|
+
] })
|
|
694
|
+
] });
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
// src/client/index.ts
|
|
698
|
+
function registerDictionaries(ctx) {
|
|
699
|
+
try {
|
|
700
|
+
ctx.locale.register(NS, { zh: ZH, en: EN });
|
|
701
|
+
return;
|
|
702
|
+
} catch {
|
|
703
|
+
}
|
|
704
|
+
try {
|
|
705
|
+
ctx.locale.register(NS, "zh", ZH);
|
|
706
|
+
ctx.locale.register(NS, "en", EN);
|
|
707
|
+
} catch {
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
function apply(ctx) {
|
|
711
|
+
setLocaleRuntime(ctx.locale);
|
|
712
|
+
try {
|
|
713
|
+
ctx.effect(
|
|
714
|
+
() => {
|
|
715
|
+
registerDictionaries(ctx);
|
|
716
|
+
return () => {
|
|
717
|
+
setLocaleRuntime(void 0);
|
|
718
|
+
};
|
|
719
|
+
},
|
|
720
|
+
"dsh-magpie-connect: locale dictionaries"
|
|
721
|
+
);
|
|
722
|
+
} catch {
|
|
723
|
+
registerDictionaries(ctx);
|
|
724
|
+
}
|
|
725
|
+
ctx.slots.inject(
|
|
726
|
+
"settings.section",
|
|
727
|
+
() => ctx.slots.register(
|
|
728
|
+
{
|
|
729
|
+
name: "settings.section",
|
|
730
|
+
id: "dsh-magpie-connect",
|
|
731
|
+
order: 12,
|
|
732
|
+
locale: NS,
|
|
733
|
+
label: () => text("nav")
|
|
734
|
+
},
|
|
735
|
+
MagpieSettings
|
|
736
|
+
)
|
|
737
|
+
);
|
|
738
|
+
installSettingsNavIcon(ctx, () => text("nav"));
|
|
739
|
+
}
|
|
740
|
+
var inject = ["slots", "locale"];
|
|
741
|
+
|
|
742
|
+
return module.exports;
|
|
743
|
+
}
|
|
744
|
+
});
|